Compare commits
2566 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fef921132c | ||
|
|
e52a93f8ac | ||
|
|
cd541f335a | ||
|
|
255b8be8cc | ||
|
|
8cd7f064ad | ||
|
|
58ae4117c9 | ||
|
|
cfa1e805bd | ||
|
|
ccedacec8c | ||
|
|
17578dc8cc | ||
|
|
76298bc26a | ||
|
|
7c84ce666e | ||
|
|
a02a7c67cb | ||
|
|
2bb913b898 | ||
|
|
94a8bb57dd | ||
|
|
f06852b5c2 | ||
|
|
fb14d26015 | ||
|
|
6a53c8eaca | ||
|
|
4a98874431 | ||
|
|
baf60502c6 | ||
|
|
2a01b78b32 | ||
|
|
b02e4efe4d | ||
|
|
3c8f6d2831 | ||
|
|
95b443af16 | ||
|
|
b54766d2b4 | ||
|
|
25929d6188 | ||
|
|
4398c962e7 | ||
|
|
fe8919c540 | ||
|
|
bdaeef856d | ||
|
|
57ad7696be | ||
|
|
7c58c83ee0 | ||
|
|
dd7aaa30ca | ||
|
|
76f95945fc | ||
|
|
869836ba79 | ||
|
|
2358552c27 | ||
|
|
e22ea5e189 | ||
|
|
496fefdd01 | ||
|
|
26f85050c1 | ||
|
|
d478b5bc6a | ||
|
|
c8337e529e | ||
|
|
f0995297cf | ||
|
|
b395df0f56 | ||
|
|
69a6cc6656 | ||
|
|
bf73216a76 | ||
|
|
621860718b | ||
|
|
c34c5da277 | ||
|
|
8dcabba31b | ||
|
|
294064f11f | ||
|
|
d125229312 | ||
|
|
11c1e23a91 | ||
|
|
82bc2e1fe4 | ||
|
|
92a00f591d | ||
|
|
04716a7fde | ||
|
|
b6155080b2 | ||
|
|
0a61de4a09 | ||
|
|
7121da100a | ||
|
|
7bee969ebf | ||
|
|
4a0a534796 | ||
|
|
a0041d9062 | ||
|
|
3dd768bb9b | ||
|
|
2a307a681f | ||
|
|
dd1211d021 | ||
|
|
09a600d68a | ||
|
|
7c25b46513 | ||
|
|
dc42486de8 | ||
|
|
36411faf43 | ||
|
|
a9cd565d65 | ||
|
|
0adbb0ad16 | ||
|
|
db31f77d63 | ||
|
|
c275afef28 | ||
|
|
4bad4f3067 | ||
|
|
d2048c037a | ||
|
|
2a39717893 | ||
|
|
49c2ae0e77 | ||
|
|
869c18f150 | ||
|
|
d79cb5ca98 | ||
|
|
acc6390312 | ||
|
|
2e59fbbccc | ||
|
|
bec0037797 | ||
|
|
d08c7ddb58 | ||
|
|
696681fefa | ||
|
|
5f9faf7a32 | ||
|
|
f160503aaf | ||
|
|
b1e9f75a28 | ||
|
|
91da98353d | ||
|
|
bc86ceb707 | ||
|
|
0baf316e5f | ||
|
|
082605f9d3 | ||
|
|
0fdd7d7a3a | ||
|
|
eee59e6af9 | ||
|
|
223a8628e3 | ||
|
|
c0bb603210 | ||
|
|
2981d8746a | ||
|
|
c06280894b | ||
|
|
2f2bdcac4d | ||
|
|
2739964a1f | ||
|
|
c3a2a44830 | ||
|
|
37a2c3b76c | ||
|
|
146a7b2aa3 | ||
|
|
7e093c951f | ||
|
|
4901188409 | ||
|
|
15d78f80a6 | ||
|
|
d61dff45c1 | ||
|
|
34abddfbbd | ||
|
|
238ebe4e8f | ||
|
|
502accabbc | ||
|
|
9d1df1dae4 | ||
|
|
a39cfb9e99 | ||
|
|
27d0e5f55e | ||
|
|
a0e5d2c495 | ||
|
|
d2c89d2a40 | ||
|
|
54f66c9094 | ||
|
|
10be00b352 | ||
|
|
9032051bf7 | ||
|
|
2d2e4c784e | ||
|
|
0d4674d8e2 | ||
|
|
ac06ad35c1 | ||
|
|
27e492d750 | ||
|
|
f8281f2a37 | ||
|
|
9fc717fa6e | ||
|
|
4a0f2f3fe9 | ||
|
|
ebdd4118fd | ||
|
|
54ae48936f | ||
|
|
3c9045a3a8 | ||
|
|
f80f179499 | ||
|
|
69c6ee0675 | ||
|
|
4e28d96bef | ||
|
|
6552cc4599 | ||
|
|
75b10cfa09 | ||
|
|
dc394f62c6 | ||
|
|
ea6d6662b4 | ||
|
|
de3ecbdd28 | ||
|
|
e5c6559836 | ||
|
|
0d422236d6 | ||
|
|
199b065fe3 | ||
|
|
c46e107107 | ||
|
|
a3f66387b2 | ||
|
|
33383bd0c3 | ||
|
|
35b8d95671 | ||
|
|
6e254fb39d | ||
|
|
f50a03dcb4 | ||
|
|
71554b2c19 | ||
|
|
e7762980ec | ||
|
|
c62099969e | ||
|
|
c45ee64800 | ||
|
|
b53c243ef7 | ||
|
|
9ee084fc40 | ||
|
|
9c969fb6ac | ||
|
|
6a8a9c4b31 | ||
|
|
bc0233e34b | ||
|
|
afd91b4e5a | ||
|
|
50349dc2af | ||
|
|
4b10981d75 | ||
|
|
b16cefd534 | ||
|
|
46d6625467 | ||
|
|
a1a8e134d2 | ||
|
|
0b6bbcc6a3 | ||
|
|
5fac237153 | ||
|
|
d2cc1c880c | ||
|
|
ac18ad5823 | ||
|
|
9ac5f6d046 | ||
|
|
08adb29d91 | ||
|
|
1721d07746 | ||
|
|
9401d560b0 | ||
|
|
7eae8523cb | ||
|
|
45b5eeeaa0 | ||
|
|
12b436e5b8 | ||
|
|
534dc7e7b7 | ||
|
|
5dfac37dac | ||
|
|
f17a4e7f8e | ||
|
|
4b586efe66 | ||
|
|
db6dc1e21b | ||
|
|
da11771dab | ||
|
|
475e3a70b0 | ||
|
|
5255afc80d | ||
|
|
7a3f59cc5d | ||
|
|
9470133e33 | ||
|
|
5ab0f9e4c0 | ||
|
|
ef91cd5375 | ||
|
|
cd9553ca10 | ||
|
|
8b27a846a6 | ||
|
|
9d961ad8aa | ||
|
|
0952f3ce03 | ||
|
|
ab33111192 | ||
|
|
9a457c5aca | ||
|
|
4f1c86c52e | ||
|
|
c605e3b5a1 | ||
|
|
5a8c9b8a95 | ||
|
|
2b8e9cab18 | ||
|
|
c3dec4b04e | ||
|
|
699aa5cd96 | ||
|
|
fea0210b6e | ||
|
|
cf12765738 | ||
|
|
17f47fbc92 | ||
|
|
1e36b6c4b6 | ||
|
|
28692fc142 | ||
|
|
6eff5a88f6 | ||
|
|
5742100973 | ||
|
|
c52eea7db7 | ||
|
|
2f59f5a8fa | ||
|
|
e77fe56e8f | ||
|
|
eea1e7b1f8 | ||
|
|
b0fbccdf10 | ||
|
|
4f3faef153 | ||
|
|
3ae3c82fbb | ||
|
|
1063fbccbe | ||
|
|
b9e60c679a | ||
|
|
88fd79069b | ||
|
|
ab859f7fa7 | ||
|
|
cc4d4dfc2b | ||
|
|
bd62e817dc | ||
|
|
de34a109e1 | ||
|
|
e0e45719fa | ||
|
|
b21b254258 | ||
|
|
ca3ef33f46 | ||
|
|
8c4803d906 | ||
|
|
ffb9e4b0eb | ||
|
|
6010dbc368 | ||
|
|
a6343bd152 | ||
|
|
9e4a7f48a4 | ||
|
|
6ad7424d4a | ||
|
|
218fa1ba35 | ||
|
|
b45db747a8 | ||
|
|
eedecc07fd | ||
|
|
dcea36de7a | ||
|
|
ed0e3f4435 | ||
|
|
8595e4bd99 | ||
|
|
e31b81294d | ||
|
|
ac6e9cf2f0 | ||
|
|
dac4ae94c0 | ||
|
|
b31b585805 | ||
|
|
1368c56655 | ||
|
|
6cab12a14f | ||
|
|
924a09a9c5 | ||
|
|
e4f6293f42 | ||
|
|
f197b32b02 | ||
|
|
b80ab36418 | ||
|
|
d5588333f7 | ||
|
|
10755275ea | ||
|
|
a30cecdf36 | ||
|
|
0068afa06c | ||
|
|
38597a6499 | ||
|
|
65ee240e8e | ||
|
|
336bcf4d11 | ||
|
|
ed74a4c213 | ||
|
|
3e29617da8 | ||
|
|
715b3e450f | ||
|
|
1ab10f3b28 | ||
|
|
304d8a80be | ||
|
|
560a3f664e | ||
|
|
41081204f9 | ||
|
|
b895dfc901 | ||
|
|
93a1d65103 | ||
|
|
443d53400d | ||
|
|
9725582089 | ||
|
|
cd2634a5d4 | ||
|
|
798d1a4f9e | ||
|
|
e13996f68a | ||
|
|
1ee077d511 | ||
|
|
ccf301c73d | ||
|
|
461fe715b7 | ||
|
|
9549bb4f4d | ||
|
|
0215722103 | ||
|
|
7c6606f27e | ||
|
|
f0b10965fb | ||
|
|
53f2bb7701 | ||
|
|
945e61d668 | ||
|
|
e74c4bb684 | ||
|
|
a8eebcb0e2 | ||
|
|
1581aa1cf5 | ||
|
|
839a2cc86d | ||
|
|
3062114f0c | ||
|
|
ab3abf23ed | ||
|
|
b5a7812ab4 | ||
|
|
565de36155 | ||
|
|
c76f078834 | ||
|
|
358a9742c5 | ||
|
|
7f9e200cfb | ||
|
|
a12710af70 | ||
|
|
871234ec76 | ||
|
|
0c062cc351 | ||
|
|
67271e4672 | ||
|
|
2489a95dab | ||
|
|
70b8bd27b8 | ||
|
|
ee88cf16d1 | ||
|
|
d83e818517 | ||
|
|
6462ceb1f5 | ||
|
|
e2f8ea110a | ||
|
|
f1acbbedf9 | ||
|
|
8510f535a5 | ||
|
|
9a97a57423 | ||
|
|
a50cc628ec | ||
|
|
dc922c9e4c | ||
|
|
2f2b0cf98a | ||
|
|
798d5eeb86 | ||
|
|
02d8cefcde | ||
|
|
f627593d63 | ||
|
|
9aeddc2cb1 | ||
|
|
6650071d24 | ||
|
|
006822c7fc | ||
|
|
8bed15e469 | ||
|
|
4200bb9ebb | ||
|
|
fdae346aa6 | ||
|
|
01acb15fab | ||
|
|
3a6764a685 | ||
|
|
e2e8a575c6 | ||
|
|
7205fb63fa | ||
|
|
c7b59fdc14 | ||
|
|
e9a59bb014 | ||
|
|
76ba063f29 | ||
|
|
2988a74fe4 | ||
|
|
72bc9e3973 | ||
|
|
31fb2bc2c3 | ||
|
|
768f8cd74c | ||
|
|
751e044ce2 | ||
|
|
3406250cf6 | ||
|
|
e510bdf4f2 | ||
|
|
fccdff05e3 | ||
|
|
e530b3d6f6 | ||
|
|
0f0b70be23 | ||
|
|
e39f235287 | ||
|
|
af5acb8d32 | ||
|
|
a2f70cb5e4 | ||
|
|
25d10f03bb | ||
|
|
85c1ad060f | ||
|
|
d9b1cc0db3 | ||
|
|
34205014e9 | ||
|
|
749106aa47 | ||
|
|
b828e0295a | ||
|
|
2345002c1c | ||
|
|
2ce18a47b4 | ||
|
|
76b380d7c0 | ||
|
|
d3244ab4da | ||
|
|
d06ccfb8e3 | ||
|
|
6f807d6f9e | ||
|
|
2b0045e23e | ||
|
|
57067bc362 | ||
|
|
abe185c003 | ||
|
|
85ca2f3562 | ||
|
|
3d03b01439 | ||
|
|
879e7d775f | ||
|
|
e9dbd10db4 | ||
|
|
acc95bd9b7 | ||
|
|
504c7b5d6d | ||
|
|
b20ab29d82 | ||
|
|
95b16a0b04 | ||
|
|
6ee64d1dc2 | ||
|
|
83ecd2d1d9 | ||
|
|
325a5dd353 | ||
|
|
e0ee35da61 | ||
|
|
b3fde98020 | ||
|
|
3c7c21cea3 | ||
|
|
c73d6c52bf | ||
|
|
c38c1454b4 | ||
|
|
06d1d23273 | ||
|
|
4081b46302 | ||
|
|
914bf49656 | ||
|
|
dc634c61c4 | ||
|
|
566878b29c | ||
|
|
0060479e33 | ||
|
|
1a0d892201 | ||
|
|
0424b63bf1 | ||
|
|
de9d3c04e2 | ||
|
|
b0e4a853cf | ||
|
|
ac8dfe29ae | ||
|
|
9d33a38ec4 | ||
|
|
e3076fa5d1 | ||
|
|
2067b2aea6 | ||
|
|
a14af95f9d | ||
|
|
8fd2ce8d47 | ||
|
|
d6edc64d65 | ||
|
|
f882158387 | ||
|
|
6f852c2dcb | ||
|
|
e47e74fc76 | ||
|
|
e604060369 | ||
|
|
80f8051c57 | ||
|
|
612c499a3d | ||
|
|
cceffe6ac4 | ||
|
|
a74416c730 | ||
|
|
0830704484 | ||
|
|
79f7eaaf9a | ||
|
|
389e038445 | ||
|
|
8f84bd7091 | ||
|
|
2146e3ded9 | ||
|
|
97c0582765 | ||
|
|
c3f230956c | ||
|
|
b914a4a93e | ||
|
|
befa0fe213 | ||
|
|
61ef5a44e0 | ||
|
|
131fd0d778 | ||
|
|
8973757b43 | ||
|
|
14ce88730f | ||
|
|
84cbfb2f91 | ||
|
|
e8f8520251 | ||
|
|
c26558cd6d | ||
|
|
71feb0516d | ||
|
|
382187089c | ||
|
|
4faeb5c44e | ||
|
|
ac8f569280 | ||
|
|
669420d31c | ||
|
|
df48cc9471 | ||
|
|
274a08070f | ||
|
|
c0e20825ac | ||
|
|
15d821f2f8 | ||
|
|
acbd38c1ed | ||
|
|
92f5f97d83 | ||
|
|
1128b9de81 | ||
|
|
fcd60467a7 | ||
|
|
2f51341633 | ||
|
|
5799f407ae | ||
|
|
c7a5e09c0e | ||
|
|
3318ac2699 | ||
|
|
437f1fea54 | ||
|
|
3ab43f894f | ||
|
|
86f98f40a1 | ||
|
|
655f1dd906 | ||
|
|
243a382485 | ||
|
|
4b74163306 | ||
|
|
50e67d7c15 | ||
|
|
c5afd8f589 | ||
|
|
c6ab65d552 | ||
|
|
1a853fe145 | ||
|
|
72abc8e4c4 | ||
|
|
e15ad2e21b | ||
|
|
5afc5529c2 | ||
|
|
7eed368dc2 | ||
|
|
600303bb5b | ||
|
|
bcfd6d1b4f | ||
|
|
e65b3a790d | ||
|
|
a28467d393 | ||
|
|
bf13d9363d | ||
|
|
ff9c472f86 | ||
|
|
46e601db6e | ||
|
|
d4482d0d26 | ||
|
|
281289c46a | ||
|
|
bc85d96938 | ||
|
|
c2475381fd | ||
|
|
6ac14f35ad | ||
|
|
de18834c91 | ||
|
|
fc7d28c723 | ||
|
|
7ac2ce50a0 | ||
|
|
9cf9661484 | ||
|
|
8dbf00ad3a | ||
|
|
e0e623fa36 | ||
|
|
4094669222 | ||
|
|
9e19244659 | ||
|
|
d41ccb6b34 | ||
|
|
72c1da2507 | ||
|
|
2e8c5ea2de | ||
|
|
65561fe431 | ||
|
|
cf401aa0b5 | ||
|
|
9b2c9936c2 | ||
|
|
e4aabc7feb | ||
|
|
610951771e | ||
|
|
f76959af63 | ||
|
|
0eb5b0437b | ||
|
|
c1ac684f9a | ||
|
|
473c36aba5 | ||
|
|
38e6722358 | ||
|
|
d2a0f86908 | ||
|
|
c6707bec97 | ||
|
|
5c6a11cb8f | ||
|
|
600cc5e167 | ||
|
|
c441a9ad97 | ||
|
|
c2d2ba29ea | ||
|
|
25af23d3ff | ||
|
|
cbd6fd8aee | ||
|
|
7a7fc20438 | ||
|
|
ca4b2b68a7 | ||
|
|
f3ae553706 | ||
|
|
fe6696b107 | ||
|
|
3a85d0f179 | ||
|
|
9845d2c87d | ||
|
|
ea8730c2a9 | ||
|
|
c81868f8f7 | ||
|
|
33d1839b75 | ||
|
|
df10a01af9 | ||
|
|
4aa40aba4c | ||
|
|
696c94e2ea | ||
|
|
bc5dfb9371 | ||
|
|
88c63b941d | ||
|
|
b8e12dc42a | ||
|
|
2974e959e5 | ||
|
|
67b2fc085c | ||
|
|
cb202c15a5 | ||
|
|
850abd440b | ||
|
|
01d125f53d | ||
|
|
3f0572c5ce | ||
|
|
cc6c45f591 | ||
|
|
8029777c4e | ||
|
|
a6171551bd | ||
|
|
6bb67ab5da | ||
|
|
a31c492c83 | ||
|
|
c36d5e4a9c | ||
|
|
17b3fc93b0 | ||
|
|
d2f4ffc433 | ||
|
|
1c8a296f49 | ||
|
|
de0e5862dd | ||
|
|
e822b8c99e | ||
|
|
48d767749d | ||
|
|
fa48c76dd1 | ||
|
|
754fe9f4ec | ||
|
|
1ad3adfff0 | ||
|
|
0c0fd4d7f7 | ||
|
|
72f5df82b2 | ||
|
|
c7407f5b6a | ||
|
|
f57975acca | ||
|
|
a8a0c9e571 | ||
|
|
e05277d56a | ||
|
|
0b1985ca7e | ||
|
|
637764ee4e | ||
|
|
c6e613c317 | ||
|
|
aa3e769463 | ||
|
|
630ba195d1 | ||
|
|
13276d2f10 | ||
|
|
d59407a339 | ||
|
|
92c2fd9409 | ||
|
|
063e6160e0 | ||
|
|
6155a10037 | ||
|
|
7428cb353c | ||
|
|
fe3b5b03eb | ||
|
|
497fb90b12 | ||
|
|
48ab892de1 | ||
|
|
a85ad88d5a | ||
|
|
cf2566ff74 | ||
|
|
619f51518a | ||
|
|
b26330adab | ||
|
|
83009bac02 | ||
|
|
8780d536c7 | ||
|
|
99f4134d9d | ||
|
|
ca02ab7d5d | ||
|
|
dc295ca0e1 | ||
|
|
8ee91095c5 | ||
|
|
49c7b2f8f4 | ||
|
|
5d80cf11ef | ||
|
|
bc929bcb90 | ||
|
|
26a3057acf | ||
|
|
96cf0a6d02 | ||
|
|
12e773f3fb | ||
|
|
c321997591 | ||
|
|
b2d98452f1 | ||
|
|
16e48aa10f | ||
|
|
4da85a5f4a | ||
|
|
a5c9d3a809 | ||
|
|
f288ba744d | ||
|
|
ba5b85de00 | ||
|
|
bd2f412225 | ||
|
|
a86cf32f55 | ||
|
|
0c8178c753 | ||
|
|
b59e06ec89 | ||
|
|
10153a371b | ||
|
|
a93c1478c0 | ||
|
|
215b7a19c9 | ||
|
|
14ed666b91 | ||
|
|
ac1d61b2c4 | ||
|
|
acb6e90158 | ||
|
|
d3609737f5 | ||
|
|
95b91cd7dd | ||
|
|
affd2a3b91 | ||
|
|
d392259364 | ||
|
|
e03f4fac64 | ||
|
|
538840351a | ||
|
|
1ddad3577c | ||
|
|
d44d1325fc | ||
|
|
dc07af6ad1 | ||
|
|
c6f1809d60 | ||
|
|
261e73bf3e | ||
|
|
8c7d2a1e96 | ||
|
|
72507977bd | ||
|
|
270829f05b | ||
|
|
b92e4f7e65 | ||
|
|
8e890135fe | ||
|
|
a6601939d5 | ||
|
|
c608e735d2 | ||
|
|
e0a1a338a5 | ||
|
|
7aa276df5a | ||
|
|
d939a72219 | ||
|
|
96fc59eee5 | ||
|
|
989f8568cf | ||
|
|
66f451124f | ||
|
|
e59ff47f6f | ||
|
|
b176be9ef7 | ||
|
|
942879bbba | ||
|
|
2065c4294f | ||
|
|
cb02f0621c | ||
|
|
971f371eab | ||
|
|
f21c56bd98 | ||
|
|
363299a27d | ||
|
|
10e74dad41 | ||
|
|
dc041b7ea0 | ||
|
|
584cfdf64c | ||
|
|
74c498cf15 | ||
|
|
a1e5855f2b | ||
|
|
d8e5a97ef3 | ||
|
|
96804b0b28 | ||
|
|
b0d69c50da | ||
|
|
de6b2e139b | ||
|
|
7204840a8a | ||
|
|
76369a01ad | ||
|
|
3a92a93604 | ||
|
|
f1c968372f | ||
|
|
759d9a642f | ||
|
|
86d86c3044 | ||
|
|
c38708c483 | ||
|
|
1673a5ade9 | ||
|
|
c56a49ddce | ||
|
|
03477ce400 | ||
|
|
14d213d13e | ||
|
|
8d86816d8d | ||
|
|
12cf3fd8e7 | ||
|
|
8c23f2de8b | ||
|
|
837481a854 | ||
|
|
b682e58df7 | ||
|
|
c4f430d0d0 | ||
|
|
c7930ab349 | ||
|
|
045baba7ea | ||
|
|
d17ac421ec | ||
|
|
049e529f66 | ||
|
|
ef6e47f625 | ||
|
|
1330cb9126 | ||
|
|
f0ee8bc89d | ||
|
|
ebc0c18534 | ||
|
|
379a4bdda6 | ||
|
|
2ce106c50f | ||
|
|
0ebdfe59ee | ||
|
|
80c700b1f8 | ||
|
|
103f935d61 | ||
|
|
164476721a | ||
|
|
54dd716d02 | ||
|
|
ab681ce637 | ||
|
|
a355de8e97 | ||
|
|
56921d6449 | ||
|
|
7e900626bc | ||
|
|
dc30c29f4e | ||
|
|
370865bb57 | ||
|
|
80015e83d4 | ||
|
|
c37c35b52b | ||
|
|
069004d4eb | ||
|
|
f11695200e | ||
|
|
ef2f8a1a18 | ||
|
|
54cc687c50 | ||
|
|
51f279160f | ||
|
|
e3113f6976 | ||
|
|
485e29a672 | ||
|
|
00e67c50ca | ||
|
|
3e7b3edb9c | ||
|
|
3c6c9d9462 | ||
|
|
6b06a9ff2b | ||
|
|
803db476bb | ||
|
|
c134ea3098 | ||
|
|
6e64f36b39 | ||
|
|
36af39e2b4 | ||
|
|
88929ab730 | ||
|
|
02f00e5339 | ||
|
|
ee67032af1 | ||
|
|
8aea00f527 | ||
|
|
50faed4a50 | ||
|
|
b982817a56 | ||
|
|
e5172a9240 | ||
|
|
dcac7942fa | ||
|
|
4e13529adb | ||
|
|
c553835228 | ||
|
|
1b87193fc1 | ||
|
|
25fca56319 | ||
|
|
bf4252394c | ||
|
|
22757e064f | ||
|
|
fc9fa37e4e | ||
|
|
2d5e3402fa | ||
|
|
b7dd26121a | ||
|
|
23bdbeef4e | ||
|
|
9ac81c5219 | ||
|
|
6b9d346b8b | ||
|
|
9e68eb4d2c | ||
|
|
f1f47ee44a | ||
|
|
436b2b3140 | ||
|
|
f6cfa8ae49 | ||
|
|
13949a8d1f | ||
|
|
88db623dc1 | ||
|
|
976413173a | ||
|
|
91d3349585 | ||
|
|
6e1a774921 | ||
|
|
6b53b509fa | ||
|
|
b8b6203ecd | ||
|
|
81e1500675 | ||
|
|
d2cd18cb1e | ||
|
|
f5ac73f681 | ||
|
|
413630813a | ||
|
|
73b6ef2293 | ||
|
|
428bfbd810 | ||
|
|
c54409bdfb | ||
|
|
b63aebfdaf | ||
|
|
335f876a46 | ||
|
|
c5e99342a3 | ||
|
|
1710eb9249 | ||
|
|
d03770f91f | ||
|
|
9fe6f7a6ea | ||
|
|
2fc605fc3e | ||
|
|
edcd5c4713 | ||
|
|
bd3df1e06a | ||
|
|
b785d1c82b | ||
|
|
93bf14f84f | ||
|
|
5a84646282 | ||
|
|
2e6cfc08f0 | ||
|
|
4b6d3d47ec | ||
|
|
985abaa12a | ||
|
|
a381a7253a | ||
|
|
b8bb509d5c | ||
|
|
f48dbd0e19 | ||
|
|
31c1278374 | ||
|
|
f6aaafd60f | ||
|
|
ae3dec19fd | ||
|
|
990baa0929 | ||
|
|
7ecb65a141 | ||
|
|
a1e55103be | ||
|
|
1b4fc54405 | ||
|
|
e5dcea1fa0 | ||
|
|
9f25195629 | ||
|
|
6936fa1c1c | ||
|
|
7b25eacfc8 | ||
|
|
33989a61e3 | ||
|
|
08d9e8d076 | ||
|
|
da43ef0982 | ||
|
|
02f12bde81 | ||
|
|
b55d5375ac | ||
|
|
281f40bd56 | ||
|
|
dcb7c0c27e | ||
|
|
d3c44a6fa6 | ||
|
|
f432dc6bdc | ||
|
|
ce21ee6001 | ||
|
|
a431f5a674 | ||
|
|
f6153f17ad | ||
|
|
c17ecbc78c | ||
|
|
0feb9f0c56 | ||
|
|
e69cb3d950 | ||
|
|
e7c03dd512 | ||
|
|
0c1371ffae | ||
|
|
8a350acf39 | ||
|
|
594b3b5531 | ||
|
|
e13d06fe20 | ||
|
|
805bb84c8f | ||
|
|
1a62338349 | ||
|
|
4795ba83ba | ||
|
|
ad5b362bca | ||
|
|
8a735452de | ||
|
|
03d0f3e9ca | ||
|
|
ff0983cc42 | ||
|
|
159a413c7d | ||
|
|
6a753d1316 | ||
|
|
c89bf30e05 | ||
|
|
ba4b5ef9f2 | ||
|
|
5b39ee221f | ||
|
|
65c4432325 | ||
|
|
32bbb27c9f | ||
|
|
ef3c030576 | ||
|
|
554a182229 | ||
|
|
9154d78e58 | ||
|
|
82d933aa3d | ||
|
|
ef0fe9b13c | ||
|
|
f6700b7094 | ||
|
|
21f00cf251 | ||
|
|
900d2bf816 | ||
|
|
3846fa3f28 | ||
|
|
52f77d61ba | ||
|
|
039341de69 | ||
|
|
5adf332a5f | ||
|
|
efbb32a498 | ||
|
|
3156dd1321 | ||
|
|
2fbeeafbb8 | ||
|
|
db680f3bcd | ||
|
|
4a20fa5275 | ||
|
|
3fb2da7174 | ||
|
|
7f8bebbdd5 | ||
|
|
597fc0265f | ||
|
|
d5d5770dac | ||
|
|
772ac64e3b | ||
|
|
92d7337f04 | ||
|
|
200425114c | ||
|
|
b92a73a2a2 | ||
|
|
e83c77b99f | ||
|
|
28aa35160d | ||
|
|
18c9bfa134 | ||
|
|
bdb7763237 | ||
|
|
bc9ee46b8f | ||
|
|
b92b734db2 | ||
|
|
2748a6cd3c | ||
|
|
888876185d | ||
|
|
03fea6358b | ||
|
|
59b0dc6735 | ||
|
|
35a42b2172 | ||
|
|
daa4056f45 | ||
|
|
bb5abe633f | ||
|
|
dc238db355 | ||
|
|
4c692c23bb | ||
|
|
b093e82db3 | ||
|
|
7a1c2108a1 | ||
|
|
4aa2b49649 | ||
|
|
cdaced4df6 | ||
|
|
cdd029853b | ||
|
|
507bafdd9c | ||
|
|
07a36123e5 | ||
|
|
a205e7ada9 | ||
|
|
25e9330bb4 | ||
|
|
b2edfa454c | ||
|
|
07767a09d9 | ||
|
|
e8d85d9269 | ||
|
|
5cf0ba079f | ||
|
|
e08b1f82ce | ||
|
|
c2196149ee | ||
|
|
65b5ce7880 | ||
|
|
9c254ec3e0 | ||
|
|
f4418e0205 | ||
|
|
a314f7b42e | ||
|
|
dc5a72cda5 | ||
|
|
380cb41ca9 | ||
|
|
83f7e633a3 | ||
|
|
ab1c920435 | ||
|
|
7094d658f8 | ||
|
|
11617291e3 | ||
|
|
790aa03834 | ||
|
|
bcd16ea5ea | ||
|
|
81c044760b | ||
|
|
b0e0e80b69 | ||
|
|
280bb1d84f | ||
|
|
bb42dceaca | ||
|
|
d0873ed551 | ||
|
|
0fbddfc47b | ||
|
|
3f1dee2650 | ||
|
|
a4b8b93e7f | ||
|
|
02d1417ef4 | ||
|
|
50812a908c | ||
|
|
1a1ed55485 | ||
|
|
09fa322a0e | ||
|
|
1a9a423c35 | ||
|
|
7b0449213c | ||
|
|
c0251f5c29 | ||
|
|
4509d8a60b | ||
|
|
b1738b0902 | ||
|
|
45259462aa | ||
|
|
772a7427a2 | ||
|
|
afa58b81f6 | ||
|
|
6822c0f0e3 | ||
|
|
0a155ecb68 | ||
|
|
15fff94447 | ||
|
|
ff06df2acb | ||
|
|
df9301d591 | ||
|
|
e51b1bbb25 | ||
|
|
aa275f4b1c | ||
|
|
ed11bda9fd | ||
|
|
ed34a3f5d4 | ||
|
|
a99b8b7984 | ||
|
|
f750254cc2 | ||
|
|
21ece182f5 | ||
|
|
6439dca43a | ||
|
|
ca424a4577 | ||
|
|
87bc2cb1ab | ||
|
|
58f22cc3b5 | ||
|
|
fa8362f000 | ||
|
|
1816206dfc | ||
|
|
fcfa994152 | ||
|
|
e7262660c2 | ||
|
|
a1e14d5740 | ||
|
|
60c11f3f30 | ||
|
|
3fe584d366 | ||
|
|
28e38321ee | ||
|
|
1faeeeeabc | ||
|
|
75a0c672b1 | ||
|
|
db829b21aa | ||
|
|
24bdc29c27 | ||
|
|
692a78984f | ||
|
|
77a399738c | ||
|
|
5d7358899d | ||
|
|
aca25b9999 | ||
|
|
182c6c534b | ||
|
|
0500f155e6 | ||
|
|
125b826f62 | ||
|
|
922bfbf724 | ||
|
|
f1e584fad9 | ||
|
|
0c4dcdea71 | ||
|
|
ec4b383198 | ||
|
|
3328c7e78b | ||
|
|
357fcd44d7 | ||
|
|
5a0a682d35 | ||
|
|
1fcb7e5aba | ||
|
|
eec867bc9e | ||
|
|
5a956d2914 | ||
|
|
e0e29cc363 | ||
|
|
9fc8e03f72 | ||
|
|
b054e93f0e | ||
|
|
653680a356 | ||
|
|
40035f2e52 | ||
|
|
a70b7daec4 | ||
|
|
0f3e7b5dac | ||
|
|
2fbc08b606 | ||
|
|
e4897f709e | ||
|
|
84445aa28b | ||
|
|
0795f9a9f2 | ||
|
|
44ae0d67f6 | ||
|
|
a74f0ca370 | ||
|
|
266c1fcdcb | ||
|
|
977c3407e7 | ||
|
|
99c2299ed4 | ||
|
|
39a08f17da | ||
|
|
57de1187fc | ||
|
|
2bba6d4c0d | ||
|
|
2f03b225f7 | ||
|
|
533bc1ce94 | ||
|
|
add9df6058 | ||
|
|
d3496f3ff5 | ||
|
|
e97f7ee725 | ||
|
|
37497295fb | ||
|
|
2e89b3b5b9 | ||
|
|
518bbc651e | ||
|
|
ffd1d97e03 | ||
|
|
e503d431f1 | ||
|
|
49a066714a | ||
|
|
7eec610d21 | ||
|
|
530507c36b | ||
|
|
4d2584d8fc | ||
|
|
0f5057920e | ||
|
|
a98000cf3b | ||
|
|
0cec8de164 | ||
|
|
1caa8d923d | ||
|
|
4fa51f8c52 | ||
|
|
a8be765aa8 | ||
|
|
d2d35d490a | ||
|
|
26ba137424 | ||
|
|
e6006663ec | ||
|
|
74eb2772b6 | ||
|
|
3878a696af | ||
|
|
49ac34c405 | ||
|
|
a7d4a980ba | ||
|
|
2196db562e | ||
|
|
2ad3e0ed4c | ||
|
|
6e03fe77ae | ||
|
|
af8ec7b5dd | ||
|
|
7fa29e7341 | ||
|
|
9c6950d163 | ||
|
|
5d4cbfe8e7 | ||
|
|
4747422110 | ||
|
|
7d1416ac74 | ||
|
|
2efaa7af7b | ||
|
|
68e259870f | ||
|
|
29c2c94784 | ||
|
|
3f2e1d078f | ||
|
|
0a259da05a | ||
|
|
1b22fe6de2 | ||
|
|
9b700c3bd2 | ||
|
|
3b72e30c36 | ||
|
|
9eba103de9 | ||
|
|
ecadee3876 | ||
|
|
699f9105ae | ||
|
|
8a19e8dafe | ||
|
|
588c056205 | ||
|
|
866a7fb641 | ||
|
|
a5fe42268f | ||
|
|
0bd6816bdd | ||
|
|
1c6670c7a1 | ||
|
|
699a0eb934 | ||
|
|
72440ab937 | ||
|
|
9ad807bd58 | ||
|
|
9fb1970ac0 | ||
|
|
48dfac2588 | ||
|
|
c6d3714e6f | ||
|
|
1345c257c3 | ||
|
|
19112a8f27 | ||
|
|
e0979fcf3f | ||
|
|
d514ecbd5e | ||
|
|
a53dbb6950 | ||
|
|
a03b88e0eb | ||
|
|
4472eb1c40 | ||
|
|
3443987127 | ||
|
|
c73a79fd42 | ||
|
|
dedbe3d431 | ||
|
|
87ef713a17 | ||
|
|
4ba8ac4fa1 | ||
|
|
e74e0531bd | ||
|
|
b67cb4bd1f | ||
|
|
22628c9ac4 | ||
|
|
4dd0862fad | ||
|
|
0ec57fbb8d | ||
|
|
19ab584d32 | ||
|
|
97fe978d14 | ||
|
|
2a74c7d897 | ||
|
|
cdf9c2fc6f | ||
|
|
235f84a0d4 | ||
|
|
ccaa490a2f | ||
|
|
8eaf11b510 | ||
|
|
57a5faa448 | ||
|
|
be87191d0a | ||
|
|
40aabe76c7 | ||
|
|
9d304cb35c | ||
|
|
ee08a4966f | ||
|
|
aeca69903e | ||
|
|
e1b3f2b95a | ||
|
|
25c7436652 | ||
|
|
771c449621 | ||
|
|
61ecaa5756 | ||
|
|
c05dddc56e | ||
|
|
8e0747fd50 | ||
|
|
1bcc87c916 | ||
|
|
45797907d3 | ||
|
|
3498dea486 | ||
|
|
a4aab8458b | ||
|
|
534744d615 | ||
|
|
dc5450b95e | ||
|
|
9e0e276740 | ||
|
|
1c9c02f3ce | ||
|
|
7774f9f402 | ||
|
|
5607219945 | ||
|
|
69ef3efd2d | ||
|
|
36c118922b | ||
|
|
1d014953e3 | ||
|
|
c5cb1d9bcc | ||
|
|
86d12cf317 | ||
|
|
db9e59ede1 | ||
|
|
cc9b1b0a05 | ||
|
|
5c29de2013 | ||
|
|
559db104f8 | ||
|
|
365c57be4c | ||
|
|
6f0c84fc68 | ||
|
|
75782d9e99 | ||
|
|
69ddf4936e | ||
|
|
4b3108283f | ||
|
|
12d177a6c8 | ||
|
|
54717dc7e2 | ||
|
|
631c909abd | ||
|
|
208746f28f | ||
|
|
61c5f8ae22 | ||
|
|
4e0cca3a08 | ||
|
|
b86ffc2370 | ||
|
|
33574c9885 | ||
|
|
672c542f99 | ||
|
|
f741fe48a1 | ||
|
|
4347ebcee2 | ||
|
|
4e3e5a5361 | ||
|
|
8e6439c3d1 | ||
|
|
b54d358feb | ||
|
|
78baa7b12d | ||
|
|
19f1dd22e9 | ||
|
|
73f583f68a | ||
|
|
52de43e329 | ||
|
|
49ddacaac0 | ||
|
|
4533b3a1c0 | ||
|
|
f30ea02794 | ||
|
|
7112dda299 | ||
|
|
02636a7108 | ||
|
|
36a9456e0d | ||
|
|
113893dcea | ||
|
|
1abbe9c7b2 | ||
|
|
7205ac791c | ||
|
|
3335b81ad4 | ||
|
|
d9c9438f3c | ||
|
|
37250843e1 | ||
|
|
072ab88721 | ||
|
|
c208e6b107 | ||
|
|
65f3185b39 | ||
|
|
34f73f8a2b | ||
|
|
cb4142a97d | ||
|
|
80d08d5a34 | ||
|
|
052aecf533 | ||
|
|
7bde714f18 | ||
|
|
5ff429f656 | ||
|
|
92f27299e1 | ||
|
|
f9013375f8 | ||
|
|
f18b0045ba | ||
|
|
18173cc4c0 | ||
|
|
6a1ffdd7a5 | ||
|
|
8db78b2190 | ||
|
|
3fcccae241 | ||
|
|
6ff8add164 | ||
|
|
58a8c3c82a | ||
|
|
92c5c656c7 | ||
|
|
61856cd648 | ||
|
|
687f82b5c2 | ||
|
|
920c864bed | ||
|
|
1360c985b7 | ||
|
|
b6f953e13b | ||
|
|
796b96071b | ||
|
|
ec56ccc690 | ||
|
|
95931b67e1 | ||
|
|
706bbb83c9 | ||
|
|
43099f47d0 | ||
|
|
eca86999c3 | ||
|
|
a00b44a5fd | ||
|
|
5b8dcff2a4 | ||
|
|
e4d36e4982 | ||
|
|
adfdbf138d | ||
|
|
8d1ba26492 | ||
|
|
792625f763 | ||
|
|
5e8eae4ef8 | ||
|
|
148212da96 | ||
|
|
23ddb12529 | ||
|
|
186a5e8f7b | ||
|
|
dfb5fe1e04 | ||
|
|
640f75373e | ||
|
|
46e5d96ced | ||
|
|
ad3fbe2052 | ||
|
|
cd6c60fd46 | ||
|
|
f7be386d5a | ||
|
|
89b2131052 | ||
|
|
e5d1ca2e3c | ||
|
|
32b8224afd | ||
|
|
00e7ab1db8 | ||
|
|
e376a53b09 | ||
|
|
17a9cd5666 | ||
|
|
fc3de662c3 | ||
|
|
8de568c2fc | ||
|
|
55661883d9 | ||
|
|
b59d3ebeaa | ||
|
|
2866dcdd03 | ||
|
|
b147f9d58c | ||
|
|
8e2a6470ac | ||
|
|
19230f7672 | ||
|
|
764dfbe46a | ||
|
|
0ec7631310 | ||
|
|
0b39ece990 | ||
|
|
97500dff57 | ||
|
|
dc6299a029 | ||
|
|
58b1e2fb98 | ||
|
|
0302fdaaba | ||
|
|
09b260e0af | ||
|
|
24b7e998b2 | ||
|
|
19068ea5c7 | ||
|
|
b5cd3eb468 | ||
|
|
91a2b5a5f7 | ||
|
|
0096f6d962 | ||
|
|
87cfe41b15 | ||
|
|
c490086097 | ||
|
|
5b3fd7537e | ||
|
|
2cab2583c0 | ||
|
|
a40a3b594d | ||
|
|
0fa586a3d8 | ||
|
|
25977cc569 | ||
|
|
0be7064493 | ||
|
|
0b13dc254a | ||
|
|
c1e953ab6e | ||
|
|
a069764af1 | ||
|
|
3dbe6c3902 | ||
|
|
9f0b380024 | ||
|
|
193b102013 | ||
|
|
511fde91fa | ||
|
|
16e3cfc589 | ||
|
|
ed2012a36c | ||
|
|
46598fde32 | ||
|
|
94d0c5fa5c | ||
|
|
4e72291588 | ||
|
|
74cdf000b4 | ||
|
|
565dc3327b | ||
|
|
462af21793 | ||
|
|
94af659c86 | ||
|
|
b63c9fc67b | ||
|
|
f519b55a47 | ||
|
|
2fb039b429 | ||
|
|
4bce5aed77 | ||
|
|
eca6032306 | ||
|
|
dd2f515af1 | ||
|
|
df25482643 | ||
|
|
df016b3bf9 | ||
|
|
8699e96609 | ||
|
|
b0dcaaf744 | ||
|
|
7db001995c | ||
|
|
c88adf9314 | ||
|
|
b13713ce98 | ||
|
|
66b89d170f | ||
|
|
4311e2e686 | ||
|
|
fd566eff7a | ||
|
|
efaa3f9e55 | ||
|
|
b625ff0902 | ||
|
|
fee80321ef | ||
|
|
4b9331f086 | ||
|
|
df9316b896 | ||
|
|
dae5f86d4e | ||
|
|
75a0cefcb3 | ||
|
|
2271aa5b89 | ||
|
|
b668e2a967 | ||
|
|
ce44c59547 | ||
|
|
84802d931d | ||
|
|
8183c4383e | ||
|
|
af249098cd | ||
|
|
8fdd063f00 | ||
|
|
fe328f6a75 | ||
|
|
ef7163acd6 | ||
|
|
6e45f0d5b8 | ||
|
|
ff41faa3fe | ||
|
|
acb2d332ea | ||
|
|
0fb86f21e4 | ||
|
|
e4991d367e | ||
|
|
3144cfafd5 | ||
|
|
c538067544 | ||
|
|
f8e137a1dc | ||
|
|
36ea38fd91 | ||
|
|
baae5a7215 | ||
|
|
a4b267227e | ||
|
|
58dd159699 | ||
|
|
80082f9d51 | ||
|
|
7975ffc10b | ||
|
|
012083a4a1 | ||
|
|
3c67723e83 | ||
|
|
7f0598b3cb | ||
|
|
c5b27e0ae0 | ||
|
|
4e7ad31f18 | ||
|
|
c7a3e9d4ac | ||
|
|
a05e7a84c4 | ||
|
|
389cb85410 | ||
|
|
81ae2bed25 | ||
|
|
0ab71bc2e7 | ||
|
|
81e6bbe643 | ||
|
|
c4723f3b24 | ||
|
|
df4d8e0411 | ||
|
|
4f1820bcad | ||
|
|
e375097e43 | ||
|
|
c51bec0034 | ||
|
|
081c3fdb5b | ||
|
|
f1e7602775 | ||
|
|
acd75ffe1c | ||
|
|
fc813cb59b | ||
|
|
044d14f542 | ||
|
|
28b9f07b99 | ||
|
|
6f20dd4e45 | ||
|
|
2fc05e5b90 | ||
|
|
9afde31f97 | ||
|
|
e835ce0697 | ||
|
|
6030f56c76 | ||
|
|
ba89b53c63 | ||
|
|
1bfb877a3b | ||
|
|
72776d6fb6 | ||
|
|
7bb93420c4 | ||
|
|
bb1b0e0581 | ||
|
|
45ddcf0df9 | ||
|
|
9c4d7a286f | ||
|
|
7b290b43b5 | ||
|
|
2e2782b030 | ||
|
|
48f23bd1ba | ||
|
|
3ece33b26a | ||
|
|
efa98379b0 | ||
|
|
324aeba70f | ||
|
|
7b6715c7b5 | ||
|
|
1ea392b6c9 | ||
|
|
8b1a3849e6 | ||
|
|
e1d7e98c92 | ||
|
|
04b2e1152c | ||
|
|
d392eba4a0 | ||
|
|
799dec4f1c | ||
|
|
11df6ec927 | ||
|
|
03e363f5d9 | ||
|
|
39211889b0 | ||
|
|
db44549276 | ||
|
|
49e702c0c7 | ||
|
|
c9c5214b3e | ||
|
|
24a537d154 | ||
|
|
c32ecf171b | ||
|
|
a62ae21628 | ||
|
|
12f05e8f72 | ||
|
|
81fb727d20 | ||
|
|
e7655c761d | ||
|
|
464fcf4300 | ||
|
|
73b67ea9df | ||
|
|
04a9c80c14 | ||
|
|
80b5ed3d22 | ||
|
|
be5ad379b6 | ||
|
|
13d901fbfa | ||
|
|
f7e7273e91 | ||
|
|
4b3bd265a6 | ||
|
|
42dcec961b | ||
|
|
6b2a3b2916 | ||
|
|
930f9ca436 | ||
|
|
a96a767b9b | ||
|
|
36627dbe78 | ||
|
|
f86bc31cbb | ||
|
|
4a08ca4b5e | ||
|
|
e857aa0640 | ||
|
|
d3c98ad334 | ||
|
|
00dadfe14d | ||
|
|
f26fa92d47 | ||
|
|
7458072df2 | ||
|
|
89aa2a1902 | ||
|
|
7ab08779dc | ||
|
|
46b686910b | ||
|
|
940a799207 | ||
|
|
778cee3b27 | ||
|
|
fb3252732b | ||
|
|
608f7b75e2 | ||
|
|
83853c3dee | ||
|
|
8a0343ad6b | ||
|
|
92d43ce620 | ||
|
|
6943822fed | ||
|
|
aa146c4125 | ||
|
|
b8ec6babb5 | ||
|
|
505f4a2b4f | ||
|
|
1bb0d017c3 | ||
|
|
f33ce615d9 | ||
|
|
0edb49d7c6 | ||
|
|
1fa5a03605 | ||
|
|
fc6bda5cd8 | ||
|
|
59589b6a71 | ||
|
|
57b0624a0a | ||
|
|
2f22395eea | ||
|
|
21bc8d4dfb | ||
|
|
2e74fd8196 | ||
|
|
fee48ab04c | ||
|
|
591f885e67 | ||
|
|
ef803016c0 | ||
|
|
bac51045e5 | ||
|
|
cb5e9393a4 | ||
|
|
097509dd2a | ||
|
|
6cd44248c7 | ||
|
|
1fd61fbcef | ||
|
|
cd2245ef03 | ||
|
|
5ddc746915 | ||
|
|
f7d67067ad | ||
|
|
d1a824f76e | ||
|
|
d7b0fc09d7 | ||
|
|
2d07a6ec1f | ||
|
|
014ba5a7aa | ||
|
|
2f12e524dd | ||
|
|
ea6af75e8e | ||
|
|
a595c6ec6f | ||
|
|
98f785d199 | ||
|
|
a0ed0c864f | ||
|
|
d4ac42749e | ||
|
|
86414671d6 | ||
|
|
6cb935982d | ||
|
|
39ad040d8a | ||
|
|
4cc3824653 | ||
|
|
6d3e0600a1 | ||
|
|
b52c9c1676 | ||
|
|
f7506251fe | ||
|
|
5b06f298f1 | ||
|
|
dc5488a198 | ||
|
|
23d162e9e4 | ||
|
|
de6b660b12 | ||
|
|
60c175a51d | ||
|
|
c0a39c8064 | ||
|
|
61f4f93cc6 | ||
|
|
764404a472 | ||
|
|
04da85c88a | ||
|
|
9551b7a597 | ||
|
|
f1d537d035 | ||
|
|
b43e723c84 | ||
|
|
5466039c1a | ||
|
|
74e11117be | ||
|
|
e0abab2dc4 | ||
|
|
08ff3ff55c | ||
|
|
0b79d99cac | ||
|
|
38f655e7b8 | ||
|
|
6f546ffe95 | ||
|
|
ef8211a46e | ||
|
|
52ea5e4074 | ||
|
|
99621cf08a | ||
|
|
a9ae9ce758 | ||
|
|
fc5a529df8 | ||
|
|
bc1081550d | ||
|
|
e311ab1605 | ||
|
|
994ade0638 | ||
|
|
cf9522bd3b | ||
|
|
7fd1858db0 | ||
|
|
c41509151b | ||
|
|
4e12853d4a | ||
|
|
e1fadbc9b9 | ||
|
|
3c4d13d8b9 | ||
|
|
732159db07 | ||
|
|
00894eaccf | ||
|
|
17818178cf | ||
|
|
89c0abfada | ||
|
|
8bbdd92739 | ||
|
|
f724ceb052 | ||
|
|
b7ac85005f | ||
|
|
8ec899a8e7 | ||
|
|
1013c6a50e | ||
|
|
2cd5d3bab3 | ||
|
|
d9494960a2 | ||
|
|
c0eb6590da | ||
|
|
a9cefcb823 | ||
|
|
d1ff491010 | ||
|
|
2aa34f05d3 | ||
|
|
135d6915ee | ||
|
|
6282195b80 | ||
|
|
adec4f08c6 | ||
|
|
b24fe2f122 | ||
|
|
7b35bcb68a | ||
|
|
4b629045c3 | ||
|
|
c6ba1d05d1 | ||
|
|
3adac90573 | ||
|
|
0332188b6b | ||
|
|
790a1e2812 | ||
|
|
3bd1e13321 | ||
|
|
0cd642ca11 | ||
|
|
d5995998b0 | ||
|
|
62babb9c22 | ||
|
|
b98c69521b | ||
|
|
6cd37b3809 | ||
|
|
238170d0e2 | ||
|
|
6fb5b25530 | ||
|
|
d63f9e1eff | ||
|
|
461865bf3b | ||
|
|
e95d9b9cf6 | ||
|
|
c52b2a4fa9 | ||
|
|
d0ec5d2da0 | ||
|
|
6134058abc | ||
|
|
bd4121c260 | ||
|
|
fbab047d7f | ||
|
|
e216144d07 | ||
|
|
94d5b11191 | ||
|
|
d3c89da2eb | ||
|
|
754a8a637e | ||
|
|
ab24a50de7 | ||
|
|
8099dde34b | ||
|
|
99198fb07f | ||
|
|
18d02a0c95 | ||
|
|
e6cac7d5fb | ||
|
|
d8d6f00fee | ||
|
|
ef5c1a1099 | ||
|
|
2d92d8ee67 | ||
|
|
ae60266477 | ||
|
|
88da5261fc | ||
|
|
15efe9f702 | ||
|
|
badbc5c66e | ||
|
|
d6eea41e13 | ||
|
|
6a2c54adf5 | ||
|
|
75d4bc7c18 | ||
|
|
834f7feb27 | ||
|
|
5d2af3f9e1 | ||
|
|
60e8e4a82a | ||
|
|
92e23476ab | ||
|
|
4560fef058 | ||
|
|
c5d6574617 | ||
|
|
de61a0ca45 | ||
|
|
98470caae1 | ||
|
|
53486c067b | ||
|
|
5b805852fa | ||
|
|
94d02eeb4e | ||
|
|
dbfec1b247 | ||
|
|
a9a1a71145 | ||
|
|
91537bf5f3 | ||
|
|
1baad08288 | ||
|
|
1c5b846488 | ||
|
|
6867760cc4 | ||
|
|
516a9209b7 | ||
|
|
e352c953dc | ||
|
|
f455846d18 | ||
|
|
6d45ac942d | ||
|
|
48939abafa | ||
|
|
fbc9595f12 | ||
|
|
ed2c714419 | ||
|
|
ef7731fb8b | ||
|
|
b5ec03f585 | ||
|
|
a8b224a364 | ||
|
|
3f3943a233 | ||
|
|
4171b4ae47 | ||
|
|
baa4c44632 | ||
|
|
ffed8f37de | ||
|
|
8978a0d159 | ||
|
|
4d09be0cd3 | ||
|
|
987be01bd6 | ||
|
|
7f59fc6321 | ||
|
|
feeb122c0d | ||
|
|
0754f108c9 | ||
|
|
ea82f86749 | ||
|
|
7bd217386a | ||
|
|
1f1e02fee1 | ||
|
|
6d1e4fb3da | ||
|
|
9090f84611 | ||
|
|
8e5ddba173 | ||
|
|
86fccb5071 | ||
|
|
414c3baf15 | ||
|
|
bbbddbf617 | ||
|
|
7638b5a95e | ||
|
|
3df6b05c00 | ||
|
|
8566c58f2b | ||
|
|
33ccb71526 | ||
|
|
2b07b92039 | ||
|
|
959bc269e4 | ||
|
|
8609068dbf | ||
|
|
d6cea80768 | ||
|
|
0f2d6fb324 | ||
|
|
f5d303045c | ||
|
|
ad61b0c84e | ||
|
|
18373bb679 | ||
|
|
c30dfe3bfe | ||
|
|
4993961c16 | ||
|
|
89aece7c28 | ||
|
|
ec96946513 | ||
|
|
e49aa0d424 | ||
|
|
b5c929572a | ||
|
|
394822aa50 | ||
|
|
d12ba5e527 | ||
|
|
ab316bcb2e | ||
|
|
93fc08df45 | ||
|
|
266dd02ef5 | ||
|
|
61c1e359e9 | ||
|
|
32c83986e5 | ||
|
|
f64af2e69d | ||
|
|
6e925c7cdd | ||
|
|
5f50f776c6 | ||
|
|
946ccf3db4 | ||
|
|
7a0aea390b | ||
|
|
ff0e6315f9 | ||
|
|
b7fb485349 | ||
|
|
45cbe66d5d | ||
|
|
bc7a6399c1 | ||
|
|
2d5a3f24aa | ||
|
|
1639429edd | ||
|
|
f81abf4883 | ||
|
|
dcddb7d50e | ||
|
|
42a763031c | ||
|
|
0964ca5918 | ||
|
|
4e870b83cd | ||
|
|
0b19c9be0b | ||
|
|
ac655902a0 | ||
|
|
e4fb293b55 | ||
|
|
d3df64ef4b | ||
|
|
93e3d14f34 | ||
|
|
bc687d412d | ||
|
|
71e85b44b0 | ||
|
|
d4b59aff97 | ||
|
|
e3c21e1f3d | ||
|
|
e012250e0a | ||
|
|
c6bf82664c | ||
|
|
c61e98009f | ||
|
|
44bccaaad6 | ||
|
|
aebca14dea | ||
|
|
4576f27f6e | ||
|
|
0c213fca40 | ||
|
|
891f596191 | ||
|
|
eb2b724902 | ||
|
|
1f8c896181 | ||
|
|
12b39e1fbe | ||
|
|
206d31f27a | ||
|
|
6709331182 | ||
|
|
9460e04ea5 | ||
|
|
462bfea733 | ||
|
|
a2d61dfaeb | ||
|
|
538425e35c | ||
|
|
2e86c1f1a2 | ||
|
|
8aa4d46ce0 | ||
|
|
cdf67a1421 | ||
|
|
93d905d93d | ||
|
|
2c35203647 | ||
|
|
216871fe56 | ||
|
|
03511f39b1 | ||
|
|
5ad0832b22 | ||
|
|
d49e7ba4b2 | ||
|
|
a621b36389 | ||
|
|
d093df02ac | ||
|
|
2e1529e78d | ||
|
|
90be1db402 | ||
|
|
29265e4181 | ||
|
|
2689a7ef13 | ||
|
|
88b58cf23d | ||
|
|
e2e433480b | ||
|
|
b8bc3e4e94 | ||
|
|
c28f52b816 | ||
|
|
ca34309f75 | ||
|
|
ea614a0f3f | ||
|
|
3e7dc7af29 | ||
|
|
0b3e3fd19a | ||
|
|
d3372dc05c | ||
|
|
7d141cb183 | ||
|
|
755699c31b | ||
|
|
acf3d4cd74 | ||
|
|
92414c91b5 | ||
|
|
ff67f402bb | ||
|
|
f048a3f1d8 | ||
|
|
9d39cb51cf | ||
|
|
7624a9d34c | ||
|
|
0fe73fb6ed | ||
|
|
ae11652493 | ||
|
|
0ab46870ae | ||
|
|
a5381374b8 | ||
|
|
7fae655651 | ||
|
|
3d9959c8e5 | ||
|
|
bc86576aa8 | ||
|
|
7c2bce8baf | ||
|
|
b062bbf58d | ||
|
|
8e5a048913 | ||
|
|
ff642ffff7 | ||
|
|
656c12cebd | ||
|
|
48f3fcf3bd | ||
|
|
d797af695b | ||
|
|
75e0161c5f | ||
|
|
c0662816f1 | ||
|
|
415a31ce23 | ||
|
|
6e603e2e51 | ||
|
|
9af318a767 | ||
|
|
30827120f6 | ||
|
|
6194e12616 | ||
|
|
59a27fb652 | ||
|
|
f8ec57c2f6 | ||
|
|
844ef5e232 | ||
|
|
5bf3f7b77e | ||
|
|
00c0afd093 | ||
|
|
5228739c87 | ||
|
|
0f6d1268c7 | ||
|
|
b2a4515d2b | ||
|
|
3576c80d33 | ||
|
|
77afd2d36c | ||
|
|
e6ddd5d9c2 | ||
|
|
b9bf1a234e | ||
|
|
0ce9122449 | ||
|
|
dc41657872 | ||
|
|
64d9380031 | ||
|
|
eca7484e30 | ||
|
|
2b5c393a13 | ||
|
|
0817d416a3 | ||
|
|
ccff753305 | ||
|
|
11481a430a | ||
|
|
e252b22735 | ||
|
|
a32ca8eb1d | ||
|
|
1979a2279f | ||
|
|
1434f942dd | ||
|
|
955d325f07 | ||
|
|
3fac3fe2d7 | ||
|
|
6ff217e74e | ||
|
|
cd667fe34b | ||
|
|
3d6202ecfd | ||
|
|
c40f0ef2bb | ||
|
|
c4b169edd1 | ||
|
|
c6bba98828 | ||
|
|
e5d4f1bb58 | ||
|
|
cf522d60ca | ||
|
|
daf72a7c61 | ||
|
|
f116ad0594 | ||
|
|
e59d40834d | ||
|
|
d06328af7f | ||
|
|
baa9d7d836 | ||
|
|
b030df55ee | ||
|
|
64eb8a2d0d | ||
|
|
7d7c36e0c7 | ||
|
|
9ad5768050 | ||
|
|
1cafbcff38 | ||
|
|
4bbf93fd0c | ||
|
|
120918bc37 | ||
|
|
253448cffb | ||
|
|
26f19fb90e | ||
|
|
e8f982e909 | ||
|
|
0fa433187e | ||
|
|
b0069299ea | ||
|
|
375d5d3e9b | ||
|
|
2d9398ae1a | ||
|
|
fc69e91636 | ||
|
|
5c56cbd672 | ||
|
|
a42255158d | ||
|
|
f3d10a97df | ||
|
|
5d15a3d69f | ||
|
|
94292872dc | ||
|
|
5c8a1e7d10 | ||
|
|
e98d8426bb | ||
|
|
77f80cecf9 | ||
|
|
bce26a1499 | ||
|
|
453f1c6edc | ||
|
|
9f8a36f2c9 | ||
|
|
e6a5945463 | ||
|
|
60393fbc5f | ||
|
|
b9a925dbd4 | ||
|
|
5dbdb1bcb5 | ||
|
|
d55cefc086 | ||
|
|
5380e6d98b | ||
|
|
45cc24e0b8 | ||
|
|
76bf1791eb | ||
|
|
7e9a4c4b16 | ||
|
|
75cd5f169f | ||
|
|
10636c82a2 | ||
|
|
04a6729963 | ||
|
|
b5617398ad | ||
|
|
da14641ccb | ||
|
|
3997bd2396 | ||
|
|
c876350e05 | ||
|
|
1e07b981f0 | ||
|
|
756e909f5e | ||
|
|
2404392daf | ||
|
|
bf6576f5af | ||
|
|
158c2ab76e | ||
|
|
56fa50385e | ||
|
|
eb05ab5fab | ||
|
|
7f87b637d5 | ||
|
|
4b213adc75 | ||
|
|
7e7d5bbf17 | ||
|
|
e18c0a0c19 | ||
|
|
02b6ffc771 | ||
|
|
340d66c24c | ||
|
|
2cbf9d3620 | ||
|
|
11e6793544 | ||
|
|
d07e0336a2 | ||
|
|
7dbfb3d9ae | ||
|
|
02ef5db6e3 | ||
|
|
bb43bb5508 | ||
|
|
a771f083a7 | ||
|
|
67f8bce1dd | ||
|
|
3b6dd23598 | ||
|
|
66bbeae7da | ||
|
|
059334a861 | ||
|
|
f874c8309f | ||
|
|
27be812cc3 | ||
|
|
2adc2e97e1 | ||
|
|
dc4279a2d0 | ||
|
|
85bff4525a | ||
|
|
bd648c0745 | ||
|
|
d5e7005edd | ||
|
|
8913c7ea18 | ||
|
|
0e2afe4f98 | ||
|
|
a936f7cdbe | ||
|
|
44fa466618 | ||
|
|
b05d84e8e3 | ||
|
|
7787c1ddd7 | ||
|
|
52bfddd2e7 | ||
|
|
f59adcdc37 | ||
|
|
e996d3398f | ||
|
|
d73892d25a | ||
|
|
1ebf614d79 | ||
|
|
f9c995f03f | ||
|
|
2dcdd561f0 | ||
|
|
90f97aa8d7 | ||
|
|
5a4b067cee | ||
|
|
cabcc761c6 | ||
|
|
a40ac1c46c | ||
|
|
85ddfc4d21 | ||
|
|
037a35df1d | ||
|
|
64c753023e | ||
|
|
9d72ffb9fe | ||
|
|
4162d4fbc6 | ||
|
|
a4d16bffd3 | ||
|
|
bcaf1489c0 | ||
|
|
a85712e8aa | ||
|
|
0f95d02cdc | ||
|
|
c151d55237 | ||
|
|
785cd6bc11 | ||
|
|
8ec7e3cc97 | ||
|
|
e376493970 | ||
|
|
08e2322d79 | ||
|
|
2832767daa | ||
|
|
62e12ee0aa | ||
|
|
80e73c1089 | ||
|
|
4f93995bd7 | ||
|
|
03c7dac92f | ||
|
|
d0b93f565a | ||
|
|
1512fbae55 | ||
|
|
4d91afdf9f | ||
|
|
c239c3fea3 | ||
|
|
a0b431e8c4 | ||
|
|
005e03aeb3 | ||
|
|
6002d373e2 | ||
|
|
a53066424b | ||
|
|
38ab02ff88 | ||
|
|
fee0b29a0b | ||
|
|
2553695029 | ||
|
|
301939983f | ||
|
|
cd9ae1fbad | ||
|
|
54e9bc86cc | ||
|
|
a1dd4c28c3 | ||
|
|
6d3857f337 | ||
|
|
c4be3e731a | ||
|
|
ea4407b847 | ||
|
|
a62a83044f | ||
|
|
e7e7b06744 | ||
|
|
2222e31885 | ||
|
|
c3f7f83c55 | ||
|
|
86e18f68c4 | ||
|
|
cc7d9e03d9 | ||
|
|
c8639ae434 | ||
|
|
85cf32516e | ||
|
|
bc85817b07 | ||
|
|
1016394be5 | ||
|
|
de35cbf4af | ||
|
|
bb1acee36a | ||
|
|
c6a2ed78c3 | ||
|
|
7729958082 | ||
|
|
ccdaec86b3 | ||
|
|
42afeef993 | ||
|
|
3d06911886 | ||
|
|
98f929e41e | ||
|
|
94d4e0231e | ||
|
|
e60cdb2e3b | ||
|
|
550c021097 | ||
|
|
1aec7f71b8 | ||
|
|
07565927f2 | ||
|
|
fda78ede1b | ||
|
|
1249a4f8d3 | ||
|
|
4e631f1536 | ||
|
|
1757dbc225 | ||
|
|
8149e204d2 | ||
|
|
412f2ef63e | ||
|
|
ea33673daa | ||
|
|
169b816613 | ||
|
|
48edf077fc | ||
|
|
91db153710 | ||
|
|
ea1f010b1a | ||
|
|
935a852745 | ||
|
|
0eb6d7de3c | ||
|
|
3118cd4fa5 | ||
|
|
18832fcb37 | ||
|
|
612554f6af | ||
|
|
1c794591b9 | ||
|
|
a8d95b284d | ||
|
|
772c2dba2f | ||
|
|
9d1a210c97 | ||
|
|
b04b966db1 | ||
|
|
e2c61d90e9 | ||
|
|
d50655c4f7 | ||
|
|
5e4c63736b | ||
|
|
b90b71c8c0 | ||
|
|
722033e906 | ||
|
|
b6ec91fcd0 | ||
|
|
e94c0d003a | ||
|
|
5c46ccb37e | ||
|
|
fd989feea3 | ||
|
|
1b53e83dde | ||
|
|
3ebe827b51 | ||
|
|
b8266e1169 | ||
|
|
4efbe24607 | ||
|
|
e96ac1f6ff | ||
|
|
14915368c7 | ||
|
|
0ff5c18743 | ||
|
|
240814cc85 | ||
|
|
1912350cc6 | ||
|
|
146faa6008 | ||
|
|
e5fa67850b | ||
|
|
1377b51341 | ||
|
|
db67fb3539 | ||
|
|
6d216406f3 | ||
|
|
ab225eaec1 | ||
|
|
4d6d9e567d | ||
|
|
0fcf0142ba | ||
|
|
ab907e4fef | ||
|
|
1c1c3eb271 | ||
|
|
a03a569534 | ||
|
|
309fb0fa83 | ||
|
|
14c1431848 | ||
|
|
c3dc32415b | ||
|
|
44d6246278 | ||
|
|
5bbd7e03f9 | ||
|
|
f5f463b411 | ||
|
|
6eaefbe25c | ||
|
|
4b5c2c85a5 | ||
|
|
0f951cd322 | ||
|
|
cf0da32fd0 | ||
|
|
5a3085c42b | ||
|
|
42cc480bf5 | ||
|
|
2822eda858 | ||
|
|
6c804b5ca2 | ||
|
|
5149d1395e | ||
|
|
f75a2dab8d | ||
|
|
a045c88c61 | ||
|
|
a5fdf917df | ||
|
|
80a0e47f1a | ||
|
|
a304313ad4 | ||
|
|
05b1d5a4da | ||
|
|
edeef3541c | ||
|
|
cd929d8e65 | ||
|
|
b005971427 | ||
|
|
c35614fb63 | ||
|
|
18e16b09f2 | ||
|
|
b18b76c1f0 | ||
|
|
c9f65267ba | ||
|
|
cce52c673b | ||
|
|
fdde216f0e | ||
|
|
d1901a97d1 | ||
|
|
eb2077b95b | ||
|
|
fad3bdeed4 | ||
|
|
e1a537e547 | ||
|
|
ba098e1199 | ||
|
|
0ec755fccf | ||
|
|
997dd433b3 | ||
|
|
4aea1567db | ||
|
|
446c8df3b4 | ||
|
|
f4bd868d6a | ||
|
|
8490264af3 | ||
|
|
505cfdd193 | ||
|
|
39ecd1545c | ||
|
|
9b80c0028d | ||
|
|
35276b55af | ||
|
|
eb63dd6227 | ||
|
|
9f24b3c584 | ||
|
|
53e951d96d | ||
|
|
17dd386937 | ||
|
|
3eb00382e7 | ||
|
|
98b5f7a26a | ||
|
|
fb70ec1cb0 | ||
|
|
47ada87ba2 | ||
|
|
7a949dd328 | ||
|
|
3982217b67 | ||
|
|
8cb61da9c2 | ||
|
|
375c780d3b | ||
|
|
f3b6c2ce5d | ||
|
|
a7a2c96382 | ||
|
|
99336ef746 | ||
|
|
72d2adfe1c | ||
|
|
707574e294 | ||
|
|
18ffbd0027 | ||
|
|
68a0e4f39a | ||
|
|
ddb99ced34 | ||
|
|
cb2782bc71 | ||
|
|
52cade9267 | ||
|
|
ec600eb2f4 | ||
|
|
61e96e2dab | ||
|
|
9f5433053d | ||
|
|
d2489a57b7 | ||
|
|
e5841cd467 | ||
|
|
820d52428f | ||
|
|
ae6931b046 | ||
|
|
90a97b90bb | ||
|
|
4b38d81f00 | ||
|
|
8c27ca9e36 | ||
|
|
4b89fc390d | ||
|
|
29c1766714 | ||
|
|
2e5a9f117c | ||
|
|
2abcbcd30f | ||
|
|
ac8bde4ea8 | ||
|
|
78a13efc6c | ||
|
|
c99e859978 | ||
|
|
ed448cb99f | ||
|
|
5d472a1f2e | ||
|
|
92a938db0e | ||
|
|
aa979b2046 | ||
|
|
2daaf899d3 | ||
|
|
fa4c6bccbc | ||
|
|
bedea4b11a | ||
|
|
bc415242f2 | ||
|
|
2eeb7552d6 | ||
|
|
3a6ecb10a7 | ||
|
|
f55004d1e4 | ||
|
|
1a3304a886 | ||
|
|
58bcbe75b7 | ||
|
|
753df6decf | ||
|
|
c32f947c18 | ||
|
|
6123e4ac8a | ||
|
|
c52f16f5b8 | ||
|
|
3dac65a012 | ||
|
|
bc089bc4c1 | ||
|
|
1075ded4dc | ||
|
|
5578ea2f30 | ||
|
|
ade3e58829 | ||
|
|
ee2e88476c | ||
|
|
1726e983ad | ||
|
|
44341f0bcc | ||
|
|
366da3d0fe | ||
|
|
f7fa2f605b | ||
|
|
6854dea47e | ||
|
|
9d7e1cd99d | ||
|
|
330f3dff77 | ||
|
|
073c46e7bf | ||
|
|
9950b2ea34 | ||
|
|
a7c2a5c49b | ||
|
|
c2c39cd0d0 | ||
|
|
b6e7c36b11 | ||
|
|
002f92fe1e | ||
|
|
d6d0cdf9aa | ||
|
|
7d002df94f | ||
|
|
f0d7408f94 | ||
|
|
7154678347 | ||
|
|
68f0743c40 | ||
|
|
3d5905c878 | ||
|
|
a344a1ca59 | ||
|
|
5f539ddfb7 | ||
|
|
a974235d10 | ||
|
|
2d17ef5c7e | ||
|
|
dda8c209df | ||
|
|
be88d5dfb8 | ||
|
|
4a537d82d3 | ||
|
|
6f36723097 | ||
|
|
35bce924f8 | ||
|
|
9356e8ccb5 | ||
|
|
1ffde24ef6 | ||
|
|
2f52bef882 | ||
|
|
b1369582e1 | ||
|
|
cf176719a8 | ||
|
|
d7ed72ac06 | ||
|
|
83322664f1 | ||
|
|
5af7e96f70 | ||
|
|
c95041d7c3 | ||
|
|
62f40dcb21 | ||
|
|
b4f88e303a | ||
|
|
cd0ec69446 | ||
|
|
909415d167 | ||
|
|
337bc6d97a | ||
|
|
6c9fab7da1 | ||
|
|
315b1f5913 | ||
|
|
c2d1859858 | ||
|
|
37ba7316e0 | ||
|
|
fc1292b1d1 | ||
|
|
0507680cc1 | ||
|
|
60475d3354 | ||
|
|
b1cd794b2c | ||
|
|
cd98ecff88 | ||
|
|
f8ec4027ee | ||
|
|
d980a5cf44 | ||
|
|
761604d044 | ||
|
|
0f4161f616 | ||
|
|
4a668c97a3 | ||
|
|
9d687c25b3 | ||
|
|
0b73082aa0 | ||
|
|
085e1ae157 | ||
|
|
7c0db3203b | ||
|
|
bc987ed03f | ||
|
|
57e1bf3afd | ||
|
|
90606bd410 | ||
|
|
9744a3745c | ||
|
|
14e051f970 | ||
|
|
2396c9b6da | ||
|
|
c386a9d140 | ||
|
|
12847593c2 | ||
|
|
6cfa024ea2 | ||
|
|
4b43d99660 | ||
|
|
c1bfc29e7f | ||
|
|
7e91e27f14 | ||
|
|
f8015036a9 | ||
|
|
b7ef1607dc | ||
|
|
b93a31dd5b | ||
|
|
fa09964f10 | ||
|
|
0038728be3 | ||
|
|
ec56651959 | ||
|
|
8259371d6a | ||
|
|
d8623991c0 | ||
|
|
0c205431b0 | ||
|
|
58dbaf4a51 | ||
|
|
3b50ebae83 | ||
|
|
8b895eff7a | ||
|
|
70af0365bf | ||
|
|
bb3e3bfa1f | ||
|
|
54aa98a752 | ||
|
|
3bff0aa1ea | ||
|
|
b012231635 | ||
|
|
6c6f05fc91 | ||
|
|
3338d5e105 | ||
|
|
390ec2f0c1 | ||
|
|
4ebdf7a6e8 | ||
|
|
6f1366dbb5 | ||
|
|
503791d3c0 | ||
|
|
902dc49de2 | ||
|
|
2d299f31e5 | ||
|
|
df298587b8 | ||
|
|
b9c33008d8 | ||
|
|
ca97f1c4a3 | ||
|
|
effed56653 | ||
|
|
7b501aa89b | ||
|
|
6c0d0d465b | ||
|
|
a52bd20912 | ||
|
|
aabcc445ee | ||
|
|
d491e504cc | ||
|
|
3142e430e7 | ||
|
|
b784d80a50 | ||
|
|
7344654308 | ||
|
|
e01b35c39c | ||
|
|
b8b2c4ee73 | ||
|
|
8cd1ce97f7 | ||
|
|
05b514b743 | ||
|
|
22596e0f5b | ||
|
|
e7031794df | ||
|
|
af69a0a1fd | ||
|
|
52fa690764 | ||
|
|
4ad411e320 | ||
|
|
09da190e93 | ||
|
|
797dd56bb7 | ||
|
|
5e1d77fcd5 | ||
|
|
2820f2658b | ||
|
|
f3fc32660b | ||
|
|
2d4b00ec24 | ||
|
|
86808f5035 | ||
|
|
82946e2372 | ||
|
|
22d117a397 | ||
|
|
662cfc9fdc | ||
|
|
a3e73909cf | ||
|
|
95bafc8ced | ||
|
|
05f1906f77 | ||
|
|
dbbb131424 | ||
|
|
fc7ec35242 | ||
|
|
7ac10472dc | ||
|
|
d255889c5c | ||
|
|
7662da22fc | ||
|
|
64cc200df0 | ||
|
|
63c983683c | ||
|
|
92f79c99f7 | ||
|
|
24f937fe4f | ||
|
|
47bb682890 | ||
|
|
9ab674ef9a | ||
|
|
83eb0de916 | ||
|
|
6359a12dbb | ||
|
|
eb8e96f413 | ||
|
|
138bd96167 | ||
|
|
0d5ea4711d | ||
|
|
fa4212f07b | ||
|
|
c7635a7e3d | ||
|
|
3923c4cfd2 | ||
|
|
6ad884080c | ||
|
|
c578a43611 | ||
|
|
aebfa7161f | ||
|
|
682bc502e2 | ||
|
|
cf018ff74c | ||
|
|
5a9cb251ad | ||
|
|
bbbf5a5edf | ||
|
|
7df0449100 | ||
|
|
820add87ea | ||
|
|
9a574aa00c | ||
|
|
10da82a331 | ||
|
|
26c816e78c | ||
|
|
808e238384 | ||
|
|
ff068e032b | ||
|
|
5072e96277 | ||
|
|
c55c1c0615 | ||
|
|
9983faef70 | ||
|
|
70a264e939 | ||
|
|
9ef6008c67 | ||
|
|
5a3e816544 | ||
|
|
3e385fb884 | ||
|
|
fa5cce7477 | ||
|
|
b2de76e8a0 | ||
|
|
edb363b236 | ||
|
|
12dcfdb5e1 | ||
|
|
86c1dd7f32 | ||
|
|
d8ff4285da | ||
|
|
7effde0478 | ||
|
|
559ee931fb | ||
|
|
cb27a7fe3e | ||
|
|
c33a8dc2c8 | ||
|
|
11fcf88b88 | ||
|
|
4f0baa80d7 | ||
|
|
ddea97bc88 | ||
|
|
102c9891a0 | ||
|
|
fb4784b695 | ||
|
|
9a0650c703 | ||
|
|
a62b93acec | ||
|
|
2d11bdc736 | ||
|
|
7d263d36a0 | ||
|
|
4965fd5888 | ||
|
|
36db8b6f59 | ||
|
|
9e69f62a39 | ||
|
|
f307021cf1 | ||
|
|
0709c402f8 | ||
|
|
df5deb8b88 | ||
|
|
111dd40097 | ||
|
|
c83e7d7995 | ||
|
|
718f964de7 | ||
|
|
ce0db9b968 | ||
|
|
3f0d602353 | ||
|
|
5364d778b0 | ||
|
|
0ddec227fa | ||
|
|
a5ea35ee56 | ||
|
|
a3e03fb889 | ||
|
|
b7711f0182 | ||
|
|
aae199ff1c | ||
|
|
8d0611a188 | ||
|
|
958b245c3d | ||
|
|
fbb77092eb | ||
|
|
ebc8328712 | ||
|
|
7967c6dfc8 | ||
|
|
fca08a5162 | ||
|
|
49f65d6762 | ||
|
|
7684e1bad5 | ||
|
|
46e974d201 | ||
|
|
ab55d0abc8 | ||
|
|
ed668d5144 | ||
|
|
dec0f28a2b | ||
|
|
de7d79f1f4 | ||
|
|
d204d580dd | ||
|
|
e4e38edf24 | ||
|
|
3721a1f90b | ||
|
|
897850c3eb | ||
|
|
a22efb25c6 | ||
|
|
f7e80879ae | ||
|
|
bf902e6398 | ||
|
|
aed817f724 | ||
|
|
5ac76d29fc | ||
|
|
81311ddd03 | ||
|
|
3c52070243 | ||
|
|
9070f50658 | ||
|
|
ecc3c56cb1 | ||
|
|
a86191f6e0 | ||
|
|
aa5fdac522 | ||
|
|
3cd32c74a1 | ||
|
|
2e2f6a03d9 | ||
|
|
25a073f20b | ||
|
|
0fb244e381 | ||
|
|
631ba70b72 | ||
|
|
0a1d6b2a6f | ||
|
|
94bfa5ea25 | ||
|
|
118c14bf1e | ||
|
|
cf395f707a | ||
|
|
6e040fa87c | ||
|
|
c0a7f84382 | ||
|
|
826d7b7c26 | ||
|
|
91e63d0f19 | ||
|
|
2d69e5f6ff | ||
|
|
23f0fcd024 | ||
|
|
3fcd82abad | ||
|
|
d766c39791 | ||
|
|
a76c3b3baa | ||
|
|
9290b4eecc | ||
|
|
eccfec4b4f | ||
|
|
80aadd3874 | ||
|
|
9da15826db | ||
|
|
8c403f8795 | ||
|
|
b010824dbd | ||
|
|
3340f8864f | ||
|
|
9fb3cdfc4c | ||
|
|
3a3a2c2702 | ||
|
|
be38919758 | ||
|
|
a816ccf6ee | ||
|
|
5e85068e35 | ||
|
|
77865ab4a1 | ||
|
|
5fc6ee27f6 | ||
|
|
5995adf8b6 | ||
|
|
c9f47ed89a | ||
|
|
d6325ffcfa | ||
|
|
9d72472114 | ||
|
|
102350a125 | ||
|
|
1c650cb136 | ||
|
|
625e74653d | ||
|
|
5bad762293 | ||
|
|
fc1ff11352 | ||
|
|
0595ba384e | ||
|
|
f80f5e9955 | ||
|
|
f689014c3e | ||
|
|
9b24655bbf | ||
|
|
c3201070a1 | ||
|
|
8a146209e4 | ||
|
|
2b719726cd | ||
|
|
27209e4836 | ||
|
|
0497762f94 | ||
|
|
b38f1e744b | ||
|
|
481c49e18e | ||
|
|
69cf9115b5 | ||
|
|
3eedd89efe | ||
|
|
ad262ea624 | ||
|
|
08cd8c95f7 | ||
|
|
c86790c6b8 | ||
|
|
e466d9252f | ||
|
|
02f8a0baa6 | ||
|
|
9f7bbe3f9d | ||
|
|
e81e0e97e0 | ||
|
|
52554c3972 | ||
|
|
48b6c4876a | ||
|
|
99e89c2540 | ||
|
|
0e8453d4ed | ||
|
|
c750b746b3 | ||
|
|
0ac07e2e83 | ||
|
|
ead6cb9ca3 | ||
|
|
c401f9211d | ||
|
|
abb72c0a9a | ||
|
|
bc9172bd43 | ||
|
|
b205a5e49d | ||
|
|
fccf9642d8 | ||
|
|
96dd68f52b | ||
|
|
7f923bb389 | ||
|
|
7ab7ebb3f6 | ||
|
|
4eacb58a3e | ||
|
|
24248832d1 | ||
|
|
a53f0900bd | ||
|
|
6a1a5a0f74 | ||
|
|
65aa4e145e | ||
|
|
cf903aa082 | ||
|
|
75dd86e8ef | ||
|
|
70a3d62c14 | ||
|
|
291e3cd229 | ||
|
|
9b28c1fdd2 | ||
|
|
d1d73da039 | ||
|
|
59f041b9a9 | ||
|
|
fbf3b9ce4d | ||
|
|
9be2e1c4c9 | ||
|
|
a06c9f890c | ||
|
|
fc8e8874a9 | ||
|
|
09e0f68616 | ||
|
|
0e7e36f80d | ||
|
|
8484dcd332 | ||
|
|
8a46296b48 | ||
|
|
b748a910b2 | ||
|
|
932603eea3 | ||
|
|
5056972f79 | ||
|
|
d99ccca291 | ||
|
|
1d9b26d9ec | ||
|
|
3a64707c6e | ||
|
|
6f4071bd75 | ||
|
|
1354fdc613 | ||
|
|
991244655a | ||
|
|
0d07d935bf | ||
|
|
bd56b642a7 | ||
|
|
d989f0edf2 | ||
|
|
f561cf9c8f | ||
|
|
13502e5467 | ||
|
|
045c2a6f05 | ||
|
|
725e9feb68 | ||
|
|
6e45126f53 | ||
|
|
6ebc39e038 | ||
|
|
8b0a7c302b | ||
|
|
0c3e50da2f | ||
|
|
d220cf4acc | ||
|
|
eb1ce7e927 | ||
|
|
46f6f41a6b | ||
|
|
2fa59fc43c | ||
|
|
b7763b3887 | ||
|
|
8c002b67d5 | ||
|
|
7692c4a377 | ||
|
|
1f0acec06c | ||
|
|
1b5295a8fe | ||
|
|
0b699a3f20 | ||
|
|
409d7a499d | ||
|
|
ba7428f3d6 | ||
|
|
c12c32d26e | ||
|
|
0ca5ea0150 | ||
|
|
11ca7c7b3e | ||
|
|
8f6c47527d | ||
|
|
dd28882b27 | ||
|
|
1b93a449b2 | ||
|
|
7cf2ec09b7 | ||
|
|
4d1952a406 | ||
|
|
b8d25e2327 | ||
|
|
89d7c7e572 | ||
|
|
75b19230eb | ||
|
|
7889ca1ca7 | ||
|
|
cec1b932bd | ||
|
|
2c7455ea2b | ||
|
|
edc9cc9278 | ||
|
|
51eafaeb4f | ||
|
|
556373d331 | ||
|
|
804cfb7482 | ||
|
|
143eae0729 | ||
|
|
29d4846de7 | ||
|
|
306178f371 | ||
|
|
371b541fbc | ||
|
|
902658fd21 | ||
|
|
0ca8dff974 | ||
|
|
a212b054e7 | ||
|
|
cccd1baa2f | ||
|
|
5dd25aed4d | ||
|
|
6ddc725b75 | ||
|
|
36ab7444a0 | ||
|
|
a8d004334a | ||
|
|
900398a632 | ||
|
|
f24bb8737d | ||
|
|
cb5e9b197a | ||
|
|
450e20ae78 | ||
|
|
5d42a76fe5 | ||
|
|
c5075a3db0 | ||
|
|
ad5bb5198b | ||
|
|
d306bc4a9a | ||
|
|
5c3b956542 | ||
|
|
ade8533f28 | ||
|
|
ad3413d6ad | ||
|
|
f3d0e3f4dd | ||
|
|
6e2e030ba7 | ||
|
|
613f993638 | ||
|
|
2566e3631b | ||
|
|
4ad6c0a8a9 | ||
|
|
0369ac450e | ||
|
|
ab16680cc8 | ||
|
|
8a344cd9b2 | ||
|
|
4e66fb4589 | ||
|
|
0043e3d623 | ||
|
|
ed168015bf | ||
|
|
1d450ef27e | ||
|
|
932e681d22 | ||
|
|
032bcd9fbe | ||
|
|
e113fa53a4 | ||
|
|
da212dc2a4 | ||
|
|
d1c5a62a9d | ||
|
|
0c777e10e5 | ||
|
|
b919b172b1 | ||
|
|
5dd8d05114 | ||
|
|
3400b32015 | ||
|
|
2e4becad60 | ||
|
|
3d485858d5 | ||
|
|
be93643808 | ||
|
|
f704352bae | ||
|
|
6683b46b07 | ||
|
|
a1fe458338 | ||
|
|
e6328e3207 | ||
|
|
8b1f703397 | ||
|
|
583c8add7e | ||
|
|
0266cc8e99 | ||
|
|
fac4132cb1 | ||
|
|
bf3864b2da | ||
|
|
7c21042858 | ||
|
|
d0fd9e4618 | ||
|
|
9b53230f83 | ||
|
|
d814b7b11e | ||
|
|
9f5421d3d4 | ||
|
|
6b9e5db3bf | ||
|
|
9eac3faf3d | ||
|
|
252de444fc | ||
|
|
c29b9cc937 | ||
|
|
6ac582a771 | ||
|
|
04b0c9f2cf | ||
|
|
6b2468f033 | ||
|
|
2737acb114 | ||
|
|
d03e9c48c5 | ||
|
|
08d9cfe82c | ||
|
|
e8ea8f91c3 | ||
|
|
e7cfa7fda5 | ||
|
|
b0b504d002 | ||
|
|
1da07ba60b | ||
|
|
cedebf8145 | ||
|
|
29832bb2c0 | ||
|
|
320d815d60 | ||
|
|
9f18401581 | ||
|
|
b3a2f0e3a3 | ||
|
|
c00dcd31d6 | ||
|
|
b836be2c84 | ||
|
|
f89c5cc072 | ||
|
|
ab7fa56bb3 | ||
|
|
7e624159ee | ||
|
|
857a791d68 | ||
|
|
171463faf5 | ||
|
|
2cafb49ffe | ||
|
|
ae12fed5fe | ||
|
|
be5547de53 | ||
|
|
cac50ef566 | ||
|
|
57a5736942 | ||
|
|
167eadf699 | ||
|
|
5676e420a6 | ||
|
|
f5edc9e973 | ||
|
|
4a305e1568 | ||
|
|
748ab221dd | ||
|
|
7d786cea8f | ||
|
|
1bf734338d | ||
|
|
98df1d6004 | ||
|
|
290e942f3e | ||
|
|
46d54f7e01 | ||
|
|
16e1715d06 | ||
|
|
52faa1bec5 | ||
|
|
c8a6465688 | ||
|
|
0273b7606e | ||
|
|
51022cb132 | ||
|
|
78f9d87ac3 | ||
|
|
e57135eaab | ||
|
|
5fbb663529 | ||
|
|
7db0f540bd | ||
|
|
c8f0afb775 | ||
|
|
51a5815098 | ||
|
|
18bd2eb729 | ||
|
|
f04fd61879 | ||
|
|
c1527cc4c8 | ||
|
|
cf1c1ed126 | ||
|
|
c4ba8f96e6 | ||
|
|
350884c627 | ||
|
|
aa756f6d68 | ||
|
|
1a77bf49f5 | ||
|
|
1b509c56fe | ||
|
|
038b10c74d | ||
|
|
39baa59625 | ||
|
|
3fc091ebb2 | ||
|
|
a557e133d3 | ||
|
|
7d4f10ccc6 | ||
|
|
39a15bef12 | ||
|
|
92c59f3ea1 | ||
|
|
226bd44e2c | ||
|
|
78d43a49c6 | ||
|
|
471651ac5a | ||
|
|
89515b0e30 | ||
|
|
1d61c0d970 | ||
|
|
35c3acbade | ||
|
|
58a2c6a13a | ||
|
|
bf0160adbd | ||
|
|
dfbc92dd3e | ||
|
|
85b0bbfd55 | ||
|
|
fb2a93dc05 | ||
|
|
4ac46bf19d | ||
|
|
4d73adb540 | ||
|
|
bdfeb1ae22 | ||
|
|
3fc116ab53 | ||
|
|
8db61a38cc | ||
|
|
0a70979934 | ||
|
|
1a2ccdf991 | ||
|
|
0adee56d76 | ||
|
|
fedd50efe4 | ||
|
|
d7de7dbe6b | ||
|
|
9fb8939efd | ||
|
|
fe8f671137 | ||
|
|
1a4de1482b | ||
|
|
090a2595e1 | ||
|
|
89dc7f817f | ||
|
|
fe0f26ce9c | ||
|
|
11349629f4 | ||
|
|
9a67652c0c | ||
|
|
b35521dfcb | ||
|
|
9faf306d1e | ||
|
|
d8393dace6 | ||
|
|
692e5275a3 | ||
|
|
1cfe517db8 | ||
|
|
e99e1dc2ac | ||
|
|
1bf4ebcabb | ||
|
|
ec4b264868 | ||
|
|
efb125b2d5 | ||
|
|
1c0fdbed59 | ||
|
|
37bb10e564 | ||
|
|
1507d5d85f | ||
|
|
2a86acfc50 | ||
|
|
e0ee01b92e | ||
|
|
6006917622 | ||
|
|
4ffcf6bf3b | ||
|
|
49cde59c4e | ||
|
|
ed7382995c | ||
|
|
a7faab53b9 | ||
|
|
a6aad25117 | ||
|
|
5f06084b19 | ||
|
|
8151fbcb2e | ||
|
|
5a8e46a6b8 | ||
|
|
c4997c52e2 | ||
|
|
ff12c22f50 | ||
|
|
ed7f09ab80 | ||
|
|
f68941992a | ||
|
|
afcd9285e6 | ||
|
|
22f78d5b33 | ||
|
|
5259142eb6 | ||
|
|
dc403ce8ab | ||
|
|
a6fddd6a2c | ||
|
|
819cd623f9 | ||
|
|
f185494de3 | ||
|
|
628a17ae72 | ||
|
|
08169b9180 | ||
|
|
1e79f2441c | ||
|
|
8680c0ba39 | ||
|
|
8a78b0dbd6 | ||
|
|
0232035e34 | ||
|
|
74f3df83db | ||
|
|
53fa0d2fe8 | ||
|
|
52aa9ab761 | ||
|
|
92cf6195b2 | ||
|
|
86a392991a | ||
|
|
30d426d667 | ||
|
|
5702c50680 | ||
|
|
e38d2e156d | ||
|
|
dfc18619a2 | ||
|
|
9e8f2c52a0 | ||
|
|
1c8f5b98f1 | ||
|
|
972470ad42 | ||
|
|
f7e3a055fb | ||
|
|
34f05fb8dc | ||
|
|
709fd34264 | ||
|
|
b888757092 | ||
|
|
0f42827047 | ||
|
|
e69d1556e1 | ||
|
|
141fbf7472 | ||
|
|
c9a3ae8149 | ||
|
|
e16a8d29ea | ||
|
|
fff50d0e50 | ||
|
|
360734b447 | ||
|
|
7e5edad32b | ||
|
|
fc47b47850 | ||
|
|
c7de058e1d | ||
|
|
0fff3c905c | ||
|
|
2fcb055c43 | ||
|
|
97e0d63102 | ||
|
|
5e04f0accd | ||
|
|
16835e3928 | ||
|
|
22e0ef1354 | ||
|
|
0141dc519c | ||
|
|
9aadc30b94 | ||
|
|
23a73fcb7c | ||
|
|
9a3b585110 | ||
|
|
09ee46860a | ||
|
|
d8f289182d | ||
|
|
dc8fa2153b | ||
|
|
32fb335832 | ||
|
|
58885854f1 | ||
|
|
3e87788541 | ||
|
|
5746df4d74 | ||
|
|
71d86c44e0 | ||
|
|
c5e50289e1 | ||
|
|
e62f1edada | ||
|
|
50e8db28b8 | ||
|
|
ef7c572018 | ||
|
|
1e962754cc | ||
|
|
0240453b07 | ||
|
|
38a80a95f2 | ||
|
|
b5e411d251 | ||
|
|
71a623276e | ||
|
|
1e76703144 | ||
|
|
6ffaf11226 | ||
|
|
fc0caec1a4 |
41
.clang-format
Normal file
41
.clang-format
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
|
||||
8
.github/FUNDING.yml
vendored
8
.github/FUNDING.yml
vendored
@@ -1,12 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: skypjack
|
||||
patreon: skypjack
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: https://www.paypal.me/skypjack
|
||||
|
||||
55
.github/workflows/analyzer.yml
vendored
Normal file
55
.github/workflows/analyzer.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: analyzer
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- wip
|
||||
|
||||
jobs:
|
||||
|
||||
iwyu:
|
||||
timeout-minutes: 30
|
||||
|
||||
env:
|
||||
IWYU: 0.18
|
||||
LLVM: 14
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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 -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
|
||||
124
.github/workflows/build.yml
vendored
124
.github/workflows/build.yml
vendored
@@ -5,11 +5,59 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
compiler:
|
||||
- pkg: g++-7
|
||||
exe: g++-7
|
||||
- pkg: g++-8
|
||||
exe: g++-8
|
||||
- pkg: g++-9
|
||||
exe: g++-9
|
||||
- pkg: g++-10
|
||||
exe: g++-10
|
||||
- pkg: clang-8
|
||||
exe: clang++-8
|
||||
- pkg: clang-9
|
||||
exe: clang++-9
|
||||
- pkg: clang-10
|
||||
exe: clang++-10
|
||||
- pkg: clang-11
|
||||
exe: clang++-11
|
||||
- pkg: clang-12
|
||||
exe: clang++-12
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install compiler
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y ${{ matrix.compiler.pkg }}
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXX: ${{ matrix.compiler.exe }}
|
||||
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
|
||||
|
||||
linux-extra:
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [g++, clang++]
|
||||
id_type: ["std::uint32_t", "std::uint64_t"]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -20,45 +68,68 @@ jobs:
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
run: |
|
||||
cmake -DBUILD_TESTING=ON -DBUILD_LIB=ON ..
|
||||
cmake -DENTT_BUILD_TESTING=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 5 -C Debug -j4
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
windows:
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, windows-2016]
|
||||
toolset: [clang-cl, default]
|
||||
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"
|
||||
exclude:
|
||||
- os: windows-2016
|
||||
toolset: clang-cl
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DBUILD_TESTING=ON -DBUILD_LIB=ON ${{ matrix.toolset_option }} ..
|
||||
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 5 -C Debug -j4
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
windows-extra:
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
id_type: ["std::uint32_t", "std::uint64_t"]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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
|
||||
|
||||
macos:
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 15
|
||||
runs-on: macOS-latest
|
||||
|
||||
steps:
|
||||
@@ -66,10 +137,33 @@ jobs:
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DBUILD_TESTING=ON -DBUILD_LIB=ON ..
|
||||
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 5 -C Debug -j4
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
macos-extra:
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
id_type: ["std::uint32_t", "std::uint64_t"]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
|
||||
runs-on: macOS-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=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
|
||||
|
||||
25
.github/workflows/coverage.yml
vendored
25
.github/workflows/coverage.yml
vendored
@@ -5,7 +5,7 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
|
||||
codecov:
|
||||
timeout-minutes: 10
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
@@ -13,21 +13,26 @@ jobs:
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXXFLAGS: "-O0 --coverage -fno-inline -fno-inline-small-functions -fno-default-inline"
|
||||
CXXFLAGS: "--coverage -fno-inline"
|
||||
CXX: g++
|
||||
run: |
|
||||
cmake -DBUILD_TESTING=ON -DBUILD_LIB=ON ..
|
||||
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 5 -C Debug -j4
|
||||
- name: Upload coverage to Codecov
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
- name: Collect data
|
||||
working-directory: build
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
run: |
|
||||
wget https://codecov.io/bash -O codecov
|
||||
chmod +x codecov
|
||||
./codecov -t $CODECOV_TOKEN -B $GITHUB_REF -s test/
|
||||
sudo apt install lcov
|
||||
lcov -c -d . -o coverage.info
|
||||
lcov -l coverage.info
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v2
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: build/coverage.info
|
||||
name: EnTT
|
||||
fail_ci_if_error: true
|
||||
|
||||
5
.github/workflows/deploy.yml
vendored
5
.github/workflows/deploy.yml
vendored
@@ -20,8 +20,7 @@ jobs:
|
||||
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
|
||||
run: git clone https://$GITHUB_ACTOR:$PERSONAL_ACCESS_TOKEN@github.com/$GITHUB_ACTOR/$GH_REPO.git
|
||||
- name: Prepare formula
|
||||
working-directory: build
|
||||
run: |
|
||||
@@ -37,4 +36,4 @@ jobs:
|
||||
git config --local user.name "$GITHUB_ACTOR"
|
||||
git add $FORMULA
|
||||
git commit -m "Update to ${{ github.ref }}"
|
||||
git push --dry-run origin master
|
||||
git push origin master
|
||||
|
||||
31
.github/workflows/sanitizer.yml
vendored
Normal file
31
.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@v2
|
||||
- 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
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,6 +5,9 @@ conan/test_package/build
|
||||
*.user
|
||||
.idea
|
||||
.vscode
|
||||
.vs
|
||||
CMakeSettings.json
|
||||
cpp.hint
|
||||
|
||||
# Bazel
|
||||
/bazel-*
|
||||
|
||||
12
AUTHORS
12
AUTHORS
@@ -4,17 +4,23 @@ skypjack
|
||||
|
||||
# Contributors
|
||||
|
||||
alexames
|
||||
BenediktConze
|
||||
bjadamson
|
||||
ceeac
|
||||
ColinH
|
||||
corystegel
|
||||
Croydon
|
||||
cschreib
|
||||
cugone
|
||||
dbacchet
|
||||
dBagrat
|
||||
djarek
|
||||
DNKpp
|
||||
DonKult
|
||||
drglove
|
||||
eliasdaler
|
||||
erez-o
|
||||
eugeneko
|
||||
gale83
|
||||
ghost
|
||||
@@ -22,16 +28,21 @@ 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
|
||||
@@ -39,6 +50,7 @@ The5-1
|
||||
vblanco20-1
|
||||
willtunnels
|
||||
WizardIke
|
||||
WoLfulus
|
||||
w1th0utnam3
|
||||
xissburg
|
||||
zaucy
|
||||
|
||||
@@ -9,7 +9,6 @@ cc_library(
|
||||
copts = select({
|
||||
"@bazel_tools//src/conditions:windows": _msvc_copts,
|
||||
"@bazel_tools//src/conditions:windows_msvc": _msvc_copts,
|
||||
"@bazel_tools//src/conditions:windows_msys": _msvc_copts,
|
||||
"//conditions:default": _gcc_copts,
|
||||
}),
|
||||
)
|
||||
|
||||
283
CMakeLists.txt
283
CMakeLists.txt
@@ -4,14 +4,6 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.12.4)
|
||||
|
||||
#
|
||||
# Building in-tree is not allowed (we take care of your craziness).
|
||||
#
|
||||
|
||||
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the source code and call cmake from there. Thank you.")
|
||||
endif()
|
||||
|
||||
#
|
||||
# Read project version
|
||||
#
|
||||
@@ -30,49 +22,82 @@ project(
|
||||
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 CXX
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
message("*")
|
||||
message("* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||
message("* Copyright (c) 2017-2020 Michele Caini <michele.caini@gmail.com>")
|
||||
message("*")
|
||||
message(VERBOSE "*")
|
||||
message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||
message(VERBOSE "* Copyright (c) 2017-2022 Michele Caini <michele.caini@gmail.com>")
|
||||
message(VERBOSE "*")
|
||||
|
||||
option(USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if availbale." ON)
|
||||
option(USE_ASAN "Use address sanitizer by adding -fsanitize=address -fno-omit-frame-pointer flags" OFF)
|
||||
#
|
||||
# CMake stuff
|
||||
#
|
||||
|
||||
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||
|
||||
#
|
||||
# Compiler stuff
|
||||
#
|
||||
|
||||
if(NOT WIN32 AND USE_LIBCPP)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CMakePushCheckState)
|
||||
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)
|
||||
|
||||
cmake_push_check_state()
|
||||
if(ENTT_USE_LIBCPP)
|
||||
if(NOT WIN32)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CMakePushCheckState)
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++")
|
||||
cmake_push_check_state()
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include<type_traits>
|
||||
int main() { return std::is_same_v<int, char>; }
|
||||
" HAS_LIBCPP)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++")
|
||||
|
||||
if(NOT HAS_LIBCPP)
|
||||
message(WARNING "The option USE_LIBCPP is set (by default) but libc++ is not available. The flag will not be added to the target.")
|
||||
check_cxx_source_compiles("
|
||||
#include<type_traits>
|
||||
int main() { return std::is_same_v<int, char>; }
|
||||
" ENTT_HAS_LIBCPP)
|
||||
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
|
||||
cmake_pop_check_state()
|
||||
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)
|
||||
@@ -85,16 +110,136 @@ target_include_directories(
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
if(USE_ASAN)
|
||||
target_compile_options(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
|
||||
target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
|
||||
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/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/storage_mixin.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(HAS_LIBCPP)
|
||||
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()
|
||||
|
||||
target_compile_features(EnTT INTERFACE cxx_std_17)
|
||||
#
|
||||
# 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
|
||||
@@ -102,19 +247,10 @@ target_compile_features(EnTT INTERFACE cxx_std_17)
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
|
||||
set(CUSTOM_INSTALL_CONFIGDIR cmake)
|
||||
else()
|
||||
set(CUSTOM_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/entt)
|
||||
endif()
|
||||
|
||||
install(TARGETS EnTT EXPORT EnTTTargets)
|
||||
|
||||
configure_package_config_file(
|
||||
${EnTT_SOURCE_DIR}/cmake/in/EnTTConfig.cmake.in
|
||||
EnTTConfig.cmake
|
||||
INSTALL_DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
|
||||
PATH_VARS CMAKE_INSTALL_INCLUDEDIR
|
||||
install(
|
||||
TARGETS EnTT
|
||||
EXPORT EnTTTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
@@ -123,10 +259,22 @@ write_basic_package_version_file(
|
||||
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 ${CUSTOM_INSTALL_CONFIGDIR}
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
|
||||
NAMESPACE EnTT::
|
||||
)
|
||||
|
||||
@@ -134,23 +282,30 @@ install(
|
||||
FILES
|
||||
${PROJECT_BINARY_DIR}/EnTTConfig.cmake
|
||||
${PROJECT_BINARY_DIR}/EnTTConfigVersion.cmake
|
||||
DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
|
||||
)
|
||||
|
||||
install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
export(PACKAGE EnTT)
|
||||
|
||||
#
|
||||
# Tests
|
||||
#
|
||||
|
||||
option(BUILD_TESTING "Enable testing with ctest." OFF)
|
||||
option(ENTT_BUILD_TESTING "Enable building tests." OFF)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
option(FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
|
||||
option(BUILD_BENCHMARK "Build benchmark." OFF)
|
||||
option(BUILD_LIB "Build lib example." OFF)
|
||||
option(BUILD_SNAPSHOT "Build snapshot example." 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()
|
||||
@@ -159,30 +314,12 @@ endif()
|
||||
# Documentation
|
||||
#
|
||||
|
||||
option(BUILD_DOCS "Enable building with documentation." OFF)
|
||||
option(ENTT_BUILD_DOCS "Enable building with documentation." OFF)
|
||||
|
||||
if(BUILD_DOCS)
|
||||
if(ENTT_BUILD_DOCS)
|
||||
find_package(Doxygen 1.8)
|
||||
|
||||
if(DOXYGEN_FOUND)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# AOB
|
||||
#
|
||||
|
||||
add_custom_target(
|
||||
aob
|
||||
SOURCES
|
||||
.github/workflows/build.yml
|
||||
.github/workflows/coverage.yml
|
||||
.github/workflows/deploy.yml
|
||||
.github/FUNDING.yml
|
||||
AUTHORS
|
||||
CONTRIBUTING.md
|
||||
LICENSE
|
||||
README.md
|
||||
TODO
|
||||
)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Contributing
|
||||
|
||||
First of all, thank you very much for taking the time to contribute to the
|
||||
`EnTT` framework.<br/>
|
||||
`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
|
||||
@@ -28,7 +28,7 @@ How to do it mostly depends on the type of contribution:
|
||||
* 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` framework has a
|
||||
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.
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2020 Michele Caini
|
||||
Copyright (c) 2017-2022 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
|
||||
|
||||
344
README.md
344
README.md
@@ -1,23 +1,27 @@
|
||||

|
||||

|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
[](https://github.com/skypjack/entt/releases)
|
||||
[](https://github.com/skypjack/entt/actions)
|
||||
[](https://codecov.io/gh/skypjack/entt)
|
||||
[](https://godbolt.org/z/v8txVr)
|
||||
[](https://godbolt.org/z/zxW73f)
|
||||
[](http://entt.docsforge.com/)
|
||||
[](https://gitter.im/skypjack/entt)
|
||||
[](https://discord.gg/5BjPWBd)
|
||||
[](https://www.paypal.me/skypjack)
|
||||
[](https://www.patreon.com/bePatron?c=1772573)
|
||||
|
||||
> `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++**, mainly known for its innovative
|
||||
**entity-component-system (ECS)** model.<br/>
|
||||
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 and the
|
||||
[**ArcGIS Runtime SDKs**](https://developers.arcgis.com/arcgis-runtime/) by
|
||||
Esri.<br/>
|
||||
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:
|
||||
|
||||
@@ -25,22 +29,21 @@ 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 meet other users
|
||||
like you. The more we are, the better for everyone.
|
||||
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.
|
||||
|
||||
Wondering why your **debug build** is so slow on Windows or how to represent a
|
||||
**hierarchy** with components?<br/>
|
||||
Check out the
|
||||
[FAQ](https://github.com/skypjack/entt/wiki/Frequently-Asked-Questions) and the
|
||||
[wiki](https://github.com/skypjack/entt/wiki) if you have these or other doubts,
|
||||
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:
|
||||
|
||||
If you use `EnTT` and you want to say thanks or support the project, please
|
||||
**consider becoming a
|
||||
[sponsor](https://github.com/users/skypjack/sponsorship)**.<br/>
|
||||
You can help me make the difference.
|
||||
[Many thanks](https://skypjack.github.io/sponsorship/) to those who supported me
|
||||
and still support me today.
|
||||
[](https://mojang.com)
|
||||
[](https://img.ly/)
|
||||
|
||||
# Table of Contents
|
||||
|
||||
@@ -48,16 +51,17 @@ and still support me today.
|
||||
* [Code Example](#code-example)
|
||||
* [Motivation](#motivation)
|
||||
* [Performance](#performance)
|
||||
* [Build Instructions](#build-instructions)
|
||||
* [Integration](#integration)
|
||||
* [Requirements](#requirements)
|
||||
* [Library](#library)
|
||||
* [Documentation](#documentation)
|
||||
* [Tests](#tests)
|
||||
* [Packaging Tools](#packaging-tools)
|
||||
* [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)
|
||||
* [Support](#support)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
@@ -75,41 +79,42 @@ 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:
|
||||
|
||||
* Statically generated integer **identifiers** for types (assigned either at
|
||||
compile-time or at runtime).
|
||||
* A `constexpr` utility for human readable **resource names**.
|
||||
* A minimal **configuration system** built using the monostate pattern.
|
||||
* An incredibly fast **entity-component system** based on sparse sets, with its
|
||||
own _pay for what you use_ policy to adjust performance and memory usage
|
||||
according to the users' requirements.
|
||||
* 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 (dependencies, snapshot, actor
|
||||
class, support for **reactive systems** and so on).
|
||||
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** (with built-in support for collectors) and a
|
||||
tiny event dispatcher for immediate and delayed events to integrate in loops.
|
||||
* 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.
|
||||
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.
|
||||
|
||||
Currently, `EnTT` is tested on Linux, Microsoft Windows and OSX. It has proven
|
||||
to work also on both Android and iOS.<br/>
|
||||
Most likely it won't be problematic on other systems as well, but it hasn't been
|
||||
sufficiently tested so far.
|
||||
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>
|
||||
#include <cstdint>
|
||||
|
||||
struct position {
|
||||
float x;
|
||||
@@ -122,52 +127,43 @@ struct velocity {
|
||||
};
|
||||
|
||||
void update(entt::registry ®istry) {
|
||||
auto view = registry.view<position, velocity>();
|
||||
auto view = registry.view<const position, velocity>();
|
||||
|
||||
for(auto entity: view) {
|
||||
// gets only the components that are going to be used ...
|
||||
// use a callback
|
||||
view.each([](const auto &pos, auto &vel) { /* ... */ });
|
||||
|
||||
auto &vel = view.get<velocity>(entity);
|
||||
|
||||
vel.dx = 0.;
|
||||
vel.dy = 0.;
|
||||
// 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()) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
std::uint64_t dt = 16;
|
||||
|
||||
for(auto i = 0; i < 10; ++i) {
|
||||
auto entity = registry.create();
|
||||
registry.assign<position>(entity, i * 1.f, i * 1.f);
|
||||
if(i % 2 == 0) { registry.assign<velocity>(entity, i * .1f, i * .1f); }
|
||||
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(dt, registry);
|
||||
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 solution both in
|
||||
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
|
||||
@@ -189,8 +185,8 @@ 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 `BUILD_BENCHMARK` option of `CMake` to `ON`, then evaluate yourself whether
|
||||
you're satisfied with the results or not.
|
||||
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/>
|
||||
@@ -210,26 +206,7 @@ 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.
|
||||
|
||||
# Build Instructions
|
||||
|
||||
## 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.
|
||||
|
||||
If you are looking for a C++14 version of `EnTT`, check out the git tag `cpp14`.
|
||||
|
||||
## Library
|
||||
# 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
|
||||
@@ -250,48 +227,41 @@ Use the line below to include only the entity-component system instead:
|
||||
Then pass the proper `-I` argument to the compiler to add the `src` directory to
|
||||
the include paths.
|
||||
|
||||
## Documentation
|
||||
## Requirements
|
||||
|
||||
The documentation is based on [doxygen](http://www.doxygen.nl/).
|
||||
To build it:
|
||||
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:
|
||||
|
||||
$ cd build
|
||||
$ cmake .. -DBUILD_DOCS=ON
|
||||
$ make
|
||||
* `CMake` version 3.7 or later.
|
||||
* `Doxygen` version 1.8 or later.
|
||||
|
||||
The API reference will be created in HTML format within the directory
|
||||
`build/docs/html`. To navigate it with your favorite browser:
|
||||
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.
|
||||
|
||||
$ cd build
|
||||
$ your_favorite_browser docs/html/index.html
|
||||
## CMake
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
It's also available [online](https://skypjack.github.io/entt/) for the latest
|
||||
version, 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
|
||||
-->
|
||||
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.
|
||||
|
||||
## Tests
|
||||
## Natvis support
|
||||
|
||||
To compile and run the tests, `EnTT` requires *googletest*.<br/>
|
||||
`cmake` will download and compile the library before compiling anything else.
|
||||
In order to build the tests, set the CMake option `BUILD_TESTING` to `ON`.
|
||||
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!
|
||||
|
||||
To build the most basic set of tests:
|
||||
|
||||
* `$ cd build`
|
||||
* `$ cmake -DBUILD_TESTING=ON ..`
|
||||
* `$ make`
|
||||
* `$ make test`
|
||||
|
||||
Note that benchmarks are not part of this set.
|
||||
|
||||
# Packaging Tools
|
||||
## Packaging Tools
|
||||
|
||||
`EnTT` is available for some of the most known packaging tools. In particular:
|
||||
|
||||
@@ -310,6 +280,12 @@ Note that benchmarks are not part of this set.
|
||||
$ 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
|
||||
@@ -324,7 +300,84 @@ Note that benchmarks are not part of this set.
|
||||
brew install skypjack/entt/entt
|
||||
```
|
||||
|
||||
Consider this list a work in progress and help me to make it longer.
|
||||
* [`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 will be created in HTML format within the directory
|
||||
`build/docs/html`. 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. If you are looking for
|
||||
something more pleasing to the eye, consider reading the nice-looking version
|
||||
available on [docsforge](https://entt.docsforge.com/): same documentation, much
|
||||
more pleasant to read.<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` will download and compile 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
|
||||
@@ -346,18 +399,14 @@ open an issue or a PR and I'll be glad to add them to the list.
|
||||
|
||||
# Contributors
|
||||
|
||||
`EnTT` was written initially as a faster alternative to other well known and
|
||||
open source entity-component systems. Nowadays this library is moving its first
|
||||
steps. Much more will come in the future and hopefully I'm going to work on it
|
||||
for a long time.<br/>
|
||||
Requests for features, PR, suggestions ad feedback are highly appreciated.
|
||||
Requests for features, PRs, suggestions ad feedback are highly appreciated.
|
||||
|
||||
If you find you can help me and want to contribute to the project with your
|
||||
experience or you do want to get part of the project for some other reasons,
|
||||
feel free to contact me directly (you can find the mail in the
|
||||
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 seriously.
|
||||
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
|
||||
@@ -371,25 +420,12 @@ know who has participated so far.
|
||||
|
||||
# License
|
||||
|
||||
Code and documentation Copyright (c) 2017-2020 Michele Caini.<br/>
|
||||
Logo Copyright (c) 2018-2020 Richard Caseres.
|
||||
Code and documentation Copyright (c) 2017-2022 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).
|
||||
[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/>
|
||||
Logo released under
|
||||
All logos released under
|
||||
[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Support
|
||||
|
||||
If you want to support this project, you can
|
||||
[offer me](https://github.com/users/skypjack/sponsorship) an espresso.<br/>
|
||||
If you find that it's not enough, feel free to
|
||||
[help me](https://www.paypal.me/skypjack) the way you prefer.
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
50
TODO
50
TODO
@@ -1,33 +1,27 @@
|
||||
* long term feature: shared_ptr less locator and resource cache
|
||||
* custom allocators and EnTT allocator-aware in general (long term feature, I don't actually need it at the moment) - see #22
|
||||
* debugging tools (#60): the issue online already contains interesting tips on this, look at it
|
||||
* work stealing job system (see #100) + mt scheduler based on const awareness for types
|
||||
* meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects (remove runtime views, welcome reflection)
|
||||
* add opaque input iterators to views and groups that return tuples <entity, T &...> (proxy), multi-pass guaranteed
|
||||
* allow to replace std:: with custom implementations
|
||||
* custom (decoupled) pools ==> N-buffering, shared components, multi-model, hibitsets, and so on
|
||||
* add examples (and credits) from @alanjfs :)
|
||||
* static reflection, hint: template<> meta_type_t<Type>: meta_descriptor<name, func..., props..., etc...> (see #342)
|
||||
* observer: user defined filters (eg .replace<T, &function> or .group<T, U, &func>)
|
||||
* can we write a bool conv func for entt::entity that silently compares it to null?
|
||||
* reset... reset everywhere...
|
||||
* is it possible to make 0 the entity null?
|
||||
* document undocumented parts (entt::overload and a few others)
|
||||
* any-of rule for views/groups (eg entity has A and any of B/C/D)
|
||||
- get -> all, exclude -> none
|
||||
* review prepare after clone and the others have been removed
|
||||
* unlock deploy.yml
|
||||
|
||||
Next:
|
||||
* review pool<T>::remove, ::assign
|
||||
* replace observer class with observer functions
|
||||
* workflow to update the single include file automatically
|
||||
* workflow to update the doc automatically
|
||||
EXAMPLES
|
||||
* filter on runtime values/variables (not only types)
|
||||
* support to polymorphic types (see #859)
|
||||
|
||||
* WIP:
|
||||
- deprecate snapshot, loader, ...
|
||||
- provide documentation to describe alternatives
|
||||
DOC:
|
||||
* storage<void>
|
||||
* custom storage/view
|
||||
* examples (and credits) from @alanjfs :)
|
||||
* update entity doc when the storage based model is in place
|
||||
|
||||
* WIP: snapshot rework/deprecation
|
||||
- remove snapshot/loader from registry, make them external (faster) tools
|
||||
- deprecate snapshot classes, update documentation to describe alternatives
|
||||
TODO (high prio):
|
||||
* remove the static storage from the const assure in the registry
|
||||
|
||||
WIP:
|
||||
* get rid of observers, storage based views made them pointless - document alternatives
|
||||
* add storage getter for filters to views and groups
|
||||
* exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details)
|
||||
* basic_storage::bind for cross-registry setups (see and remove todo from entity_copy.cpp)
|
||||
* process scheduler: reviews, use free lists internally
|
||||
* dedicated entity storage, in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
|
||||
* entity-only and exclude-only views (both solved with entity storage and storage<void>)
|
||||
* custom allocators all over (registry, ...)
|
||||
* add test for maximum number of entities reached
|
||||
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
set(ENTT_VERSION "@PROJECT_VERSION@")
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set_and_check(ENTT_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS "3.0")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/EnTTTargets.cmake")
|
||||
endif()
|
||||
|
||||
set(EnTT_VERSION "@PROJECT_VERSION@")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/EnTTTargets.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
|
||||
8
cmake/in/entt.pc.in
Normal file
8
cmake/in/entt.pc.in
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
cmake/modules/JoinPaths.cmake
Normal file
23
cmake/modules/JoinPaths.cmake
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’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()
|
||||
@@ -43,8 +43,8 @@ int main() {
|
||||
|
||||
for(auto i = 0; i < 10; ++i) {
|
||||
auto entity = registry.create();
|
||||
registry.assign<position>(entity, i * 1.f, i * 1.f);
|
||||
if(i % 2 == 0) { registry.assign<velocity>(entity, i * .1f, i * .1f); }
|
||||
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);
|
||||
|
||||
@@ -16,6 +16,8 @@ add_custom_target(
|
||||
VERBATIM
|
||||
SOURCES
|
||||
dox/extra.dox
|
||||
md/config.md
|
||||
md/container.md
|
||||
md/core.md
|
||||
md/entity.md
|
||||
md/faq.md
|
||||
@@ -23,9 +25,12 @@ add_custom_target(
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
550
docs/doxy.in
550
docs/doxy.in
@@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.8.16
|
||||
# Doxyfile 1.9.4
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project.
|
||||
@@ -12,6 +12,15 @@
|
||||
# For lists, items can also be appended using:
|
||||
# TAG += value [value, ...]
|
||||
# Values that contain spaces should be placed between quotes (\" \").
|
||||
#
|
||||
# Note:
|
||||
#
|
||||
# Use doxygen to compare the used configuration file with the template
|
||||
# configuration file:
|
||||
# doxygen -x [configFile]
|
||||
# Use doxygen to compare the used configuration file with the template
|
||||
# configuration file without replacing the environment variables:
|
||||
# doxygen -x_noenv [configFile]
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
@@ -60,16 +69,28 @@ PROJECT_LOGO =
|
||||
|
||||
OUTPUT_DIRECTORY = @DOXY_OUTPUT_DIRECTORY@
|
||||
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
|
||||
# directories (in 2 levels) under the output directory of each output format and
|
||||
# will distribute the generated files over these directories. Enabling this
|
||||
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096
|
||||
# sub-directories (in 2 levels) under the output directory of each output format
|
||||
# and will distribute the generated files over these directories. Enabling this
|
||||
# option can be useful when feeding doxygen a huge amount of source files, where
|
||||
# putting all generated files in the same directory would otherwise causes
|
||||
# performance problems for the file system.
|
||||
# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to
|
||||
# control the number of sub-directories.
|
||||
# The default value is: NO.
|
||||
|
||||
CREATE_SUBDIRS = NO
|
||||
|
||||
# Controls the number of sub-directories that will be created when
|
||||
# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every
|
||||
# level increment doubles the number of directories, resulting in 4096
|
||||
# directories at level 8 which is the default and also the maximum value. The
|
||||
# sub-directories are organized in 2 levels, the first level always has a fixed
|
||||
# numer of 16 directories.
|
||||
# Minimum value: 0, maximum value: 8, default value: 8.
|
||||
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
|
||||
|
||||
CREATE_SUBDIRS_LEVEL = 8
|
||||
|
||||
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
|
||||
# characters to appear in the names of generated files. If set to NO, non-ASCII
|
||||
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
|
||||
@@ -81,26 +102,18 @@ ALLOW_UNICODE_NAMES = NO
|
||||
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all constant output in the proper language.
|
||||
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
|
||||
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
|
||||
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
|
||||
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
|
||||
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
|
||||
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
|
||||
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
|
||||
# Ukrainian and Vietnamese.
|
||||
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,
|
||||
# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English
|
||||
# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,
|
||||
# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with
|
||||
# English messages), Korean, Korean-en (Korean with English messages), Latvian,
|
||||
# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,
|
||||
# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,
|
||||
# Swedish, Turkish, Ukrainian and Vietnamese.
|
||||
# The default value is: English.
|
||||
|
||||
OUTPUT_LANGUAGE = English
|
||||
|
||||
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
|
||||
# documentation generated by doxygen is written. Doxygen will use this
|
||||
# information to generate all generated output in the proper direction.
|
||||
# Possible values are: None, LTR, RTL and Context.
|
||||
# The default value is: None.
|
||||
|
||||
OUTPUT_TEXT_DIRECTION = None
|
||||
|
||||
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
|
||||
# descriptions after the members that are listed in the file and class
|
||||
# documentation (similar to Javadoc). Set to NO to disable this.
|
||||
@@ -217,6 +230,14 @@ QT_AUTOBRIEF = NO
|
||||
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
|
||||
# By default Python docstrings are displayed as preformatted text and doxygen's
|
||||
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
|
||||
# doxygen's special commands can be used and the contents of the docstring
|
||||
# documentation blocks is shown as doxygen documentation.
|
||||
# The default value is: YES.
|
||||
|
||||
PYTHON_DOCSTRING = YES
|
||||
|
||||
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
|
||||
# documentation from any documented member that it re-implements.
|
||||
# The default value is: YES.
|
||||
@@ -240,25 +261,19 @@ TAB_SIZE = 4
|
||||
# the documentation. An alias has the form:
|
||||
# name=value
|
||||
# For example adding
|
||||
# "sideeffect=@par Side Effects:\n"
|
||||
# "sideeffect=@par Side Effects:^^"
|
||||
# will allow you to put the command \sideeffect (or @sideeffect) in the
|
||||
# documentation, which will result in a user-defined paragraph with heading
|
||||
# "Side Effects:". You can put \n's in the value part of an alias to insert
|
||||
# newlines (in the resulting output). You can put ^^ in the value part of an
|
||||
# alias to insert a newline as if a physical newline was in the original file.
|
||||
# When you need a literal { or } or , in the value part of an alias you have to
|
||||
# escape them by means of a backslash (\), this can lead to conflicts with the
|
||||
# commands \{ and \} for these it is advised to use the version @{ and @} or use
|
||||
# a double escape (\\{ and \\})
|
||||
# "Side Effects:". Note that you cannot put \n's in the value part of an alias
|
||||
# to insert newlines (in the resulting output). You can put ^^ in the value part
|
||||
# of an alias to insert a newline as if a physical newline was in the original
|
||||
# file. When you need a literal { or } or , in the value part of an alias you
|
||||
# have to escape them by means of a backslash (\), this can lead to conflicts
|
||||
# with the commands \{ and \} for these it is advised to use the version @{ and
|
||||
# @} or use a double escape (\\{ and \\})
|
||||
|
||||
ALIASES =
|
||||
|
||||
# This tag can be used to specify a number of word-keyword mappings (TCL only).
|
||||
# A mapping has the form "name=value". For example adding "class=itcl::class"
|
||||
# will allow you to use the command class in the itcl::class meaning.
|
||||
|
||||
TCL_SUBST =
|
||||
|
||||
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
|
||||
# only. Doxygen will then generate output that is more tailored for C. For
|
||||
# instance, some of the names that are used will be different. The list of all
|
||||
@@ -299,19 +314,22 @@ OPTIMIZE_OUTPUT_SLICE = NO
|
||||
# parses. With this tag you can assign which parser to use for a given
|
||||
# extension. Doxygen has a built-in mapping, but you can override or extend it
|
||||
# using this tag. The format is ext=language, where ext is a file extension, and
|
||||
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
|
||||
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
|
||||
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
|
||||
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
|
||||
# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,
|
||||
# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
|
||||
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
|
||||
# tries to guess whether the code is fixed or free formatted code, this is the
|
||||
# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
|
||||
# .inc files as Fortran files (default is PHP), and .f files as C (default is
|
||||
# Fortran), use: inc=Fortran f=C.
|
||||
# default for Fortran type files). For instance to make doxygen treat .inc files
|
||||
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
|
||||
# use: inc=Fortran f=C.
|
||||
#
|
||||
# Note: For files without extension you can use no_extension as a placeholder.
|
||||
#
|
||||
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
|
||||
# the files are not read by doxygen.
|
||||
# the files are not read by doxygen. When specifying no_extension you should add
|
||||
# * to the FILE_PATTERNS.
|
||||
#
|
||||
# Note see also the list of default file extension mappings.
|
||||
|
||||
EXTENSION_MAPPING =
|
||||
|
||||
@@ -445,6 +463,19 @@ TYPEDEF_HIDES_STRUCT = NO
|
||||
|
||||
LOOKUP_CACHE_SIZE = 0
|
||||
|
||||
# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use
|
||||
# during processing. When set to 0 doxygen will based this on the number of
|
||||
# cores available in the system. You can set it explicitly to a value larger
|
||||
# than 0 to get more control over the balance between CPU load and processing
|
||||
# speed. At this moment only the input processing can be done using multiple
|
||||
# threads. Since this is still an experimental feature the default is set to 1,
|
||||
# which effectively disables parallel processing. Please report any issues you
|
||||
# encounter. Generating dot graphs in parallel is controlled by the
|
||||
# DOT_NUM_THREADS setting.
|
||||
# Minimum value: 0, maximum value: 32, default value: 1.
|
||||
|
||||
NUM_PROC_THREADS = 1
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -508,6 +539,13 @@ EXTRACT_LOCAL_METHODS = NO
|
||||
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
|
||||
# If this flag is set to YES, the name of an unnamed parameter in a declaration
|
||||
# will be determined by the corresponding definition. By default unnamed
|
||||
# parameters remain unnamed in the output.
|
||||
# The default value is: YES.
|
||||
|
||||
RESOLVE_UNNAMED_PARAMS = YES
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
|
||||
# undocumented members inside documented classes or files. If set to NO these
|
||||
# members will be included in the various overviews, but no documentation
|
||||
@@ -525,8 +563,8 @@ HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
|
||||
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
|
||||
# (class|struct|union) declarations. If set to NO, these declarations will be
|
||||
# included in the documentation.
|
||||
# declarations. If set to NO, these declarations will be included in the
|
||||
# documentation.
|
||||
# The default value is: NO.
|
||||
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
@@ -545,11 +583,18 @@ HIDE_IN_BODY_DOCS = NO
|
||||
|
||||
INTERNAL_DOCS = NO
|
||||
|
||||
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
|
||||
# names in lower-case letters. If set to YES, upper-case letters are also
|
||||
# allowed. This is useful if you have classes or files whose names only differ
|
||||
# in case and if your file system supports case sensitive file names. Windows
|
||||
# (including Cygwin) ands Mac users are advised to set this option to NO.
|
||||
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
|
||||
# able to match the capabilities of the underlying filesystem. In case the
|
||||
# filesystem is case sensitive (i.e. it supports files in the same directory
|
||||
# whose names only differ in casing), the option must be set to YES to properly
|
||||
# deal with such files in case they appear in the input. For filesystems that
|
||||
# are not case sensitive the option should be set to NO to properly deal with
|
||||
# output files written for symbols that only differ in casing, such as for two
|
||||
# classes, one named CLASS and the other named Class, and to also support
|
||||
# references to files without having to specify the exact matching casing. On
|
||||
# Windows (including Cygwin) and MacOS, users should typically set this option
|
||||
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
||||
# YES.
|
||||
# The default value is: system dependent.
|
||||
|
||||
CASE_SENSE_NAMES = YES
|
||||
@@ -568,6 +613,12 @@ HIDE_SCOPE_NAMES = NO
|
||||
|
||||
HIDE_COMPOUND_REFERENCE= NO
|
||||
|
||||
# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class
|
||||
# will show which file needs to be included to use the class.
|
||||
# The default value is: YES.
|
||||
|
||||
SHOW_HEADERFILE = YES
|
||||
|
||||
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
|
||||
# the files that are included by a file in the documentation of that file.
|
||||
# The default value is: YES.
|
||||
@@ -725,7 +776,8 @@ FILE_VERSION_FILTER =
|
||||
# output files in an output format independent way. To create the layout file
|
||||
# that represents doxygen's defaults, run doxygen with the -l option. You can
|
||||
# optionally specify a file name after the option, if omitted DoxygenLayout.xml
|
||||
# will be used as the name of the layout file.
|
||||
# will be used as the name of the layout file. See also section "Changing the
|
||||
# layout of pages" for information.
|
||||
#
|
||||
# Note that if you run doxygen from a directory containing a file called
|
||||
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
|
||||
@@ -771,24 +823,35 @@ WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
|
||||
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
|
||||
# potential errors in the documentation, such as not documenting some parameters
|
||||
# in a documented function, or documenting parameters that don't exist or using
|
||||
# markup commands wrongly.
|
||||
# potential errors in the documentation, such as documenting some parameters in
|
||||
# a documented function twice, or documenting parameters that don't exist or
|
||||
# using markup commands wrongly.
|
||||
# The default value is: YES.
|
||||
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
|
||||
# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete
|
||||
# function parameter documentation. If set to NO, doxygen will accept that some
|
||||
# parameters have no documentation without warning.
|
||||
# The default value is: YES.
|
||||
|
||||
WARN_IF_INCOMPLETE_DOC = YES
|
||||
|
||||
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
|
||||
# are documented, but have no documentation for their parameters or return
|
||||
# value. If set to NO, doxygen will only warn about wrong or incomplete
|
||||
# parameter documentation, but not about the absence of documentation. If
|
||||
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
|
||||
# value. If set to NO, doxygen will only warn about wrong parameter
|
||||
# documentation, but not about the absence of documentation. If EXTRACT_ALL is
|
||||
# set to YES then this flag will automatically be disabled. See also
|
||||
# WARN_IF_INCOMPLETE_DOC
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_NO_PARAMDOC = YES
|
||||
|
||||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
||||
# a warning is encountered.
|
||||
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
||||
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
||||
# at the end of the doxygen process doxygen will return with a non-zero status.
|
||||
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_AS_ERROR = NO
|
||||
@@ -799,13 +862,27 @@ WARN_AS_ERROR = NO
|
||||
# and the warning text. Optionally the format may contain $version, which will
|
||||
# be replaced by the version of the file (if it could be obtained via
|
||||
# FILE_VERSION_FILTER)
|
||||
# See also: WARN_LINE_FORMAT
|
||||
# The default value is: $file:$line: $text.
|
||||
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
|
||||
# In the $text part of the WARN_FORMAT command it is possible that a reference
|
||||
# to a more specific place is given. To make it easier to jump to this place
|
||||
# (outside of doxygen) the user can define a custom "cut" / "paste" string.
|
||||
# Example:
|
||||
# WARN_LINE_FORMAT = "'vi $file +$line'"
|
||||
# See also: WARN_FORMAT
|
||||
# The default value is: at line $line of file $file.
|
||||
|
||||
WARN_LINE_FORMAT = "at line $line of file $file"
|
||||
|
||||
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
|
||||
# messages should be written. If left blank the output is written to standard
|
||||
# error (stderr).
|
||||
# error (stderr). In case the file specified cannot be opened for writing the
|
||||
# warning and error messages are written to standard error. When as file - is
|
||||
# specified the warning and error messages are written to standard output
|
||||
# (stdout).
|
||||
|
||||
WARN_LOGFILE =
|
||||
|
||||
@@ -826,8 +903,8 @@ INPUT = @DOXY_SOURCE_DIRECTORY@ \
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
|
||||
# possible encodings.
|
||||
# documentation (see:
|
||||
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
||||
# The default value is: UTF-8.
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
@@ -840,11 +917,15 @@ INPUT_ENCODING = UTF-8
|
||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||
# read by doxygen.
|
||||
#
|
||||
# Note the list of default checked file patterns might differ from the list of
|
||||
# default file extension mappings.
|
||||
#
|
||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
|
||||
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
|
||||
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,
|
||||
# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C
|
||||
# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
|
||||
# *.vhdl, *.ucf, *.qsf and *.ice.
|
||||
|
||||
FILE_PATTERNS = *.h \
|
||||
*.hpp \
|
||||
@@ -886,7 +967,7 @@ EXCLUDE_PATTERNS =
|
||||
# (namespaces, classes, functions, etc.) that should be excluded from the
|
||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||
# AClass::ANamespace, ANamespace::*Test
|
||||
# ANamespace::AClass, ANamespace::*Test
|
||||
#
|
||||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories use the pattern */test/*
|
||||
@@ -1062,16 +1143,24 @@ USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
|
||||
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
|
||||
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
|
||||
# cost of reduced performance. This can be particularly helpful with template
|
||||
# rich C++ code for which doxygen's built-in parser lacks the necessary type
|
||||
# information.
|
||||
# clang parser (see:
|
||||
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
|
||||
# performance. This can be particularly helpful with template rich C++ code for
|
||||
# which doxygen's built-in parser lacks the necessary type information.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# generated with the -Duse_libclang=ON option for CMake.
|
||||
# The default value is: NO.
|
||||
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
|
||||
# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS
|
||||
# tag is set to YES then doxygen will add the directory of each input to the
|
||||
# include path.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
|
||||
|
||||
CLANG_ADD_INC_PATHS = YES
|
||||
|
||||
# If clang assisted parsing is enabled you can provide the compiler with command
|
||||
# line options that you would normally use when invoking the compiler. Note that
|
||||
# the include paths will already be set by doxygen for the files and directories
|
||||
@@ -1081,10 +1170,13 @@ CLANG_ASSISTED_PARSING = NO
|
||||
CLANG_OPTIONS =
|
||||
|
||||
# If clang assisted parsing is enabled you can provide the clang parser with the
|
||||
# path to the compilation database (see:
|
||||
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files
|
||||
# were built. This is equivalent to specifying the "-p" option to a clang tool,
|
||||
# such as clang-check. These options will then be passed to the parser.
|
||||
# path to the directory containing a file called compile_commands.json. This
|
||||
# file is the compilation database (see:
|
||||
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
|
||||
# options used when the source files were built. This is equivalent to
|
||||
# specifying the -p option to a clang tool, such as clang-check. These options
|
||||
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
|
||||
# will be added as well.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# generated with the -Duse_libclang=ON option for CMake.
|
||||
|
||||
@@ -1101,13 +1193,6 @@ CLANG_DATABASE_PATH =
|
||||
|
||||
ALPHABETICAL_INDEX = YES
|
||||
|
||||
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
|
||||
# which the alphabetical index list will be split.
|
||||
# Minimum value: 1, maximum value: 20, default value: 5.
|
||||
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
||||
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
|
||||
# In case all classes in a project start with a common prefix, all classes will
|
||||
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
|
||||
# can be used to specify a prefix (or a list of prefixes) that should be ignored
|
||||
@@ -1207,7 +1292,7 @@ HTML_EXTRA_FILES =
|
||||
|
||||
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
|
||||
# will adjust the colors in the style sheet and background images according to
|
||||
# this color. Hue is specified as an angle on a colorwheel, see
|
||||
# this color. Hue is specified as an angle on a color-wheel, see
|
||||
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
|
||||
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
|
||||
# purple, and 360 is red again.
|
||||
@@ -1217,7 +1302,7 @@ HTML_EXTRA_FILES =
|
||||
HTML_COLORSTYLE_HUE = 220
|
||||
|
||||
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
|
||||
# in the HTML output. For a value of 0 the output will use grayscales only. A
|
||||
# in the HTML output. For a value of 0 the output will use gray-scales only. A
|
||||
# value of 255 will produce the most vivid colors.
|
||||
# Minimum value: 0, maximum value: 255, default value: 100.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
@@ -1246,9 +1331,9 @@ HTML_TIMESTAMP = NO
|
||||
|
||||
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
||||
# documentation will contain a main index with vertical navigation menus that
|
||||
# are dynamically created via Javascript. If disabled, the navigation index will
|
||||
# are dynamically created via JavaScript. If disabled, the navigation index will
|
||||
# consists of multiple levels of tabs that are statically embedded in every HTML
|
||||
# page. Disable this option to support browsers that do not have Javascript,
|
||||
# page. Disable this option to support browsers that do not have JavaScript,
|
||||
# like the Qt help browser.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
@@ -1278,10 +1363,11 @@ HTML_INDEX_NUM_ENTRIES = 100
|
||||
|
||||
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
|
||||
# generated that can be used as input for Apple's Xcode 3 integrated development
|
||||
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
|
||||
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
|
||||
# Makefile in the HTML output directory. Running make will produce the docset in
|
||||
# that directory and running make install will install the docset in
|
||||
# environment (see:
|
||||
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
|
||||
# create a documentation set, doxygen will generate a Makefile in the HTML
|
||||
# output directory. Running make will produce the docset in that directory and
|
||||
# running make install will install the docset in
|
||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
|
||||
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
|
||||
# genXcode/_index.html for more information.
|
||||
@@ -1298,6 +1384,13 @@ GENERATE_DOCSET = NO
|
||||
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
|
||||
# This tag determines the URL of the docset feed. A documentation feed provides
|
||||
# an umbrella under which multiple documentation sets from a single provider
|
||||
# (such as a company or product suite) can be grouped.
|
||||
# This tag requires that the tag GENERATE_DOCSET is set to YES.
|
||||
|
||||
DOCSET_FEEDURL =
|
||||
|
||||
# This tag specifies a string that should uniquely identify the documentation
|
||||
# set bundle. This should be a reverse domain-name style string, e.g.
|
||||
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
|
||||
@@ -1323,8 +1416,12 @@ DOCSET_PUBLISHER_NAME = Publisher
|
||||
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
|
||||
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
|
||||
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
|
||||
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
|
||||
# Windows.
|
||||
# on Windows. In the beginning of 2021 Microsoft took the original page, with
|
||||
# a.o. the download links, offline the HTML help workshop was already many years
|
||||
# in maintenance mode). You can download the HTML help workshop from the web
|
||||
# archives at Installation executable (see:
|
||||
# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo
|
||||
# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).
|
||||
#
|
||||
# The HTML Help Workshop contains a compiler that can convert all HTML output
|
||||
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
|
||||
@@ -1354,7 +1451,7 @@ CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
|
||||
# The GENERATE_CHI flag controls if a separate .chi index file is generated
|
||||
# (YES) or that it should be included in the master .chm file (NO).
|
||||
# (YES) or that it should be included in the main .chm file (NO).
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
|
||||
|
||||
@@ -1399,7 +1496,8 @@ QCH_FILE =
|
||||
|
||||
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
|
||||
# Project output. For more information please see Qt Help Project / Namespace
|
||||
# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
||||
# (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
||||
# The default value is: org.doxygen.Project.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1407,8 +1505,8 @@ QHP_NAMESPACE = org.doxygen.Project
|
||||
|
||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
|
||||
# Help Project output. For more information please see Qt Help Project / Virtual
|
||||
# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
|
||||
# folders).
|
||||
# Folders (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
|
||||
# The default value is: doc.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1416,16 +1514,16 @@ QHP_VIRTUAL_FOLDER = doc
|
||||
|
||||
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
|
||||
# filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# Filters (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_CUST_FILTER_NAME =
|
||||
|
||||
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
|
||||
# custom filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# Filters (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
@@ -1437,9 +1535,9 @@ QHP_CUST_FILTER_ATTRS =
|
||||
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
|
||||
# The QHG_LOCATION tag can be used to specify the location of Qt's
|
||||
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
|
||||
# generated .qhp file.
|
||||
# The QHG_LOCATION tag can be used to specify the location (absolute path
|
||||
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
|
||||
# run qhelpgenerator on the generated .qhp file.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHG_LOCATION =
|
||||
@@ -1482,16 +1580,28 @@ DISABLE_INDEX = NO
|
||||
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
|
||||
# (i.e. any modern browser). Windows users are probably better off using the
|
||||
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
|
||||
# further fine-tune the look of the index. As an example, the default style
|
||||
# sheet generated by doxygen has an example that shows how to put an image at
|
||||
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
|
||||
# the same information as the tab index, you could consider setting
|
||||
# DISABLE_INDEX to YES when enabling this option.
|
||||
# further fine tune the look of the index (see "Fine-tuning the output"). As an
|
||||
# example, the default style sheet generated by doxygen has an example that
|
||||
# shows how to put an image at the root of the tree instead of the PROJECT_NAME.
|
||||
# Since the tree basically has the same information as the tab index, you could
|
||||
# consider setting DISABLE_INDEX to YES when enabling this option.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
GENERATE_TREEVIEW = NO
|
||||
|
||||
# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the
|
||||
# FULL_SIDEBAR option determines if the side bar is limited to only the treeview
|
||||
# area (value NO) or if it should extend to the full height of the window (value
|
||||
# YES). Setting this to YES gives a layout similar to
|
||||
# https://docs.readthedocs.io with more room for contents, but less room for the
|
||||
# project logo, title, and description. If either GENERATE_TREEVIEW or
|
||||
# DISABLE_INDEX is set to NO, this option has no effect.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
FULL_SIDEBAR = NO
|
||||
|
||||
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
|
||||
# doxygen will group on one line in the generated HTML documentation.
|
||||
#
|
||||
@@ -1516,6 +1626,24 @@ TREEVIEW_WIDTH = 250
|
||||
|
||||
EXT_LINKS_IN_WINDOW = NO
|
||||
|
||||
# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email
|
||||
# addresses.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
OBFUSCATE_EMAILS = YES
|
||||
|
||||
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
|
||||
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
|
||||
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
|
||||
# the HTML output. These images will generally look nicer at scaled resolutions.
|
||||
# Possible values are: png (the default) and svg (looks nicer but requires the
|
||||
# pdf2svg or inkscape tool).
|
||||
# The default value is: png.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_FORMULA_FORMAT = png
|
||||
|
||||
# Use this tag to change the font size of LaTeX formulas included as images in
|
||||
# the HTML documentation. When you change the font size after a successful
|
||||
# doxygen run you need to manually remove any form_*.png images from the HTML
|
||||
@@ -1536,8 +1664,14 @@ FORMULA_FONTSIZE = 10
|
||||
|
||||
FORMULA_TRANSPARENT = YES
|
||||
|
||||
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
|
||||
# to create new LaTeX commands to be used in formulas as building blocks. See
|
||||
# the section "Including formulas" for details.
|
||||
|
||||
FORMULA_MACROFILE =
|
||||
|
||||
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
|
||||
# https://www.mathjax.org) which uses client side Javascript for the rendering
|
||||
# https://www.mathjax.org) which uses client side JavaScript for the rendering
|
||||
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
|
||||
# installed or if you want to formulas look prettier in the HTML output. When
|
||||
# enabled you may also need to install MathJax separately and configure the path
|
||||
@@ -1547,11 +1681,29 @@ FORMULA_TRANSPARENT = YES
|
||||
|
||||
USE_MATHJAX = NO
|
||||
|
||||
# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.
|
||||
# Note that the different versions of MathJax have different requirements with
|
||||
# regards to the different settings, so it is possible that also other MathJax
|
||||
# settings have to be changed when switching between the different MathJax
|
||||
# versions.
|
||||
# Possible values are: MathJax_2 and MathJax_3.
|
||||
# The default value is: MathJax_2.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
MATHJAX_VERSION = MathJax_2
|
||||
|
||||
# When MathJax is enabled you can set the default output format to be used for
|
||||
# the MathJax output. See the MathJax site (see:
|
||||
# http://docs.mathjax.org/en/latest/output.html) for more details.
|
||||
# the MathJax output. For more details about the output format see MathJax
|
||||
# version 2 (see:
|
||||
# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3
|
||||
# (see:
|
||||
# http://docs.mathjax.org/en/latest/web/components/output.html).
|
||||
# Possible values are: HTML-CSS (which is slower, but has the best
|
||||
# compatibility), NativeMML (i.e. MathML) and SVG.
|
||||
# compatibility. This is the name for Mathjax version 2, for MathJax version 3
|
||||
# this will be translated into chtml), NativeMML (i.e. MathML. Only supported
|
||||
# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This
|
||||
# is the name for Mathjax version 3, for MathJax version 2 this will be
|
||||
# translated into HTML-CSS) and SVG.
|
||||
# The default value is: HTML-CSS.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
@@ -1564,22 +1716,29 @@ MATHJAX_FORMAT = HTML-CSS
|
||||
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
|
||||
# Content Delivery Network so you can quickly see the result without installing
|
||||
# MathJax. However, it is strongly recommended to install a local copy of
|
||||
# MathJax from https://www.mathjax.org before deployment.
|
||||
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
|
||||
# MathJax from https://www.mathjax.org before deployment. The default value is:
|
||||
# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2
|
||||
# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/
|
||||
|
||||
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
|
||||
# extension names that should be enabled during MathJax rendering. For example
|
||||
# for MathJax version 2 (see
|
||||
# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):
|
||||
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
|
||||
# For example for MathJax version 3 (see
|
||||
# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):
|
||||
# MATHJAX_EXTENSIONS = ams
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
MATHJAX_EXTENSIONS =
|
||||
|
||||
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
|
||||
# of code that will be used on startup of the MathJax code. See the MathJax site
|
||||
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
|
||||
# (see:
|
||||
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
|
||||
# example see the documentation.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
@@ -1607,7 +1766,7 @@ MATHJAX_CODEFILE =
|
||||
SEARCHENGINE = YES
|
||||
|
||||
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
|
||||
# implemented using a web server instead of a web client using Javascript. There
|
||||
# implemented using a web server instead of a web client using JavaScript. There
|
||||
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
|
||||
# setting. When disabled, doxygen will generate a PHP script for searching and
|
||||
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
|
||||
@@ -1626,7 +1785,8 @@ SERVER_BASED_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: https://xapian.org/).
|
||||
# Xapian (see:
|
||||
# https://xapian.org/).
|
||||
#
|
||||
# See the section "External Indexing and Searching" for details.
|
||||
# The default value is: NO.
|
||||
@@ -1639,8 +1799,9 @@ EXTERNAL_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: https://xapian.org/). See the section "External Indexing and
|
||||
# Searching" for details.
|
||||
# Xapian (see:
|
||||
# https://xapian.org/). See the section "External Indexing and Searching" for
|
||||
# details.
|
||||
# This tag requires that the tag SEARCHENGINE is set to YES.
|
||||
|
||||
SEARCHENGINE_URL =
|
||||
@@ -1749,29 +1910,31 @@ PAPER_TYPE = a4
|
||||
|
||||
EXTRA_PACKAGES =
|
||||
|
||||
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
|
||||
# generated LaTeX document. The header should contain everything until the first
|
||||
# chapter. If it is left blank doxygen will generate a standard header. See
|
||||
# section "Doxygen usage" for information on how to let doxygen write the
|
||||
# default header to a separate file.
|
||||
# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for
|
||||
# the generated LaTeX document. The header should contain everything until the
|
||||
# first chapter. If it is left blank doxygen will generate a standard header. It
|
||||
# is highly recommended to start with a default header using
|
||||
# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty
|
||||
# and then modify the file new_header.tex. See also section "Doxygen usage" for
|
||||
# information on how to generate the default header that doxygen normally uses.
|
||||
#
|
||||
# Note: Only use a user-defined header if you know what you are doing! The
|
||||
# following commands have a special meaning inside the header: $title,
|
||||
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
|
||||
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
|
||||
# string, for the replacement values of the other commands the user is referred
|
||||
# to HTML_HEADER.
|
||||
# Note: Only use a user-defined header if you know what you are doing!
|
||||
# Note: The header is subject to change so you typically have to regenerate the
|
||||
# default header when upgrading to a newer version of doxygen. The following
|
||||
# commands have a special meaning inside the header (and footer): For a
|
||||
# description of the possible markers and block names see the documentation.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_HEADER =
|
||||
|
||||
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
|
||||
# generated LaTeX document. The footer should contain everything after the last
|
||||
# chapter. If it is left blank doxygen will generate a standard footer. See
|
||||
# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for
|
||||
# the generated LaTeX document. The footer should contain everything after the
|
||||
# last chapter. If it is left blank doxygen will generate a standard footer. See
|
||||
# LATEX_HEADER for more information on how to generate a default footer and what
|
||||
# special commands can be used inside the footer.
|
||||
#
|
||||
# Note: Only use a user-defined footer if you know what you are doing!
|
||||
# special commands can be used inside the footer. See also section "Doxygen
|
||||
# usage" for information on how to generate the default footer that doxygen
|
||||
# normally uses. Note: Only use a user-defined footer if you know what you are
|
||||
# doing!
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_FOOTER =
|
||||
@@ -1804,9 +1967,11 @@ LATEX_EXTRA_FILES =
|
||||
|
||||
PDF_HYPERLINKS = YES
|
||||
|
||||
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
|
||||
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
|
||||
# higher quality PDF documentation.
|
||||
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
|
||||
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
|
||||
# files. Set this option to YES, to get a higher quality PDF documentation.
|
||||
#
|
||||
# See also section LATEX_CMD_NAME for selecting the engine.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
@@ -1814,8 +1979,7 @@ USE_PDFLATEX = YES
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep running
|
||||
# if errors occur, instead of asking the user for help. This option is also used
|
||||
# when generating formulas in HTML.
|
||||
# if errors occur, instead of asking the user for help.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
@@ -1828,16 +1992,6 @@ LATEX_BATCHMODE = NO
|
||||
|
||||
LATEX_HIDE_INDICES = NO
|
||||
|
||||
# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
|
||||
# code with syntax highlighting in the LaTeX output.
|
||||
#
|
||||
# Note that which sources are shown also depends on other settings such as
|
||||
# SOURCE_BROWSER.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_SOURCE_CODE = NO
|
||||
|
||||
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
|
||||
# bibliography, e.g. plainnat, or ieeetr. See
|
||||
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
|
||||
@@ -1918,16 +2072,6 @@ RTF_STYLESHEET_FILE =
|
||||
|
||||
RTF_EXTENSIONS_FILE =
|
||||
|
||||
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
|
||||
# with syntax highlighting in the RTF output.
|
||||
#
|
||||
# Note that which sources are shown also depends on other settings such as
|
||||
# SOURCE_BROWSER.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_RTF is set to YES.
|
||||
|
||||
RTF_SOURCE_CODE = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -2024,15 +2168,6 @@ GENERATE_DOCBOOK = NO
|
||||
|
||||
DOCBOOK_OUTPUT = docbook
|
||||
|
||||
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
|
||||
# program listings (including syntax highlighting and cross-referencing
|
||||
# information) to the DOCBOOK output. Note that enabling this will significantly
|
||||
# increase the size of the DOCBOOK output.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
|
||||
|
||||
DOCBOOK_PROGRAMLISTING = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -2100,7 +2235,7 @@ ENABLE_PREPROCESSING = YES
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
|
||||
|
||||
MACRO_EXPANSION = NO
|
||||
MACRO_EXPANSION = YES
|
||||
|
||||
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
|
||||
# the macro expansion is limited to the macros specified with the PREDEFINED and
|
||||
@@ -2119,7 +2254,8 @@ SEARCH_INCLUDES = YES
|
||||
|
||||
# The INCLUDE_PATH tag can be used to specify one or more directories that
|
||||
# contain include files that are not input files but should be processed by the
|
||||
# preprocessor.
|
||||
# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of
|
||||
# RECURSIVE has no effect here.
|
||||
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
|
||||
|
||||
INCLUDE_PATH =
|
||||
@@ -2211,15 +2347,6 @@ EXTERNAL_PAGES = YES
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
|
||||
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
|
||||
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
|
||||
# disabled, but it is recommended to install and use dot, since it yields more
|
||||
# powerful graphs.
|
||||
# The default value is: YES.
|
||||
|
||||
CLASS_DIAGRAMS = YES
|
||||
|
||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||
# then run dia to produce the diagram and insert it in the documentation. The
|
||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||
@@ -2238,7 +2365,7 @@ HIDE_UNDOC_RELATIONS = YES
|
||||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# Bell Labs. The other options in this section have no effect if this option is
|
||||
# set to NO
|
||||
# The default value is: YES.
|
||||
# The default value is: NO.
|
||||
|
||||
HAVE_DOT = YES
|
||||
|
||||
@@ -2276,11 +2403,14 @@ DOT_FONTSIZE = 10
|
||||
|
||||
DOT_FONTPATH =
|
||||
|
||||
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
|
||||
# each documented class showing the direct and indirect inheritance relations.
|
||||
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
|
||||
# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
|
||||
# graph for each documented class showing the direct and indirect inheritance
|
||||
# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
|
||||
# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
|
||||
# to TEXT the direct and indirect inheritance relations will be shown as texts /
|
||||
# links.
|
||||
# Possible values are: NO, YES, TEXT and GRAPH.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
CLASS_GRAPH = YES
|
||||
|
||||
@@ -2294,7 +2424,8 @@ CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
|
||||
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
|
||||
# groups, showing the direct groups dependencies.
|
||||
# groups, showing the direct groups dependencies. See also the chapter Grouping
|
||||
# in the manual.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
@@ -2317,10 +2448,32 @@ UML_LOOK = NO
|
||||
# but if the number exceeds 15, the total amount of fields shown is limited to
|
||||
# 10.
|
||||
# Minimum value: 0, maximum value: 100, default value: 10.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
# This tag requires that the tag UML_LOOK is set to YES.
|
||||
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
|
||||
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
|
||||
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
|
||||
# tag is set to YES, doxygen will add type and arguments for attributes and
|
||||
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
|
||||
# will not generate fields with class member information in the UML graphs. The
|
||||
# class diagrams will look similar to the default class diagrams but using UML
|
||||
# notation for the relationships.
|
||||
# Possible values are: NO, YES and NONE.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag UML_LOOK is set to YES.
|
||||
|
||||
DOT_UML_DETAILS = NO
|
||||
|
||||
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
|
||||
# to display on a single line. If the actual line length exceeds this threshold
|
||||
# significantly it will wrapped across multiple lines. Some heuristics are apply
|
||||
# to avoid ugly line breaks.
|
||||
# Minimum value: 0, maximum value: 1000, default value: 17.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_WRAP_THRESHOLD = 17
|
||||
|
||||
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
|
||||
# collaboration graphs will show the relations between templates and their
|
||||
# instances.
|
||||
@@ -2387,6 +2540,13 @@ GRAPHICAL_HIERARCHY = YES
|
||||
|
||||
DIRECTORY_GRAPH = YES
|
||||
|
||||
# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels
|
||||
# of child directories generated in directory dependency graphs by dot.
|
||||
# Minimum value: 1, maximum value: 25, default value: 1.
|
||||
# This tag requires that the tag DIRECTORY_GRAPH is set to YES.
|
||||
|
||||
DIR_GRAPH_MAX_DEPTH = 1
|
||||
|
||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||
# generated by dot. For an explanation of the image formats see the section
|
||||
# output formats in the documentation of the dot tool (Graphviz (see:
|
||||
@@ -2394,9 +2554,7 @@ DIRECTORY_GRAPH = YES
|
||||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
||||
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
||||
# requirement).
|
||||
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
|
||||
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
|
||||
# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
|
||||
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
|
||||
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
|
||||
# png:gdiplus:gdiplus.
|
||||
# The default value is: png.
|
||||
@@ -2442,10 +2600,10 @@ MSCFILE_DIRS =
|
||||
DIAFILE_DIRS =
|
||||
|
||||
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
|
||||
# path where java can find the plantuml.jar file. If left blank, it is assumed
|
||||
# PlantUML is not used or called during a preprocessing step. Doxygen will
|
||||
# generate a warning when it encounters a \startuml command in this case and
|
||||
# will not generate output for the diagram.
|
||||
# path where java can find the plantuml.jar file or to the filename of jar file
|
||||
# to be used. If left blank, it is assumed PlantUML is not used or called during
|
||||
# a preprocessing step. Doxygen will generate a warning when it encounters a
|
||||
# \startuml command in this case and will not generate output for the diagram.
|
||||
|
||||
PLANTUML_JAR_PATH =
|
||||
|
||||
@@ -2507,14 +2665,18 @@ DOT_MULTI_TARGETS = NO
|
||||
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
|
||||
# explaining the meaning of the various boxes and arrows in the dot generated
|
||||
# graphs.
|
||||
# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal
|
||||
# graphical representation for inheritance and collaboration diagrams is used.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
GENERATE_LEGEND = YES
|
||||
|
||||
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
|
||||
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
|
||||
# files that are used to generate the various graphs.
|
||||
#
|
||||
# Note: This setting is not only used for dot files but also for msc temporary
|
||||
# files.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_CLEANUP = YES
|
||||
|
||||
121
docs/md/config.md
Normal file
121
docs/md/config.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# 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.
|
||||
67
docs/md/container.md
Normal file
67
docs/md/container.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# 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 functionality 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,
|
||||
`std::unordered_map`.<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, `std::unordered_set`.<br/>
|
||||
Therefore, there is no need to go into the API description.
|
||||
953
docs/md/core.md
953
docs/md/core.md
File diff suppressed because it is too large
Load Diff
1497
docs/md/entity.md
1497
docs/md/entity.md
File diff suppressed because it is too large
Load Diff
145
docs/md/faq.md
145
docs/md/faq.md
@@ -13,18 +13,20 @@
|
||||
* [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'll try to put the answers to the
|
||||
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, try to
|
||||
[open a new issue](https://github.com/skypjack/entt/issues/new) or enter the
|
||||
[gitter channel](https://gitter.im/skypjack/entt) and ask your question.
|
||||
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.
|
||||
|
||||
@@ -44,14 +46,14 @@ 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 in Visual Studio 2017
|
||||
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, the macro `ENTT_ASSERT` should be redefined to disable internal checks
|
||||
made by `EnTT` in debug:
|
||||
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)
|
||||
@@ -60,70 +62,52 @@ made by `EnTT` in debug:
|
||||
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 for most cases. If
|
||||
you want something more, you can can also switch to an optimization level `O0`
|
||||
or preferably `O1`.
|
||||
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 what’s 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 can certainly allow or
|
||||
not different techniques depending on how the data are laid out.
|
||||
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 techniques that fit well with the model of
|
||||
`EnTT`. [Here](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.
|
||||
|
||||
Long story short, you can always define a tree where the nodes expose implicit
|
||||
lists of children by means of the following type:
|
||||
|
||||
```cpp
|
||||
struct relationship {
|
||||
std::size_t children{};
|
||||
entt::entity first{entt::null};
|
||||
entt::entity prev{entt::null};
|
||||
entt::entity next{entt::null};
|
||||
entt::entity parent{entt::null};
|
||||
// ... other data members ...
|
||||
};
|
||||
```
|
||||
|
||||
The sort functionalities of `EnTT`, the groups and all the other features of the
|
||||
library can help then to get the best in terms of data locality and therefore
|
||||
performance from this component.
|
||||
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 as an underlying type.
|
||||
* 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.
|
||||
|
||||
These identifiers are nothing more than enum classes with some salt.<br/>
|
||||
To simplify the creation of new identifiers, `EnTT` provides the macro
|
||||
`ENTT_OPAQUE_TYPE` that accepts two arguments:
|
||||
|
||||
* The name you want to give to the new identifier (watch out for namespaces).
|
||||
* The underlying type to use (either `std::uint16_t`, `std::uint32_t`
|
||||
or `std::uint64_t`).
|
||||
|
||||
In fact, this is the definition of `entt::entity`:
|
||||
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
|
||||
ENTT_OPAQUE_TYPE(entity, std::uint32_t)
|
||||
enum class entity: std::uint32_t {};
|
||||
```
|
||||
|
||||
The use of this macro is highly recommended, so as not to run into problems if
|
||||
the requirements for the identifiers should change in the future.
|
||||
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 could generate a warning.<br/>
|
||||
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.
|
||||
|
||||
@@ -132,7 +116,7 @@ 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}\
|
||||
#define HS(str) __pragma(warning(suppress:4307)) entt::hashed_string{str}
|
||||
#else
|
||||
#define HS(str) entt::hashed_string{str}
|
||||
#endif
|
||||
@@ -154,7 +138,7 @@ 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 to include any other header
|
||||
It consists in defining the `NOMINMAX` macro before including any other header
|
||||
so as to get rid of the extra definitions:
|
||||
|
||||
```cpp
|
||||
@@ -167,15 +151,14 @@ 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. This trait doesn't check if an object can
|
||||
actually be copied but only verifies if there is a copy constructor
|
||||
available.<br/>
|
||||
This can lead to surprising results due to some idiosyncrasies of the standard
|
||||
mainly related to the need to guarantee backward compatibility.
|
||||
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 no matter if its value
|
||||
type is copyable or not. As a result, `std::is_copy_constructible_v` is true
|
||||
for the following specialization:
|
||||
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 {
|
||||
@@ -183,18 +166,50 @@ struct type {
|
||||
};
|
||||
```
|
||||
|
||||
When trying to assign an instance of this type to an entity in the ECS part,
|
||||
this may trigger a compilation error because we cannot really make a copy of
|
||||
it.<br/>
|
||||
As a workaround, users can mark the type explicitly as non-copyable:
|
||||
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;
|
||||
};
|
||||
```
|
||||
|
||||
Unfortunately, this will also disable aggregate initialization.
|
||||
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
|
||||
|
||||
The `registry` class offers 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.
|
||||
|
||||
299
docs/md/graph.md
Normal file
299
docs/md/graph.md
Normal file
@@ -0,0 +1,299 @@
|
||||
# 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. 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 will take 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 has been inserted or was already
|
||||
present. The second one instead returns the number of deleted elements (0 or 1).
|
||||
|
||||
An adjacency matrix must be 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()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Note that the same result can be obtained with the following snippet, since the
|
||||
vertices are 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 can be used to get them as
|
||||
pairs of vertices:
|
||||
|
||||
```cpp
|
||||
for(auto [lhs, rhs]: adjacency_matrix.edges()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
On the other hand, if the goal is to visit all the in- or out-edges of a given
|
||||
vertex, the `in_edges` and `out_edges` functions are meant for that:
|
||||
|
||||
```cpp
|
||||
for(auto [lhs, rhs]: adjacency_matrix.out_edges(3u)) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
As might be expected, these 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 functionality 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);
|
||||
```
|
||||
|
||||
However, there is also the option of providing a callback to which the vertices
|
||||
are passed and which can be used to add (`dot`) properties to the output from
|
||||
time to time:
|
||||
|
||||
```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
|
||||
data managed externally 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 have been 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 can be 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`.
|
||||
That is, 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 has been created (which requires no constructor arguments),
|
||||
the first thing to do is to bind a task. This will indicate to the builder who
|
||||
intends to consume the resources that will be specified immediately after:
|
||||
|
||||
```cpp
|
||||
entt::flow builder{};
|
||||
builder.bind("task_1"_hs);
|
||||
```
|
||||
|
||||
Note that 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 is not 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 he deems it necessary.
|
||||
|
||||
Once a task has been associated with the flow builder, it can be 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, these 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.
|
||||
|
||||
## 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 force
|
||||
the order execution:
|
||||
|
||||
```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_2` and `task_3` **after** `task_1`.
|
||||
This is due to the fact that the latter 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();
|
||||
```
|
||||
|
||||
The search 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()) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Starting from them, using the other functions appropriately (such as `out_edges`
|
||||
to retrieve the children of a given task or `edges` to access their identifiers)
|
||||
it will be possible to instantiate an execution graph.
|
||||
@@ -5,80 +5,76 @@
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [The EnTT way](#the-entt-way)
|
||||
* [Meta context](#meta-context)
|
||||
* [Memory management](#memory-management)
|
||||
* [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
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
# 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 to different types.<br/>
|
||||
Fortunately, nowadays using `EnTT` across boundaries is straightforward. In
|
||||
fact, everything just works transparently in almost all cases. There are only a
|
||||
few exceptions, easy to deal with anyway.
|
||||
identifiers with different types.<br/>
|
||||
Fortunately, nowadays using `EnTT` across boundaries is much easier.
|
||||
|
||||
# The EnTT way
|
||||
## Smooth until proven otherwise
|
||||
|
||||
Many classes in `EnTT` make extensive use of type erasure for their purposes.
|
||||
This isn't a problem in itself (in fact, it's the basis of an API so convenient
|
||||
This isn't a problem on itself (in fact, it's the basis of an API so convenient
|
||||
to use). However, a way is needed to recognize the objects whose type has been
|
||||
erased on the other side of a boundary.<br/>
|
||||
The `type_info` class template is how identifiers are generated and thus made
|
||||
available to the rest of the library.
|
||||
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.
|
||||
|
||||
In general, this class doesn't arouse much interest. The only exception is in
|
||||
case of conflicts between identifiers (definitely uncommon though) or where the
|
||||
default solution proposed by `EnTT` isn't suitable for the user's purposes.<br/>
|
||||
The section dedicated to this core class contains all the details to get around
|
||||
the problem 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` can be used where there is a need 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.
|
||||
|
||||
# Meta context
|
||||
For anyone who needs more details, the test suite contains multiple 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 to a static context to which the visible components are
|
||||
attached and different contexts don't relate to each other, they must be
|
||||
_shared_ to allow the use of meta types across boundaries.
|
||||
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.
|
||||
|
||||
Sharing a context is trivial though. First of all, the local one must be
|
||||
acquired in the main space:
|
||||
Fortunately, sharing a context is also trivial to do. First of all, the local
|
||||
one is acquired in the main space:
|
||||
|
||||
```cpp
|
||||
entt::meta_ctx ctx{};
|
||||
auto handle = entt::locator<entt::meta_ctx>::handle();
|
||||
```
|
||||
|
||||
Then, it must passed to the receiving space that will set it as its global
|
||||
context, thus releasing the local one that remains available but is no longer
|
||||
referred to by the runtime reflection system:
|
||||
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::meta_ctx::bind(ctx);
|
||||
entt::locator<entt::meta_ctx>::reset(handle);
|
||||
```
|
||||
|
||||
From now on, both spaces will refer to the same context and on it will be
|
||||
attached the new visible meta types, no matter where they are created.<br/>
|
||||
A context can also be reset and then associated again locally as:
|
||||
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 resetting the main context doesn't also propagate changes across
|
||||
boundaries. In other words, resetting a context results in the decoupling of the
|
||||
two sides and therefore a divergence in the contents.
|
||||
|
||||
```cpp
|
||||
entt::meta_ctx::bind{entt::meta_ctx{});
|
||||
```
|
||||
|
||||
This is allowed because local and global contexts are separated. Therefore, it's
|
||||
always possible to make the local context the current one again.
|
||||
|
||||
Before to release a context, all locally registered types should be reset to
|
||||
avoid dangling references. Otherwise, if a type is accessed from another space
|
||||
by name, there could be an attempt to address its parts that are no longer
|
||||
available.
|
||||
|
||||
# Memory Management
|
||||
## Memory Management
|
||||
|
||||
There is another subtle problem due to memory management that can lead to
|
||||
headaches.<br/>
|
||||
|
||||
178
docs/md/links.md
178
docs/md/links.md
@@ -3,8 +3,8 @@
|
||||
`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.
|
||||
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. Where I put the word _apparently_ means that the use of `EnTT` is
|
||||
@@ -17,10 +17,31 @@ I hope this list can grow much more in the future:
|
||||
* [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.
|
||||
* [Land of the Rair](https://github.com/LandOfTheRair/core2): the new backend
|
||||
of [a retro-style MUD](https://rair.land/) for the new age.
|
||||
* [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
|
||||
@@ -32,8 +53,8 @@ I hope this list can grow much more in the future:
|
||||
* [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/reworks/EnttPong): an example of how to make
|
||||
Pong with `EnTT`.
|
||||
* [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
|
||||
@@ -52,22 +73,64 @@ I hope this list can grow much more in the future:
|
||||
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® 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.
|
||||
* [starlight](https://github.com/DomRe/starlight): game programming framework
|
||||
using `Allegro`, `Lua` and modern C++.
|
||||
* [Apparently](https://github.com/JosiahWI/qub3d-libdeps)
|
||||
[Qub3d](https://qub3d.org/): because blocks should be open source.
|
||||
* [shiva](https://github.com/Milerius/shiva): modern C++ engine with
|
||||
modularity.
|
||||
* [NovusCore](https://github.com/novuscore/NovusCore): a modern take on World
|
||||
of Warcraft emulation.
|
||||
* [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
|
||||
@@ -76,13 +139,60 @@ I hope this list can grow much more in the future:
|
||||
developed for educational purposes.
|
||||
* [Lumos](https://github.com/jmorton06/Lumos): game engine written in C++
|
||||
using OpenGL and Vulkan.
|
||||
* [Chrysalis](https://github.com/ivanhawkes/Chrysalis): action RPG SDK for
|
||||
CRYENGINE games.
|
||||
* [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.
|
||||
|
||||
* Articles and blog posts:
|
||||
* 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.
|
||||
* [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
|
||||
@@ -94,27 +204,51 @@ I hope this list can grow much more in the future:
|
||||
* [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 about the process followed and the results of the integration
|
||||
of `EnTT` into `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:
|
||||
* The [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
|
||||
* [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).
|
||||
* [Sequentity](https://github.com/alanjfs/sequentity): A MIDI-like
|
||||
sequencer/tracker for C++ and `ImGui` (with `Magnum` and `EnTT`).
|
||||
* [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/).
|
||||
|
||||
@@ -7,69 +7,82 @@
|
||||
|
||||
* [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. This template based implementation
|
||||
tries to fill the gap and to get rid of the burden of defining a different
|
||||
specific locator for each application.<br/>
|
||||
This class is tiny, partially unsafe and thus risky to use. Moreover it doesn't
|
||||
fit probably most of the scenarios in which a service locator is required. Look
|
||||
at it as a small tool that can sometimes be useful if users know how to handle
|
||||
it.
|
||||
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 API is straightforward. The basic idea is that services are implemented by
|
||||
means of interfaces and rely on polymorphism.<br/>
|
||||
The locator is instantiated with the base type of the service if any and a
|
||||
concrete implementation is provided along with all the parameters required to
|
||||
initialize it. As an example:
|
||||
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
|
||||
// the service has no base type, a locator is used to treat it as a kind of singleton
|
||||
entt::service_locator<my_service>::set(params...);
|
||||
|
||||
// sets up an opaque service
|
||||
entt::service_locator<audio_interface>::set<audio_implementation>(params...);
|
||||
|
||||
// resets (destroys) the service
|
||||
entt::service_locator<audio_interface>::reset();
|
||||
entt::locator<interface>::emplace<service>(argument);
|
||||
entt::locator<interface>::allocate_emplace<service>(allocator, argument);
|
||||
```
|
||||
|
||||
The locator can also be queried to know if an active service is currently set
|
||||
and to retrieve it if necessary (either as a pointer or as a reference):
|
||||
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
|
||||
// no service currently set
|
||||
auto empty = entt::service_locator<audio_interface>::empty();
|
||||
|
||||
// gets a (possibly empty) shared pointer to the service ...
|
||||
std::shared_ptr<audio_interface> ptr = entt::service_locator<audio_interface>::get();
|
||||
|
||||
// ... or a reference, but it's undefined behaviour if the service isn't set yet
|
||||
audio_interface &ref = entt::service_locator<audio_interface>::ref();
|
||||
interface &service = entt::locator<interface>::value();
|
||||
```
|
||||
|
||||
A common use is to wrap the different locators in a container class, creating
|
||||
aliases for the various services:
|
||||
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
|
||||
struct locator {
|
||||
using camera = entt::service_locator<camera_interface>;
|
||||
using audio = entt::service_locator<audio_interface>;
|
||||
// ...
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
void init() {
|
||||
locator::camera::set<camera_null>();
|
||||
locator::audio::set<audio_implementation>(params...);
|
||||
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.
|
||||
|
||||
942
docs/md/meta.md
942
docs/md/meta.md
File diff suppressed because it is too large
Load Diff
359
docs/md/poly.md
Normal file
359
docs/md/poly.md
Normal file
@@ -0,0 +1,359 @@
|
||||
# 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/>
|
||||
This is, among others, 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/>
|
||||
What users get is an object that can be passed around as such and not through a
|
||||
reference or a pointer, as 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. Among the most important, 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/>
|
||||
Among all, the two that I prefer 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, this 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, it will be sufficient to provide a generic
|
||||
implementation to fulfill the concept.<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 introduced:
|
||||
|
||||
```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 must be 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 exists also 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>
|
||||
Because, in fact, this is exactly 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 can be 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 are present in 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 will be
|
||||
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` and instead 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, also the list of types must be 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 will only be 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 have been introduced, it will be possible
|
||||
to use the `poly` class template to contain 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();
|
||||
```
|
||||
|
||||
The `poly` class template offers a wide range of constructors, from the default
|
||||
one (which will return 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
|
||||
won'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()` will invoke the `data` member function of the
|
||||
poly object, `instance->data()` will map 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 instead 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.
|
||||
@@ -28,9 +28,9 @@ A typical process must inherit from the `process` class template that stays true
|
||||
to the CRTP idiom. Moreover, derived classes must specify what's the intended
|
||||
type for elapsed times.
|
||||
|
||||
A process should expose publicly the following member functions whether
|
||||
required (note that it isn't required to define a function unless the derived
|
||||
class wants to _override_ the default behavior):
|
||||
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 *);`
|
||||
|
||||
@@ -98,7 +98,7 @@ private:
|
||||
Lambdas and functors can't be used directly with a scheduler for they are not
|
||||
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.
|
||||
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 arguments to
|
||||
|
||||
75
docs/md/reference.md
Normal file
75
docs/md/reference.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Similar projects
|
||||
|
||||
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.
|
||||
|
||||
Below an incomplete list of those 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.
|
||||
|
||||
I hope this list can grow much more in the future:
|
||||
|
||||
* 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#
|
||||
* [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`.
|
||||
|
||||
If you know of other resources out there that can be of interest for the reader,
|
||||
feel free to open an issue or a PR and I'll be glad to add them to this page.
|
||||
@@ -7,231 +7,185 @@
|
||||
|
||||
* [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 part of a software like
|
||||
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
|
||||
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. Instead, it offers a minimal and perhaps trivial cache that can be useful
|
||||
most of the time during prototyping and sometimes even in a production
|
||||
environment.<br/>
|
||||
For those interested in the subject, the plan is to improve it considerably over
|
||||
time in terms of performance, memory usage and functionalities. Hoping to make
|
||||
it, of course, one step at a time.
|
||||
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
|
||||
|
||||
There are three main actors in the model: the resource, the loader and the
|
||||
cache.
|
||||
|
||||
The _resource_ is whatever users want it to be. An image, a video, an audio,
|
||||
whatever. There are no limits.<br/>
|
||||
As a minimal example:
|
||||
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; };
|
||||
```
|
||||
|
||||
A _loader_ is a class the aim of which is to load a specific resource. It has to
|
||||
inherit directly from the dedicated base class as in the following example:
|
||||
The _loader_ is a callable type the aim of which is to load a specific resource:
|
||||
|
||||
```cpp
|
||||
struct my_loader final: entt::loader<my_loader, my_resource> {
|
||||
// ...
|
||||
};
|
||||
```
|
||||
struct my_loader final {
|
||||
using result_type = std::shared_ptr<my_resource>;
|
||||
|
||||
Where `my_resource` is the type of resources it creates.<br/>
|
||||
A resource loader must also expose a public const member function named `load`
|
||||
that accepts a variable number of arguments and returns a shared pointer to a
|
||||
resource.<br/>
|
||||
As an example:
|
||||
|
||||
```cpp
|
||||
struct my_loader: entt::loader<my_loader, my_resource> {
|
||||
std::shared_ptr<my_resource> load(int value) const {
|
||||
result_type operator()(int value) const {
|
||||
// ...
|
||||
return std::shared_ptr<my_resource>(new my_resource{ value });
|
||||
return std::make_shared<my_resource>(value);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
In general, resource loaders should not have a state or retain data of any type.
|
||||
They should let the cache manage their resources instead.<br/>
|
||||
As a side note, base class and CRTP idiom aren't strictly required with the
|
||||
current implementation. One could argue that a cache can easily work with
|
||||
loaders of any type. However, future changes won't be breaking ones by forcing
|
||||
the use of a base class today and that's why the model is already in its place.
|
||||
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:
|
||||
resource and (optionally) a loader:
|
||||
|
||||
```cpp
|
||||
using my_cache = entt::cache<my_resource>;
|
||||
using my_cache = entt::resource_cache<my_resource, my_loader>;
|
||||
|
||||
// ...
|
||||
|
||||
my_cache cache{};
|
||||
```
|
||||
|
||||
The idea is to create different caches for different types of resources and to
|
||||
manage each one independently in the most appropriate way.<br/>
|
||||
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 and then
|
||||
discarded when users leave it.
|
||||
an application while meshes can be associated with a single scene only, then
|
||||
discarded when a player leaves it.
|
||||
|
||||
A cache offers a set of basic functionalities to query its internal state and to
|
||||
_organize_ 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
|
||||
// gets the number of resources managed by a cache
|
||||
const auto size = cache.size();
|
||||
struct my_loader {
|
||||
using result_type = std::shared_ptr<my_resource>;
|
||||
|
||||
// checks if a cache contains at least a valid resource
|
||||
const auto empty = cache.empty();
|
||||
struct from_disk_tag{};
|
||||
struct from_network_tag{};
|
||||
|
||||
// clears a cache and discards its content
|
||||
cache.clear();
|
||||
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)...);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Besides these member functions, a cache contains what is needed to load, use and
|
||||
discard resources of the given type.<br/>
|
||||
Before to explore this part of the interface, it makes sense to mention how
|
||||
resources are identified. The type of the identifiers to use is defined as:
|
||||
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::cache<resource>::id_type
|
||||
entt::resource_cache<my_resource, my_loader> cache{};
|
||||
```
|
||||
|
||||
Where `id_type` is an alias for `entt::hashed_string::hash_type`. Therefore,
|
||||
resource identifiers are created explicitly as in the following example:
|
||||
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
|
||||
constexpr auto identifier = entt::cache<resource>::id_type{"my/resource/identifier"_hs};
|
||||
// this is equivalent to the following
|
||||
constexpr auto hs = entt::hashed_string{"my/resource/identifier"};
|
||||
```
|
||||
for(auto [id, res]: cache) {
|
||||
// ...
|
||||
}
|
||||
|
||||
The class `hashed_string` is described in a dedicated section, so I won't go in
|
||||
details here.
|
||||
|
||||
Resources are loaded and thus stored in a cache through the `load` member
|
||||
function. It accepts the loader to use as a template parameter, the resource
|
||||
identifier and the parameters used to construct the resource as arguments:
|
||||
|
||||
```cpp
|
||||
// uses the identifier declared above
|
||||
cache.load<my_loader>(identifier, 0);
|
||||
|
||||
// uses a const char * directly as an identifier
|
||||
cache.load<my_loader>("another/identifier"_hs, 42);
|
||||
```
|
||||
|
||||
The function returns a handle to the resource, whether it already exists or is
|
||||
loaded. In case the loader returns an invalid pointer, the handle is invalid as
|
||||
well and therefore it can be easily used with an `if` statement:
|
||||
|
||||
```cpp
|
||||
if(auto handle = cache.load<my_loader>("another/identifier"_hs, 42); handle) {
|
||||
if(entt::resource<my_resource> res = cache["resource/id"_hs]; res) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Before trying to load a resource, the `contains` member function can be used to
|
||||
know if a cache already contains a specific resource:
|
||||
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 exists = cache.contains("my/identifier"_hs);
|
||||
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;
|
||||
```
|
||||
|
||||
There exists also a member function to use to force a reload of an already
|
||||
existing resource if needed:
|
||||
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.
|
||||
|
||||
```cpp
|
||||
auto handle = cache.reload<my_loader>("another/identifier"_hs, 42);
|
||||
```
|
||||
|
||||
As above, the function returns a handle to the resource that is invalid in case
|
||||
of errors. The `reload` member function is a kind of alias of the following
|
||||
snippet:
|
||||
|
||||
```cpp
|
||||
cache.discard(identifier);
|
||||
cache.load<my_loader>(identifier, 42);
|
||||
```
|
||||
|
||||
Where the `discard` member function is used to get rid of a resource if loaded.
|
||||
In case the cache doesn't contain a resource for the given identifier, `discard`
|
||||
does nothing and returns immediately.
|
||||
|
||||
So far, so good. Resources are finally loaded and stored within the cache.<br/>
|
||||
They are returned to users in the form of handles. To get one of them later on:
|
||||
|
||||
```cpp
|
||||
auto handle = cache.handle("my/identifier"_hs);
|
||||
```
|
||||
|
||||
The idea behind a handle is the same of the flyweight pattern. In other terms,
|
||||
resources aren't copied around. Instead, instances are shared between handles.
|
||||
Users of a resource own a handle that guarantees that a resource isn't destroyed
|
||||
until all the handles are destroyed, even if the resource itself is removed from
|
||||
the cache.<br/>
|
||||
Handles are tiny objects both movable and copyable. They return the contained
|
||||
resource as a const reference on request:
|
||||
|
||||
* By means of the `get` member function:
|
||||
|
||||
```cpp
|
||||
const auto &resource = handle.get();
|
||||
```
|
||||
|
||||
* Using the proper cast operator:
|
||||
|
||||
```cpp
|
||||
const auto &resource = handle;
|
||||
```
|
||||
|
||||
* Through the dereference operator:
|
||||
|
||||
```cpp
|
||||
const auto &resource = *handle;
|
||||
```
|
||||
|
||||
The resource can also be accessed directly using the arrow operator if required:
|
||||
|
||||
```cpp
|
||||
auto value = handle->value;
|
||||
```
|
||||
|
||||
To test if a handle is still valid, the cast operator to `bool` allows users to
|
||||
use it in a guard:
|
||||
|
||||
```cpp
|
||||
if(handle) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Finally, in case there is the need to load a resource and thus to get a handle
|
||||
without storing the resource itself in the cache, users can rely on the `temp`
|
||||
member function template.<br/>
|
||||
The declaration is similar to that of `load`, a (possibly invalid) handle for
|
||||
the resource is returned also in this case:
|
||||
|
||||
```cpp
|
||||
if(auto handle = cache.temp<my_loader>(42); handle) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Do not forget to test the handle for validity. Otherwise, getting a reference to
|
||||
the resource it points may result in undefined behavior.
|
||||
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.
|
||||
|
||||
@@ -7,8 +7,11 @@
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Delegate](#delegate)
|
||||
* [Runtime arguments](#runtime-arguments)
|
||||
* [Lambda support](#lambda-support)
|
||||
* [Signals](#signals)
|
||||
* [Event dispatcher](#event-dispatcher)
|
||||
* [Named queues](#named-queues)
|
||||
* [Event emitter](#event-emitter)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
@@ -16,27 +19,27 @@
|
||||
|
||||
# Introduction
|
||||
|
||||
Signals are usually a core part of games and software architectures in
|
||||
general.<br/>
|
||||
Roughly speaking, they help to decouple the various parts of a system while
|
||||
allowing them to communicate with each other somehow.
|
||||
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 these terms,
|
||||
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` does not perform
|
||||
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
|
||||
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 and members provided along with an instance on which to invoke
|
||||
them.<br/>
|
||||
free functions and member functions 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
|
||||
@@ -49,21 +52,19 @@ delegates:
|
||||
entt::delegate<int(int)> delegate{};
|
||||
```
|
||||
|
||||
All what is needed to create an instance is to specify the type of the function
|
||||
the delegate will _contain_, that is the signature of the free function or the
|
||||
member one wants to assign to it.
|
||||
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.
|
||||
|
||||
Attempting to use an empty delegate by invoking its function call operator
|
||||
results in undefined behavior or most likely a crash. Before to use a delegate,
|
||||
it must be initialized.<br/>
|
||||
There exists a bunch of overloads of the `connect` member function to do that.
|
||||
As an example of use:
|
||||
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) { return i }
|
||||
int f(const int &i) const { return i; }
|
||||
};
|
||||
|
||||
// bind a free function to the delegate
|
||||
@@ -74,7 +75,7 @@ my_struct instance;
|
||||
delegate.connect<&my_struct::f>(instance);
|
||||
```
|
||||
|
||||
The delegate class accepts also data members, if needed. In this case, the
|
||||
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.
|
||||
|
||||
@@ -91,14 +92,11 @@ delegate.connect<&g>(c);
|
||||
delegate(42);
|
||||
```
|
||||
|
||||
The function `g` will be invoked with a reference to `c` and `42`. However, the
|
||||
The 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.
|
||||
|
||||
Another interesting aspect of the delegate class is that it accepts also
|
||||
functions with a list of parameters that is shorter than that of the function
|
||||
type used to specialize the delegate itself.<br/>
|
||||
The following code is therefore perfectly valid:
|
||||
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() { /* ... */ }
|
||||
@@ -137,17 +135,17 @@ already shown in the examples above:
|
||||
auto ret = delegate(42);
|
||||
```
|
||||
|
||||
In all cases, the listeners don't have to strictly follow the signature of the
|
||||
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, note that members of a class 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:
|
||||
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>();
|
||||
|
||||
@@ -155,11 +153,84 @@ my_struct instance;
|
||||
delegate(instance, 42);
|
||||
```
|
||||
|
||||
In this case, it's not possible to deduce the function type since the first
|
||||
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)`.
|
||||
|
||||
# Signals
|
||||
|
||||
Signal handlers work with references to classes, function pointers and pointers
|
||||
@@ -171,16 +242,17 @@ 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 can be used as a private data member without exposing any
|
||||
_publish_ functionality to the clients of a class. 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.
|
||||
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 the listeners
|
||||
can be literally _collected_ and used later by the caller. Otherwise, the class
|
||||
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 is sufficient to provide the type of
|
||||
To create instances of signal handlers it's sufficient to provide the type of
|
||||
function to which they refer:
|
||||
|
||||
```cpp
|
||||
@@ -224,13 +296,13 @@ sink.disconnect(instance);
|
||||
sink.disconnect();
|
||||
```
|
||||
|
||||
As shown above, the listeners don't have to strictly follow the signature of the
|
||||
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/>
|
||||
It's also possible to connect a listener before other listeners already
|
||||
contained by the signal. The `before` function returns a `sink` object correctly
|
||||
initialized for the purpose that can be used to connect one or more listeners in
|
||||
It's also possible to connect a listener before other elements already contained
|
||||
by the signal. The `before` function returns a `sink` object that is correctly
|
||||
initialized for the purpose and can be used to connect one or more listeners in
|
||||
order and in the desired position:
|
||||
|
||||
```cpp
|
||||
@@ -239,20 +311,19 @@ sink.before<&foo>().connect<&listener::bar>(instance);
|
||||
|
||||
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. 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.
|
||||
`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 can be published through a signal by means of the `publish`
|
||||
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 should be used instead. Below is
|
||||
a minimal example to show how to use it:
|
||||
To collect data, the `collect` member function is used instead:
|
||||
|
||||
```cpp
|
||||
int f() { return 0; }
|
||||
@@ -286,7 +357,7 @@ case:
|
||||
struct my_collector {
|
||||
std::vector<int> vec{};
|
||||
|
||||
bool operator()(int v) noexcept {
|
||||
bool operator()(int v) {
|
||||
vec.push_back(v);
|
||||
return true;
|
||||
}
|
||||
@@ -300,23 +371,20 @@ signal.collect(std::ref(collector));
|
||||
|
||||
# Event dispatcher
|
||||
|
||||
The event dispatcher class is designed so as to be used in a loop. It allows
|
||||
users both to trigger immediate events or to queue events to be published all
|
||||
together once per tick.<br/>
|
||||
This class shares part of its API with the one of the signal handler, but it
|
||||
doesn't require that all the types of events are specified when declared:
|
||||
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{};
|
||||
```
|
||||
|
||||
In order to register an instance of a class to a dispatcher, its type must
|
||||
expose one or more member functions the arguments of which are such that
|
||||
`const E &` can be converted to them for each type of event `E`, no matter what
|
||||
the return value is.<br/>
|
||||
The name of the member function aimed to receive the event must be provided to
|
||||
the `connect` member function of the sink in charge for the specific event:
|
||||
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; };
|
||||
@@ -334,8 +402,10 @@ dispatcher.sink<an_event>().connect<&listener::receive>(listener);
|
||||
dispatcher.sink<another_event>().connect<&listener::method>(listener);
|
||||
```
|
||||
|
||||
The `disconnect` member function follows the same pattern and can be used to
|
||||
remove one listener at a time or all of them at once:
|
||||
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);
|
||||
@@ -343,14 +413,10 @@ 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. It offers a convenient approach that
|
||||
relieves users from having to create the event itself. Instead, it's enough to
|
||||
specify the type of event and provide all the parameters required to construct
|
||||
it.<br/>
|
||||
As an example:
|
||||
to all the listeners registered so far:
|
||||
|
||||
```cpp
|
||||
dispatcher.trigger<an_event>(42);
|
||||
dispatcher.trigger(an_event{42});
|
||||
dispatcher.trigger<another_event>();
|
||||
```
|
||||
|
||||
@@ -359,20 +425,18 @@ 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
|
||||
allows to maintain control over the moment they are sent to listeners. The
|
||||
signature of this method is more or less the same of `trigger`:
|
||||
helps to maintain control over the moment they are sent to listeners:
|
||||
|
||||
```cpp
|
||||
dispatcher.enqueue<an_event>(42);
|
||||
dispatcher.enqueue<another_event>();
|
||||
dispatcher.enqueue(another_event{});
|
||||
```
|
||||
|
||||
Events are stored aside until the `update` member function is invoked, then all
|
||||
the messages that are still pending are sent to the listeners at once:
|
||||
Events are stored aside until the `update` member function is invoked:
|
||||
|
||||
```cpp
|
||||
// emits all the events of the given type at once
|
||||
dispatcher.update<my_event>();
|
||||
dispatcher.update<an_event>();
|
||||
|
||||
// emits all the events queued so far at once
|
||||
dispatcher.update();
|
||||
@@ -381,6 +445,30 @@ 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
|
||||
@@ -389,8 +477,7 @@ 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 a custom emitter type, derived classes must inherit directly from the
|
||||
base class as:
|
||||
To create an emitter type, derived classes must inherit from the base as:
|
||||
|
||||
```cpp
|
||||
struct my_emitter: emitter<my_emitter> {
|
||||
@@ -398,18 +485,10 @@ struct my_emitter: emitter<my_emitter> {
|
||||
}
|
||||
```
|
||||
|
||||
The full list of accepted types of events isn't required. Handlers are created
|
||||
internally on the fly and thus each type of event is accepted by default.
|
||||
|
||||
Whenever an event is published, an emitter provides the listeners with a
|
||||
reference to itself along with a const reference to the event. Therefore
|
||||
listeners have an handy way to work with it without incurring in the need of
|
||||
capturing a reference to the emitter itself.<br/>
|
||||
In addition, an opaque object is returned each time a connection is established
|
||||
between an emitter and a listener, allowing the caller to disconnect them at a
|
||||
later time.<br/>
|
||||
The opaque object used to handle connections is both movable and copyable. On
|
||||
the other side, an event emitter is movable but not copyable by default.
|
||||
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:
|
||||
|
||||
@@ -417,90 +496,54 @@ To create new instances of an emitter, no arguments are required:
|
||||
my_emitter emitter{};
|
||||
```
|
||||
|
||||
Listeners must be movable and callable objects (free functions, lambdas,
|
||||
functors, `std::function`s, whatever) whose function type is:
|
||||
Listeners are movable and callable objects (free functions, lambdas, functors,
|
||||
`std::function`s, whatever) whose function type is compatible with:
|
||||
|
||||
```cpp
|
||||
void(const Event &, my_emitter &)
|
||||
void(Type &, my_emitter &)
|
||||
```
|
||||
|
||||
Where `Event` is the type of event they want to listen.<br/>
|
||||
There are two ways to attach a listener to an event emitter that differ
|
||||
slightly from each other:
|
||||
|
||||
* To register a long-lived listener, use the `on` member function. It is meant
|
||||
to register a listener designed to be invoked more than once for the given
|
||||
event type.<br/>
|
||||
As an example:
|
||||
|
||||
```cpp
|
||||
auto conn = emitter.on<my_event>([](const my_event &event, my_emitter &emitter) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
The connection object can be freely discarded. Otherwise, it can be used later
|
||||
to disconnect the listener if required.
|
||||
|
||||
* To register a short-lived listener, use the `once` member function. It is
|
||||
meant to register a listener designed to be invoked only once for the given
|
||||
event type. The listener is automatically disconnected after the first
|
||||
invocation.<br/>
|
||||
As an example:
|
||||
|
||||
```cpp
|
||||
auto conn = emitter.once<my_event>([](const my_event &event, my_emitter &emitter) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
The connection object can be freely discarded. Otherwise, it can be used later
|
||||
to disconnect the listener if required.
|
||||
|
||||
In both cases, the connection object can be used with the `erase` member
|
||||
function:
|
||||
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.erase(conn);
|
||||
emitter.on<my_event>([](const my_event &event, my_emitter &emitter) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
There are also two member functions to use either to disconnect all the
|
||||
listeners for a given type of event or to clear the 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
|
||||
// removes all the listener for the specific event
|
||||
emitter.clear<my_event>();
|
||||
// resets the listener for my_event
|
||||
emitter.erase<my_event>();
|
||||
|
||||
// removes all the listeners registered so far
|
||||
emitter.clear();
|
||||
// resets all listeners
|
||||
emitter.clear()
|
||||
```
|
||||
|
||||
To send an event to all the listeners that are interested in it, the `publish`
|
||||
member function offers a convenient approach that relieves users from having to
|
||||
create the event:
|
||||
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);
|
||||
emitter.publish(my_event{42});
|
||||
```
|
||||
|
||||
Finally, the `empty` member function tests if there exists at least either a
|
||||
listener registered with the event emitter or to a given type of event:
|
||||
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
|
||||
bool empty;
|
||||
|
||||
// checks if there is any listener registered for the specific event
|
||||
empty = emitter.empty<my_event>();
|
||||
|
||||
// checks it there are listeners registered with the event emitter
|
||||
empty = emitter.empty();
|
||||
if(emitter.contains<my_event>()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
In general, the event emitter is a handy tool when the derived classes _wrap_
|
||||
asynchronous operations, because it introduces a _nice-to-have_ model based on
|
||||
events and listeners that kindly hides the complexity behind the scenes. However
|
||||
it is not limited to such uses.
|
||||
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
docs/md/unreal.md
Normal file
107
docs/md/unreal.md
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
entt.imp
Normal file
34
entt.imp
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
natvis/entt/config.natvis
Normal file
3
natvis/entt/config.natvis
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
natvis/entt/container.natvis
Normal file
33
natvis/entt/container.natvis
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
natvis/entt/core.natvis
Normal file
32
natvis/entt/core.natvis
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>
|
||||
153
natvis/entt/entity.natvis
Normal file
153
natvis/entt/entity.natvis
Normal file
@@ -0,0 +1,153 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::basic_registry<*>">
|
||||
<Intrinsic Name="pools_size" Expression="pools.packed.first_base::value.size()"/>
|
||||
<Intrinsic Name="vars_size" Expression="vars.ctx.packed.first_base::value.size()"/>
|
||||
<Intrinsic Name="to_entity" Expression="*((entity_traits::entity_type *)&entity) & entity_traits::entity_mask">
|
||||
<Parameter Name="entity" Type="entity_traits::value_type &"/>
|
||||
</Intrinsic>
|
||||
<DisplayString>{{ size={ epool.size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item IncludeView="simple" Name="[epool]">epool,view(simple)nr</Item>
|
||||
<Synthetic Name="[epool]" ExcludeView="simple">
|
||||
<DisplayString>{ epool.size() }</DisplayString>
|
||||
<Expand>
|
||||
<CustomListItems>
|
||||
<Variable Name="pos" InitialValue="0" />
|
||||
<Variable Name="last" InitialValue="epool.size()"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="to_entity(epool[pos]) == pos">
|
||||
<Item Name="[{ pos }]">epool[pos]</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[destroyed]" ExcludeView="simple">
|
||||
<DisplayString>{ to_entity(free_list) != entity_traits::entity_mask }</DisplayString>
|
||||
<Expand>
|
||||
<CustomListItems>
|
||||
<Variable Name="it" InitialValue="to_entity(free_list)" />
|
||||
<Loop>
|
||||
<Break Condition="it == entity_traits::entity_mask"/>
|
||||
<Item Name="[{ it }]">epool[it]</Item>
|
||||
<Exec>it = to_entity(epool[it])</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<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_size() }</DisplayString>
|
||||
<Expand>
|
||||
<IndexListItems>
|
||||
<Size>vars_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() * entity_traits::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() * entity_traits::page_size"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<Exec>page = pos / entity_traits::page_size</Exec>
|
||||
<Exec>offset = pos & (entity_traits::page_size - 1)</Exec>
|
||||
<If Condition="sparse[page] && (*((entity_traits::entity_type *)&sparse[page][offset]) < ~entity_traits::entity_mask)">
|
||||
<Item Name="[{ pos }]">*((entity_traits::entity_type *)&sparse[page][offset]) & entity_traits::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="*((entity_traits::entity_type *)&packed[pos]) < ~entity_traits::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">packed.first_base::value.capacity() * comp_traits::page_size</Item>
|
||||
<Item Name="[page size]" Optional="true" ExcludeView="simple">comp_traits::page_size</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="packed.first_base::value.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::entity_traits::entity_type *)&base_type::packed[pos]) < ~base_type::entity_traits::entity_mask">
|
||||
<Item Name="[{ pos }:{ base_type::packed[pos] }]">packed.first_base::value[pos / comp_traits::page_size][pos & (comp_traits::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
natvis/entt/graph.natvis
Normal file
19
natvis/entt/graph.natvis
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
natvis/entt/locator.natvis
Normal file
3
natvis/entt/locator.natvis
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
natvis/entt/meta.natvis
Normal file
121
natvis/entt/meta.natvis
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
natvis/entt/platform.natvis
Normal file
3
natvis/entt/platform.natvis
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
natvis/entt/poly.natvis
Normal file
6
natvis/entt/poly.natvis
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
natvis/entt/process.natvis
Normal file
3
natvis/entt/process.natvis
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
natvis/entt/resource.natvis
Normal file
15
natvis/entt/resource.natvis
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>
|
||||
56
natvis/entt/signal.natvis
Normal file
56
natvis/entt/signal.natvis
Normal file
@@ -0,0 +1,56 @@
|
||||
<?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.packed.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>
|
||||
<Item Name="[offset]">offset</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,67 +1,81 @@
|
||||
#ifndef ENTT_CONFIG_CONFIG_H
|
||||
#define ENTT_CONFIG_CONFIG_H
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#ifndef ENTT_NOEXCEPT
|
||||
# define ENTT_NOEXCEPT noexcept
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_HS_SUFFIX
|
||||
# define ENTT_HS_SUFFIX _hs
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_HWS_SUFFIX
|
||||
# define ENTT_HWS_SUFFIX _hws
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_USE_ATOMIC
|
||||
# define ENTT_MAYBE_ATOMIC(Type) Type
|
||||
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
|
||||
# define ENTT_CONSTEXPR
|
||||
# define ENTT_THROW throw
|
||||
# define ENTT_TRY try
|
||||
# define ENTT_CATCH catch(...)
|
||||
#else
|
||||
# include <atomic>
|
||||
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
||||
# define ENTT_CONSTEXPR constexpr // use only with throwing functions (waiting for C++20)
|
||||
# define ENTT_THROW
|
||||
# define ENTT_TRY if(true)
|
||||
# define ENTT_CATCH if(false)
|
||||
#endif
|
||||
|
||||
#ifdef ENTT_USE_ATOMIC
|
||||
# include <atomic>
|
||||
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
||||
#else
|
||||
# define ENTT_MAYBE_ATOMIC(Type) Type
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_ID_TYPE
|
||||
# include <cstdint>
|
||||
# define ENTT_ID_TYPE std::uint32_t
|
||||
# include <cstdint>
|
||||
# define ENTT_ID_TYPE std::uint32_t
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_PAGE_SIZE
|
||||
# define ENTT_PAGE_SIZE 32768
|
||||
#ifndef ENTT_SPARSE_PAGE
|
||||
# define ENTT_SPARSE_PAGE 4096
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_ASSERT
|
||||
# include <cassert>
|
||||
# define ENTT_ASSERT(condition) assert(condition)
|
||||
#ifndef ENTT_PACKED_PAGE
|
||||
# define ENTT_PACKED_PAGE 1024
|
||||
#endif
|
||||
|
||||
#ifdef ENTT_DISABLE_ASSERT
|
||||
# undef ENTT_ASSERT
|
||||
# define ENTT_ASSERT(condition, msg) (void(0))
|
||||
#elif !defined ENTT_ASSERT
|
||||
# include <cassert>
|
||||
# define ENTT_ASSERT(condition, msg) assert(condition)
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_DISABLE_ETO
|
||||
# include <type_traits>
|
||||
# define ENTT_ENABLE_ETO(Type) (std::is_default_constructible_v<Type> && std::is_empty_v<Type>)
|
||||
#ifdef ENTT_DISABLE_ASSERT
|
||||
# undef ENTT_ASSERT_CONSTEXPR
|
||||
# define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0))
|
||||
#elif !defined ENTT_ASSERT_CONSTEXPR
|
||||
# define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg)
|
||||
#endif
|
||||
|
||||
#ifdef ENTT_NO_ETO
|
||||
# define ENTT_ETO_TYPE(Type) void
|
||||
#else
|
||||
# // sfinae-friendly definition
|
||||
# define ENTT_ENABLE_ETO(Type) (false && std::is_void_v<Type>)
|
||||
# define ENTT_ETO_TYPE(Type) Type
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_STANDARD_CPP
|
||||
# if defined _MSC_VER
|
||||
# define ENTT_PRETTY_FUNCTION __FUNCSIG__
|
||||
# define ENTT_PRETTY_FUNCTION_CONSTEXPR ENTT_PRETTY_FUNCTION
|
||||
# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8)
|
||||
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
# define ENTT_PRETTY_FUNCTION_CONSTEXPR ENTT_PRETTY_FUNCTION
|
||||
# elif defined __GNUC__
|
||||
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
# endif
|
||||
#ifdef ENTT_STANDARD_CPP
|
||||
# define ENTT_NONSTD false
|
||||
#else
|
||||
# define ENTT_NONSTD true
|
||||
# if defined __clang__ || defined __GNUC__
|
||||
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
# define ENTT_PRETTY_FUNCTION_PREFIX '='
|
||||
# define ENTT_PRETTY_FUNCTION_SUFFIX ']'
|
||||
# elif defined _MSC_VER
|
||||
# define ENTT_PRETTY_FUNCTION __FUNCSIG__
|
||||
# define ENTT_PRETTY_FUNCTION_PREFIX '<'
|
||||
# define ENTT_PRETTY_FUNCTION_SUFFIX '>'
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined _MSC_VER
|
||||
# pragma detect_mismatch("entt.version", ENTT_VERSION)
|
||||
# pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY))
|
||||
# pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE))
|
||||
# pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
7
src/entt/config/macro.h
Normal file
7
src/entt/config/macro.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef ENTT_CONFIG_MACRO_H
|
||||
#define ENTT_CONFIG_MACRO_H
|
||||
|
||||
#define ENTT_STR(arg) #arg
|
||||
#define ENTT_XSTR(arg) ENTT_STR(arg)
|
||||
|
||||
#endif
|
||||
@@ -1,10 +1,14 @@
|
||||
#ifndef ENTT_CONFIG_VERSION_H
|
||||
#define ENTT_CONFIG_VERSION_H
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
#define ENTT_VERSION_MAJOR 3
|
||||
#define ENTT_VERSION_MINOR 3
|
||||
#define ENTT_VERSION_PATCH 2
|
||||
#define ENTT_VERSION_MINOR 11
|
||||
#define ENTT_VERSION_PATCH 1
|
||||
|
||||
#define ENTT_VERSION \
|
||||
ENTT_XSTR(ENTT_VERSION_MAJOR) \
|
||||
"." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH)
|
||||
|
||||
#endif
|
||||
|
||||
1060
src/entt/container/dense_map.hpp
Normal file
1060
src/entt/container/dense_map.hpp
Normal file
File diff suppressed because it is too large
Load Diff
895
src/entt/container/dense_set.hpp
Normal file
895
src/entt/container/dense_set.hpp
Normal file
@@ -0,0 +1,895 @@
|
||||
#ifndef ENTT_CONTAINER_DENSE_SET_HPP
|
||||
#define ENTT_CONTAINER_DENSE_SET_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "../core/memory.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
class dense_set_iterator final {
|
||||
template<typename>
|
||||
friend class dense_set_iterator;
|
||||
|
||||
public:
|
||||
using value_type = typename It::value_type::second_type;
|
||||
using pointer = const value_type *;
|
||||
using reference = const value_type &;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
constexpr dense_set_iterator() noexcept
|
||||
: it{} {}
|
||||
|
||||
constexpr dense_set_iterator(const It iter) noexcept
|
||||
: it{iter} {}
|
||||
|
||||
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
|
||||
constexpr dense_set_iterator(const dense_set_iterator<Other> &other) noexcept
|
||||
: it{other.it} {}
|
||||
|
||||
constexpr dense_set_iterator &operator++() noexcept {
|
||||
return ++it, *this;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator operator++(int) noexcept {
|
||||
dense_set_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator &operator--() noexcept {
|
||||
return --it, *this;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator operator--(int) noexcept {
|
||||
dense_set_iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator &operator+=(const difference_type value) noexcept {
|
||||
it += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator operator+(const difference_type value) const noexcept {
|
||||
dense_set_iterator copy = *this;
|
||||
return (copy += value);
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator &operator-=(const difference_type value) noexcept {
|
||||
return (*this += -value);
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator operator-(const difference_type value) const noexcept {
|
||||
return (*this + -value);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
|
||||
return it[value].second;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::addressof(it->second);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend constexpr std::ptrdiff_t operator-(const dense_set_iterator<ILhs> &, const dense_set_iterator<IRhs> &) noexcept;
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend constexpr bool operator==(const dense_set_iterator<ILhs> &, const dense_set_iterator<IRhs> &) noexcept;
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend constexpr bool operator<(const dense_set_iterator<ILhs> &, const dense_set_iterator<IRhs> &) noexcept;
|
||||
|
||||
private:
|
||||
It it;
|
||||
};
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept {
|
||||
return lhs.it - rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator<(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept {
|
||||
return lhs.it < rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator>(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator<=(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator>=(const dense_set_iterator<ILhs> &lhs, const dense_set_iterator<IRhs> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
class dense_set_local_iterator final {
|
||||
template<typename>
|
||||
friend class dense_set_local_iterator;
|
||||
|
||||
public:
|
||||
using value_type = typename It::value_type::second_type;
|
||||
using pointer = const value_type *;
|
||||
using reference = const value_type &;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
constexpr dense_set_local_iterator() noexcept
|
||||
: it{},
|
||||
offset{} {}
|
||||
|
||||
constexpr dense_set_local_iterator(It iter, const std::size_t pos) noexcept
|
||||
: it{iter},
|
||||
offset{pos} {}
|
||||
|
||||
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
|
||||
constexpr dense_set_local_iterator(const dense_set_local_iterator<Other> &other) noexcept
|
||||
: it{other.it},
|
||||
offset{other.offset} {}
|
||||
|
||||
constexpr dense_set_local_iterator &operator++() noexcept {
|
||||
return offset = it[offset].first, *this;
|
||||
}
|
||||
|
||||
constexpr dense_set_local_iterator operator++(int) noexcept {
|
||||
dense_set_local_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::addressof(it[offset].second);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t index() const noexcept {
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
std::size_t offset;
|
||||
};
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<ILhs> &lhs, const dense_set_local_iterator<IRhs> &rhs) noexcept {
|
||||
return lhs.index() == rhs.index();
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator<ILhs> &lhs, const dense_set_local_iterator<IRhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Associative container for unique objects of a given type.
|
||||
*
|
||||
* Internally, elements are organized into buckets. Which bucket an element is
|
||||
* placed into depends entirely on its hash. Elements with the same hash code
|
||||
* appear in the same bucket.
|
||||
*
|
||||
* @tparam Type Value type of the associative container.
|
||||
* @tparam Hash Type of function to use to hash the values.
|
||||
* @tparam KeyEqual Type of function to use to compare the values for equality.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Hash, typename KeyEqual, typename Allocator>
|
||||
class dense_set {
|
||||
static constexpr float default_threshold = 0.875f;
|
||||
static constexpr std::size_t minimum_capacity = 8u;
|
||||
|
||||
using node_type = std::pair<std::size_t, Type>;
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
|
||||
using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
|
||||
using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::size_t value_to_bucket(const Other &value) const noexcept {
|
||||
return fast_mod(static_cast<size_type>(sparse.second()(value)), bucket_count());
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) {
|
||||
for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
|
||||
if(packed.second()(*it, value)) {
|
||||
return begin() + static_cast<typename iterator::difference_type>(it.index());
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) const {
|
||||
for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
|
||||
if(packed.second()(*it, value)) {
|
||||
return cbegin() + static_cast<typename iterator::difference_type>(it.index());
|
||||
}
|
||||
}
|
||||
|
||||
return cend();
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto insert_or_do_nothing(Other &&value) {
|
||||
const auto index = value_to_bucket(value);
|
||||
|
||||
if(auto it = constrained_find(value, index); it != end()) {
|
||||
return std::make_pair(it, false);
|
||||
}
|
||||
|
||||
packed.first().emplace_back(sparse.first()[index], std::forward<Other>(value));
|
||||
sparse.first()[index] = packed.first().size() - 1u;
|
||||
rehash_if_required();
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
}
|
||||
|
||||
void move_and_pop(const std::size_t pos) {
|
||||
if(const auto last = size() - 1u; pos != last) {
|
||||
size_type *curr = sparse.first().data() + value_to_bucket(packed.first().back().second);
|
||||
packed.first()[pos] = std::move(packed.first().back());
|
||||
for(; *curr != last; curr = &packed.first()[*curr].first) {}
|
||||
*curr = pos;
|
||||
}
|
||||
|
||||
packed.first().pop_back();
|
||||
}
|
||||
|
||||
void rehash_if_required() {
|
||||
if(size() > (bucket_count() * max_load_factor())) {
|
||||
rehash(bucket_count() * 2u);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Key type of the container. */
|
||||
using key_type = Type;
|
||||
/*! @brief Value type of the container. */
|
||||
using value_type = Type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Type of function to use to hash the elements. */
|
||||
using hasher = Hash;
|
||||
/*! @brief Type of function to use to compare the elements for equality. */
|
||||
using key_equal = KeyEqual;
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>;
|
||||
/*! @brief Constant random access iterator type. */
|
||||
using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_iterator>;
|
||||
/*! @brief Forward iterator type. */
|
||||
using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>;
|
||||
/*! @brief Constant forward iterator type. */
|
||||
using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_iterator>;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
dense_set()
|
||||
: dense_set{minimum_capacity} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit dense_set(const allocator_type &allocator)
|
||||
: dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator and user
|
||||
* supplied minimal number of buckets.
|
||||
* @param cnt Minimal number of buckets.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_set(const size_type cnt, const allocator_type &allocator)
|
||||
: dense_set{cnt, hasher{}, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator, hash
|
||||
* function and user supplied minimal number of buckets.
|
||||
* @param cnt Minimal number of buckets.
|
||||
* @param hash Hash function to use.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator)
|
||||
: dense_set{cnt, hash, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator, hash
|
||||
* function, compare function and user supplied minimal number of buckets.
|
||||
* @param cnt Minimal number of buckets.
|
||||
* @param hash Hash function to use.
|
||||
* @param equal Compare function to use.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{})
|
||||
: sparse{allocator, hash},
|
||||
packed{allocator, equal},
|
||||
threshold{default_threshold} {
|
||||
rehash(cnt);
|
||||
}
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
dense_set(const dense_set &) = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_set(const dense_set &other, const allocator_type &allocator)
|
||||
: sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())},
|
||||
packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
dense_set(dense_set &&) noexcept(std::is_nothrow_move_constructible_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_constructible_v<compressed_pair<packed_container_type, key_equal>>) = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_set(dense_set &&other, const allocator_type &allocator)
|
||||
: sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))},
|
||||
packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator.
|
||||
* @return This container.
|
||||
*/
|
||||
dense_set &operator=(const dense_set &) = default;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @return This container.
|
||||
*/
|
||||
dense_set &operator=(dense_set &&) noexcept(std::is_nothrow_move_assignable_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_assignable_v<compressed_pair<packed_container_type, key_equal>>) = default;
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return sparse.first().get_allocator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning.
|
||||
*
|
||||
* The returned iterator points to the first instance of the internal array.
|
||||
* If the array is empty, the returned iterator will be equal to `end()`.
|
||||
*
|
||||
* @return An iterator to the first instance of the internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cbegin() const noexcept {
|
||||
return packed.first().begin();
|
||||
}
|
||||
|
||||
/*! @copydoc cbegin */
|
||||
[[nodiscard]] const_iterator begin() const noexcept {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] iterator begin() noexcept {
|
||||
return packed.first().begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end.
|
||||
*
|
||||
* The returned iterator points to the element following the last instance
|
||||
* of the internal array. Attempting to dereference the returned iterator
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @return An iterator to the element following the last instance of the
|
||||
* internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cend() const noexcept {
|
||||
return packed.first().end();
|
||||
}
|
||||
|
||||
/*! @copydoc cend */
|
||||
[[nodiscard]] const_iterator end() const noexcept {
|
||||
return cend();
|
||||
}
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] iterator end() noexcept {
|
||||
return packed.first().end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a container is empty.
|
||||
* @return True if the container is empty, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept {
|
||||
return packed.first().empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a container.
|
||||
* @return Number of elements in a container.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return packed.first().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum possible number of elements.
|
||||
* @return Maximum possible number of elements.
|
||||
*/
|
||||
[[nodiscard]] size_type max_size() const noexcept {
|
||||
return packed.first().max_size();
|
||||
}
|
||||
|
||||
/*! @brief Clears the container. */
|
||||
void clear() noexcept {
|
||||
sparse.first().clear();
|
||||
packed.first().clear();
|
||||
rehash(0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an element into the container, if it does not exist.
|
||||
* @param value An element to insert into the container.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
std::pair<iterator, bool> insert(const value_type &value) {
|
||||
return insert_or_do_nothing(value);
|
||||
}
|
||||
|
||||
/*! @copydoc insert */
|
||||
std::pair<iterator, bool> insert(value_type &&value) {
|
||||
return insert_or_do_nothing(std::move(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts elements into the container, if they do not exist.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
*/
|
||||
template<typename It>
|
||||
void insert(It first, It last) {
|
||||
for(; first != last; ++first) {
|
||||
insert(*first);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an element in-place, if it does not exist.
|
||||
*
|
||||
* The element is also constructed when the container already has the key,
|
||||
* in which case the newly constructed object is destroyed immediately.
|
||||
*
|
||||
* @tparam Args Types of arguments to forward to the constructor of the
|
||||
* element.
|
||||
* @param args Arguments to forward to the constructor of the element.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
template<typename... Args>
|
||||
std::pair<iterator, bool> emplace(Args &&...args) {
|
||||
if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::decay_t<Args>, value_type>)) {
|
||||
return insert_or_do_nothing(std::forward<Args>(args)...);
|
||||
} else {
|
||||
auto &node = packed.first().emplace_back(std::piecewise_construct, std::make_tuple(packed.first().size()), std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
const auto index = value_to_bucket(node.second);
|
||||
|
||||
if(auto it = constrained_find(node.second, index); it != end()) {
|
||||
packed.first().pop_back();
|
||||
return std::make_pair(it, false);
|
||||
}
|
||||
|
||||
std::swap(node.first, sparse.first()[index]);
|
||||
rehash_if_required();
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes an element from a given position.
|
||||
* @param pos An iterator to the element to remove.
|
||||
* @return An iterator following the removed element.
|
||||
*/
|
||||
iterator erase(const_iterator pos) {
|
||||
const auto diff = pos - cbegin();
|
||||
erase(*pos);
|
||||
return begin() + diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the given elements from a container.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
* @return An iterator following the last removed element.
|
||||
*/
|
||||
iterator erase(const_iterator first, const_iterator last) {
|
||||
const auto dist = first - cbegin();
|
||||
|
||||
for(auto from = last - cbegin(); from != dist; --from) {
|
||||
erase(packed.first()[from - 1u].second);
|
||||
}
|
||||
|
||||
return (begin() + dist);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the element associated with a given value.
|
||||
* @param value Value of an element to remove.
|
||||
* @return Number of elements removed (either 0 or 1).
|
||||
*/
|
||||
size_type erase(const value_type &value) {
|
||||
for(size_type *curr = sparse.first().data() + value_to_bucket(value); *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].first) {
|
||||
if(packed.second()(packed.first()[*curr].second, value)) {
|
||||
const auto index = *curr;
|
||||
*curr = packed.first()[*curr].first;
|
||||
move_and_pop(index);
|
||||
return 1u;
|
||||
}
|
||||
}
|
||||
|
||||
return 0u;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given container.
|
||||
* @param other Container to exchange the content with.
|
||||
*/
|
||||
void swap(dense_set &other) {
|
||||
using std::swap;
|
||||
swap(sparse, other.sparse);
|
||||
swap(packed, other.packed);
|
||||
swap(threshold, other.threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements matching a value (either 1 or 0).
|
||||
* @param key Key value of an element to search for.
|
||||
* @return Number of elements matching the key (either 1 or 0).
|
||||
*/
|
||||
[[nodiscard]] size_type count(const value_type &key) const {
|
||||
return find(key) != end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements matching a key (either 1 or 0).
|
||||
* @tparam Other Type of the key value of an element to search for.
|
||||
* @param key Key value of an element to search for.
|
||||
* @return Number of elements matching the key (either 1 or 0).
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>>
|
||||
count(const Other &key) const {
|
||||
return find(key) != end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an element with a given value.
|
||||
* @param value Value of an element to search for.
|
||||
* @return An iterator to an element with the given value. If no such
|
||||
* element is found, a past-the-end iterator is returned.
|
||||
*/
|
||||
[[nodiscard]] iterator find(const value_type &value) {
|
||||
return constrained_find(value, value_to_bucket(value));
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
[[nodiscard]] const_iterator find(const value_type &value) const {
|
||||
return constrained_find(value, value_to_bucket(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an element that compares _equivalent_ to a given value.
|
||||
* @tparam Other Type of an element to search for.
|
||||
* @param value Value of an element to search for.
|
||||
* @return An iterator to an element with the given value. If no such
|
||||
* element is found, a past-the-end iterator is returned.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
|
||||
find(const Other &value) {
|
||||
return constrained_find(value, value_to_bucket(value));
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
|
||||
find(const Other &value) const {
|
||||
return constrained_find(value, value_to_bucket(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a range containing all elements with a given value.
|
||||
* @param value Value of an element to search for.
|
||||
* @return A pair of iterators pointing to the first element and past the
|
||||
* last element of the range.
|
||||
*/
|
||||
[[nodiscard]] std::pair<iterator, iterator> equal_range(const value_type &value) {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == end())};
|
||||
}
|
||||
|
||||
/*! @copydoc equal_range */
|
||||
[[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const value_type &value) const {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == cend())};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a range containing all elements that compare _equivalent_
|
||||
* to a given value.
|
||||
* @tparam Other Type of an element to search for.
|
||||
* @param value Value of an element to search for.
|
||||
* @return A pair of iterators pointing to the first element and past the
|
||||
* last element of the range.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>>
|
||||
equal_range(const Other &value) {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == end())};
|
||||
}
|
||||
|
||||
/*! @copydoc equal_range */
|
||||
template<class Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<const_iterator, const_iterator>>>
|
||||
equal_range(const Other &value) const {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == cend())};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the container contains an element with a given value.
|
||||
* @param value Value of an element to search for.
|
||||
* @return True if there is such an element, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const value_type &value) const {
|
||||
return (find(value) != cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the container contains an element that compares
|
||||
* _equivalent_ to a given value.
|
||||
* @tparam Other Type of an element to search for.
|
||||
* @param value Value of an element to search for.
|
||||
* @return True if there is such an element, false otherwise.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>>
|
||||
contains(const Other &value) const {
|
||||
return (find(value) != cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator cbegin(const size_type index) const {
|
||||
return {packed.first().begin(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator begin(const size_type index) const {
|
||||
return cbegin(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] local_iterator begin(const size_type index) {
|
||||
return {packed.first().begin(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
|
||||
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator end(const size_type index) const {
|
||||
return cend(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
|
||||
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of buckets.
|
||||
* @return The number of buckets.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket_count() const {
|
||||
return sparse.first().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum number of buckets.
|
||||
* @return The maximum number of buckets.
|
||||
*/
|
||||
[[nodiscard]] size_type max_bucket_count() const {
|
||||
return sparse.first().max_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a given bucket.
|
||||
* @param index The index of the bucket to examine.
|
||||
* @return The number of elements in the given bucket.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket_size(const size_type index) const {
|
||||
return static_cast<size_type>(std::distance(begin(index), end(index)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the bucket for a given element.
|
||||
* @param value The value of the element to examine.
|
||||
* @return The bucket for the given element.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket(const value_type &value) const {
|
||||
return value_to_bucket(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the average number of elements per bucket.
|
||||
* @return The average number of elements per bucket.
|
||||
*/
|
||||
[[nodiscard]] float load_factor() const {
|
||||
return size() / static_cast<float>(bucket_count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum average number of elements per bucket.
|
||||
* @return The maximum average number of elements per bucket.
|
||||
*/
|
||||
[[nodiscard]] float max_load_factor() const {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the desired maximum average number of elements per bucket.
|
||||
* @param value A desired maximum average number of elements per bucket.
|
||||
*/
|
||||
void max_load_factor(const float value) {
|
||||
ENTT_ASSERT(value > 0.f, "Invalid load factor");
|
||||
threshold = value;
|
||||
rehash(0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserves at least the specified number of buckets and regenerates
|
||||
* the hash table.
|
||||
* @param cnt New number of buckets.
|
||||
*/
|
||||
void rehash(const size_type cnt) {
|
||||
auto value = cnt > minimum_capacity ? cnt : minimum_capacity;
|
||||
const auto cap = static_cast<size_type>(size() / max_load_factor());
|
||||
value = value > cap ? value : cap;
|
||||
|
||||
if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
|
||||
sparse.first().resize(sz);
|
||||
|
||||
for(auto &&elem: sparse.first()) {
|
||||
elem = std::numeric_limits<size_type>::max();
|
||||
}
|
||||
|
||||
for(size_type pos{}, last = size(); pos < last; ++pos) {
|
||||
const auto index = value_to_bucket(packed.first()[pos].second);
|
||||
packed.first()[pos].first = std::exchange(sparse.first()[index], pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserves space for at least the specified number of elements and
|
||||
* regenerates the hash table.
|
||||
* @param cnt New number of elements.
|
||||
*/
|
||||
void reserve(const size_type cnt) {
|
||||
packed.first().reserve(cnt);
|
||||
rehash(static_cast<size_type>(std::ceil(cnt / max_load_factor())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function used to hash the elements.
|
||||
* @return The function used to hash the elements.
|
||||
*/
|
||||
[[nodiscard]] hasher hash_function() const {
|
||||
return sparse.second();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function used to compare elements for equality.
|
||||
* @return The function used to compare elements for equality.
|
||||
*/
|
||||
[[nodiscard]] key_equal key_eq() const {
|
||||
return packed.second();
|
||||
}
|
||||
|
||||
private:
|
||||
compressed_pair<sparse_container_type, hasher> sparse;
|
||||
compressed_pair<packed_container_type, key_equal> packed;
|
||||
float threshold;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
26
src/entt/container/fwd.hpp
Normal file
26
src/entt/container/fwd.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef ENTT_CONTAINER_FWD_HPP
|
||||
#define ENTT_CONTAINER_FWD_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<
|
||||
typename Key,
|
||||
typename Type,
|
||||
typename = std::hash<Key>,
|
||||
typename = std::equal_to<Key>,
|
||||
typename = std::allocator<std::pair<const Key, Type>>>
|
||||
class dense_map;
|
||||
|
||||
template<
|
||||
typename Type,
|
||||
typename = std::hash<Type>,
|
||||
typename = std::equal_to<Type>,
|
||||
typename = std::allocator<Type>>
|
||||
class dense_set;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,18 +1,15 @@
|
||||
#ifndef ENTT_CORE_ALGORITHM_HPP
|
||||
#define ENTT_CORE_ALGORITHM_HPP
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "utility.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function object to wrap `std::sort` in a class type.
|
||||
*
|
||||
@@ -36,12 +33,11 @@ struct std_sort {
|
||||
* @param args Arguments to forward to the sort function, if any.
|
||||
*/
|
||||
template<typename It, typename Compare = std::less<>, typename... Args>
|
||||
void operator()(It first, It last, Compare compare = Compare{}, Args &&... args) const {
|
||||
void operator()(It first, It last, Compare compare = Compare{}, Args &&...args) const {
|
||||
std::sort(std::forward<Args>(args)..., std::move(first), std::move(last), std::move(compare));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*! @brief Function object for performing insertion sort. */
|
||||
struct insertion_sort {
|
||||
/**
|
||||
@@ -58,12 +54,12 @@ struct insertion_sort {
|
||||
template<typename It, typename Compare = std::less<>>
|
||||
void operator()(It first, It last, Compare compare = Compare{}) const {
|
||||
if(first < last) {
|
||||
for(auto it = first+1; it < last; ++it) {
|
||||
for(auto it = first + 1; it < last; ++it) {
|
||||
auto value = std::move(*it);
|
||||
auto pre = it;
|
||||
|
||||
for(; pre > first && compare(value, *(pre-1)); --pre) {
|
||||
*pre = std::move(*(pre-1));
|
||||
for(; pre > first && compare(value, *(pre - 1)); --pre) {
|
||||
*pre = std::move(*(pre - 1));
|
||||
}
|
||||
|
||||
*pre = std::move(value);
|
||||
@@ -72,7 +68,6 @@ struct insertion_sort {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function object for performing LSD radix sort.
|
||||
* @tparam Bit Number of bits processed per pass.
|
||||
@@ -80,7 +75,7 @@ struct insertion_sort {
|
||||
*/
|
||||
template<std::size_t Bit, std::size_t N>
|
||||
struct radix_sort {
|
||||
static_assert((N % Bit) == 0);
|
||||
static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass");
|
||||
|
||||
/**
|
||||
* @brief Sorts the elements in a range.
|
||||
@@ -111,17 +106,17 @@ struct radix_sort {
|
||||
std::size_t index[buckets]{};
|
||||
std::size_t count[buckets]{};
|
||||
|
||||
std::for_each(from, to, [&getter, &count, start](const value_type &item) {
|
||||
++count[(getter(item) >> start) & mask];
|
||||
});
|
||||
for(auto it = from; it != to; ++it) {
|
||||
++count[(getter(*it) >> start) & mask];
|
||||
}
|
||||
|
||||
std::for_each(std::next(std::begin(index)), std::end(index), [index = std::begin(index), count = std::begin(count)](auto &item) mutable {
|
||||
item = *(index++) + *(count++);
|
||||
});
|
||||
for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
|
||||
index[pos + 1u] = index[pos] + count[pos];
|
||||
}
|
||||
|
||||
std::for_each(from, to, [&getter, &out, &index, start](value_type &item) {
|
||||
out[index[(getter(item) >> start) & mask]++] = std::move(item);
|
||||
});
|
||||
for(auto it = from; it != to; ++it) {
|
||||
out[index[(getter(*it) >> start) & mask]++] = std::move(*it);
|
||||
}
|
||||
};
|
||||
|
||||
for(std::size_t pass = 0; pass < (passes & ~1); pass += 2) {
|
||||
@@ -137,8 +132,6 @@ struct radix_sort {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
510
src/entt/core/any.hpp
Normal file
510
src/entt/core/any.hpp
Normal file
@@ -0,0 +1,510 @@
|
||||
#ifndef ENTT_CORE_ANY_HPP
|
||||
#define ENTT_CORE_ANY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
enum class any_operation : std::uint8_t {
|
||||
copy,
|
||||
move,
|
||||
transfer,
|
||||
assign,
|
||||
destroy,
|
||||
compare,
|
||||
get
|
||||
};
|
||||
|
||||
enum class any_policy : std::uint8_t {
|
||||
owner,
|
||||
ref,
|
||||
cref
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief A SBO friendly, type-safe container for single values of any type.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Optional alignment requirement.
|
||||
*/
|
||||
template<std::size_t Len, std::size_t Align>
|
||||
class basic_any {
|
||||
using operation = internal::any_operation;
|
||||
using policy = internal::any_policy;
|
||||
using vtable_type = const void *(const operation, const basic_any &, const void *);
|
||||
|
||||
struct storage_type {
|
||||
alignas(Align) std::byte data[Len + !Len];
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
static constexpr bool in_situ = Len && alignof(Type) <= Align && sizeof(Type) <= Len &&std::is_nothrow_move_constructible_v<Type>;
|
||||
|
||||
template<typename Type>
|
||||
static const void *basic_vtable(const operation op, const basic_any &value, const void *other) {
|
||||
static_assert(!std::is_same_v<Type, void> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
|
||||
const Type *element = nullptr;
|
||||
|
||||
if constexpr(in_situ<Type>) {
|
||||
element = value.owner() ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance);
|
||||
} else {
|
||||
element = static_cast<const Type *>(value.instance);
|
||||
}
|
||||
|
||||
switch(op) {
|
||||
case operation::copy:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*element);
|
||||
}
|
||||
break;
|
||||
case operation::move:
|
||||
if constexpr(in_situ<Type>) {
|
||||
if(value.owner()) {
|
||||
return new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(element))};
|
||||
}
|
||||
}
|
||||
|
||||
return (static_cast<basic_any *>(const_cast<void *>(other))->instance = std::exchange(const_cast<basic_any &>(value).instance, nullptr));
|
||||
case operation::transfer:
|
||||
if constexpr(std::is_move_assignable_v<Type>) {
|
||||
*const_cast<Type *>(element) = std::move(*static_cast<Type *>(const_cast<void *>(other)));
|
||||
return other;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case operation::assign:
|
||||
if constexpr(std::is_copy_assignable_v<Type>) {
|
||||
*const_cast<Type *>(element) = *static_cast<const Type *>(other);
|
||||
return other;
|
||||
}
|
||||
break;
|
||||
case operation::destroy:
|
||||
if constexpr(in_situ<Type>) {
|
||||
element->~Type();
|
||||
} else if constexpr(std::is_array_v<Type>) {
|
||||
delete[] element;
|
||||
} else {
|
||||
delete element;
|
||||
}
|
||||
break;
|
||||
case operation::compare:
|
||||
if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
|
||||
return *element == *static_cast<const Type *>(other) ? other : nullptr;
|
||||
} else {
|
||||
return (element == other) ? other : nullptr;
|
||||
}
|
||||
case operation::get:
|
||||
return element;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args>
|
||||
void initialize([[maybe_unused]] Args &&...args) {
|
||||
info = &type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
vtable = basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
|
||||
|
||||
if constexpr(std::is_lvalue_reference_v<Type>) {
|
||||
static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments");
|
||||
mode = std::is_const_v<std::remove_reference_t<Type>> ? policy::cref : policy::ref;
|
||||
instance = (std::addressof(args), ...);
|
||||
} else if constexpr(in_situ<std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
new(&storage) std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...};
|
||||
} else {
|
||||
new(&storage) std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...);
|
||||
}
|
||||
} else {
|
||||
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
instance = new std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...};
|
||||
} else {
|
||||
instance = new std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
basic_any(const basic_any &other, const policy pol) noexcept
|
||||
: instance{other.data()},
|
||||
info{other.info},
|
||||
vtable{other.vtable},
|
||||
mode{pol} {}
|
||||
|
||||
public:
|
||||
/*! @brief Size of the internal storage. */
|
||||
static constexpr auto length = Len;
|
||||
/*! @brief Alignment requirement. */
|
||||
static constexpr auto alignment = Align;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
constexpr basic_any() noexcept
|
||||
: basic_any{std::in_place_type<void>} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a wrapper by directly initializing the new object.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
explicit basic_any(std::in_place_type_t<Type>, Args &&...args)
|
||||
: instance{},
|
||||
info{},
|
||||
vtable{},
|
||||
mode{policy::owner} {
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a wrapper from a given value.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
|
||||
basic_any(Type &&value)
|
||||
: basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
basic_any(const basic_any &other)
|
||||
: basic_any{} {
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::copy, other, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_any(basic_any &&other) noexcept
|
||||
: instance{},
|
||||
info{other.info},
|
||||
vtable{other.vtable},
|
||||
mode{other.mode} {
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::move, other, this);
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Frees the internal storage, whatever it means. */
|
||||
~basic_any() {
|
||||
if(vtable && owner()) {
|
||||
vtable(operation::destroy, *this, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This any object.
|
||||
*/
|
||||
basic_any &operator=(const basic_any &other) {
|
||||
reset();
|
||||
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::copy, other, this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This any object.
|
||||
*/
|
||||
basic_any &operator=(basic_any &&other) noexcept {
|
||||
reset();
|
||||
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::move, other, this);
|
||||
info = other.info;
|
||||
vtable = other.vtable;
|
||||
mode = other.mode;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Value assignment operator.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
* @return This any object.
|
||||
*/
|
||||
template<typename Type>
|
||||
std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>, basic_any &>
|
||||
operator=(Type &&value) {
|
||||
emplace<std::decay_t<Type>>(std::forward<Type>(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the object type if any, `type_id<void>()` otherwise.
|
||||
* @return The object type if any, `type_id<void>()` otherwise.
|
||||
*/
|
||||
[[nodiscard]] const type_info &type() const noexcept {
|
||||
return *info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] const void *data() const noexcept {
|
||||
return vtable ? vtable(operation::get, *this, nullptr) : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @param req Expected type.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] const void *data(const type_info &req) const noexcept {
|
||||
return *info == req ? data() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data() noexcept {
|
||||
return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @param req Expected type.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data(const type_info &req) noexcept {
|
||||
return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the contained object by creating a new instance directly.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
void emplace(Args &&...args) {
|
||||
reset();
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a value to the contained object without replacing it.
|
||||
* @param other The value to assign to the contained object.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool assign(const basic_any &other) {
|
||||
if(vtable && mode != policy::cref && *info == *other.info) {
|
||||
return (vtable(operation::assign, *this, other.data()) != nullptr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! @copydoc assign */
|
||||
bool assign(basic_any &&other) {
|
||||
if(vtable && mode != policy::cref && *info == *other.info) {
|
||||
if(auto *val = other.data(); val) {
|
||||
return (vtable(operation::transfer, *this, val) != nullptr);
|
||||
} else {
|
||||
return (vtable(operation::assign, *this, std::as_const(other).data()) != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! @brief Destroys contained object */
|
||||
void reset() {
|
||||
if(vtable && owner()) {
|
||||
vtable(operation::destroy, *this, nullptr);
|
||||
}
|
||||
|
||||
// unnecessary but it helps to detect nasty bugs
|
||||
ENTT_ASSERT((instance = nullptr) == nullptr, "");
|
||||
info = &type_id<void>();
|
||||
vtable = nullptr;
|
||||
mode = policy::owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns false if a wrapper is empty, true otherwise.
|
||||
* @return False if the wrapper is empty, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] explicit operator bool() const noexcept {
|
||||
return vtable != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if two wrappers differ in their content.
|
||||
* @param other Wrapper with which to compare.
|
||||
* @return False if the two objects differ in their content, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool operator==(const basic_any &other) const noexcept {
|
||||
if(vtable && *info == *other.info) {
|
||||
return (vtable(operation::compare, *this, other.data()) != nullptr);
|
||||
}
|
||||
|
||||
return (!vtable && !other.vtable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if two wrappers differ in their content.
|
||||
* @param other Wrapper with which to compare.
|
||||
* @return True if the two objects differ in their content, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool operator!=(const basic_any &other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Aliasing constructor.
|
||||
* @return A wrapper that shares a reference to an unmanaged object.
|
||||
*/
|
||||
[[nodiscard]] basic_any as_ref() noexcept {
|
||||
return basic_any{*this, (mode == policy::cref ? policy::cref : policy::ref)};
|
||||
}
|
||||
|
||||
/*! @copydoc as_ref */
|
||||
[[nodiscard]] basic_any as_ref() const noexcept {
|
||||
return basic_any{*this, policy::cref};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a wrapper owns its object, false otherwise.
|
||||
* @return True if the wrapper owns its object, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool owner() const noexcept {
|
||||
return (mode == policy::owner);
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
const void *instance;
|
||||
storage_type storage;
|
||||
};
|
||||
const type_info *info;
|
||||
vtable_type *vtable;
|
||||
policy mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Performs type-safe access to the contained object.
|
||||
* @tparam Type Type to which conversion is required.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Alignment requirement.
|
||||
* @param data Target any object.
|
||||
* @return The element converted to the requested type.
|
||||
*/
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type any_cast(const basic_any<Len, Align> &data) noexcept {
|
||||
const auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(*instance);
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type any_cast(basic_any<Len, Align> &data) noexcept {
|
||||
// forces const on non-reference types to make them work also with wrappers for const references
|
||||
auto *const instance = any_cast<std::remove_reference_t<const Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(*instance);
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type any_cast(basic_any<Len, Align> &&data) noexcept {
|
||||
if constexpr(std::is_copy_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
if(auto *const instance = any_cast<std::remove_reference_t<Type>>(&data); instance) {
|
||||
return static_cast<Type>(std::move(*instance));
|
||||
} else {
|
||||
return any_cast<Type>(data);
|
||||
}
|
||||
} else {
|
||||
auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(std::move(*instance));
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
const Type *any_cast(const basic_any<Len, Align> *data) noexcept {
|
||||
const auto &info = type_id<std::remove_cv_t<Type>>();
|
||||
return static_cast<const Type *>(data->data(info));
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type *any_cast(basic_any<Len, Align> *data) noexcept {
|
||||
if constexpr(std::is_const_v<Type>) {
|
||||
// last attempt to make wrappers for const references return their values
|
||||
return any_cast<Type>(&std::as_const(*data));
|
||||
} else {
|
||||
const auto &info = type_id<std::remove_cv_t<Type>>();
|
||||
return static_cast<Type *>(data->data(info));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a wrapper from a given type, passing it all arguments.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Optional alignment requirement.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
* @return A properly initialized wrapper for an object of the given type.
|
||||
*/
|
||||
template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args>
|
||||
basic_any<Len, Align> make_any(Args &&...args) {
|
||||
return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forwards its argument and avoids copies for lvalue references.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Optional alignment requirement.
|
||||
* @tparam Type Type of argument to use to construct the new instance.
|
||||
* @param value Parameter to use to construct the instance.
|
||||
* @return A properly initialized and not necessarily owning wrapper.
|
||||
*/
|
||||
template<std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename Type>
|
||||
basic_any<Len, Align> forward_as_any(Type &&value) {
|
||||
return basic_any<Len, Align>{std::in_place_type<Type &&>, std::forward<Type>(value)};
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,33 +1,30 @@
|
||||
#ifndef ENTT_CORE_ATTRIBUTE_H
|
||||
#define ENTT_CORE_ATTRIBUTE_H
|
||||
|
||||
|
||||
#ifndef ENTT_EXPORT
|
||||
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
|
||||
# define ENTT_EXPORT __declspec(dllexport)
|
||||
# define ENTT_IMPORT __declspec(dllimport)
|
||||
# define ENTT_HIDDEN
|
||||
# elif defined __GNUC__ && __GNUC__ >= 4
|
||||
# define ENTT_EXPORT __attribute__((visibility("default")))
|
||||
# define ENTT_IMPORT __attribute__((visibility("default")))
|
||||
# define ENTT_HIDDEN __attribute__((visibility("hidden")))
|
||||
# else /* Unsupported compiler */
|
||||
# define ENTT_EXPORT
|
||||
# define ENTT_IMPORT
|
||||
# define ENTT_HIDDEN
|
||||
# endif
|
||||
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
|
||||
# define ENTT_EXPORT __declspec(dllexport)
|
||||
# define ENTT_IMPORT __declspec(dllimport)
|
||||
# define ENTT_HIDDEN
|
||||
# elif defined __GNUC__ && __GNUC__ >= 4
|
||||
# define ENTT_EXPORT __attribute__((visibility("default")))
|
||||
# define ENTT_IMPORT __attribute__((visibility("default")))
|
||||
# define ENTT_HIDDEN __attribute__((visibility("hidden")))
|
||||
# else /* Unsupported compiler */
|
||||
# define ENTT_EXPORT
|
||||
# define ENTT_IMPORT
|
||||
# define ENTT_HIDDEN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_API
|
||||
# if defined ENTT_API_EXPORT
|
||||
# define ENTT_API ENTT_EXPORT
|
||||
# elif defined ENTT_API_IMPORT
|
||||
# define ENTT_API ENTT_IMPORT
|
||||
# else /* No API */
|
||||
# define ENTT_API
|
||||
# endif
|
||||
# if defined ENTT_API_EXPORT
|
||||
# define ENTT_API ENTT_EXPORT
|
||||
# elif defined ENTT_API_IMPORT
|
||||
# define ENTT_API ENTT_IMPORT
|
||||
# else /* No API */
|
||||
# define ENTT_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
279
src/entt/core/compressed_pair.hpp
Normal file
279
src/entt/core/compressed_pair.hpp
Normal file
@@ -0,0 +1,279 @@
|
||||
#ifndef ENTT_CORE_COMPRESSED_PAIR_HPP
|
||||
#define ENTT_CORE_COMPRESSED_PAIR_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, std::size_t, typename = void>
|
||||
struct compressed_pair_element {
|
||||
using reference = Type &;
|
||||
using const_reference = const Type &;
|
||||
|
||||
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<Type>>>
|
||||
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<Type>)
|
||||
: value{} {}
|
||||
|
||||
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
|
||||
constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<Type, Arg>)
|
||||
: value{std::forward<Arg>(arg)} {}
|
||||
|
||||
template<typename... Args, std::size_t... Index>
|
||||
constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<Type, Args...>)
|
||||
: value{std::forward<Args>(std::get<Index>(args))...} {}
|
||||
|
||||
[[nodiscard]] constexpr reference get() noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_reference get() const noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
Type value;
|
||||
};
|
||||
|
||||
template<typename Type, std::size_t Tag>
|
||||
struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Type>>>: Type {
|
||||
using reference = Type &;
|
||||
using const_reference = const Type &;
|
||||
using base_type = Type;
|
||||
|
||||
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<base_type>>>
|
||||
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<base_type>)
|
||||
: base_type{} {}
|
||||
|
||||
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
|
||||
constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<base_type, Arg>)
|
||||
: base_type{std::forward<Arg>(arg)} {}
|
||||
|
||||
template<typename... Args, std::size_t... Index>
|
||||
constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<base_type, Args...>)
|
||||
: base_type{std::forward<Args>(std::get<Index>(args))...} {}
|
||||
|
||||
[[nodiscard]] constexpr reference get() noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_reference get() const noexcept {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief A compressed pair.
|
||||
*
|
||||
* A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to
|
||||
* reduce its final size to a minimum.
|
||||
*
|
||||
* @tparam First The type of the first element that the pair stores.
|
||||
* @tparam Second The type of the second element that the pair stores.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
class compressed_pair final
|
||||
: internal::compressed_pair_element<First, 0u>,
|
||||
internal::compressed_pair_element<Second, 1u> {
|
||||
using first_base = internal::compressed_pair_element<First, 0u>;
|
||||
using second_base = internal::compressed_pair_element<Second, 1u>;
|
||||
|
||||
public:
|
||||
/*! @brief The type of the first element that the pair stores. */
|
||||
using first_type = First;
|
||||
/*! @brief The type of the second element that the pair stores. */
|
||||
using second_type = Second;
|
||||
|
||||
/**
|
||||
* @brief Default constructor, conditionally enabled.
|
||||
*
|
||||
* This constructor is only available when the types that the pair stores
|
||||
* are both at least default constructible.
|
||||
*
|
||||
* @tparam Dummy Dummy template parameter used for internal purposes.
|
||||
*/
|
||||
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>>
|
||||
constexpr compressed_pair() noexcept(std::is_nothrow_default_constructible_v<first_base> &&std::is_nothrow_default_constructible_v<second_base>)
|
||||
: first_base{},
|
||||
second_base{} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
constexpr compressed_pair(const compressed_pair &other) noexcept(std::is_nothrow_copy_constructible_v<first_base> &&std::is_nothrow_copy_constructible_v<second_base>) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
constexpr compressed_pair(compressed_pair &&other) noexcept(std::is_nothrow_move_constructible_v<first_base> &&std::is_nothrow_move_constructible_v<second_base>) = default;
|
||||
|
||||
/**
|
||||
* @brief Constructs a pair from its values.
|
||||
* @tparam Arg Type of value to use to initialize the first element.
|
||||
* @tparam Other Type of value to use to initialize the second element.
|
||||
* @param arg Value to use to initialize the first element.
|
||||
* @param other Value to use to initialize the second element.
|
||||
*/
|
||||
template<typename Arg, typename Other>
|
||||
constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(std::is_nothrow_constructible_v<first_base, Arg> &&std::is_nothrow_constructible_v<second_base, Other>)
|
||||
: first_base{std::forward<Arg>(arg)},
|
||||
second_base{std::forward<Other>(other)} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a pair by forwarding the arguments to its parts.
|
||||
* @tparam Args Types of arguments to use to initialize the first element.
|
||||
* @tparam Other Types of arguments to use to initialize the second element.
|
||||
* @param args Arguments to use to initialize the first element.
|
||||
* @param other Arguments to use to initialize the second element.
|
||||
*/
|
||||
template<typename... Args, typename... Other>
|
||||
constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other) noexcept(std::is_nothrow_constructible_v<first_base, Args...> &&std::is_nothrow_constructible_v<second_base, Other...>)
|
||||
: first_base{std::move(args), std::index_sequence_for<Args...>{}},
|
||||
second_base{std::move(other), std::index_sequence_for<Other...>{}} {}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This compressed pair object.
|
||||
*/
|
||||
constexpr compressed_pair &operator=(const compressed_pair &other) noexcept(std::is_nothrow_copy_assignable_v<first_base> &&std::is_nothrow_copy_assignable_v<second_base>) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This compressed pair object.
|
||||
*/
|
||||
constexpr compressed_pair &operator=(compressed_pair &&other) noexcept(std::is_nothrow_move_assignable_v<first_base> &&std::is_nothrow_move_assignable_v<second_base>) = default;
|
||||
|
||||
/**
|
||||
* @brief Returns the first element that a pair stores.
|
||||
* @return The first element that a pair stores.
|
||||
*/
|
||||
[[nodiscard]] constexpr first_type &first() noexcept {
|
||||
return static_cast<first_base &>(*this).get();
|
||||
}
|
||||
|
||||
/*! @copydoc first */
|
||||
[[nodiscard]] constexpr const first_type &first() const noexcept {
|
||||
return static_cast<const first_base &>(*this).get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the second element that a pair stores.
|
||||
* @return The second element that a pair stores.
|
||||
*/
|
||||
[[nodiscard]] constexpr second_type &second() noexcept {
|
||||
return static_cast<second_base &>(*this).get();
|
||||
}
|
||||
|
||||
/*! @copydoc second */
|
||||
[[nodiscard]] constexpr const second_type &second() const noexcept {
|
||||
return static_cast<const second_base &>(*this).get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swaps two compressed pair objects.
|
||||
* @param other The compressed pair to swap with.
|
||||
*/
|
||||
constexpr void swap(compressed_pair &other) noexcept(std::is_nothrow_swappable_v<first_type> &&std::is_nothrow_swappable_v<second_type>) {
|
||||
using std::swap;
|
||||
swap(first(), other.first());
|
||||
swap(second(), other.second());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts an element from the compressed pair.
|
||||
* @tparam Index An integer value that is either 0 or 1.
|
||||
* @return Returns a reference to the first element if `Index` is 0 and a
|
||||
* reference to the second element if `Index` is 1.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
constexpr decltype(auto) get() noexcept {
|
||||
if constexpr(Index == 0u) {
|
||||
return first();
|
||||
} else {
|
||||
static_assert(Index == 1u, "Index out of bounds");
|
||||
return second();
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
template<std::size_t Index>
|
||||
constexpr decltype(auto) get() const noexcept {
|
||||
if constexpr(Index == 0u) {
|
||||
return first();
|
||||
} else {
|
||||
static_assert(Index == 1u, "Index out of bounds");
|
||||
return second();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Type Type of value to use to initialize the first element.
|
||||
* @tparam Other Type of value to use to initialize the second element.
|
||||
*/
|
||||
template<typename Type, typename Other>
|
||||
compressed_pair(Type &&, Other &&) -> compressed_pair<std::decay_t<Type>, std::decay_t<Other>>;
|
||||
|
||||
/**
|
||||
* @brief Swaps two compressed pair objects.
|
||||
* @tparam First The type of the first element that the pairs store.
|
||||
* @tparam Second The type of the second element that the pairs store.
|
||||
* @param lhs A valid compressed pair object.
|
||||
* @param rhs A valid compressed pair object.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
inline constexpr void swap(compressed_pair<First, Second> &lhs, compressed_pair<First, Second> &rhs) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
// disable structured binding support for clang 6, it messes when specializing tuple_size
|
||||
#if !defined __clang_major__ || __clang_major__ > 6
|
||||
namespace std {
|
||||
|
||||
/**
|
||||
* @brief `std::tuple_size` specialization for `compressed_pair`s.
|
||||
* @tparam First The type of the first element that the pair stores.
|
||||
* @tparam Second The type of the second element that the pair stores.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_t, 2u> {};
|
||||
|
||||
/**
|
||||
* @brief `std::tuple_element` specialization for `compressed_pair`s.
|
||||
* @tparam Index The index of the type to return.
|
||||
* @tparam First The type of the first element that the pair stores.
|
||||
* @tparam Second The type of the second element that the pair stores.
|
||||
*/
|
||||
template<size_t Index, typename First, typename Second>
|
||||
struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {
|
||||
static_assert(Index < 2u, "Index out of bounds");
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
#endif
|
||||
|
||||
#endif
|
||||
97
src/entt/core/enum.hpp
Normal file
97
src/entt/core/enum.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef ENTT_CORE_ENUM_HPP
|
||||
#define ENTT_CORE_ENUM_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Enable bitmask support for enum classes.
|
||||
* @tparam Type The enum type for which to enable bitmask support.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct enum_as_bitmask: std::false_type {};
|
||||
|
||||
/*! @copydoc enum_as_bitmask */
|
||||
template<typename Type>
|
||||
struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>: std::is_enum<Type> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The enum class type for which to enable bitmask support.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
/**
|
||||
* @brief Operator available for enums for which bitmask support is enabled.
|
||||
* @tparam Type Enum class type.
|
||||
* @param lhs The first value to use.
|
||||
* @param rhs The second value to use.
|
||||
* @return The result of invoking the operator on the underlying types of the
|
||||
* two values provided.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator|(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator&(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator^(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator available for enums for which bitmask support is enabled.
|
||||
* @tparam Type Enum class type.
|
||||
* @param value The value to use.
|
||||
* @return The result of invoking the operator on the underlying types of the
|
||||
* value provided.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator~(const Type value) noexcept {
|
||||
return static_cast<Type>(~static_cast<std::underlying_type_t<Type>>(value));
|
||||
}
|
||||
|
||||
/*! @copydoc operator~ */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, bool>
|
||||
operator!(const Type value) noexcept {
|
||||
return !static_cast<std::underlying_type_t<Type>>(value);
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
|
||||
operator|=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs | rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
|
||||
operator&=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs & rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
|
||||
operator^=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs ^ rhs));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,13 +1,11 @@
|
||||
#ifndef ENTT_CORE_FAMILY_HPP
|
||||
#define ENTT_CORE_FAMILY_HPP
|
||||
|
||||
|
||||
#include "../config/config.h"
|
||||
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dynamic identifier generator.
|
||||
*
|
||||
@@ -17,20 +15,18 @@ namespace entt {
|
||||
*/
|
||||
template<typename...>
|
||||
class family {
|
||||
inline static ENTT_MAYBE_ATOMIC(ENTT_ID_TYPE) identifier{};
|
||||
inline static ENTT_MAYBE_ATOMIC(id_type) identifier{};
|
||||
|
||||
public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using family_type = ENTT_ID_TYPE;
|
||||
using value_type = id_type;
|
||||
|
||||
/*! @brief Statically generated unique identifier for the given type. */
|
||||
template<typename... Type>
|
||||
// at the time I'm writing, clang crashes during compilation if auto is used instead of family_type
|
||||
inline static const family_type type = identifier++;
|
||||
inline static const value_type value = identifier++;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
20
src/entt/core/fwd.hpp
Normal file
20
src/entt/core/fwd.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef ENTT_CORE_FWD_HPP
|
||||
#define ENTT_CORE_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(double[2])>
|
||||
class basic_any;
|
||||
|
||||
/*! @brief Alias declaration for type identifiers. */
|
||||
using id_type = ENTT_ID_TYPE;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using any = basic_any<>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,28 +1,22 @@
|
||||
#ifndef ENTT_CORE_HASHED_STRING_HPP
|
||||
#define ENTT_CORE_HASHED_STRING_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "../config/config.h"
|
||||
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename>
|
||||
struct fnv1a_traits;
|
||||
|
||||
|
||||
template<>
|
||||
struct fnv1a_traits<std::uint32_t> {
|
||||
using type = std::uint32_t;
|
||||
@@ -30,7 +24,6 @@ struct fnv1a_traits<std::uint32_t> {
|
||||
static constexpr std::uint32_t prime = 16777619;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct fnv1a_traits<std::uint64_t> {
|
||||
using type = std::uint64_t;
|
||||
@@ -38,72 +31,101 @@ struct fnv1a_traits<std::uint64_t> {
|
||||
static constexpr std::uint64_t prime = 1099511628211ull;
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
struct basic_hashed_string {
|
||||
using value_type = Char;
|
||||
using size_type = std::size_t;
|
||||
using hash_type = id_type;
|
||||
|
||||
}
|
||||
const value_type *repr;
|
||||
size_type length;
|
||||
hash_type hash;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond TURN_OFF_DOXYGEN
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Zero overhead unique identifier.
|
||||
*
|
||||
* A hashed string is a compile-time tool that allows users to use
|
||||
* human-readable identifers in the codebase while using their numeric
|
||||
* human-readable identifiers in the codebase while using their numeric
|
||||
* counterparts at runtime.<br/>
|
||||
* Because of that, a hashed string can also be used in constant expressions if
|
||||
* required.
|
||||
*
|
||||
* @warning
|
||||
* This class doesn't take ownership of user-supplied strings nor does it make a
|
||||
* copy of them.
|
||||
*
|
||||
* @tparam Char Character type.
|
||||
*/
|
||||
template<typename Char>
|
||||
class basic_hashed_string {
|
||||
using traits_type = internal::fnv1a_traits<ENTT_ID_TYPE>;
|
||||
class basic_hashed_string: internal::basic_hashed_string<Char> {
|
||||
using base_type = internal::basic_hashed_string<Char>;
|
||||
using hs_traits = internal::fnv1a_traits<id_type>;
|
||||
|
||||
struct const_wrapper {
|
||||
// non-explicit constructor on purpose
|
||||
constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {}
|
||||
const Char *str;
|
||||
constexpr const_wrapper(const Char *str) noexcept
|
||||
: repr{str} {}
|
||||
|
||||
const Char *repr;
|
||||
};
|
||||
|
||||
// Fowler–Noll–Vo hash function v. 1a - the good
|
||||
static constexpr ENTT_ID_TYPE helper(const Char *curr) ENTT_NOEXCEPT {
|
||||
auto value = traits_type::offset;
|
||||
[[nodiscard]] static constexpr auto helper(const Char *str) noexcept {
|
||||
base_type base{str, 0u, hs_traits::offset};
|
||||
|
||||
while(*curr != 0) {
|
||||
value = (value ^ static_cast<traits_type::type>(*(curr++))) * traits_type::prime;
|
||||
for(; str[base.length]; ++base.length) {
|
||||
base.hash = (base.hash ^ static_cast<hs_traits::type>(str[base.length])) * hs_traits::prime;
|
||||
}
|
||||
|
||||
return value;
|
||||
return base;
|
||||
}
|
||||
|
||||
// Fowler–Noll–Vo hash function v. 1a - the good
|
||||
[[nodiscard]] static constexpr auto helper(const Char *str, const std::size_t len) noexcept {
|
||||
base_type base{str, len, hs_traits::offset};
|
||||
|
||||
for(size_type pos{}; pos < len; ++pos) {
|
||||
base.hash = (base.hash ^ static_cast<hs_traits::type>(str[pos])) * hs_traits::prime;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Character type. */
|
||||
using value_type = Char;
|
||||
using value_type = typename base_type::value_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using hash_type = ENTT_ID_TYPE;
|
||||
using size_type = typename base_type::size_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using hash_type = typename base_type::hash_type;
|
||||
|
||||
/**
|
||||
* @brief Returns directly the numeric representation of a string view.
|
||||
* @param str Human-readable identifier.
|
||||
* @param len Length of the string to hash.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
[[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept {
|
||||
return basic_hashed_string{str, len};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns directly the numeric representation of a string.
|
||||
*
|
||||
* Forcing template resolution avoids implicit conversions. An
|
||||
* human-readable identifier can be anything but a plain, old bunch of
|
||||
* characters.<br/>
|
||||
* Example of use:
|
||||
* @code{.cpp}
|
||||
* const auto value = basic_hashed_string<char>::to_value("my.png");
|
||||
* @endcode
|
||||
*
|
||||
* @tparam N Number of characters of the identifier.
|
||||
* @param str Human-readable identifer.
|
||||
* @param str Human-readable identifier.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT {
|
||||
return helper(str);
|
||||
[[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) noexcept {
|
||||
return basic_hashed_string{str};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,109 +133,98 @@ public:
|
||||
* @param wrapper Helps achieving the purpose by relying on overloading.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT {
|
||||
return helper(wrapper.str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns directly the numeric representation of a string view.
|
||||
* @param str Human-readable identifer.
|
||||
* @param size Length of the string to hash.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
static hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
|
||||
ENTT_ID_TYPE partial{traits_type::offset};
|
||||
while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
|
||||
return partial;
|
||||
[[nodiscard]] static constexpr hash_type value(const_wrapper wrapper) noexcept {
|
||||
return basic_hashed_string{wrapper};
|
||||
}
|
||||
|
||||
/*! @brief Constructs an empty hashed string. */
|
||||
constexpr basic_hashed_string() ENTT_NOEXCEPT
|
||||
: str{nullptr}, hash{}
|
||||
{}
|
||||
constexpr basic_hashed_string() noexcept
|
||||
: base_type{} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a hashed string from a string view.
|
||||
* @param str Human-readable identifier.
|
||||
* @param len Length of the string to hash.
|
||||
*/
|
||||
constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept
|
||||
: base_type{helper(str, len)} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a hashed string from an array of const characters.
|
||||
*
|
||||
* Forcing template resolution avoids implicit conversions. An
|
||||
* human-readable identifier can be anything but a plain, old bunch of
|
||||
* characters.<br/>
|
||||
* Example of use:
|
||||
* @code{.cpp}
|
||||
* basic_hashed_string<char> hs{"my.png"};
|
||||
* @endcode
|
||||
*
|
||||
* @tparam N Number of characters of the identifier.
|
||||
* @param curr Human-readable identifer.
|
||||
* @param str Human-readable identifier.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT
|
||||
: str{curr}, hash{helper(curr)}
|
||||
{}
|
||||
constexpr basic_hashed_string(const value_type (&str)[N]) noexcept
|
||||
: base_type{helper(str)} {}
|
||||
|
||||
/**
|
||||
* @brief Explicit constructor on purpose to avoid constructing a hashed
|
||||
* string directly from a `const value_type *`.
|
||||
*
|
||||
* @warning
|
||||
* The lifetime of the string is not extended nor is it copied.
|
||||
*
|
||||
* @param wrapper Helps achieving the purpose by relying on overloading.
|
||||
*/
|
||||
explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
|
||||
: str{wrapper.str}, hash{helper(wrapper.str)}
|
||||
{}
|
||||
explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept
|
||||
: base_type{helper(wrapper.repr)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns the size a hashed string.
|
||||
* @return The size of the hashed string.
|
||||
*/
|
||||
[[nodiscard]] constexpr size_type size() const noexcept {
|
||||
return base_type::length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the human-readable representation of a hashed string.
|
||||
* @return The string used to initialize the instance.
|
||||
* @return The string used to initialize the hashed string.
|
||||
*/
|
||||
constexpr const value_type * data() const ENTT_NOEXCEPT {
|
||||
return str;
|
||||
[[nodiscard]] constexpr const value_type *data() const noexcept {
|
||||
return base_type::repr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the numeric representation of a hashed string.
|
||||
* @return The numeric representation of the instance.
|
||||
* @return The numeric representation of the hashed string.
|
||||
*/
|
||||
constexpr hash_type value() const ENTT_NOEXCEPT {
|
||||
return hash;
|
||||
[[nodiscard]] constexpr hash_type value() const noexcept {
|
||||
return base_type::hash;
|
||||
}
|
||||
|
||||
/*! @copydoc data */
|
||||
constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); }
|
||||
[[nodiscard]] constexpr operator const value_type *() const noexcept {
|
||||
return data();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the numeric representation of a hashed string.
|
||||
* @return The numeric representation of the instance.
|
||||
* @return The numeric representation of the hashed string.
|
||||
*/
|
||||
constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); }
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @param other Hashed string with which to compare.
|
||||
* @return True if the two hashed strings are identical, false otherwise.
|
||||
*/
|
||||
constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT {
|
||||
return hash == other.hash;
|
||||
[[nodiscard]] constexpr operator hash_type() const noexcept {
|
||||
return value();
|
||||
}
|
||||
|
||||
private:
|
||||
const value_type *str;
|
||||
hash_type hash;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
*
|
||||
* It allows to deduce the character type of the hashed string directly from a
|
||||
* human-readable identifer provided to the constructor.
|
||||
*
|
||||
* @tparam Char Character type.
|
||||
* @param str Human-readable identifier.
|
||||
* @param len Length of the string to hash.
|
||||
*/
|
||||
template<typename Char>
|
||||
basic_hashed_string(const Char *str, const std::size_t len) -> basic_hashed_string<Char>;
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Char Character type.
|
||||
* @tparam N Number of characters of the identifier.
|
||||
* @param str Human-readable identifer.
|
||||
* @param str Human-readable identifier.
|
||||
*/
|
||||
template<typename Char, std::size_t N>
|
||||
basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT
|
||||
-> basic_hashed_string<Char>;
|
||||
|
||||
basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>;
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
@@ -223,40 +234,101 @@ basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT
|
||||
* @return True if the two hashed strings are identical, false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
|
||||
[[nodiscard]] constexpr bool operator==(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return lhs.value() == rhs.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the two hashed strings differ, false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is less than the second, false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator<(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return lhs.value() < rhs.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is less than or equal to the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator<=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is greater than the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator>(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is greater than or equal to the second,
|
||||
* false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator>=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
/*! @brief Aliases for common character types. */
|
||||
using hashed_string = basic_hashed_string<char>;
|
||||
|
||||
|
||||
/*! @brief Aliases for common character types. */
|
||||
using hashed_wstring = basic_hashed_string<wchar_t>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
/**
|
||||
* @brief User defined literal for hashed strings.
|
||||
* @param str The literal without its suffix.
|
||||
* @return A properly initialized hashed string.
|
||||
*/
|
||||
constexpr entt::hashed_string operator"" ENTT_HS_SUFFIX(const char *str, std::size_t) ENTT_NOEXCEPT {
|
||||
return entt::hashed_string{str};
|
||||
[[nodiscard]] constexpr hashed_string operator"" _hs(const char *str, std::size_t) noexcept {
|
||||
return hashed_string{str};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief User defined literal for hashed wstrings.
|
||||
* @param str The literal without its suffix.
|
||||
* @return A properly initialized hashed wstring.
|
||||
*/
|
||||
constexpr entt::hashed_wstring operator"" ENTT_HWS_SUFFIX(const wchar_t *str, std::size_t) ENTT_NOEXCEPT {
|
||||
return entt::hashed_wstring{str};
|
||||
[[nodiscard]] constexpr hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) noexcept {
|
||||
return hashed_wstring{str};
|
||||
}
|
||||
|
||||
} // namespace literals
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,65 +1,35 @@
|
||||
#ifndef ENTT_CORE_IDENT_HPP
|
||||
#define ENTT_CORE_IDENT_HPP
|
||||
|
||||
|
||||
#include <tuple>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
|
||||
#include <utility>
|
||||
#include "fwd.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Types identifiers.
|
||||
*
|
||||
* Variable template used to generate identifiers at compile-time for the given
|
||||
* types. Use the `get` member function to know what's the identifier associated
|
||||
* to the specific type.
|
||||
*
|
||||
* @note
|
||||
* Identifiers are constant expression and can be used in any context where such
|
||||
* an expression is required. As an example:
|
||||
* @code{.cpp}
|
||||
* using id = entt::identifier<a_type, another_type>;
|
||||
*
|
||||
* switch(a_type_identifier) {
|
||||
* case id::type<a_type>:
|
||||
* // ...
|
||||
* break;
|
||||
* case id::type<another_type>:
|
||||
* // ...
|
||||
* break;
|
||||
* default:
|
||||
* // ...
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @tparam Types List of types for which to generate identifiers.
|
||||
* @brief Type integral identifiers.
|
||||
* @tparam Type List of types for which to generate identifiers.
|
||||
*/
|
||||
template<typename... Types>
|
||||
class identifier {
|
||||
using tuple_type = std::tuple<std::decay_t<Types>...>;
|
||||
|
||||
template<typename Type, std::size_t... Indexes>
|
||||
static constexpr ENTT_ID_TYPE get(std::index_sequence<Indexes...>) {
|
||||
static_assert(std::disjunction_v<std::is_same<Type, Types>...>);
|
||||
return (0 + ... + (std::is_same_v<Type, std::tuple_element_t<Indexes, tuple_type>> ? ENTT_ID_TYPE(Indexes) : ENTT_ID_TYPE{}));
|
||||
template<typename... Type>
|
||||
class ident {
|
||||
template<typename Curr, std::size_t... Index>
|
||||
[[nodiscard]] static constexpr id_type get(std::index_sequence<Index...>) noexcept {
|
||||
static_assert((std::is_same_v<Curr, Type> || ...), "Invalid type");
|
||||
return (0 + ... + (std::is_same_v<Curr, type_list_element_t<Index, type_list<std::decay_t<Type>...>>> ? id_type{Index} : id_type{}));
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using identifier_type = ENTT_ID_TYPE;
|
||||
using value_type = id_type;
|
||||
|
||||
/*! @brief Statically generated unique identifier for the given type. */
|
||||
template<typename Type>
|
||||
static constexpr identifier_type type = get<std::decay_t<Type>>(std::index_sequence_for<Types...>{});
|
||||
template<typename Curr>
|
||||
static constexpr value_type value = get<std::decay_t<Curr>>(std::index_sequence_for<Type...>{});
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
197
src/entt/core/iterator.hpp
Normal file
197
src/entt/core/iterator.hpp
Normal file
@@ -0,0 +1,197 @@
|
||||
#ifndef ENTT_CORE_ITERATOR_HPP
|
||||
#define ENTT_CORE_ITERATOR_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Helper type to use as pointer with input iterators.
|
||||
* @tparam Type of wrapped value.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct input_iterator_pointer final {
|
||||
/*! @brief Value type. */
|
||||
using value_type = Type;
|
||||
/*! @brief Pointer type. */
|
||||
using pointer = Type *;
|
||||
/*! @brief Reference type. */
|
||||
using reference = Type &;
|
||||
|
||||
/**
|
||||
* @brief Constructs a proxy object by move.
|
||||
* @param val Value to use to initialize the proxy object.
|
||||
*/
|
||||
constexpr input_iterator_pointer(value_type &&val) noexcept(std::is_nothrow_move_constructible_v<value_type>)
|
||||
: value{std::move(val)} {}
|
||||
|
||||
/**
|
||||
* @brief Access operator for accessing wrapped values.
|
||||
* @return A pointer to the wrapped value.
|
||||
*/
|
||||
[[nodiscard]] constexpr pointer operator->() noexcept {
|
||||
return std::addressof(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dereference operator for accessing wrapped values.
|
||||
* @return A reference to the wrapped value.
|
||||
*/
|
||||
[[nodiscard]] constexpr reference operator*() noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
Type value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Plain iota iterator (waiting for C++20).
|
||||
* @tparam Type Value type.
|
||||
*/
|
||||
template<typename Type>
|
||||
class iota_iterator final {
|
||||
static_assert(std::is_integral_v<Type>, "Not an integral type");
|
||||
|
||||
public:
|
||||
/*! @brief Value type, likely an integral one. */
|
||||
using value_type = Type;
|
||||
/*! @brief Invalid pointer type. */
|
||||
using pointer = void;
|
||||
/*! @brief Non-reference type, same as value type. */
|
||||
using reference = value_type;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
/*! @brief Iterator category. */
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
constexpr iota_iterator() noexcept
|
||||
: current{} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an iota iterator from a given value.
|
||||
* @param init The initial value assigned to the iota iterator.
|
||||
*/
|
||||
constexpr iota_iterator(const value_type init) noexcept
|
||||
: current{init} {}
|
||||
|
||||
/**
|
||||
* @brief Pre-increment operator.
|
||||
* @return This iota iterator.
|
||||
*/
|
||||
constexpr iota_iterator &operator++() noexcept {
|
||||
return ++current, *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Post-increment operator.
|
||||
* @return This iota iterator.
|
||||
*/
|
||||
constexpr iota_iterator operator++(int) noexcept {
|
||||
iota_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dereference operator.
|
||||
* @return The underlying value.
|
||||
*/
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return current;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type current;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Comparison operator.
|
||||
* @tparam Type Value type of the iota iterator.
|
||||
* @param lhs A properly initialized iota iterator.
|
||||
* @param rhs A properly initialized iota iterator.
|
||||
* @return True if the two iterators are identical, false otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr bool operator==(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
|
||||
return *lhs == *rhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Comparison operator.
|
||||
* @tparam Type Value type of the iota iterator.
|
||||
* @param lhs A properly initialized iota iterator.
|
||||
* @param rhs A properly initialized iota iterator.
|
||||
* @return True if the two iterators differ, false otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr bool operator!=(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility class to create an iterable object from a pair of iterators.
|
||||
* @tparam It Type of iterator.
|
||||
* @tparam Sentinel Type of sentinel.
|
||||
*/
|
||||
template<typename It, typename Sentinel = It>
|
||||
struct iterable_adaptor final {
|
||||
/*! @brief Value type. */
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
/*! @brief Iterator type. */
|
||||
using iterator = It;
|
||||
/*! @brief Sentinel type. */
|
||||
using sentinel = Sentinel;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
constexpr iterable_adaptor() noexcept(std::is_nothrow_default_constructible_v<iterator> &&std::is_nothrow_default_constructible_v<sentinel>)
|
||||
: first{},
|
||||
last{} {}
|
||||
|
||||
/**
|
||||
* @brief Creates an iterable object from a pair of iterators.
|
||||
* @param from Begin iterator.
|
||||
* @param to End iterator.
|
||||
*/
|
||||
constexpr iterable_adaptor(iterator from, sentinel to) noexcept(std::is_nothrow_move_constructible_v<iterator> &&std::is_nothrow_move_constructible_v<sentinel>)
|
||||
: first{std::move(from)},
|
||||
last{std::move(to)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning.
|
||||
* @return An iterator to the first element of the range.
|
||||
*/
|
||||
[[nodiscard]] constexpr iterator begin() const noexcept {
|
||||
return first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end.
|
||||
* @return An iterator to the element following the last element of the
|
||||
* range.
|
||||
*/
|
||||
[[nodiscard]] constexpr sentinel end() const noexcept {
|
||||
return last;
|
||||
}
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] constexpr iterator cbegin() const noexcept {
|
||||
return begin();
|
||||
}
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] constexpr sentinel cend() const noexcept {
|
||||
return end();
|
||||
}
|
||||
|
||||
private:
|
||||
It first;
|
||||
Sentinel last;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
289
src/entt/core/memory.hpp
Normal file
289
src/entt/core/memory.hpp
Normal file
@@ -0,0 +1,289 @@
|
||||
#ifndef ENTT_CORE_MEMORY_HPP
|
||||
#define ENTT_CORE_MEMORY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Checks whether a value is a power of two or not.
|
||||
* @param value A value that may or may not be a power of two.
|
||||
* @return True if the value is a power of two, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr bool is_power_of_two(const std::size_t value) noexcept {
|
||||
return value && ((value & (value - 1)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the smallest power of two greater than or equal to a value.
|
||||
* @param value The value to use.
|
||||
* @return The smallest power of two greater than or equal to the given value.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr std::size_t next_power_of_two(const std::size_t value) noexcept {
|
||||
ENTT_ASSERT_CONSTEXPR(value < (std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)), "Numeric limits exceeded");
|
||||
std::size_t curr = value - (value != 0u);
|
||||
|
||||
for(int next = 1; next < std::numeric_limits<std::size_t>::digits; next = next * 2) {
|
||||
curr |= curr >> next;
|
||||
}
|
||||
|
||||
return ++curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fast module utility function (powers of two only).
|
||||
* @param value A value for which to calculate the modulus.
|
||||
* @param mod _Modulus_, it must be a power of two.
|
||||
* @return The common remainder.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) noexcept {
|
||||
ENTT_ASSERT_CONSTEXPR(is_power_of_two(mod), "Value must be a power of two");
|
||||
return value & (mod - 1u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
|
||||
* @tparam Type Pointer type.
|
||||
* @param ptr Fancy or raw pointer.
|
||||
* @return A raw pointer that represents the address of the original pointer.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto to_address(Type &&ptr) noexcept {
|
||||
if constexpr(std::is_pointer_v<std::decay_t<Type>>) {
|
||||
return ptr;
|
||||
} else {
|
||||
return to_address(std::forward<Type>(ptr).operator->());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to design allocation-aware containers.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param lhs A valid allocator.
|
||||
* @param rhs Another valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
|
||||
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
|
||||
lhs = rhs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to design allocation-aware containers.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param lhs A valid allocator.
|
||||
* @param rhs Another valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
|
||||
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
|
||||
lhs = std::move(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to design allocation-aware containers.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param lhs A valid allocator.
|
||||
* @param rhs Another valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
|
||||
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
|
||||
using std::swap;
|
||||
swap(lhs, rhs);
|
||||
} else {
|
||||
ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deleter for allocator-aware unique pointers (waiting for C++20).
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
struct allocation_deleter: private Allocator {
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Pointer type. */
|
||||
using pointer = typename std::allocator_traits<Allocator>::pointer;
|
||||
|
||||
/**
|
||||
* @brief Inherited constructors.
|
||||
* @param alloc The allocator to use.
|
||||
*/
|
||||
constexpr allocation_deleter(const allocator_type &alloc) noexcept(std::is_nothrow_copy_constructible_v<allocator_type>)
|
||||
: Allocator{alloc} {}
|
||||
|
||||
/**
|
||||
* @brief Destroys the pointed object and deallocates its memory.
|
||||
* @param ptr A valid pointer to an object of the given type.
|
||||
*/
|
||||
constexpr void operator()(pointer ptr) noexcept(std::is_nothrow_destructible_v<typename allocator_type::value_type>) {
|
||||
using alloc_traits = typename std::allocator_traits<Allocator>;
|
||||
alloc_traits::destroy(*this, to_address(ptr));
|
||||
alloc_traits::deallocate(*this, ptr, 1u);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Allows `std::unique_ptr` to use allocators (waiting for C++20).
|
||||
* @tparam Type Type of object to allocate for and to construct.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param allocator The allocator to use.
|
||||
* @param args Parameters to use to construct the object.
|
||||
* @return A properly initialized unique pointer with a custom deleter.
|
||||
*/
|
||||
template<typename Type, typename Allocator, typename... Args>
|
||||
ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) {
|
||||
static_assert(!std::is_array_v<Type>, "Array types are not supported");
|
||||
|
||||
using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Type>;
|
||||
using allocator_type = typename alloc_traits::allocator_type;
|
||||
|
||||
allocator_type alloc{allocator};
|
||||
auto ptr = alloc_traits::allocate(alloc, 1u);
|
||||
|
||||
ENTT_TRY {
|
||||
alloc_traits::construct(alloc, to_address(ptr), std::forward<Args>(args)...);
|
||||
}
|
||||
ENTT_CATCH {
|
||||
alloc_traits::deallocate(alloc, ptr, 1u);
|
||||
ENTT_THROW;
|
||||
}
|
||||
|
||||
return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
|
||||
}
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type>
|
||||
struct uses_allocator_construction {
|
||||
template<typename Allocator, typename... Params>
|
||||
static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept {
|
||||
if constexpr(!std::uses_allocator_v<Type, Allocator> && std::is_constructible_v<Type, Params...>) {
|
||||
return std::forward_as_tuple(std::forward<Params>(params)...);
|
||||
} else {
|
||||
static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request");
|
||||
|
||||
if constexpr(std::is_constructible_v<Type, std::allocator_arg_t, const Allocator &, Params...>) {
|
||||
return std::tuple<std::allocator_arg_t, const Allocator &, Params &&...>{std::allocator_arg, allocator, std::forward<Params>(params)...};
|
||||
} else {
|
||||
static_assert(std::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
|
||||
return std::forward_as_tuple(std::forward<Params>(params)..., allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type, typename Other>
|
||||
struct uses_allocator_construction<std::pair<Type, Other>> {
|
||||
using type = std::pair<Type, Other>;
|
||||
|
||||
template<typename Allocator, typename First, typename Second>
|
||||
static constexpr auto args(const Allocator &allocator, std::piecewise_construct_t, First &&first, Second &&second) noexcept {
|
||||
return std::make_tuple(
|
||||
std::piecewise_construct,
|
||||
std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<First>(first)),
|
||||
std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<Second>(second)));
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
static constexpr auto args(const Allocator &allocator) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
|
||||
}
|
||||
|
||||
template<typename Allocator, typename First, typename Second>
|
||||
static constexpr auto args(const Allocator &allocator, First &&first, Second &&second) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::forward<First>(first)), std::forward_as_tuple(std::forward<Second>(second)));
|
||||
}
|
||||
|
||||
template<typename Allocator, typename First, typename Second>
|
||||
static constexpr auto args(const Allocator &allocator, const std::pair<First, Second> &value) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(value.first), std::forward_as_tuple(value.second));
|
||||
}
|
||||
|
||||
template<typename Allocator, typename First, typename Second>
|
||||
static constexpr auto args(const Allocator &allocator, std::pair<First, Second> &&value) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::move(value.first)), std::forward_as_tuple(std::move(value.second)));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Uses-allocator construction utility (waiting for C++20).
|
||||
*
|
||||
* Primarily intended for internal use. Prepares the argument list needed to
|
||||
* create an object of a given type by means of uses-allocator construction.
|
||||
*
|
||||
* @tparam Type Type to return arguments for.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param allocator The allocator to use.
|
||||
* @param args Parameters to use to construct the object.
|
||||
* @return The arguments needed to create an object of the given type.
|
||||
*/
|
||||
template<typename Type, typename Allocator, typename... Args>
|
||||
constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) noexcept {
|
||||
return internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Uses-allocator construction utility (waiting for C++20).
|
||||
*
|
||||
* Primarily intended for internal use. Creates an object of a given type by
|
||||
* means of uses-allocator construction.
|
||||
*
|
||||
* @tparam Type Type of object to create.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param allocator The allocator to use.
|
||||
* @param args Parameters to use to construct the object.
|
||||
* @return A newly created object of the given type.
|
||||
*/
|
||||
template<typename Type, typename Allocator, typename... Args>
|
||||
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args) {
|
||||
return std::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Uses-allocator construction utility (waiting for C++20).
|
||||
*
|
||||
* Primarily intended for internal use. Creates an object of a given type by
|
||||
* means of uses-allocator construction at an uninitialized memory location.
|
||||
*
|
||||
* @tparam Type Type of object to create.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param value Memory location in which to place the object.
|
||||
* @param allocator The allocator to use.
|
||||
* @param args Parameters to use to construct the object.
|
||||
* @return A pointer to the newly created object of the given type.
|
||||
*/
|
||||
template<typename Type, typename Allocator, typename... Args>
|
||||
constexpr Type *uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args) {
|
||||
return std::apply([value](auto &&...curr) { return new(value) Type(std::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,13 +1,11 @@
|
||||
#ifndef ENTT_CORE_MONOSTATE_HPP
|
||||
#define ENTT_CORE_MONOSTATE_HPP
|
||||
|
||||
|
||||
#include "../config/config.h"
|
||||
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Minimal implementation of the monostate pattern.
|
||||
*
|
||||
@@ -19,7 +17,7 @@ namespace entt {
|
||||
* both during an assignment and when they try to read back their data.
|
||||
* Otherwise, they can incur in unexpected results.
|
||||
*/
|
||||
template<ENTT_ID_TYPE>
|
||||
template<id_type>
|
||||
struct monostate {
|
||||
/**
|
||||
* @brief Assigns a value of a specific type to a given key.
|
||||
@@ -27,7 +25,7 @@ struct monostate {
|
||||
* @param val User data to assign to the given key.
|
||||
*/
|
||||
template<typename Type>
|
||||
void operator=(Type val) const ENTT_NOEXCEPT {
|
||||
void operator=(Type val) const noexcept {
|
||||
value<Type> = val;
|
||||
}
|
||||
|
||||
@@ -37,7 +35,7 @@ struct monostate {
|
||||
* @return Stored value, if any.
|
||||
*/
|
||||
template<typename Type>
|
||||
operator Type() const ENTT_NOEXCEPT {
|
||||
operator Type() const noexcept {
|
||||
return value<Type>;
|
||||
}
|
||||
|
||||
@@ -46,16 +44,13 @@ private:
|
||||
inline static ENTT_MAYBE_ATOMIC(Type) value{};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Value Value used to differentiate between different variables.
|
||||
*/
|
||||
template<ENTT_ID_TYPE Value>
|
||||
template<id_type Value>
|
||||
inline monostate<Value> monostate_v = {};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
103
src/entt/core/tuple.hpp
Normal file
103
src/entt/core/tuple.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef ENTT_CORE_TUPLE_HPP
|
||||
#define ENTT_CORE_TUPLE_HPP
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename>
|
||||
struct is_tuple_impl: std::false_type {};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_tuple_impl<std::tuple<Args...>>: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is a
|
||||
* tuple, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_tuple: internal::is_tuple_impl<std::remove_cv_t<Type>> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_tuple_v = is_tuple<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Utility function to unwrap tuples of a single element.
|
||||
* @tparam Type Tuple type of any sizes.
|
||||
* @param value A tuple object of the given type.
|
||||
* @return The tuple itself if it contains more than one element, the first
|
||||
* element otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept {
|
||||
if constexpr(std::tuple_size_v<std::remove_reference_t<Type>> == 1u) {
|
||||
return std::get<0>(std::forward<Type>(value));
|
||||
} else {
|
||||
return std::forward<Type>(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility class to forward-and-apply tuple objects.
|
||||
* @tparam Func Type of underlying invocable object.
|
||||
*/
|
||||
template<typename Func>
|
||||
struct forward_apply: private Func {
|
||||
/**
|
||||
* @brief Constructs a forward-and-apply object.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<class... Args>
|
||||
constexpr forward_apply(Args &&...args) noexcept(std::is_nothrow_constructible_v<Func, Args...>)
|
||||
: Func{std::forward<Args>(args)...} {}
|
||||
|
||||
/**
|
||||
* @brief Forwards and applies the arguments with the underlying function.
|
||||
* @tparam Type Tuple-like type to forward to the underlying function.
|
||||
* @param args Parameters to forward to the underlying function.
|
||||
* @return Return value of the underlying function, if any.
|
||||
*/
|
||||
template<class Type>
|
||||
constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(std::apply(std::declval<Func &>(), args))) {
|
||||
return std::apply(static_cast<Func &>(*this), std::forward<Type>(args));
|
||||
}
|
||||
|
||||
/*! @copydoc operator()() */
|
||||
template<class Type>
|
||||
constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(std::apply(std::declval<const Func &>(), args))) {
|
||||
return std::apply(static_cast<const Func &>(*this), std::forward<Type>(args));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Func Type of underlying invocable object.
|
||||
*/
|
||||
template<typename Func>
|
||||
forward_apply(Func) -> forward_apply<std::remove_reference_t<std::remove_cv_t<Func>>>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,80 +1,274 @@
|
||||
#ifndef ENTT_CORE_TYPE_INFO_HPP
|
||||
#define ENTT_CORE_TYPE_INFO_HPP
|
||||
|
||||
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/attribute.h"
|
||||
#include "fwd.hpp"
|
||||
#include "hashed_string.hpp"
|
||||
|
||||
|
||||
#ifndef ENTT_PRETTY_FUNCTION
|
||||
# define ENTT_TYPE_ID_API ENTT_API
|
||||
#else
|
||||
# define ENTT_TYPE_ID_API
|
||||
#endif
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
#ifndef ENTT_PRETTY_FUNCTION
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
struct ENTT_API type_id_generator {
|
||||
static ENTT_ID_TYPE next() ENTT_NOEXCEPT {
|
||||
static ENTT_ID_TYPE value{};
|
||||
struct ENTT_API type_index final {
|
||||
[[nodiscard]] static id_type next() noexcept {
|
||||
static ENTT_MAYBE_ATOMIC(id_type) value{};
|
||||
return value++;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto stripped_type_name() noexcept {
|
||||
#if defined ENTT_PRETTY_FUNCTION
|
||||
std::string_view pretty_function{ENTT_PRETTY_FUNCTION};
|
||||
auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1);
|
||||
auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first);
|
||||
return value;
|
||||
#else
|
||||
return std::string_view{""};
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
|
||||
[[nodiscard]] static constexpr std::string_view type_name(int) noexcept {
|
||||
constexpr auto value = stripped_type_name<Type>();
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static std::string_view type_name(char) noexcept {
|
||||
static const auto value = stripped_type_name<Type>();
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
|
||||
[[nodiscard]] static constexpr id_type type_hash(int) noexcept {
|
||||
constexpr auto stripped = stripped_type_name<Type>();
|
||||
constexpr auto value = hashed_string::value(stripped.data(), stripped.size());
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static id_type type_hash(char) noexcept {
|
||||
static const auto value = [](const auto stripped) {
|
||||
return hashed_string::value(stripped.data(), stripped.size());
|
||||
}(stripped_type_name<Type>());
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond TURN_OFF_DOXYGEN
|
||||
* @endcond
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Types identifiers.
|
||||
* @tparam Type Type for which to generate an identifier.
|
||||
* @brief Type sequential identifier.
|
||||
* @tparam Type Type for which to generate a sequential identifier.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct ENTT_TYPE_ID_API type_info {
|
||||
struct ENTT_API type_index final {
|
||||
/**
|
||||
* @brief Returns the sequential identifier of a given type.
|
||||
* @return The sequential identifier of a given type.
|
||||
*/
|
||||
[[nodiscard]] static id_type value() noexcept {
|
||||
static const id_type value = internal::type_index::next();
|
||||
return value;
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator id_type() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type hash.
|
||||
* @tparam Type Type for which to generate a hash value.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct type_hash final {
|
||||
/**
|
||||
* @brief Returns the numeric representation of a given type.
|
||||
* @return The numeric representation of the given type.
|
||||
*/
|
||||
#if defined ENTT_PRETTY_FUNCTION_CONSTEXPR
|
||||
static constexpr ENTT_ID_TYPE id() ENTT_NOEXCEPT {
|
||||
constexpr auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION_CONSTEXPR);
|
||||
return value;
|
||||
}
|
||||
#elif defined ENTT_PRETTY_FUNCTION
|
||||
static ENTT_ID_TYPE id() ENTT_NOEXCEPT {
|
||||
static const auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION);
|
||||
return value;
|
||||
}
|
||||
#if defined ENTT_PRETTY_FUNCTION
|
||||
[[nodiscard]] static constexpr id_type value() noexcept {
|
||||
return internal::type_hash<Type>(0);
|
||||
#else
|
||||
static ENTT_ID_TYPE id() ENTT_NOEXCEPT {
|
||||
static const ENTT_ID_TYPE value = internal::type_id_generator::next();
|
||||
return value;
|
||||
}
|
||||
[[nodiscard]] static constexpr id_type value() noexcept {
|
||||
return type_index<Type>::value();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator id_type() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type name.
|
||||
* @tparam Type Type for which to generate a name.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct type_name final {
|
||||
/**
|
||||
* @brief Returns the name of a given type.
|
||||
* @return The name of the given type.
|
||||
*/
|
||||
[[nodiscard]] static constexpr std::string_view value() noexcept {
|
||||
return internal::type_name<Type>(0);
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator std::string_view() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
/*! @brief Implementation specific information about a type. */
|
||||
struct type_info final {
|
||||
/**
|
||||
* @brief Constructs a type info object for a given type.
|
||||
* @tparam Type Type for which to construct a type info object.
|
||||
*/
|
||||
template<typename Type>
|
||||
constexpr type_info(std::in_place_type_t<Type>) noexcept
|
||||
: seq{type_index<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
|
||||
identifier{type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
|
||||
alias{type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()} {}
|
||||
|
||||
/**
|
||||
* @brief Type index.
|
||||
* @return Type index.
|
||||
*/
|
||||
[[nodiscard]] constexpr id_type index() const noexcept {
|
||||
return seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Type hash.
|
||||
* @return Type hash.
|
||||
*/
|
||||
[[nodiscard]] constexpr id_type hash() const noexcept {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Type name.
|
||||
* @return Type name.
|
||||
*/
|
||||
[[nodiscard]] constexpr std::string_view name() const noexcept {
|
||||
return alias;
|
||||
}
|
||||
|
||||
private:
|
||||
id_type seq;
|
||||
id_type identifier;
|
||||
std::string_view alias;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares the contents of two type info objects.
|
||||
* @param lhs A type info object.
|
||||
* @param rhs A type info object.
|
||||
* @return True if the two type info objects are identical, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr bool operator==(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return lhs.hash() == rhs.hash();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares the contents of two type info objects.
|
||||
* @param lhs A type info object.
|
||||
* @param rhs A type info object.
|
||||
* @return True if the two type info objects differ, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr bool operator!=(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is less than the second, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator<(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return lhs.index() < rhs.index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is less than or equal to the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator<=(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is greater than the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator>(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is greater than or equal to the second,
|
||||
* false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator>=(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the type info object associated to a given type.
|
||||
*
|
||||
* The returned element refers to an object with static storage duration.<br/>
|
||||
* The type doesn't need to be a complete type. If the type is a reference, the
|
||||
* result refers to the referenced type. In all cases, top-level cv-qualifiers
|
||||
* are ignored.
|
||||
*
|
||||
* @tparam Type Type for which to generate a type info object.
|
||||
* @return A reference to a properly initialized type info object.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] const type_info &type_id() noexcept {
|
||||
if constexpr(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
static type_info instance{std::in_place_type<Type>};
|
||||
return instance;
|
||||
} else {
|
||||
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc type_id */
|
||||
template<typename Type>
|
||||
[[nodiscard]] const type_info &type_id(Type &&) noexcept {
|
||||
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,76 +1,219 @@
|
||||
#ifndef ENTT_CORE_TYPE_TRAITS_HPP
|
||||
#define ENTT_CORE_TYPE_TRAITS_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/hashed_string.hpp"
|
||||
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class to disambiguate overloaded functions.
|
||||
* @tparam N Number of choices available.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
struct choice_t
|
||||
// Unfortunately, doxygen cannot parse such a construct.
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
: choice_t<N-1>
|
||||
/*! @endcond TURN_OFF_DOXYGEN */
|
||||
// Unfortunately, doxygen cannot parse such a construct.
|
||||
: /*! @cond TURN_OFF_DOXYGEN */ choice_t<N - 1> /*! @endcond */
|
||||
{};
|
||||
|
||||
|
||||
/*! @copybrief choice_t */
|
||||
template<>
|
||||
struct choice_t<0> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Variable template for the choice trick.
|
||||
* @tparam N Number of choices available.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
constexpr choice_t<N> choice{};
|
||||
|
||||
|
||||
/*! @brief A class to use to push around lists of types, nothing more. */
|
||||
template<typename...>
|
||||
struct type_list {};
|
||||
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename>
|
||||
struct type_list_size;
|
||||
|
||||
inline constexpr choice_t<N> choice{};
|
||||
|
||||
/**
|
||||
* @brief Compile-time number of elements in a type list.
|
||||
* @brief Identity type trait.
|
||||
*
|
||||
* Useful to establish non-deduced contexts in template argument deduction
|
||||
* (waiting for C++20) or to provide types through function arguments.
|
||||
*
|
||||
* @tparam Type A type.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct type_identity {
|
||||
/*! @brief Identity type. */
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type A type.
|
||||
*/
|
||||
template<typename Type>
|
||||
using type_identity_t = typename type_identity<Type>::type;
|
||||
|
||||
/**
|
||||
* @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains.
|
||||
* @tparam Type The type of which to return the size.
|
||||
* @tparam The size of the type if `sizeof` accepts it, 0 otherwise.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct size_of: std::integral_constant<std::size_t, 0u> {};
|
||||
|
||||
/*! @copydoc size_of */
|
||||
template<typename Type>
|
||||
struct size_of<Type, std::void_t<decltype(sizeof(Type))>>
|
||||
: std::integral_constant<std::size_t, sizeof(Type)> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type of which to return the size.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr std::size_t size_of_v = size_of<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Using declaration to be used to _repeat_ the same type a number of
|
||||
* times equal to the size of a given parameter pack.
|
||||
* @tparam Type A type to repeat.
|
||||
*/
|
||||
template<typename Type, typename>
|
||||
using unpack_as_type = Type;
|
||||
|
||||
/**
|
||||
* @brief Helper variable template to be used to _repeat_ the same value a
|
||||
* number of times equal to the size of a given parameter pack.
|
||||
* @tparam Value A value to repeat.
|
||||
*/
|
||||
template<auto Value, typename>
|
||||
inline constexpr auto unpack_as_value = Value;
|
||||
|
||||
/**
|
||||
* @brief Wraps a static constant.
|
||||
* @tparam Value A static constant.
|
||||
*/
|
||||
template<auto Value>
|
||||
using integral_constant = std::integral_constant<decltype(Value), Value>;
|
||||
|
||||
/**
|
||||
* @brief Alias template to facilitate the creation of named values.
|
||||
* @tparam Value A constant value at least convertible to `id_type`.
|
||||
*/
|
||||
template<id_type Value>
|
||||
using tag = integral_constant<Value>;
|
||||
|
||||
/**
|
||||
* @brief A class to use to push around lists of types, nothing more.
|
||||
* @tparam Type Types provided by the type list.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct type_list_size<type_list<Type...>>
|
||||
: std::integral_constant<std::size_t, sizeof...(Type)>
|
||||
{};
|
||||
struct type_list {
|
||||
/*! @brief Type list type. */
|
||||
using type = type_list;
|
||||
/*! @brief Compile-time number of elements in the type list. */
|
||||
static constexpr auto size = sizeof...(Type);
|
||||
};
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<std::size_t, typename>
|
||||
struct type_list_element;
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the types of a type list.
|
||||
* @tparam Index Index of the type to return.
|
||||
* @tparam First First type provided by the type list.
|
||||
* @tparam Other Other types provided by the type list.
|
||||
*/
|
||||
template<std::size_t Index, typename First, typename... Other>
|
||||
struct type_list_element<Index, type_list<First, Other...>>
|
||||
: type_list_element<Index - 1u, type_list<Other...>> {};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the types of a type list.
|
||||
* @tparam First First type provided by the type list.
|
||||
* @tparam Other Other types provided by the type list.
|
||||
*/
|
||||
template<typename First, typename... Other>
|
||||
struct type_list_element<0u, type_list<First, Other...>> {
|
||||
/*! @brief Searched type. */
|
||||
using type = First;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Index Index of the type to return.
|
||||
* @tparam List Type list to search into.
|
||||
*/
|
||||
template<std::size_t Index, typename List>
|
||||
using type_list_element_t = typename type_list_element<Index, List>::type;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename, typename>
|
||||
struct type_list_index;
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time type access to the types of a type list.
|
||||
* @tparam Type Type to look for and for which to return the index.
|
||||
* @tparam First First type provided by the type list.
|
||||
* @tparam Other Other types provided by the type list.
|
||||
*/
|
||||
template<typename Type, typename First, typename... Other>
|
||||
struct type_list_index<Type, type_list<First, Other...>> {
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 1u + type_list_index<Type, type_list<Other...>>::value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time type access to the types of a type list.
|
||||
* @tparam Type Type to look for and for which to return the index.
|
||||
* @tparam Other Other types provided by the type list.
|
||||
*/
|
||||
template<typename Type, typename... Other>
|
||||
struct type_list_index<Type, type_list<Type, Other...>> {
|
||||
static_assert(type_list_index<Type, type_list<Other...>>::value == sizeof...(Other), "Non-unique type");
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time type access to the types of a type list.
|
||||
* @tparam Type Type to look for and for which to return the index.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct type_list_index<Type, type_list<>> {
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam List Type list.
|
||||
* @tparam Type Type to look for and for which to return the index.
|
||||
*/
|
||||
template<class List>
|
||||
constexpr auto type_list_size_v = type_list_size<List>::value;
|
||||
template<typename Type, typename List>
|
||||
inline constexpr std::size_t type_list_index_v = type_list_index<Type, List>::value;
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
* @tparam Type Types provided by the first type list.
|
||||
* @tparam Other Types provided by the second type list.
|
||||
* @return A type list composed by the types of both the type lists.
|
||||
*/
|
||||
template<typename... Type, typename... Other>
|
||||
constexpr type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct type_list_cat;
|
||||
|
||||
|
||||
/*! @brief Concatenates multiple type lists. */
|
||||
template<>
|
||||
struct type_list_cat<> {
|
||||
@@ -78,7 +221,6 @@ struct type_list_cat<> {
|
||||
using type = type_list<>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
* @tparam Type Types provided by the first type list.
|
||||
@@ -91,7 +233,6 @@ struct type_list_cat<type_list<Type...>, type_list<Other...>, List...> {
|
||||
using type = typename type_list_cat<type_list<Type..., Other...>, List...>::type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
* @tparam Type Types provided by the type list.
|
||||
@@ -102,7 +243,6 @@ struct type_list_cat<type_list<Type...>> {
|
||||
using type = type_list<Type...>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Type lists to concatenate.
|
||||
@@ -110,12 +250,10 @@ struct type_list_cat<type_list<Type...>> {
|
||||
template<typename... List>
|
||||
using type_list_cat_t = typename type_list_cat<List...>::type;
|
||||
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename>
|
||||
struct type_list_unique;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Removes duplicates types from a type list.
|
||||
* @tparam Type One of the types provided by the given type list.
|
||||
@@ -125,13 +263,11 @@ template<typename Type, typename... Other>
|
||||
struct type_list_unique<type_list<Type, Other...>> {
|
||||
/*! @brief A type list without duplicate types. */
|
||||
using type = std::conditional_t<
|
||||
std::disjunction_v<std::is_same<Type, Other>...>,
|
||||
(std::is_same_v<Type, Other> || ...),
|
||||
typename type_list_unique<type_list<Other...>>::type,
|
||||
type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>
|
||||
>;
|
||||
type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>>;
|
||||
};
|
||||
|
||||
|
||||
/*! @brief Removes duplicates types from a type list. */
|
||||
template<>
|
||||
struct type_list_unique<type_list<>> {
|
||||
@@ -139,7 +275,6 @@ struct type_list_unique<type_list<>> {
|
||||
using type = type_list<>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type A type list.
|
||||
@@ -147,28 +282,415 @@ struct type_list_unique<type_list<>> {
|
||||
template<typename Type>
|
||||
using type_list_unique_t = typename type_list_unique<Type>::type;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a type list contains a
|
||||
* given type, false otherwise.
|
||||
* @tparam List Type list.
|
||||
* @tparam Type Type to look for.
|
||||
*/
|
||||
template<typename List, typename Type>
|
||||
struct type_list_contains;
|
||||
|
||||
/**
|
||||
* @copybrief type_list_contains
|
||||
* @tparam Type Types provided by the type list.
|
||||
* @tparam Other Type to look for.
|
||||
*/
|
||||
template<typename... Type, typename Other>
|
||||
struct type_list_contains<type_list<Type...>, Other>: std::disjunction<std::is_same<Type, Other>...> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam List Type list.
|
||||
* @tparam Type Type to look for.
|
||||
*/
|
||||
template<typename List, typename Type>
|
||||
inline constexpr bool type_list_contains_v = type_list_contains<List, Type>::value;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct type_list_diff;
|
||||
|
||||
/**
|
||||
* @brief Computes the difference between two type lists.
|
||||
* @tparam Type Types provided by the first type list.
|
||||
* @tparam Other Types provided by the second type list.
|
||||
*/
|
||||
template<typename... Type, typename... Other>
|
||||
struct type_list_diff<type_list<Type...>, type_list<Other...>> {
|
||||
/*! @brief A type list that is the difference between the two type lists. */
|
||||
using type = type_list_cat_t<std::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Type lists between which to compute the difference.
|
||||
*/
|
||||
template<typename... List>
|
||||
using type_list_diff_t = typename type_list_diff<List...>::type;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename, template<typename...> class>
|
||||
struct type_list_transform;
|
||||
|
||||
/**
|
||||
* @brief Applies a given _function_ to a type list and generate a new list.
|
||||
* @tparam Type Types provided by the type list.
|
||||
* @tparam Op Unary operation as template class with a type member named `type`.
|
||||
*/
|
||||
template<typename... Type, template<typename...> class Op>
|
||||
struct type_list_transform<type_list<Type...>, Op> {
|
||||
/*! @brief Resulting type list after applying the transform function. */
|
||||
using type = type_list<typename Op<Type>::type...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Type list.
|
||||
* @tparam Op Unary operation as template class with a type member named `type`.
|
||||
*/
|
||||
template<typename List, template<typename...> class Op>
|
||||
using type_list_transform_t = typename type_list_transform<List, Op>::type;
|
||||
|
||||
/**
|
||||
* @brief A class to use to push around lists of constant values, nothing more.
|
||||
* @tparam Value Values provided by the value list.
|
||||
*/
|
||||
template<auto... Value>
|
||||
struct value_list {
|
||||
/*! @brief Value list type. */
|
||||
using type = value_list;
|
||||
/*! @brief Compile-time number of elements in the value list. */
|
||||
static constexpr auto size = sizeof...(Value);
|
||||
};
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<std::size_t, typename>
|
||||
struct value_list_element;
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the values of a value list.
|
||||
* @tparam Index Index of the value to return.
|
||||
* @tparam Value First value provided by the value list.
|
||||
* @tparam Other Other values provided by the value list.
|
||||
*/
|
||||
template<std::size_t Index, auto Value, auto... Other>
|
||||
struct value_list_element<Index, value_list<Value, Other...>>
|
||||
: value_list_element<Index - 1u, value_list<Other...>> {};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the types of a type list.
|
||||
* @tparam Value First value provided by the value list.
|
||||
* @tparam Other Other values provided by the value list.
|
||||
*/
|
||||
template<auto Value, auto... Other>
|
||||
struct value_list_element<0u, value_list<Value, Other...>> {
|
||||
/*! @brief Searched value. */
|
||||
static constexpr auto value = Value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Index Index of the value to return.
|
||||
* @tparam List Value list to search into.
|
||||
*/
|
||||
template<std::size_t Index, typename List>
|
||||
inline constexpr auto value_list_element_v = value_list_element<Index, List>::value;
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
* @tparam Value Values provided by the first value list.
|
||||
* @tparam Other Values provided by the second value list.
|
||||
* @return A value list composed by the values of both the value lists.
|
||||
*/
|
||||
template<auto... Value, auto... Other>
|
||||
constexpr value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct value_list_cat;
|
||||
|
||||
/*! @brief Concatenates multiple value lists. */
|
||||
template<>
|
||||
struct value_list_cat<> {
|
||||
/*! @brief A value list composed by the values of all the value lists. */
|
||||
using type = value_list<>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
* @tparam Value Values provided by the first value list.
|
||||
* @tparam Other Values provided by the second value list.
|
||||
* @tparam List Other value lists, if any.
|
||||
*/
|
||||
template<auto... Value, auto... Other, typename... List>
|
||||
struct value_list_cat<value_list<Value...>, value_list<Other...>, List...> {
|
||||
/*! @brief A value list composed by the values of all the value lists. */
|
||||
using type = typename value_list_cat<value_list<Value..., Other...>, List...>::type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
* @tparam Value Values provided by the value list.
|
||||
*/
|
||||
template<auto... Value>
|
||||
struct value_list_cat<value_list<Value...>> {
|
||||
/*! @brief A value list composed by the values of all the value lists. */
|
||||
using type = value_list<Value...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Value lists to concatenate.
|
||||
*/
|
||||
template<typename... List>
|
||||
using value_list_cat_t = typename value_list_cat<List...>::type;
|
||||
|
||||
/*! @brief Same as std::is_invocable, but with tuples. */
|
||||
template<typename, typename>
|
||||
struct is_applicable: std::false_type {};
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Tuple Tuple-like type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Func, template<typename...> class Tuple, typename... Args>
|
||||
struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Tuple Tuple-like type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Func, template<typename...> class Tuple, typename... Args>
|
||||
struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args...> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Func, typename Args>
|
||||
inline constexpr bool is_applicable_v = is_applicable<Func, Args>::value;
|
||||
|
||||
/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */
|
||||
template<typename, typename, typename>
|
||||
struct is_applicable_r: std::false_type {};
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable_r
|
||||
* @tparam Ret The type to which the return type of the function should be
|
||||
* convertible.
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Ret, typename Func, typename... Args>
|
||||
struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret, Func, Args...> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Ret The type to which the return type of the function should be
|
||||
* convertible.
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Ret, typename Func, typename Args>
|
||||
inline constexpr bool is_applicable_r_v = is_applicable_r<Ret, Func, Args>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is
|
||||
* complete, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_complete: std::false_type {};
|
||||
|
||||
/*! @copydoc is_complete */
|
||||
template<typename Type>
|
||||
struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_complete_v = is_complete<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is an
|
||||
* iterator, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_iterator: std::false_type {};
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_iterator_category: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/*! @copydoc is_iterator */
|
||||
template<typename Type>
|
||||
struct is_iterator<Type, std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_pointer_t<Type>>, void>>>
|
||||
: internal::has_iterator_category<Type> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_iterator_v = is_iterator<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is both
|
||||
* an empty and non-final class, false otherwise.
|
||||
* @tparam Type The type to test
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_ebco_eligible
|
||||
: std::conjunction<std::is_empty<Type>, std::negation<std::is_final<Type>>> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_ebco_eligible_v = is_ebco_eligible<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if `Type::is_transparent`
|
||||
* is valid and denotes a type, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_transparent: std::false_type {};
|
||||
|
||||
/*! @copydoc is_transparent */
|
||||
template<typename Type>
|
||||
struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_transparent_v = is_transparent<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is
|
||||
* equality comparable, false otherwise.
|
||||
* @tparam Type Potentially equality comparable type.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = std::void_t<>>
|
||||
template<typename Type, typename = void>
|
||||
struct is_equality_comparable: std::false_type {};
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_tuple_size_value: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct has_tuple_size_value<Type, std::void_t<decltype(std::tuple_size<const Type>::value)>>: std::true_type {};
|
||||
|
||||
template<typename Type, std::size_t... Index>
|
||||
[[nodiscard]] constexpr bool unpack_maybe_equality_comparable(std::index_sequence<Index...>) {
|
||||
return (is_equality_comparable<std::tuple_element_t<Index, Type>>::value && ...);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
[[nodiscard]] constexpr bool maybe_equality_comparable(choice_t<0>) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto maybe_equality_comparable(choice_t<1>) -> decltype(std::declval<typename Type::value_type>(), bool{}) {
|
||||
if constexpr(is_iterator_v<Type>) {
|
||||
return true;
|
||||
} else if constexpr(std::is_same_v<typename Type::value_type, Type>) {
|
||||
return maybe_equality_comparable<Type>(choice<0>);
|
||||
} else {
|
||||
return is_equality_comparable<typename Type::value_type>::value;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<is_complete_v<std::tuple_size<std::remove_cv_t<Type>>>, bool> maybe_equality_comparable(choice_t<2>) {
|
||||
if constexpr(has_tuple_size_value<Type>::value) {
|
||||
return unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
|
||||
} else {
|
||||
return maybe_equality_comparable<Type>(choice<1>);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/*! @copydoc is_equality_comparable */
|
||||
template<typename Type>
|
||||
struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>>: std::true_type {};
|
||||
|
||||
struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>>
|
||||
: std::bool_constant<internal::maybe_equality_comparable<Type>(choice<2>)> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Potentially equality comparable type.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<class Type>
|
||||
constexpr auto is_equality_comparable_v = is_equality_comparable<Type>::value;
|
||||
template<typename Type>
|
||||
inline constexpr bool is_equality_comparable_v = is_equality_comparable<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Transcribes the constness of a type to another type.
|
||||
* @tparam To The type to which to transcribe the constness.
|
||||
* @tparam From The type from which to transcribe the constness.
|
||||
*/
|
||||
template<typename To, typename From>
|
||||
struct constness_as {
|
||||
/*! @brief The type resulting from the transcription of the constness. */
|
||||
using type = std::remove_const_t<To>;
|
||||
};
|
||||
|
||||
/*! @copydoc constness_as */
|
||||
template<typename To, typename From>
|
||||
struct constness_as<To, const From> {
|
||||
/*! @brief The type resulting from the transcription of the constness. */
|
||||
using type = const To;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Alias template to facilitate the transcription of the constness.
|
||||
* @tparam To The type to which to transcribe the constness.
|
||||
* @tparam From The type from which to transcribe the constness.
|
||||
*/
|
||||
template<typename To, typename From>
|
||||
using constness_as_t = typename constness_as<To, From>::type;
|
||||
|
||||
/**
|
||||
* @brief Extracts the class of a non-static member object or function.
|
||||
@@ -176,23 +698,22 @@ constexpr auto is_equality_comparable_v = is_equality_comparable<Type>::value;
|
||||
*/
|
||||
template<typename Member>
|
||||
class member_class {
|
||||
static_assert(std::is_member_pointer_v<Member>);
|
||||
static_assert(std::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function");
|
||||
|
||||
template<typename Class, typename Ret, typename... Args>
|
||||
static Class * clazz(Ret(Class:: *)(Args...));
|
||||
static Class *clazz(Ret (Class::*)(Args...));
|
||||
|
||||
template<typename Class, typename Ret, typename... Args>
|
||||
static Class * clazz(Ret(Class:: *)(Args...) const);
|
||||
static Class *clazz(Ret (Class::*)(Args...) const);
|
||||
|
||||
template<typename Class, typename Type>
|
||||
static Class * clazz(Type Class:: *);
|
||||
static Class *clazz(Type Class::*);
|
||||
|
||||
public:
|
||||
/*! @brief The class of the given non-static member object or function. */
|
||||
using type = std::remove_pointer_t<decltype(clazz(std::declval<Member>()))>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Member A pointer to a non-static member object or function.
|
||||
@@ -200,30 +721,38 @@ public:
|
||||
template<typename Member>
|
||||
using member_class_t = typename member_class<Member>::type;
|
||||
|
||||
/**
|
||||
* @brief Extracts the n-th argument of a given function or member function.
|
||||
* @tparam Index The index of the argument to extract.
|
||||
* @tparam Candidate A valid function, member function or data member.
|
||||
*/
|
||||
template<std::size_t Index, auto Candidate>
|
||||
class nth_argument {
|
||||
template<typename Ret, typename... Args>
|
||||
static constexpr type_list<Args...> pick_up(Ret (*)(Args...));
|
||||
|
||||
template<typename Ret, typename Class, typename... Args>
|
||||
static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...));
|
||||
|
||||
template<typename Ret, typename Class, typename... Args>
|
||||
static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...) const);
|
||||
|
||||
template<typename Type, typename Class>
|
||||
static constexpr type_list<Type> pick_up(Type Class ::*);
|
||||
|
||||
public:
|
||||
/*! @brief N-th argument of the given function or member function. */
|
||||
using type = type_list_element_t<Index, decltype(pick_up(Candidate))>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Alias template to ease the creation of named values.
|
||||
* @tparam Value A constant value at least convertible to `ENTT_ID_TYPE`.
|
||||
* @brief Helper type.
|
||||
* @tparam Index The index of the argument to extract.
|
||||
* @tparam Candidate A valid function, member function or data member.
|
||||
*/
|
||||
template<ENTT_ID_TYPE Value>
|
||||
using tag = std::integral_constant<ENTT_ID_TYPE, Value>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Defines an enum class to use for opaque identifiers and a dedicate
|
||||
* `to_integer` function to convert the identifiers to their underlying type.
|
||||
* @param clazz The name to use for the enum class.
|
||||
* @param type The underlying type for the enum class.
|
||||
*/
|
||||
#define ENTT_OPAQUE_TYPE(clazz, type)\
|
||||
enum class clazz: type {};\
|
||||
constexpr auto to_integral(const clazz id) ENTT_NOEXCEPT {\
|
||||
return static_cast<std::underlying_type_t<clazz>>(id);\
|
||||
}\
|
||||
static_assert(true)
|
||||
template<std::size_t Index, auto Candidate>
|
||||
using nth_argument_t = typename nth_argument<Index, Candidate>::type;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#ifndef ENTT_CORE_UTILITY_HPP
|
||||
#define ENTT_CORE_UTILITY_HPP
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/*! @brief Identity function object (waiting for C++20). */
|
||||
struct identity {
|
||||
/*! @brief Indicates that this is a transparent function object. */
|
||||
using is_transparent = void;
|
||||
|
||||
/**
|
||||
* @brief Returns its argument unchanged.
|
||||
* @tparam Type Type of the argument.
|
||||
@@ -18,12 +18,11 @@ struct identity {
|
||||
* @return The submitted value as-is.
|
||||
*/
|
||||
template<class Type>
|
||||
constexpr Type && operator()(Type &&value) const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept {
|
||||
return std::forward<Type>(value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constant utility to disambiguate overloaded members of a class.
|
||||
* @tparam Type Type of the desired overload.
|
||||
@@ -32,8 +31,9 @@ struct identity {
|
||||
* @return Pointer to the member.
|
||||
*/
|
||||
template<typename Type, typename Class>
|
||||
constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; }
|
||||
|
||||
[[nodiscard]] constexpr auto overload(Type Class::*member) noexcept {
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constant utility to disambiguate overloaded functions.
|
||||
@@ -42,8 +42,9 @@ constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; }
|
||||
* @return Pointer to the function.
|
||||
*/
|
||||
template<typename Func>
|
||||
constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; }
|
||||
|
||||
[[nodiscard]] constexpr auto overload(Func *func) noexcept {
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper type for visitors.
|
||||
@@ -54,7 +55,6 @@ struct overloaded: Func... {
|
||||
using Func::operator()...;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Func Types of function objects.
|
||||
@@ -62,7 +62,6 @@ struct overloaded: Func... {
|
||||
template<class... Func>
|
||||
overloaded(Func...) -> overloaded<Func...>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic implementation of a y-combinator.
|
||||
* @tparam Func Type of a potentially recursive function.
|
||||
@@ -73,9 +72,8 @@ struct y_combinator {
|
||||
* @brief Constructs a y-combinator from a given function.
|
||||
* @param recursive A potentially recursive function.
|
||||
*/
|
||||
y_combinator(Func recursive):
|
||||
func{std::move(recursive)}
|
||||
{}
|
||||
constexpr y_combinator(Func recursive) noexcept(std::is_nothrow_move_constructible_v<Func>)
|
||||
: func{std::move(recursive)} {}
|
||||
|
||||
/**
|
||||
* @brief Invokes a y-combinator and therefore its underlying function.
|
||||
@@ -83,14 +81,14 @@ struct y_combinator {
|
||||
* @param args Parameters to use to invoke the underlying function.
|
||||
* @return Return value of the underlying function, if any.
|
||||
*/
|
||||
template <class... Args>
|
||||
decltype(auto) operator()(Args &&... args) const {
|
||||
template<class... Args>
|
||||
constexpr decltype(auto) operator()(Args &&...args) const noexcept(std::is_nothrow_invocable_v<Func, const y_combinator &, Args...>) {
|
||||
return func(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! @copydoc operator()() */
|
||||
template <class... Args>
|
||||
decltype(auto) operator()(Args &&... args) {
|
||||
template<class... Args>
|
||||
constexpr decltype(auto) operator()(Args &&...args) noexcept(std::is_nothrow_invocable_v<Func, y_combinator &, Args...>) {
|
||||
return func(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -98,8 +96,6 @@ private:
|
||||
Func func;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,206 +0,0 @@
|
||||
#ifndef ENTT_ENTITY_ACTOR_HPP
|
||||
#define ENTT_ENTITY_ACTOR_HPP
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "registry.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dedicated to those who aren't confident with the
|
||||
* entity-component-system architecture.
|
||||
*
|
||||
* Tiny wrapper around a registry, for all those users that aren't confident
|
||||
* with entity-component-system architecture and prefer to iterate objects
|
||||
* directly.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
struct basic_actor {
|
||||
/*! @brief Type of registry used internally. */
|
||||
using registry_type = basic_registry<Entity>;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
|
||||
basic_actor() ENTT_NOEXCEPT
|
||||
: entt{entt::null}, reg{nullptr}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
*
|
||||
* After actor move construction, instances that have been moved from are
|
||||
* placed in a valid but unspecified state. It's highly discouraged to
|
||||
* continue using them.
|
||||
*
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_actor(basic_actor &&other) ENTT_NOEXCEPT
|
||||
: entt{other.entt}, reg{other.reg}
|
||||
{
|
||||
other.entt = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an actor from a given registry.
|
||||
* @param ref An instance of the registry class.
|
||||
*/
|
||||
explicit basic_actor(registry_type &ref)
|
||||
: entt{ref.create()}, reg{&ref}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Constructs an actor from a given entity.
|
||||
* @param entity A valid entity identifier.
|
||||
* @param ref An instance of the registry class.
|
||||
*/
|
||||
explicit basic_actor(entity_type entity, registry_type &ref) ENTT_NOEXCEPT
|
||||
: entt{entity}, reg{&ref}
|
||||
{
|
||||
ENTT_ASSERT(ref.valid(entity));
|
||||
}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
virtual ~basic_actor() {
|
||||
if(*this) {
|
||||
reg->destroy(entt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
*
|
||||
* After actor move assignment, instances that have been moved from are
|
||||
* placed in a valid but unspecified state. It's highly discouraged to
|
||||
* continue using them.
|
||||
*
|
||||
* @param other The instance to move from.
|
||||
* @return This actor.
|
||||
*/
|
||||
basic_actor & operator=(basic_actor &&other) ENTT_NOEXCEPT {
|
||||
if(this != &other) {
|
||||
auto tmp{std::move(other)};
|
||||
std::swap(reg, tmp.reg);
|
||||
std::swap(entt, tmp.entt);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns the given component to an actor.
|
||||
*
|
||||
* A new instance of the given component is created and initialized with the
|
||||
* arguments provided (the component must have a proper constructor or be of
|
||||
* aggregate type). Then the component is assigned to the actor.<br/>
|
||||
* In case the actor already has a component of the given type, it's
|
||||
* replaced with the new one.
|
||||
*
|
||||
* @tparam Component Type of the component to create.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return A reference to the newly created component.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) assign(Args &&... args) {
|
||||
return reg->template assign_or_replace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the given component from an actor.
|
||||
* @tparam Component Type of the component to remove.
|
||||
*/
|
||||
template<typename Component>
|
||||
void remove() {
|
||||
reg->template remove<Component>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if an actor has the given components.
|
||||
* @tparam Component Components for which to perform the check.
|
||||
* @return True if the actor has all the components, false otherwise.
|
||||
*/
|
||||
template<typename... Component>
|
||||
bool has() const {
|
||||
return reg->template has<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns references to the given components for an actor.
|
||||
* @tparam Component Types of components to get.
|
||||
* @return References to the components owned by the actor.
|
||||
*/
|
||||
template<typename... Component>
|
||||
decltype(auto) get() const {
|
||||
return std::as_const(*reg).template get<Component...>(entt);
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
template<typename... Component>
|
||||
decltype(auto) get() {
|
||||
return reg->template get<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns pointers to the given components for an actor.
|
||||
* @tparam Component Types of components to get.
|
||||
* @return Pointers to the components owned by the actor.
|
||||
*/
|
||||
template<typename... Component>
|
||||
auto try_get() const {
|
||||
return std::as_const(*reg).template try_get<Component...>(entt);
|
||||
}
|
||||
|
||||
/*! @copydoc try_get */
|
||||
template<typename... Component>
|
||||
auto try_get() {
|
||||
return reg->template try_get<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the underlying registry.
|
||||
* @return A reference to the underlying registry.
|
||||
*/
|
||||
const registry_type & backend() const ENTT_NOEXCEPT {
|
||||
return *reg;
|
||||
}
|
||||
|
||||
/*! @copydoc backend */
|
||||
registry_type & backend() ENTT_NOEXCEPT {
|
||||
return const_cast<registry_type &>(std::as_const(*this).backend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the entity associated with an actor.
|
||||
* @return The entity associated with the actor.
|
||||
*/
|
||||
entity_type entity() const ENTT_NOEXCEPT {
|
||||
return entt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if an actor refers to a valid entity or not.
|
||||
* @return True if the actor refers to a valid entity, false otherwise.
|
||||
*/
|
||||
explicit operator bool() const {
|
||||
return reg && reg->valid(entt);
|
||||
}
|
||||
|
||||
private:
|
||||
entity_type entt;
|
||||
registry_type *reg;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
64
src/entt/entity/component.hpp
Normal file
64
src/entt/entity/component.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef ENTT_ENTITY_COMPONENT_HPP
|
||||
#define ENTT_ENTITY_COMPONENT_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, typename = void>
|
||||
struct in_place_delete: std::bool_constant<!(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>)> {};
|
||||
|
||||
template<typename Type>
|
||||
struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>>
|
||||
: std::true_type {};
|
||||
|
||||
template<typename Type, typename = void>
|
||||
struct page_size: std::integral_constant<std::size_t, !std::is_empty_v<ENTT_ETO_TYPE(Type)> * ENTT_PACKED_PAGE> {};
|
||||
|
||||
template<typename Type>
|
||||
struct page_size<Type, std::enable_if_t<std::is_convertible_v<decltype(Type::page_size), std::size_t>>>
|
||||
: std::integral_constant<std::size_t, Type::page_size> {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Common way to access various properties of components.
|
||||
* @tparam Type Type of component.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct component_traits {
|
||||
static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
|
||||
|
||||
/*! @brief Component type. */
|
||||
using type = Type;
|
||||
|
||||
/*! @brief Pointer stability, default is `false`. */
|
||||
static constexpr bool in_place_delete = internal::in_place_delete<Type>::value;
|
||||
/*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */
|
||||
static constexpr std::size_t page_size = internal::page_size<Type>::value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Type of component.
|
||||
*/
|
||||
template<class Type>
|
||||
inline constexpr bool ignore_as_empty_v = (std::is_void_v<Type> || component_traits<Type>::page_size == 0u);
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,175 +1,339 @@
|
||||
#ifndef ENTT_ENTITY_ENTITY_HPP
|
||||
#define ENTT_ENTITY_ENTITY_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/type_traits.hpp"
|
||||
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entity traits.
|
||||
*
|
||||
* Primary template isn't defined on purpose. All the specializations give a
|
||||
* compile-time error unless the template parameter is an accepted entity type.
|
||||
*/
|
||||
template<typename>
|
||||
struct entt_traits;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entity traits for a 16 bits entity identifier.
|
||||
*
|
||||
* A 16 bits entity identifier guarantees:
|
||||
*
|
||||
* * 12 bits for the entity number (up to 4k entities).
|
||||
* * 4 bit for the version (resets in [0-15]).
|
||||
*/
|
||||
template<>
|
||||
struct entt_traits<std::uint16_t> {
|
||||
/*! @brief Underlying entity type. */
|
||||
using entity_type = std::uint16_t;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = std::uint8_t;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::int32_t;
|
||||
|
||||
/*! @brief Mask to use to get the entity number out of an identifier. */
|
||||
static constexpr std::uint16_t entity_mask = 0xFFF;
|
||||
/*! @brief Mask to use to get the version out of an identifier. */
|
||||
static constexpr std::uint16_t version_mask = 0xF;
|
||||
/*! @brief Extent of the entity number within an identifier. */
|
||||
static constexpr auto entity_shift = 12;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entity traits for a 32 bits entity identifier.
|
||||
*
|
||||
* A 32 bits entity identifier guarantees:
|
||||
*
|
||||
* * 20 bits for the entity number (suitable for almost all the games).
|
||||
* * 12 bit for the version (resets in [0-4095]).
|
||||
*/
|
||||
template<>
|
||||
struct entt_traits<std::uint32_t> {
|
||||
/*! @brief Underlying entity type. */
|
||||
using entity_type = std::uint32_t;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = std::uint16_t;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::int64_t;
|
||||
|
||||
/*! @brief Mask to use to get the entity number out of an identifier. */
|
||||
static constexpr std::uint32_t entity_mask = 0xFFFFF;
|
||||
/*! @brief Mask to use to get the version out of an identifier. */
|
||||
static constexpr std::uint32_t version_mask = 0xFFF;
|
||||
/*! @brief Extent of the entity number within an identifier. */
|
||||
static constexpr auto entity_shift = 20;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entity traits for a 64 bits entity identifier.
|
||||
*
|
||||
* A 64 bits entity identifier guarantees:
|
||||
*
|
||||
* * 32 bits for the entity number (an indecently large number).
|
||||
* * 32 bit for the version (an indecently large number).
|
||||
*/
|
||||
template<>
|
||||
struct entt_traits<std::uint64_t> {
|
||||
/*! @brief Underlying entity type. */
|
||||
using entity_type = std::uint64_t;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = std::uint32_t;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::int64_t;
|
||||
|
||||
/*! @brief Mask to use to get the entity number out of an identifier. */
|
||||
static constexpr std::uint64_t entity_mask = 0xFFFFFFFF;
|
||||
/*! @brief Mask to use to get the version out of an identifier. */
|
||||
static constexpr std::uint64_t version_mask = 0xFFFFFFFF;
|
||||
/*! @brief Extent of the entity number within an identifier. */
|
||||
static constexpr auto entity_shift = 32;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct entt_traits;
|
||||
|
||||
class null {
|
||||
template<typename Entity>
|
||||
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
|
||||
template<typename Type>
|
||||
struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>>
|
||||
: entt_traits<std::underlying_type_t<Type>> {};
|
||||
|
||||
template<typename Type>
|
||||
struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>>
|
||||
: entt_traits<typename Type::entity_type> {};
|
||||
|
||||
template<>
|
||||
struct entt_traits<std::uint32_t> {
|
||||
using entity_type = std::uint32_t;
|
||||
using version_type = std::uint16_t;
|
||||
|
||||
static constexpr entity_type entity_mask = 0xFFFFF;
|
||||
static constexpr entity_type version_mask = 0xFFF;
|
||||
static constexpr std::size_t entity_shift = 20u;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct entt_traits<std::uint64_t> {
|
||||
using entity_type = std::uint64_t;
|
||||
using version_type = std::uint32_t;
|
||||
|
||||
static constexpr entity_type entity_mask = 0xFFFFFFFF;
|
||||
static constexpr entity_type version_mask = 0xFFFFFFFF;
|
||||
static constexpr std::size_t entity_shift = 32u;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Entity traits.
|
||||
* @tparam Type Type of identifier.
|
||||
*/
|
||||
template<typename Type>
|
||||
class entt_traits: internal::entt_traits<Type> {
|
||||
using base_type = internal::entt_traits<Type>;
|
||||
|
||||
public:
|
||||
template<typename Entity>
|
||||
constexpr operator Entity() const ENTT_NOEXCEPT {
|
||||
return Entity{traits_type<Entity>::entity_mask};
|
||||
/*! @brief Value type. */
|
||||
using value_type = Type;
|
||||
/*! @brief Underlying entity type. */
|
||||
using entity_type = typename base_type::entity_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename base_type::version_type;
|
||||
/*! @brief Reserved identifier. */
|
||||
static constexpr entity_type reserved = base_type::entity_mask | (base_type::version_mask << base_type::entity_shift);
|
||||
/*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */
|
||||
static constexpr auto page_size = ENTT_SPARSE_PAGE;
|
||||
|
||||
/**
|
||||
* @brief Converts an entity to its underlying type.
|
||||
* @param value The value to convert.
|
||||
* @return The integral representation of the given value.
|
||||
*/
|
||||
[[nodiscard]] static constexpr entity_type to_integral(const value_type value) noexcept {
|
||||
return static_cast<entity_type>(value);
|
||||
}
|
||||
|
||||
constexpr bool operator==(null) const ENTT_NOEXCEPT {
|
||||
/**
|
||||
* @brief Returns the entity part once converted to the underlying type.
|
||||
* @param value The value to convert.
|
||||
* @return The integral representation of the entity part.
|
||||
*/
|
||||
[[nodiscard]] static constexpr entity_type to_entity(const value_type value) noexcept {
|
||||
return (to_integral(value) & base_type::entity_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the version part once converted to the underlying type.
|
||||
* @param value The value to convert.
|
||||
* @return The integral representation of the version part.
|
||||
*/
|
||||
[[nodiscard]] static constexpr version_type to_version(const value_type value) noexcept {
|
||||
return (to_integral(value) >> base_type::entity_shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an identifier from its parts.
|
||||
*
|
||||
* If the version part is not provided, a tombstone is returned.<br/>
|
||||
* If the entity part is not provided, a null identifier is returned.
|
||||
*
|
||||
* @param entity The entity part of the identifier.
|
||||
* @param version The version part of the identifier.
|
||||
* @return A properly constructed identifier.
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) noexcept {
|
||||
return value_type{(entity & base_type::entity_mask) | (static_cast<entity_type>(version) << base_type::entity_shift)};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Combines two identifiers in a single one.
|
||||
*
|
||||
* The returned identifier is a copy of the first element except for its
|
||||
* version, which is taken from the second element.
|
||||
*
|
||||
* @param lhs The identifier from which to take the entity part.
|
||||
* @param rhs The identifier from which to take the version part.
|
||||
* @return A properly constructed identifier.
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept {
|
||||
constexpr auto mask = (base_type::version_mask << base_type::entity_shift);
|
||||
return value_type{(lhs & base_type::entity_mask) | (rhs & mask)};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_integral
|
||||
* @tparam Entity The value type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept {
|
||||
return entt_traits<Entity>::to_integral(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_entity
|
||||
* @tparam Entity The value type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept {
|
||||
return entt_traits<Entity>::to_entity(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_version
|
||||
* @tparam Entity The value type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::version_type to_version(const Entity value) noexcept {
|
||||
return entt_traits<Entity>::to_version(value);
|
||||
}
|
||||
|
||||
/*! @brief Null object for all identifiers. */
|
||||
struct null_t {
|
||||
/**
|
||||
* @brief Converts the null object to identifiers of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @return The null representation for the given type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr operator Entity() const noexcept {
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
return entity_traits::combine(entity_traits::reserved, entity_traits::reserved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two null objects.
|
||||
* @param other A null object.
|
||||
* @return True in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(null) const ENTT_NOEXCEPT {
|
||||
/**
|
||||
* @brief Compares two null objects.
|
||||
* @param other A null object.
|
||||
* @return False in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
|
||||
return (to_integral(entity) & traits_type<Entity>::entity_mask) == to_integral(static_cast<Entity>(*this));
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
return entity_traits::to_entity(entity) == entity_traits::to_entity(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
|
||||
return !(entity == *this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A null object yet to be converted.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
constexpr bool operator==(const Entity entity, null other) ENTT_NOEXCEPT {
|
||||
return other == entity;
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity, const null_t other) noexcept {
|
||||
return other.operator==(entity);
|
||||
}
|
||||
|
||||
|
||||
template<typename Entity>
|
||||
constexpr bool operator!=(const Entity entity, null other) ENTT_NOEXCEPT {
|
||||
return other != entity;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond TURN_OFF_DOXYGEN
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A null object yet to be converted.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity, const null_t other) noexcept {
|
||||
return !(other == entity);
|
||||
}
|
||||
|
||||
/*! @brief Tombstone object for all identifiers. */
|
||||
struct tombstone_t {
|
||||
/**
|
||||
* @brief Converts the tombstone object to identifiers of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @return The tombstone representation for the given type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr operator Entity() const noexcept {
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
return entity_traits::combine(entity_traits::reserved, entity_traits::reserved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two tombstone objects.
|
||||
* @param other A tombstone object.
|
||||
* @return True in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two tombstone objects.
|
||||
* @param other A tombstone object.
|
||||
* @return False in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
return entity_traits::to_version(entity) == entity_traits::to_version(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
|
||||
return !(entity == *this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A tombstone object yet to be converted.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity, const tombstone_t other) noexcept {
|
||||
return other.operator==(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A tombstone object yet to be converted.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity, const tombstone_t other) noexcept {
|
||||
return !(other == entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compile-time constant for null entities.
|
||||
*
|
||||
* There exist implicit conversions from this variable to entity identifiers of
|
||||
* any allowed type. Similarly, there exist comparision operators between the
|
||||
* null entity and any other entity identifier.
|
||||
* There exist implicit conversions from this variable to identifiers of any
|
||||
* allowed type. Similarly, there exist comparison operators between the null
|
||||
* entity and any other identifier.
|
||||
*/
|
||||
constexpr auto null = internal::null{};
|
||||
inline constexpr null_t null{};
|
||||
|
||||
/**
|
||||
* @brief Compile-time constant for tombstone entities.
|
||||
*
|
||||
* There exist implicit conversions from this variable to identifiers of any
|
||||
* allowed type. Similarly, there exist comparison operators between the
|
||||
* tombstone entity and any other identifier.
|
||||
*/
|
||||
inline constexpr tombstone_t tombstone{};
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,122 +1,206 @@
|
||||
#ifndef ENTT_ENTITY_FWD_HPP
|
||||
#define ENTT_ENTITY_FWD_HPP
|
||||
|
||||
|
||||
#include "../config/config.h"
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @brief Default entity identifier. */
|
||||
enum class entity : id_type {};
|
||||
|
||||
template<typename Entity = entity, typename = std::allocator<Entity>>
|
||||
class basic_sparse_set;
|
||||
|
||||
template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
|
||||
class basic_storage;
|
||||
|
||||
template<typename Type>
|
||||
class sigh_storage_mixin;
|
||||
|
||||
/**
|
||||
* @brief Provides a common way to define storage types.
|
||||
* @tparam Type Storage value type.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
|
||||
struct storage_type {
|
||||
/*! @brief Type-to-storage conversion result. */
|
||||
using type = sigh_storage_mixin<basic_storage<Type, Entity, Allocator>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using storage_type_t = typename storage_type<Args...>::type;
|
||||
|
||||
/**
|
||||
* Type-to-storage conversion utility that preserves constness.
|
||||
* @tparam Type Storage value type, eventually const.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
|
||||
struct storage_for {
|
||||
/*! @brief Type-to-storage conversion result. */
|
||||
using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using storage_for_t = typename storage_for<Args...>::type;
|
||||
|
||||
template<typename Entity = entity, typename = std::allocator<Entity>>
|
||||
class basic_registry;
|
||||
|
||||
template<typename, typename, typename = void>
|
||||
class basic_view;
|
||||
|
||||
template<typename Type, typename = std::allocator<Type *>>
|
||||
class basic_runtime_view;
|
||||
|
||||
template<typename, typename, typename>
|
||||
class basic_group;
|
||||
|
||||
template<typename>
|
||||
class basic_observer;
|
||||
|
||||
template<typename>
|
||||
class basic_organizer;
|
||||
|
||||
template<typename, typename...>
|
||||
struct basic_handle;
|
||||
|
||||
template<typename>
|
||||
class basic_snapshot;
|
||||
|
||||
template<typename>
|
||||
class basic_snapshot_loader;
|
||||
|
||||
template<typename>
|
||||
class basic_continuous_loader;
|
||||
|
||||
/**
|
||||
* @brief Alias for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct exclude_t: type_list<Type...> {};
|
||||
|
||||
using exclude_t = type_list<Type...>;
|
||||
|
||||
/**
|
||||
* @brief Variable template for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
constexpr exclude_t<Type...> exclude{};
|
||||
|
||||
inline constexpr exclude_t<Type...> exclude{};
|
||||
|
||||
/**
|
||||
* @brief Alias for lists of observed components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct get_t: type_list<Type...>{};
|
||||
|
||||
using get_t = type_list<Type...>;
|
||||
|
||||
/**
|
||||
* @brief Variable template for lists of observed components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
constexpr get_t<Type...> get{};
|
||||
inline constexpr get_t<Type...> get{};
|
||||
|
||||
/**
|
||||
* @brief Alias for lists of owned components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
using owned_t = type_list<Type...>;
|
||||
|
||||
/*! @class basic_registry */
|
||||
template <typename>
|
||||
class basic_registry;
|
||||
|
||||
/*! @class basic_view */
|
||||
template<typename...>
|
||||
class basic_view;
|
||||
|
||||
/*! @class basic_runtime_view */
|
||||
template<typename>
|
||||
class basic_runtime_view;
|
||||
|
||||
/*! @class basic_group */
|
||||
template<typename...>
|
||||
class basic_group;
|
||||
|
||||
/*! @class basic_observer */
|
||||
template<typename>
|
||||
class basic_observer;
|
||||
|
||||
/*! @struct basic_actor */
|
||||
template <typename>
|
||||
struct basic_actor;
|
||||
|
||||
/*! @class basic_snapshot */
|
||||
template<typename>
|
||||
class basic_snapshot;
|
||||
|
||||
/*! @class basic_snapshot_loader */
|
||||
template<typename>
|
||||
class basic_snapshot_loader;
|
||||
|
||||
/*! @class basic_continuous_loader */
|
||||
template<typename>
|
||||
class basic_continuous_loader;
|
||||
/**
|
||||
* @brief Variable template for lists of owned components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
inline constexpr owned_t<Type...> owned{};
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
ENTT_OPAQUE_TYPE(entity, ENTT_ID_TYPE);
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using registry = basic_registry<entity>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using observer = basic_observer<entity>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using actor = basic_actor<entity>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot = basic_snapshot<entity>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot_loader = basic_snapshot_loader<entity>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using continuous_loader = basic_continuous_loader<entity>;
|
||||
using sparse_set = basic_sparse_set<>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Types Types of components iterated by the view.
|
||||
* @tparam Type Type of objects assigned to the entities.
|
||||
*/
|
||||
template<typename... Types>
|
||||
using view = basic_view<entity, Types...>;
|
||||
template<typename Type>
|
||||
using storage = basic_storage<Type>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using runtime_view = basic_runtime_view<entity>;
|
||||
using registry = basic_registry<>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using observer = basic_observer<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using organizer = basic_organizer<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using handle = basic_handle<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using const_handle = basic_handle<const registry>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Types Types of components iterated by the group.
|
||||
* @tparam Args Other template parameters.
|
||||
*/
|
||||
template<typename... Types>
|
||||
using group = basic_group<entity, Types...>;
|
||||
template<typename... Args>
|
||||
using handle_view = basic_handle<registry, Args...>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using const_handle_view = basic_handle<const registry, Args...>;
|
||||
|
||||
}
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot = basic_snapshot<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot_loader = basic_snapshot_loader<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using continuous_loader = basic_continuous_loader<registry>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Get Types of storage iterated by the view.
|
||||
* @tparam Exclude Types of storage used to filter the view.
|
||||
*/
|
||||
template<typename Get, typename Exclude = exclude_t<>>
|
||||
using view = basic_view<type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using runtime_view = basic_runtime_view<sparse_set>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using const_runtime_view = basic_runtime_view<const sparse_set>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Owned Types of storage _owned_ by the group.
|
||||
* @tparam Get Types of storage _observed_ by the group.
|
||||
* @tparam Exclude Types of storage used to filter the group.
|
||||
*/
|
||||
template<typename Owned, typename Get, typename Exclude>
|
||||
using group = basic_group<type_list_transform_t<Owned, storage_for>, type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
382
src/entt/entity/handle.hpp
Normal file
382
src/entt/entity/handle.hpp
Normal file
@@ -0,0 +1,382 @@
|
||||
#ifndef ENTT_ENTITY_HANDLE_HPP
|
||||
#define ENTT_ENTITY_HANDLE_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
class handle_storage_iterator final {
|
||||
template<typename Other>
|
||||
friend class handle_storage_iterator;
|
||||
|
||||
using underlying_type = std::remove_reference_t<typename It::value_type::second_type>;
|
||||
using entity_type = typename underlying_type::entity_type;
|
||||
|
||||
public:
|
||||
using value_type = typename std::iterator_traits<It>::value_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;
|
||||
|
||||
constexpr handle_storage_iterator() noexcept
|
||||
: entt{null},
|
||||
it{},
|
||||
last{} {}
|
||||
|
||||
constexpr handle_storage_iterator(entity_type value, It from, It to) noexcept
|
||||
: entt{value},
|
||||
it{from},
|
||||
last{to} {
|
||||
while(it != last && !it->second.contains(entt)) { ++it; }
|
||||
}
|
||||
|
||||
constexpr handle_storage_iterator &operator++() noexcept {
|
||||
while(++it != last && !it->second.contains(entt)) {}
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr handle_storage_iterator operator++(int) noexcept {
|
||||
handle_storage_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *it;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend constexpr bool operator==(const handle_storage_iterator<ILhs> &, const handle_storage_iterator<IRhs> &) noexcept;
|
||||
|
||||
private:
|
||||
entity_type entt;
|
||||
It it;
|
||||
It last;
|
||||
};
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator==(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Non-owning handle to an entity.
|
||||
*
|
||||
* Tiny wrapper around a registry and an entity.
|
||||
*
|
||||
* @tparam Registry Basic registry type.
|
||||
* @tparam Scope Types to which to restrict the scope of a handle.
|
||||
*/
|
||||
template<typename Registry, typename... Scope>
|
||||
struct basic_handle {
|
||||
/*! @brief Type of registry accepted by the handle. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename registry_type::version_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename registry_type::size_type;
|
||||
|
||||
/*! @brief Constructs an invalid handle. */
|
||||
basic_handle() noexcept
|
||||
: reg{},
|
||||
entt{null} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a handle from a given registry and entity.
|
||||
* @param ref An instance of the registry class.
|
||||
* @param value A valid identifier.
|
||||
*/
|
||||
basic_handle(registry_type &ref, entity_type value) noexcept
|
||||
: reg{&ref},
|
||||
entt{value} {}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to use to _visit_ a handle.
|
||||
*
|
||||
* The iterable object returns a pair that contains the name and a reference
|
||||
* to the current storage.<br/>
|
||||
* Returned storage are those that contain the entity associated with the
|
||||
* handle.
|
||||
*
|
||||
* @return An iterable object to use to _visit_ the handle.
|
||||
*/
|
||||
[[nodiscard]] auto storage() const noexcept {
|
||||
auto iterable = reg->storage();
|
||||
using iterator_type = internal::handle_storage_iterator<typename decltype(iterable)::iterator>;
|
||||
return iterable_adaptor{iterator_type{entt, iterable.begin(), iterable.end()}, iterator_type{entt, iterable.end(), iterable.end()}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a const handle from a non-const one.
|
||||
* @tparam Other A valid entity type (see entt_traits for more details).
|
||||
* @tparam Args Scope of the handle to construct.
|
||||
* @return A const handle referring to the same registry and the same
|
||||
* entity.
|
||||
*/
|
||||
template<typename Other, typename... Args>
|
||||
operator basic_handle<Other, Args...>() const noexcept {
|
||||
static_assert(std::is_same_v<Other, Registry> || std::is_same_v<std::remove_const_t<Other>, Registry>, "Invalid conversion between different handles");
|
||||
static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v<type_list<Scope...>, Args>))), "Invalid conversion between different handles");
|
||||
|
||||
return reg ? basic_handle<Other, Args...>{*reg, entt} : basic_handle<Other, Args...>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a handle to its underlying entity.
|
||||
* @return The contained identifier.
|
||||
*/
|
||||
[[nodiscard]] operator entity_type() const noexcept {
|
||||
return entity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle refers to non-null registry pointer and entity.
|
||||
* @return True if the handle refers to non-null registry and entity, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] explicit operator bool() const noexcept {
|
||||
return reg && reg->valid(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle refers to a valid entity or not.
|
||||
* @return True if the handle refers to a valid entity, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool valid() const {
|
||||
return reg->valid(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the underlying registry, if any.
|
||||
* @return A pointer to the underlying registry, if any.
|
||||
*/
|
||||
[[nodiscard]] registry_type *registry() const noexcept {
|
||||
return reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the entity associated with a handle.
|
||||
* @return The entity associated with the handle.
|
||||
*/
|
||||
[[nodiscard]] entity_type entity() const noexcept {
|
||||
return entt;
|
||||
}
|
||||
|
||||
/*! @brief Destroys the entity associated with a handle. */
|
||||
void destroy() {
|
||||
reg->destroy(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroys the entity associated with a handle.
|
||||
* @param version A desired version upon destruction.
|
||||
*/
|
||||
void destroy(const version_type version) {
|
||||
reg->destroy(entt, version);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns the given component to a handle.
|
||||
* @tparam Component Type of component to create.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return A reference to the newly created component.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template emplace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns or replaces the given component for a handle.
|
||||
* @tparam Component Type of component to assign or replace.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return A reference to the newly created component.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) emplace_or_replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template emplace_or_replace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Patches the given component for a handle.
|
||||
* @tparam Component Type of component to patch.
|
||||
* @tparam Func Types of the function objects to invoke.
|
||||
* @param func Valid function objects.
|
||||
* @return A reference to the patched component.
|
||||
*/
|
||||
template<typename Component, typename... Func>
|
||||
decltype(auto) patch(Func &&...func) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template patch<Component>(entt, std::forward<Func>(func)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the given component for a handle.
|
||||
* @tparam Component Type of component to replace.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return A reference to the component being replaced.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template replace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the given components from a handle.
|
||||
* @tparam Component Types of components to remove.
|
||||
* @return The number of components actually removed.
|
||||
*/
|
||||
template<typename... Component>
|
||||
size_type remove() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
|
||||
return reg->template remove<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases the given components from a handle.
|
||||
* @tparam Component Types of components to erase.
|
||||
*/
|
||||
template<typename... Component>
|
||||
void erase() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
|
||||
reg->template erase<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle has all the given components.
|
||||
* @tparam Component Components for which to perform the check.
|
||||
* @return True if the handle has all the components, false otherwise.
|
||||
*/
|
||||
template<typename... Component>
|
||||
[[nodiscard]] decltype(auto) all_of() const {
|
||||
return reg->template all_of<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle has at least one of the given components.
|
||||
* @tparam Component Components for which to perform the check.
|
||||
* @return True if the handle has at least one of the given components,
|
||||
* false otherwise.
|
||||
*/
|
||||
template<typename... Component>
|
||||
[[nodiscard]] decltype(auto) any_of() const {
|
||||
return reg->template any_of<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns references to the given components for a handle.
|
||||
* @tparam Component Types of components to get.
|
||||
* @return References to the components owned by the handle.
|
||||
*/
|
||||
template<typename... Component>
|
||||
[[nodiscard]] decltype(auto) get() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
|
||||
return reg->template get<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the given component for a handle.
|
||||
* @tparam Component Type of component to get.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return Reference to the component owned by the handle.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
[[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template get_or_emplace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns pointers to the given components for a handle.
|
||||
* @tparam Component Types of components to get.
|
||||
* @return Pointers to the components owned by the handle.
|
||||
*/
|
||||
template<typename... Component>
|
||||
[[nodiscard]] auto try_get() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
|
||||
return reg->template try_get<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle has components assigned.
|
||||
* @return True if the handle has no components assigned, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool orphan() const {
|
||||
return reg->orphan(entt);
|
||||
}
|
||||
|
||||
private:
|
||||
registry_type *reg;
|
||||
entity_type entt;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares two handles.
|
||||
* @tparam Args Scope of the first handle.
|
||||
* @tparam Other Scope of the second handle.
|
||||
* @param lhs A valid handle.
|
||||
* @param rhs A valid handle.
|
||||
* @return True if both handles refer to the same registry and the same
|
||||
* entity, false otherwise.
|
||||
*/
|
||||
template<typename... Args, typename... Other>
|
||||
[[nodiscard]] bool operator==(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
|
||||
return lhs.registry() == rhs.registry() && lhs.entity() == rhs.entity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two handles.
|
||||
* @tparam Args Scope of the first handle.
|
||||
* @tparam Other Scope of the second handle.
|
||||
* @param lhs A valid handle.
|
||||
* @param rhs A valid handle.
|
||||
* @return False if both handles refer to the same registry and the same
|
||||
* entity, true otherwise.
|
||||
*/
|
||||
template<typename... Args, typename... Other>
|
||||
[[nodiscard]] bool operator!=(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,117 +1,144 @@
|
||||
#ifndef ENTT_ENTITY_HELPER_HPP
|
||||
#define ENTT_ENTITY_HELPER_HPP
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../config/config.h"
|
||||
#include "registry.hpp"
|
||||
#include "../signal/delegate.hpp"
|
||||
#include "component.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include "group.hpp"
|
||||
#include "view.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Converts a registry to a view.
|
||||
* @tparam Const Constness of the accepted registry.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<bool Const, typename Entity>
|
||||
struct as_view {
|
||||
template<typename Registry>
|
||||
class as_view {
|
||||
template<typename... Get, typename... Exclude>
|
||||
auto dispatch(get_t<Get...>, exclude_t<Exclude...>) const {
|
||||
return reg.template view<constness_as_t<typename Get::value_type, Get>...>(exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{});
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Type of registry to convert. */
|
||||
using registry_type = std::conditional_t<Const, const entt::basic_registry<Entity>, entt::basic_registry<Entity>>;
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = std::remove_const_t<typename registry_type::entity_type>;
|
||||
|
||||
/**
|
||||
* @brief Constructs a converter for a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
as_view(registry_type &source) ENTT_NOEXCEPT: reg{source} {}
|
||||
as_view(registry_type &source) noexcept
|
||||
: reg{source} {}
|
||||
|
||||
/**
|
||||
* @brief Conversion function from a registry to a view.
|
||||
* @tparam Exclude Types of components used to filter the view.
|
||||
* @tparam Component Type of components used to construct the view.
|
||||
* @tparam Get Type of storage used to construct the view.
|
||||
* @tparam Exclude Types of storage used to filter the view.
|
||||
* @return A newly created view.
|
||||
*/
|
||||
template<typename Exclude, typename... Component>
|
||||
operator entt::basic_view<Entity, Exclude, Component...>() const {
|
||||
return reg.template view<Component...>(Exclude{});
|
||||
template<typename Get, typename Exclude>
|
||||
operator basic_view<Get, Exclude>() const {
|
||||
return dispatch(Get{}, Exclude{});
|
||||
}
|
||||
|
||||
private:
|
||||
registry_type ®
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
*
|
||||
* It allows to deduce the constness of a registry directly from the instance
|
||||
* provided to the constructor.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
as_view(basic_registry<Entity> &) ENTT_NOEXCEPT -> as_view<false, Entity>;
|
||||
|
||||
|
||||
/*! @copydoc as_view */
|
||||
template<typename Entity>
|
||||
as_view(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_view<true, Entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Converts a registry to a group.
|
||||
* @tparam Const Constness of the accepted registry.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<bool Const, typename Entity>
|
||||
struct as_group {
|
||||
template<typename Registry>
|
||||
class as_group {
|
||||
template<typename... Owned, typename... Get, typename... Exclude>
|
||||
auto dispatch(owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>) const {
|
||||
if constexpr(std::is_const_v<registry_type>) {
|
||||
return reg.template group_if_exists<typename Owned::value_type...>(get_t<typename Get::value_type...>{}, exclude_t<typename Exclude::value_type...>{});
|
||||
} else {
|
||||
return reg.template group<constness_as_t<typename Owned::value_type, Owned>...>(get_t<constness_as_t<typename Get::value_type, Get>...>{}, exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{});
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Type of registry to convert. */
|
||||
using registry_type = std::conditional_t<Const, const entt::basic_registry<Entity>, entt::basic_registry<Entity>>;
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = std::remove_const_t<typename registry_type::entity_type>;
|
||||
|
||||
/**
|
||||
* @brief Constructs a converter for a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
as_group(registry_type &source) ENTT_NOEXCEPT: reg{source} {}
|
||||
as_group(registry_type &source) noexcept
|
||||
: reg{source} {}
|
||||
|
||||
/**
|
||||
* @brief Conversion function from a registry to a group.
|
||||
* @tparam Exclude Types of components used to filter the group.
|
||||
* @tparam Get Types of components observed by the group.
|
||||
* @tparam Owned Types of components owned by the group.
|
||||
* @tparam Owned Types of _owned_ by the group.
|
||||
* @tparam Get Types of storage _observed_ by the group.
|
||||
* @tparam Exclude Types of storage used to filter the group.
|
||||
* @return A newly created group.
|
||||
*/
|
||||
template<typename Exclude, typename Get, typename... Owned>
|
||||
operator entt::basic_group<Entity, Exclude, Get, Owned...>() const {
|
||||
return reg.template group<Owned...>(Get{}, Exclude{});
|
||||
template<typename Owned, typename Get, typename Exclude>
|
||||
operator basic_group<Owned, Get, Exclude>() const {
|
||||
return dispatch(Owned{}, Get{}, Exclude{});
|
||||
}
|
||||
|
||||
private:
|
||||
registry_type ®
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
*
|
||||
* It allows to deduce the constness of a registry directly from the instance
|
||||
* provided to the constructor.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @brief Helper to create a listener that directly invokes a member function.
|
||||
* @tparam Member Member function to invoke on a component of the given type.
|
||||
* @tparam Registry Basic registry type.
|
||||
* @param reg A registry that contains the given entity and its components.
|
||||
* @param entt Entity from which to get the component.
|
||||
*/
|
||||
template<typename Entity>
|
||||
as_group(basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<false, Entity>;
|
||||
|
||||
|
||||
/*! @copydoc as_group */
|
||||
template<typename Entity>
|
||||
as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<true, Entity>;
|
||||
|
||||
|
||||
template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, Member>>>
|
||||
void invoke(Registry ®, const typename Registry::entity_type entt) {
|
||||
static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
|
||||
delegate<void(Registry &, const typename Registry::entity_type)> func;
|
||||
func.template connect<Member>(reg.template get<member_class_t<decltype(Member)>>(entt));
|
||||
func(reg, entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the entity associated with a given component.
|
||||
*
|
||||
* @warning
|
||||
* Currently, this function only works correctly with the default pool as it
|
||||
* makes assumptions about how the components are laid out.
|
||||
*
|
||||
* @tparam Registry Basic registry type.
|
||||
* @tparam Component Type of component.
|
||||
* @param reg A registry that contains the given entity and its components.
|
||||
* @param instance A valid component instance.
|
||||
* @return The entity associated with the given component.
|
||||
*/
|
||||
template<typename Registry, typename Component>
|
||||
typename Registry::entity_type to_entity(const Registry ®, const Component &instance) {
|
||||
const auto &storage = reg.template storage<Component>();
|
||||
const typename Registry::base_type &base = storage;
|
||||
const auto *addr = std::addressof(instance);
|
||||
|
||||
for(auto it = base.rbegin(), last = base.rend(); it < last; it += component_traits<Component>::page_size) {
|
||||
if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(component_traits<Component>::page_size)) {
|
||||
return *(it + dist);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
#ifndef ENTT_ENTITY_OBSERVER_HPP
|
||||
#define ENTT_ENTITY_OBSERVER_HPP
|
||||
|
||||
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include <utility>
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "registry.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "../signal/delegate.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include "storage.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/*! @brief Grouping matcher. */
|
||||
template<typename...>
|
||||
struct matcher {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Collector.
|
||||
*
|
||||
@@ -32,7 +26,6 @@ struct matcher {};
|
||||
template<typename...>
|
||||
struct basic_collector;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Collector.
|
||||
*
|
||||
@@ -50,7 +43,7 @@ struct basic_collector<> {
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename... AllOf, typename... NoneOf>
|
||||
static constexpr auto group(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
|
||||
static constexpr auto group(exclude_t<NoneOf...> = {}) noexcept {
|
||||
return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>>{};
|
||||
}
|
||||
|
||||
@@ -60,7 +53,7 @@ struct basic_collector<> {
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename AnyOf>
|
||||
static constexpr auto replace() ENTT_NOEXCEPT {
|
||||
static constexpr auto update() noexcept {
|
||||
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>>{};
|
||||
}
|
||||
};
|
||||
@@ -85,7 +78,7 @@ struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename... AllOf, typename... NoneOf>
|
||||
static constexpr auto group(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
|
||||
static constexpr auto group(exclude_t<NoneOf...> = {}) noexcept {
|
||||
return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>, current_type, Other...>{};
|
||||
}
|
||||
|
||||
@@ -95,7 +88,7 @@ struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename AnyOf>
|
||||
static constexpr auto replace() ENTT_NOEXCEPT {
|
||||
static constexpr auto update() noexcept {
|
||||
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>, current_type, Other...>{};
|
||||
}
|
||||
|
||||
@@ -106,16 +99,14 @@ struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename... AllOf, typename... NoneOf>
|
||||
static constexpr auto where(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
|
||||
static constexpr auto where(exclude_t<NoneOf...> = {}) noexcept {
|
||||
using extended_type = matcher<type_list<Reject..., NoneOf...>, type_list<Require..., AllOf...>, Rule...>;
|
||||
return basic_collector<extended_type, Other...>{};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*! @brief Variable template used to ease the definition of collectors. */
|
||||
constexpr basic_collector<> collector{};
|
||||
|
||||
inline constexpr basic_collector<> collector{};
|
||||
|
||||
/**
|
||||
* @brief Observer.
|
||||
@@ -129,8 +120,8 @@ constexpr basic_collector<> collector{};
|
||||
* collector:
|
||||
*
|
||||
* * Observing matcher: an observer will return at least all the living entities
|
||||
* for which one or more of the given components have been explicitly
|
||||
* replaced and not yet destroyed.
|
||||
* for which one or more of the given components have been updated and not yet
|
||||
* destroyed.
|
||||
* * Grouping matcher: an observer will return at least all the living entities
|
||||
* that would have entered the given group if it existed and that would have
|
||||
* not yet left it.
|
||||
@@ -164,11 +155,11 @@ constexpr basic_collector<> collector{};
|
||||
* from the registry before being destroyed to avoid crashes due to dangling
|
||||
* pointers.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
class basic_observer {
|
||||
using payload_type = std::uint32_t;
|
||||
template<typename Registry>
|
||||
class basic_observer: private basic_storage<std::uint32_t, typename Registry::entity_type> {
|
||||
using base_type = basic_storage<std::uint32_t, typename Registry::entity_type>;
|
||||
|
||||
template<typename>
|
||||
struct matcher_handler;
|
||||
@@ -176,70 +167,78 @@ class basic_observer {
|
||||
template<typename... Reject, typename... Require, typename AnyOf>
|
||||
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
|
||||
template<std::size_t Index>
|
||||
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> ®, const Entity entt) {
|
||||
if(reg.template has<Require...>(entt) && !reg.template any<Reject...>(entt)) {
|
||||
if(auto *comp = obs.view.try_get(entt); !comp) {
|
||||
obs.view.construct(entt);
|
||||
static void maybe_valid_if(basic_observer &obs, Registry ®, const typename Registry::entity_type entt) {
|
||||
if(reg.template all_of<Require...>(entt) && !reg.template any_of<Reject...>(entt)) {
|
||||
if(!obs.contains(entt)) {
|
||||
obs.emplace(entt);
|
||||
}
|
||||
|
||||
obs.view.get(entt) |= (1 << Index);
|
||||
obs.get(entt) |= (1 << Index);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
|
||||
if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
|
||||
obs.view.destroy(entt);
|
||||
static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) {
|
||||
if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) {
|
||||
obs.erase(entt);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void connect(basic_observer &obs, basic_registry<Entity> ®) {
|
||||
static void connect(basic_observer &obs, Registry ®) {
|
||||
(reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
|
||||
(reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
|
||||
reg.template on_replace<AnyOf>().template connect<&maybe_valid_if<Index>>(obs);
|
||||
reg.template on_update<AnyOf>().template connect<&maybe_valid_if<Index>>(obs);
|
||||
reg.template on_destroy<AnyOf>().template connect<&discard_if<Index>>(obs);
|
||||
}
|
||||
|
||||
static void disconnect(basic_observer &obs, basic_registry<Entity> ®) {
|
||||
static void disconnect(basic_observer &obs, Registry ®) {
|
||||
(reg.template on_destroy<Require>().disconnect(obs), ...);
|
||||
(reg.template on_construct<Reject>().disconnect(obs), ...);
|
||||
reg.template on_replace<AnyOf>().disconnect(obs);
|
||||
reg.template on_update<AnyOf>().disconnect(obs);
|
||||
reg.template on_destroy<AnyOf>().disconnect(obs);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
|
||||
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> {
|
||||
template<std::size_t Index>
|
||||
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> ®, const Entity entt) {
|
||||
if(reg.template has<AllOf..., Require...>(entt) && !reg.template any<NoneOf..., Reject...>(entt)) {
|
||||
if(auto *comp = obs.view.try_get(entt); !comp) {
|
||||
obs.view.construct(entt);
|
||||
template<std::size_t Index, typename... Ignore>
|
||||
static void maybe_valid_if(basic_observer &obs, Registry ®, const typename Registry::entity_type entt) {
|
||||
auto condition = [®, entt]() {
|
||||
if constexpr(sizeof...(Ignore) == 0) {
|
||||
return reg.template all_of<AllOf..., Require...>(entt) && !reg.template any_of<NoneOf..., Reject...>(entt);
|
||||
} else {
|
||||
return reg.template all_of<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !reg.template any_of<NoneOf>(entt)) && ...) && !reg.template any_of<Reject...>(entt);
|
||||
}
|
||||
};
|
||||
|
||||
if(condition()) {
|
||||
if(!obs.contains(entt)) {
|
||||
obs.emplace(entt);
|
||||
}
|
||||
|
||||
obs.view.get(entt) |= (1 << Index);
|
||||
obs.get(entt) |= (1 << Index);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
|
||||
if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
|
||||
obs.view.destroy(entt);
|
||||
static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) {
|
||||
if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) {
|
||||
obs.erase(entt);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void connect(basic_observer &obs, basic_registry<Entity> ®) {
|
||||
static void connect(basic_observer &obs, Registry ®) {
|
||||
(reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
|
||||
(reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
|
||||
(reg.template on_construct<AllOf>().template connect<&maybe_valid_if<Index>>(obs), ...);
|
||||
(reg.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index>>(obs), ...);
|
||||
(reg.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index, NoneOf>>(obs), ...);
|
||||
(reg.template on_destroy<AllOf>().template connect<&discard_if<Index>>(obs), ...);
|
||||
(reg.template on_construct<NoneOf>().template connect<&discard_if<Index>>(obs), ...);
|
||||
}
|
||||
|
||||
static void disconnect(basic_observer &obs, basic_registry<Entity> ®) {
|
||||
static void disconnect(basic_observer &obs, Registry ®) {
|
||||
(reg.template on_destroy<Require>().disconnect(obs), ...);
|
||||
(reg.template on_construct<Reject>().disconnect(obs), ...);
|
||||
(reg.template on_construct<AllOf>().disconnect(obs), ...);
|
||||
@@ -250,29 +249,30 @@ class basic_observer {
|
||||
};
|
||||
|
||||
template<typename... Matcher>
|
||||
static void disconnect(basic_observer &obs, basic_registry<Entity> ®) {
|
||||
static void disconnect(Registry ®, basic_observer &obs) {
|
||||
(matcher_handler<Matcher>::disconnect(obs, reg), ...);
|
||||
}
|
||||
|
||||
template<typename... Matcher, std::size_t... Index>
|
||||
void connect(basic_registry<Entity> ®, std::index_sequence<Index...>) {
|
||||
static_assert(sizeof...(Matcher) < std::numeric_limits<payload_type>::digits);
|
||||
void connect(Registry ®, std::index_sequence<Index...>) {
|
||||
static_assert(sizeof...(Matcher) < std::numeric_limits<typename base_type::value_type>::digits, "Too many matchers");
|
||||
(matcher_handler<Matcher>::template connect<Index>(*this, reg), ...);
|
||||
release = &basic_observer::disconnect<Matcher...>;
|
||||
release.template connect<&basic_observer::disconnect<Matcher...>>(reg);
|
||||
}
|
||||
|
||||
public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Input iterator type. */
|
||||
using iterator_type = typename sparse_set<Entity>::iterator_type;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename registry_type::base_type::iterator;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_observer()
|
||||
: target{}, release{}, view{}
|
||||
{}
|
||||
: release{} {}
|
||||
|
||||
/*! @brief Default copy constructor, deleted on purpose. */
|
||||
basic_observer(const basic_observer &) = delete;
|
||||
@@ -285,11 +285,8 @@ public:
|
||||
* @param reg A valid reference to a registry.
|
||||
*/
|
||||
template<typename... Matcher>
|
||||
basic_observer(basic_registry<entity_type> ®, basic_collector<Matcher...>)
|
||||
: target{®},
|
||||
release{},
|
||||
view{}
|
||||
{
|
||||
basic_observer(registry_type ®, basic_collector<Matcher...>)
|
||||
: basic_observer{} {
|
||||
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
|
||||
}
|
||||
|
||||
@@ -300,13 +297,13 @@ public:
|
||||
* @brief Default copy assignment operator, deleted on purpose.
|
||||
* @return This observer.
|
||||
*/
|
||||
basic_observer & operator=(const basic_observer &) = delete;
|
||||
basic_observer &operator=(const basic_observer &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator, deleted on purpose.
|
||||
* @return This observer.
|
||||
*/
|
||||
basic_observer & operator=(basic_observer &&) = delete;
|
||||
basic_observer &operator=(basic_observer &&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Connects an observer to a given registry.
|
||||
@@ -314,18 +311,17 @@ public:
|
||||
* @param reg A valid reference to a registry.
|
||||
*/
|
||||
template<typename... Matcher>
|
||||
void connect(basic_registry<entity_type> ®, basic_collector<Matcher...>) {
|
||||
void connect(registry_type ®, basic_collector<Matcher...>) {
|
||||
disconnect();
|
||||
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
|
||||
target = ®
|
||||
view.clear();
|
||||
base_type::clear();
|
||||
}
|
||||
|
||||
/*! @brief Disconnects an observer from the registry it keeps track of. */
|
||||
void disconnect() {
|
||||
if(release) {
|
||||
release(*this, *target);
|
||||
release = nullptr;
|
||||
release(*this);
|
||||
release.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,32 +329,32 @@ public:
|
||||
* @brief Returns the number of elements in an observer.
|
||||
* @return Number of elements.
|
||||
*/
|
||||
size_type size() const ENTT_NOEXCEPT {
|
||||
return view.size();
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return base_type::size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether an observer is empty.
|
||||
* @return True if the observer is empty, false otherwise.
|
||||
*/
|
||||
bool empty() const ENTT_NOEXCEPT {
|
||||
return view.empty();
|
||||
[[nodiscard]] bool empty() const noexcept {
|
||||
return base_type::empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Direct access to the list of entities of the observer.
|
||||
*
|
||||
* The returned pointer is such that range `[data(), data() + size()]` is
|
||||
* The returned pointer is such that range `[data(), data() + size())` is
|
||||
* always a valid range, even if the container is empty.
|
||||
*
|
||||
* @note
|
||||
* There are no guarantees on the order of the entities. Use `begin` and
|
||||
* `end` if you want to iterate the observer in the expected order.
|
||||
* Entities are in the reverse order as returned by the `begin`/`end`
|
||||
* iterators.
|
||||
*
|
||||
* @return A pointer to the array of entities.
|
||||
*/
|
||||
const entity_type * data() const ENTT_NOEXCEPT {
|
||||
return view.data();
|
||||
[[nodiscard]] const entity_type *data() const noexcept {
|
||||
return base_type::data();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -369,8 +365,8 @@ public:
|
||||
*
|
||||
* @return An iterator to the first entity of the observer.
|
||||
*/
|
||||
iterator_type begin() const ENTT_NOEXCEPT {
|
||||
return view.sparse_set<entity_type>::begin();
|
||||
[[nodiscard]] iterator begin() const noexcept {
|
||||
return base_type::base_type::begin();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -383,13 +379,13 @@ public:
|
||||
* @return An iterator to the entity following the last entity of the
|
||||
* observer.
|
||||
*/
|
||||
iterator_type end() const ENTT_NOEXCEPT {
|
||||
return view.sparse_set<entity_type>::end();
|
||||
[[nodiscard]] iterator end() const noexcept {
|
||||
return base_type::base_type::end();
|
||||
}
|
||||
|
||||
/*! @brief Clears the underlying container. */
|
||||
void clear() ENTT_NOEXCEPT {
|
||||
view.clear();
|
||||
void clear() noexcept {
|
||||
base_type::clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -407,8 +403,6 @@ public:
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
static_assert(std::is_invocable_v<Func, entity_type>);
|
||||
|
||||
for(const auto entity: *this) {
|
||||
func(entity);
|
||||
}
|
||||
@@ -430,13 +424,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
basic_registry<entity_type> *target;
|
||||
void(* release)(basic_observer &, basic_registry<entity_type> &);
|
||||
storage<entity_type, payload_type> view;
|
||||
delegate<void(basic_observer &)> release;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
412
src/entt/entity/organizer.hpp
Normal file
412
src/entt/entity/organizer.hpp
Normal file
@@ -0,0 +1,412 @@
|
||||
#ifndef ENTT_ENTITY_ORGANIZER_HPP
|
||||
#define ENTT_ENTITY_ORGANIZER_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "../graph/adjacency_matrix.hpp"
|
||||
#include "../graph/flow.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "helper.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename>
|
||||
struct is_view: std::false_type {};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_view<basic_view<Args...>>: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool is_view_v = is_view<Type>::value;
|
||||
|
||||
template<typename Type, typename Override>
|
||||
struct unpack_type {
|
||||
using ro = std::conditional_t<
|
||||
type_list_contains_v<Override, const Type> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
|
||||
type_list<std::remove_const_t<Type>>,
|
||||
type_list<>>;
|
||||
|
||||
using rw = std::conditional_t<
|
||||
type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, const Type>),
|
||||
type_list<Type>,
|
||||
type_list<>>;
|
||||
};
|
||||
|
||||
template<typename... Args, typename... Override>
|
||||
struct unpack_type<basic_registry<Args...>, type_list<Override...>> {
|
||||
using ro = type_list<>;
|
||||
using rw = type_list<>;
|
||||
};
|
||||
|
||||
template<typename... Args, typename... Override>
|
||||
struct unpack_type<const basic_registry<Args...>, type_list<Override...>>
|
||||
: unpack_type<basic_registry<Args...>, type_list<Override...>> {};
|
||||
|
||||
template<typename... Get, typename... Exclude, typename... Override>
|
||||
struct unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {
|
||||
using ro = type_list_cat_t<type_list<typename Exclude::value_type...>, typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::ro...>;
|
||||
using rw = type_list_cat_t<typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::rw...>;
|
||||
};
|
||||
|
||||
template<typename... Get, typename... Exclude, typename... Override>
|
||||
struct unpack_type<const basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>>
|
||||
: unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {};
|
||||
|
||||
template<typename, typename>
|
||||
struct resource_traits;
|
||||
|
||||
template<typename... Args, typename... Req>
|
||||
struct resource_traits<type_list<Args...>, type_list<Req...>> {
|
||||
using args = type_list<std::remove_const_t<Args>...>;
|
||||
using ro = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::ro..., typename unpack_type<Req, type_list<>>::ro...>;
|
||||
using rw = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::rw..., typename unpack_type<Req, type_list<>>::rw...>;
|
||||
};
|
||||
|
||||
template<typename... Req, typename Ret, typename... Args>
|
||||
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(Args...));
|
||||
|
||||
template<typename... Req, typename Ret, typename Type, typename... Args>
|
||||
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, Args...));
|
||||
|
||||
template<typename... Req, typename Ret, typename Class, typename... Args>
|
||||
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...));
|
||||
|
||||
template<typename... Req, typename Ret, typename Class, typename... Args>
|
||||
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Utility class for creating a static task graph.
|
||||
*
|
||||
* This class offers minimal support (but sufficient in many cases) for creating
|
||||
* an execution graph from functions and their requirements on resources.<br/>
|
||||
* Note that the resulting tasks aren't executed in any case. This isn't the
|
||||
* goal of the tool. Instead, they are returned to the user in the form of a
|
||||
* graph that allows for safe execution.
|
||||
*
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Registry>
|
||||
class basic_organizer final {
|
||||
using callback_type = void(const void *, Registry &);
|
||||
using prepare_type = void(Registry &);
|
||||
using dependency_type = std::size_t(const bool, const type_info **, const std::size_t);
|
||||
|
||||
struct vertex_data final {
|
||||
std::size_t ro_count{};
|
||||
std::size_t rw_count{};
|
||||
const char *name{};
|
||||
const void *payload{};
|
||||
callback_type *callback{};
|
||||
dependency_type *dependency;
|
||||
prepare_type *prepare{};
|
||||
const type_info *info{};
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static decltype(auto) extract(Registry ®) {
|
||||
if constexpr(std::is_same_v<Type, Registry>) {
|
||||
return reg;
|
||||
} else if constexpr(internal::is_view_v<Type>) {
|
||||
return as_view{reg};
|
||||
} else {
|
||||
return reg.ctx().template emplace<std::remove_reference_t<Type>>();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] static auto to_args(Registry ®, type_list<Args...>) {
|
||||
return std::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
|
||||
}
|
||||
|
||||
template<typename... Type>
|
||||
static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const std::size_t count) {
|
||||
if constexpr(sizeof...(Type) == 0u) {
|
||||
return {};
|
||||
} else {
|
||||
const type_info *info[sizeof...(Type)]{&type_id<Type>()...};
|
||||
const auto length = count < sizeof...(Type) ? count : sizeof...(Type);
|
||||
|
||||
for(std::size_t pos{}; pos < length; ++pos) {
|
||||
buffer[pos] = info[pos];
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... RO, typename... RW>
|
||||
void track_dependencies(std::size_t index, const bool requires_registry, type_list<RO...>, type_list<RW...>) {
|
||||
builder.bind(static_cast<id_type>(index));
|
||||
builder.set(type_hash<Registry>::value(), requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u));
|
||||
(builder.ro(type_hash<RO>::value()), ...);
|
||||
(builder.rw(type_hash<RW>::value()), ...);
|
||||
}
|
||||
|
||||
public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Raw task function type. */
|
||||
using function_type = callback_type;
|
||||
|
||||
/*! @brief Vertex type of a task graph defined as an adjacency list. */
|
||||
struct vertex {
|
||||
/**
|
||||
* @brief Constructs a vertex of the task graph.
|
||||
* @param vtype True if the vertex is a top-level one, false otherwise.
|
||||
* @param data The data associated with the vertex.
|
||||
* @param edges The indices of the children in the adjacency list.
|
||||
*/
|
||||
vertex(const bool vtype, vertex_data data, std::vector<std::size_t> edges)
|
||||
: is_top_level{vtype},
|
||||
node{std::move(data)},
|
||||
reachable{std::move(edges)} {}
|
||||
|
||||
/**
|
||||
* @brief Fills a buffer with the type info objects for the writable
|
||||
* resources of a vertex.
|
||||
* @param buffer A buffer pre-allocated by the user.
|
||||
* @param length The length of the user-supplied buffer.
|
||||
* @return The number of type info objects written to the buffer.
|
||||
*/
|
||||
size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept {
|
||||
return node.dependency(false, buffer, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fills a buffer with the type info objects for the read-only
|
||||
* resources of a vertex.
|
||||
* @param buffer A buffer pre-allocated by the user.
|
||||
* @param length The length of the user-supplied buffer.
|
||||
* @return The number of type info objects written to the buffer.
|
||||
*/
|
||||
size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept {
|
||||
return node.dependency(true, buffer, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of read-only resources of a vertex.
|
||||
* @return The number of read-only resources of the vertex.
|
||||
*/
|
||||
size_type ro_count() const noexcept {
|
||||
return node.ro_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of writable resources of a vertex.
|
||||
* @return The number of writable resources of the vertex.
|
||||
*/
|
||||
size_type rw_count() const noexcept {
|
||||
return node.rw_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a vertex is also a top-level one.
|
||||
* @return True if the vertex is a top-level one, false otherwise.
|
||||
*/
|
||||
bool top_level() const noexcept {
|
||||
return is_top_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a type info object associated with a vertex.
|
||||
* @return A properly initialized type info object.
|
||||
*/
|
||||
const type_info &info() const noexcept {
|
||||
return *node.info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a user defined name associated with a vertex, if any.
|
||||
* @return The user defined name associated with the vertex, if any.
|
||||
*/
|
||||
const char *name() const noexcept {
|
||||
return node.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function associated with a vertex.
|
||||
* @return The function associated with the vertex.
|
||||
*/
|
||||
function_type *callback() const noexcept {
|
||||
return node.callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the payload associated with a vertex, if any.
|
||||
* @return The payload associated with the vertex, if any.
|
||||
*/
|
||||
const void *data() const noexcept {
|
||||
return node.payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the list of nodes reachable from a given vertex.
|
||||
* @return The list of nodes reachable from the vertex.
|
||||
*/
|
||||
const std::vector<std::size_t> &children() const noexcept {
|
||||
return reachable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepares a registry and assures that all required resources
|
||||
* are properly instantiated before using them.
|
||||
* @param reg A valid registry.
|
||||
*/
|
||||
void prepare(registry_type ®) const {
|
||||
node.prepare ? node.prepare(reg) : void();
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_top_level;
|
||||
vertex_data node;
|
||||
std::vector<std::size_t> reachable;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Adds a free function to the task list.
|
||||
* @tparam Candidate Function to add to the task list.
|
||||
* @tparam Req Additional requirements and/or override resource access mode.
|
||||
* @param name Optional name to associate with the task.
|
||||
*/
|
||||
template<auto Candidate, typename... Req>
|
||||
void emplace(const char *name = nullptr) {
|
||||
using resource_type = decltype(internal::free_function_to_resource_traits<Req...>(Candidate));
|
||||
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
|
||||
|
||||
callback_type *callback = +[](const void *, registry_type ®) {
|
||||
std::apply(Candidate, to_args(reg, typename resource_type::args{}));
|
||||
};
|
||||
|
||||
vertex_data vdata{
|
||||
resource_type::ro::size,
|
||||
resource_type::rw::size,
|
||||
name,
|
||||
nullptr,
|
||||
callback,
|
||||
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
+[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); },
|
||||
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
|
||||
|
||||
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
vertices.push_back(std::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a free function with payload or a member function with an
|
||||
* instance to the task list.
|
||||
* @tparam Candidate Function or member to add to the task list.
|
||||
* @tparam Req Additional requirements and/or override resource access mode.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid object that fits the purpose.
|
||||
* @param name Optional name to associate with the task.
|
||||
*/
|
||||
template<auto Candidate, typename... Req, typename Type>
|
||||
void emplace(Type &value_or_instance, const char *name = nullptr) {
|
||||
using resource_type = decltype(internal::constrained_function_to_resource_traits<Req...>(Candidate));
|
||||
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
|
||||
|
||||
callback_type *callback = +[](const void *payload, registry_type ®) {
|
||||
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
|
||||
std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
|
||||
};
|
||||
|
||||
vertex_data vdata{
|
||||
resource_type::ro::size,
|
||||
resource_type::rw::size,
|
||||
name,
|
||||
&value_or_instance,
|
||||
callback,
|
||||
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
+[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); },
|
||||
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
|
||||
|
||||
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
vertices.push_back(std::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an user defined function with optional payload to the task
|
||||
* list.
|
||||
* @tparam Req Additional requirements and/or override resource access mode.
|
||||
* @param func Function to add to the task list.
|
||||
* @param payload User defined arbitrary data.
|
||||
* @param name Optional name to associate with the task.
|
||||
*/
|
||||
template<typename... Req>
|
||||
void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) {
|
||||
using resource_type = internal::resource_traits<type_list<>, type_list<Req...>>;
|
||||
track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
|
||||
vertex_data vdata{
|
||||
resource_type::ro::size,
|
||||
resource_type::rw::size,
|
||||
name,
|
||||
payload,
|
||||
func,
|
||||
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
nullptr,
|
||||
&type_id<void>()};
|
||||
|
||||
vertices.push_back(std::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates a task graph for the current content.
|
||||
* @return The adjacency list of the task graph.
|
||||
*/
|
||||
std::vector<vertex> graph() {
|
||||
std::vector<vertex> adjacency_list{};
|
||||
adjacency_list.reserve(vertices.size());
|
||||
auto adjacency_matrix = builder.graph();
|
||||
|
||||
for(auto curr: adjacency_matrix.vertices()) {
|
||||
const auto iterable = adjacency_matrix.in_edges(curr);
|
||||
std::vector<std::size_t> reachable{};
|
||||
|
||||
for(auto &&edge: adjacency_matrix.out_edges(curr)) {
|
||||
reachable.push_back(edge.second);
|
||||
}
|
||||
|
||||
adjacency_list.emplace_back(iterable.cbegin() == iterable.cend(), vertices[curr], std::move(reachable));
|
||||
}
|
||||
|
||||
return adjacency_list;
|
||||
}
|
||||
|
||||
/*! @brief Erases all elements from a container. */
|
||||
void clear() {
|
||||
builder.clear();
|
||||
vertices.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<vertex_data> vertices;
|
||||
flow builder;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,108 @@
|
||||
#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
|
||||
#define ENTT_ENTITY_RUNTIME_VIEW_HPP
|
||||
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "sparse_set.hpp"
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Set>
|
||||
class runtime_view_iterator final {
|
||||
using iterator_type = typename Set::iterator;
|
||||
|
||||
[[nodiscard]] bool valid() const {
|
||||
return (!tombstone_check || *it != tombstone)
|
||||
&& std::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
|
||||
&& std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
|
||||
}
|
||||
|
||||
public:
|
||||
using difference_type = typename iterator_type::difference_type;
|
||||
using value_type = typename iterator_type::value_type;
|
||||
using pointer = typename iterator_type::pointer;
|
||||
using reference = typename iterator_type::reference;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
|
||||
constexpr runtime_view_iterator() noexcept
|
||||
: pools{},
|
||||
filter{},
|
||||
it{},
|
||||
tombstone_check{} {}
|
||||
|
||||
runtime_view_iterator(const std::vector<Set *> &cpools, const std::vector<Set *> &ignore, iterator_type curr) noexcept
|
||||
: pools{&cpools},
|
||||
filter{&ignore},
|
||||
it{curr},
|
||||
tombstone_check{pools->size() == 1u && (*pools)[0u]->policy() == deletion_policy::in_place} {
|
||||
if(it != (*pools)[0]->end() && !valid()) {
|
||||
++(*this);
|
||||
}
|
||||
}
|
||||
|
||||
runtime_view_iterator &operator++() {
|
||||
while(++it != (*pools)[0]->end() && !valid()) {}
|
||||
return *this;
|
||||
}
|
||||
|
||||
runtime_view_iterator operator++(int) {
|
||||
runtime_view_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
runtime_view_iterator &operator--() {
|
||||
while(--it != (*pools)[0]->begin() && !valid()) {}
|
||||
return *this;
|
||||
}
|
||||
|
||||
runtime_view_iterator operator--(int) {
|
||||
runtime_view_iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const noexcept {
|
||||
return it.operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const noexcept {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const runtime_view_iterator &other) const noexcept {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator!=(const runtime_view_iterator &other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<Set *> *pools;
|
||||
const std::vector<Set *> *filter;
|
||||
iterator_type it;
|
||||
bool tombstone_check;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* @brief Runtime view.
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Generic runtime view.
|
||||
*
|
||||
* Runtime views iterate over those entities that have at least all the given
|
||||
* components in their bags. During initialization, a runtime view looks at the
|
||||
@@ -52,122 +137,130 @@ namespace entt {
|
||||
* Lifetime of a view must not overcome that of the registry that generated it.
|
||||
* In any other case, attempting to use a view results in undefined behavior.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Type Common base type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Entity>
|
||||
template<typename Type, typename Allocator>
|
||||
class basic_runtime_view {
|
||||
/*! @brief A registry is allowed to create views. */
|
||||
friend class basic_registry<Entity>;
|
||||
|
||||
using underlying_iterator_type = typename sparse_set<Entity>::iterator_type;
|
||||
|
||||
class iterator {
|
||||
friend class basic_runtime_view<Entity>;
|
||||
|
||||
using direct_type = std::vector<const sparse_set<Entity> *>;
|
||||
|
||||
iterator(const direct_type *all, underlying_iterator_type curr) ENTT_NOEXCEPT
|
||||
: pools{all},
|
||||
it{curr}
|
||||
{
|
||||
if(it != (*pools)[0]->end() && !valid()) {
|
||||
++(*this);
|
||||
}
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
return std::all_of(pools->begin()++, pools->end(), [entt = *it](const auto *curr) {
|
||||
return curr->has(entt);
|
||||
});
|
||||
}
|
||||
|
||||
public:
|
||||
using difference_type = typename underlying_iterator_type::difference_type;
|
||||
using value_type = typename underlying_iterator_type::value_type;
|
||||
using pointer = typename underlying_iterator_type::pointer;
|
||||
using reference = typename underlying_iterator_type::reference;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
|
||||
iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
iterator & operator++() {
|
||||
while(++it != (*pools)[0]->end() && !valid());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) {
|
||||
iterator orig = *this;
|
||||
return operator++(), orig;
|
||||
}
|
||||
|
||||
iterator & operator--() ENTT_NOEXCEPT {
|
||||
while(--it != (*pools)[0]->begin() && !valid());
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator--(int) ENTT_NOEXCEPT {
|
||||
iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
bool operator==(const iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.it == it;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
pointer operator->() const {
|
||||
return it.operator->();
|
||||
}
|
||||
|
||||
reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
const direct_type *pools;
|
||||
underlying_iterator_type it;
|
||||
};
|
||||
|
||||
basic_runtime_view(std::vector<const sparse_set<Entity> *> others) ENTT_NOEXCEPT
|
||||
: pools{std::move(others)}
|
||||
{
|
||||
const auto it = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
|
||||
return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
|
||||
});
|
||||
|
||||
// brings the best candidate (if any) on front of the vector
|
||||
std::rotate(pools.begin(), it, pools.end());
|
||||
}
|
||||
|
||||
bool valid() const {
|
||||
return !pools.empty() && pools.front();
|
||||
}
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type");
|
||||
using container_type = std::vector<Type *, Allocator>;
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
using entity_type = typename Type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Input iterator type. */
|
||||
using iterator_type = iterator;
|
||||
/*! @brief Common type among all storage types. */
|
||||
using base_type = Type;
|
||||
/*! @brief Bidirectional iterator type. */
|
||||
using iterator = internal::runtime_view_iterator<base_type>;
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid views. */
|
||||
basic_runtime_view() noexcept
|
||||
: basic_runtime_view{allocator_type{}} {}
|
||||
|
||||
/**
|
||||
* @brief Estimates the number of entities that have the given components.
|
||||
* @return Estimated number of entities that have the given components.
|
||||
* @brief Constructs an empty, invalid view with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
size_type size() const {
|
||||
return valid() ? pools.front()->size() : size_type{};
|
||||
explicit basic_runtime_view(const allocator_type &allocator)
|
||||
: pools{allocator},
|
||||
filter{allocator} {}
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
basic_runtime_view(const basic_runtime_view &) = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_runtime_view(const basic_runtime_view &other, const allocator_type &allocator)
|
||||
: pools{other.pools, allocator},
|
||||
filter{other.filter, allocator} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_runtime_view(basic_runtime_view &&) noexcept(std::is_nothrow_move_constructible_v<container_type>) = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_runtime_view(basic_runtime_view &&other, const allocator_type &allocator)
|
||||
: pools{std::move(other.pools), allocator},
|
||||
filter{std::move(other.filter), allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator.
|
||||
* @return This container.
|
||||
*/
|
||||
basic_runtime_view &operator=(const basic_runtime_view &) = default;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @return This container.
|
||||
*/
|
||||
basic_runtime_view &operator=(basic_runtime_view &&) noexcept(std::is_nothrow_move_assignable_v<container_type>) = default;
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given view.
|
||||
* @param other View to exchange the content with.
|
||||
*/
|
||||
void swap(basic_runtime_view &other) {
|
||||
using std::swap;
|
||||
swap(pools, other.pools);
|
||||
swap(filter, other.filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the view is definitely empty.
|
||||
* @return True if the view is definitely empty, false otherwise.
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
bool empty() const {
|
||||
return !valid() || pools.front()->empty();
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return pools.get_allocator();
|
||||
}
|
||||
|
||||
/*! @brief Clears the view. */
|
||||
void clear() {
|
||||
pools.clear();
|
||||
filter.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends an opaque storage object to a runtime view.
|
||||
* @param base An opaque reference to a storage object.
|
||||
* @return This runtime view.
|
||||
*/
|
||||
basic_runtime_view &iterate(base_type &base) {
|
||||
if(pools.empty() || !(base.size() < pools[0u]->size())) {
|
||||
pools.push_back(&base);
|
||||
} else {
|
||||
pools.push_back(std::exchange(pools[0u], &base));
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an opaque storage object as a filter of a runtime view.
|
||||
* @param base An opaque reference to a storage object.
|
||||
* @return This runtime view.
|
||||
*/
|
||||
basic_runtime_view &exclude(base_type &base) {
|
||||
filter.push_back(&base);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Estimates the number of entities iterated by the view.
|
||||
* @return Estimated number of entities iterated by the view.
|
||||
*/
|
||||
[[nodiscard]] size_type size_hint() const {
|
||||
return pools.empty() ? size_type{} : pools.front()->size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,20 +271,10 @@ public:
|
||||
* components. If the view is empty, the returned iterator will be equal to
|
||||
* `end()`.
|
||||
*
|
||||
* @note
|
||||
* Input iterators stay true to the order imposed to the underlying data
|
||||
* structures.
|
||||
*
|
||||
* @return An iterator to the first entity that has the given components.
|
||||
*/
|
||||
iterator_type begin() const {
|
||||
iterator_type it{};
|
||||
|
||||
if(valid()) {
|
||||
it = { &pools, pools[0]->begin() };
|
||||
}
|
||||
|
||||
return it;
|
||||
[[nodiscard]] iterator begin() const {
|
||||
return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->begin()};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,32 +285,22 @@ public:
|
||||
* has the given components. Attempting to dereference the returned iterator
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @note
|
||||
* Input iterators stay true to the order imposed to the underlying data
|
||||
* structures.
|
||||
*
|
||||
* @return An iterator to the entity following the last entity that has the
|
||||
* given components.
|
||||
*/
|
||||
iterator_type end() const {
|
||||
iterator_type it{};
|
||||
|
||||
if(valid()) {
|
||||
it = { &pools, pools[0]->end() };
|
||||
}
|
||||
|
||||
return it;
|
||||
[[nodiscard]] iterator end() const {
|
||||
return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->end()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a view contains an entity.
|
||||
* @param entt A valid entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return True if the view contains the given entity, false otherwise.
|
||||
*/
|
||||
bool contains(const entity_type entt) const {
|
||||
return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *view) {
|
||||
return view->find(entt) != view->end();
|
||||
});
|
||||
[[nodiscard]] bool contains(const entity_type entt) const {
|
||||
return !pools.empty()
|
||||
&& std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
|
||||
&& std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -253,11 +326,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<const sparse_set<Entity> *> pools;
|
||||
container_type pools;
|
||||
container_type filter;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
#ifndef ENTT_ENTITY_SNAPSHOT_HPP
|
||||
#define ENTT_ENTITY_SNAPSHOT_HPP
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../container/dense_map.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "component.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include "view.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class to create snapshots from a registry.
|
||||
*
|
||||
@@ -24,99 +26,77 @@ namespace entt {
|
||||
* This type can be used in both cases if provided with a correctly configured
|
||||
* output archive.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
template<typename Registry>
|
||||
class basic_snapshot {
|
||||
/*! @brief A registry is allowed to create snapshots. */
|
||||
friend class basic_registry<Entity>;
|
||||
|
||||
using follow_fn_type = Entity(const basic_registry<Entity> &, const Entity);
|
||||
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
|
||||
|
||||
basic_snapshot(const basic_registry<Entity> *source, Entity init, follow_fn_type *fn) ENTT_NOEXCEPT
|
||||
: reg{source},
|
||||
seed{init},
|
||||
follow{fn}
|
||||
{}
|
||||
using entity_traits = entt_traits<typename Registry::entity_type>;
|
||||
|
||||
template<typename Component, typename Archive, typename It>
|
||||
void get(Archive &archive, std::size_t sz, It first, It last) const {
|
||||
archive(typename traits_type::entity_type(sz));
|
||||
const auto view = reg->template view<const Component>();
|
||||
archive(typename entity_traits::entity_type(sz));
|
||||
|
||||
while(first != last) {
|
||||
const auto entt = *(first++);
|
||||
|
||||
if(reg->template has<Component>(entt)) {
|
||||
if constexpr(std::is_empty_v<Component>) {
|
||||
archive(entt);
|
||||
} else {
|
||||
archive(entt, reg->template get<Component>(entt));
|
||||
}
|
||||
if(reg->template all_of<Component>(entt)) {
|
||||
std::apply(archive, std::tuple_cat(std::make_tuple(entt), view.get(entt)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Component, typename Archive, typename It, std::size_t... Indexes>
|
||||
void component(Archive &archive, It first, It last, std::index_sequence<Indexes...>) const {
|
||||
std::array<std::size_t, sizeof...(Indexes)> size{};
|
||||
template<typename... Component, typename Archive, typename It, std::size_t... Index>
|
||||
void component(Archive &archive, It first, It last, std::index_sequence<Index...>) const {
|
||||
std::array<std::size_t, sizeof...(Index)> size{};
|
||||
auto begin = first;
|
||||
|
||||
while(begin != last) {
|
||||
const auto entt = *(begin++);
|
||||
((reg->template has<Component>(entt) ? ++size[Indexes] : size[Indexes]), ...);
|
||||
((reg->template all_of<Component>(entt) ? ++size[Index] : 0u), ...);
|
||||
}
|
||||
|
||||
(get<Component>(archive, size[Indexes], first, last), ...);
|
||||
(get<Component>(archive, size[Index], first, last), ...);
|
||||
}
|
||||
|
||||
public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs an instance that is bound to a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
basic_snapshot(const registry_type &source) noexcept
|
||||
: reg{&source} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_snapshot(basic_snapshot &&) = default;
|
||||
basic_snapshot(basic_snapshot &&) noexcept = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This snapshot. */
|
||||
basic_snapshot & operator=(basic_snapshot &&) = default;
|
||||
basic_snapshot &operator=(basic_snapshot &&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Puts aside all the entities that are still in use.
|
||||
* @brief Puts aside all the entities from the underlying registry.
|
||||
*
|
||||
* Entities are serialized along with their versions. Destroyed entities are
|
||||
* not taken in consideration by this function.
|
||||
* taken in consideration as well by this function.
|
||||
*
|
||||
* @tparam Archive Type of output archive.
|
||||
* @param archive A valid reference to an output archive.
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot & entities(Archive &archive) const {
|
||||
archive(typename traits_type::entity_type(reg->alive()));
|
||||
reg->each([&archive](const auto entt) { archive(entt); });
|
||||
return *this;
|
||||
}
|
||||
const basic_snapshot &entities(Archive &archive) const {
|
||||
const auto sz = reg->size();
|
||||
|
||||
/**
|
||||
* @brief Puts aside destroyed entities.
|
||||
*
|
||||
* Entities are serialized along with their versions. Entities that are
|
||||
* still in use are not taken in consideration by this function.
|
||||
*
|
||||
* @tparam Archive Type of output archive.
|
||||
* @param archive A valid reference to an output archive.
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot & destroyed(Archive &archive) const {
|
||||
auto size = reg->size() - reg->alive();
|
||||
archive(typename traits_type::entity_type(size));
|
||||
archive(typename entity_traits::entity_type(sz + 1u));
|
||||
archive(reg->released());
|
||||
|
||||
if(size) {
|
||||
auto curr = seed;
|
||||
archive(curr);
|
||||
|
||||
for(--size; size; --size) {
|
||||
curr = follow(*reg, curr);
|
||||
archive(curr);
|
||||
}
|
||||
for(auto first = reg->data(), last = first + sz; first != last; ++first) {
|
||||
archive(*first);
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -134,9 +114,15 @@ public:
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename... Component, typename Archive>
|
||||
const basic_snapshot & component(Archive &archive) const {
|
||||
(component<Component>(archive, reg->template data<Component>(), reg->template data<Component>() + reg->template size<Component>()), ...);
|
||||
return *this;
|
||||
const basic_snapshot &component(Archive &archive) const {
|
||||
if constexpr(sizeof...(Component) == 1u) {
|
||||
const auto view = reg->template view<const Component...>();
|
||||
(component<Component>(archive, view.rbegin(), view.rend()), ...);
|
||||
return *this;
|
||||
} else {
|
||||
(component<Component>(archive), ...);
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,18 +140,15 @@ public:
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename... Component, typename Archive, typename It>
|
||||
const basic_snapshot & component(Archive &archive, It first, It last) const {
|
||||
const basic_snapshot &component(Archive &archive, It first, It last) const {
|
||||
component<Component...>(archive, first, last, std::index_sequence_for<Component...>{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const basic_registry<Entity> *reg;
|
||||
const Entity seed;
|
||||
follow_fn_type *follow;
|
||||
const registry_type *reg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class to restore a snapshot as a whole.
|
||||
*
|
||||
@@ -174,64 +157,59 @@ private:
|
||||
* originally had.<br/>
|
||||
* An example of use is the implementation of a save/restore utility.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
template<typename Registry>
|
||||
class basic_snapshot_loader {
|
||||
/*! @brief A registry is allowed to create snapshot loaders. */
|
||||
friend class basic_registry<Entity>;
|
||||
using entity_traits = entt_traits<typename Registry::entity_type>;
|
||||
|
||||
using force_fn_type = void(basic_registry<Entity> &, const Entity, const bool);
|
||||
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
|
||||
template<typename Component, typename Archive>
|
||||
void assign(Archive &archive) const {
|
||||
typename entity_traits::entity_type length{};
|
||||
entity_type entt;
|
||||
|
||||
basic_snapshot_loader(basic_registry<Entity> *source, force_fn_type *fn) ENTT_NOEXCEPT
|
||||
: reg{source},
|
||||
force{fn}
|
||||
{
|
||||
// to restore a snapshot as a whole requires a clean registry
|
||||
ENTT_ASSERT(reg->empty());
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
void assure(Archive &archive, bool discard) const {
|
||||
typename traits_type::entity_type length{};
|
||||
archive(length);
|
||||
|
||||
while(length--) {
|
||||
Entity entt{};
|
||||
archive(entt);
|
||||
force(*reg, entt, discard);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type, typename Archive, typename... Args>
|
||||
void assign(Archive &archive, Args... args) const {
|
||||
typename traits_type::entity_type length{};
|
||||
archive(length);
|
||||
|
||||
while(length--) {
|
||||
static constexpr auto discard = false;
|
||||
Entity entt{};
|
||||
|
||||
if constexpr(std::is_empty_v<Type>) {
|
||||
if constexpr(ignore_as_empty_v<Component>) {
|
||||
while(length--) {
|
||||
archive(entt);
|
||||
force(*reg, entt, discard);
|
||||
reg->template assign<Type>(args..., entt);
|
||||
} else {
|
||||
Type instance{};
|
||||
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
|
||||
ENTT_ASSERT(entity == entt, "Entity not available for use");
|
||||
reg->template emplace<Component>(entt);
|
||||
}
|
||||
} else {
|
||||
Component instance;
|
||||
|
||||
while(length--) {
|
||||
archive(entt, instance);
|
||||
force(*reg, entt, discard);
|
||||
reg->template assign<Type>(args..., entt, std::as_const(instance));
|
||||
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
|
||||
ENTT_ASSERT(entity == entt, "Entity not available for use");
|
||||
reg->template emplace<Component>(entt, std::move(instance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs an instance that is bound to a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
basic_snapshot_loader(registry_type &source) noexcept
|
||||
: reg{&source} {
|
||||
// restoring a snapshot as a whole requires a clean registry
|
||||
ENTT_ASSERT(reg->empty(), "Registry must be empty");
|
||||
}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_snapshot_loader(basic_snapshot_loader &&) = default;
|
||||
basic_snapshot_loader(basic_snapshot_loader &&) noexcept = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This loader. */
|
||||
basic_snapshot_loader & operator=(basic_snapshot_loader &&) = default;
|
||||
basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Restores entities that were in use during serialization.
|
||||
@@ -244,26 +222,18 @@ public:
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot_loader & entities(Archive &archive) const {
|
||||
static constexpr auto discard = false;
|
||||
assure(archive, discard);
|
||||
return *this;
|
||||
}
|
||||
const basic_snapshot_loader &entities(Archive &archive) const {
|
||||
typename entity_traits::entity_type length{};
|
||||
|
||||
archive(length);
|
||||
std::vector<entity_type> all(length);
|
||||
|
||||
for(std::size_t pos{}; pos < length; ++pos) {
|
||||
archive(all[pos]);
|
||||
}
|
||||
|
||||
reg->assign(++all.cbegin(), all.cend(), all[0u]);
|
||||
|
||||
/**
|
||||
* @brief Restores entities that were destroyed during serialization.
|
||||
*
|
||||
* This function restores the entities that were destroyed during
|
||||
* serialization and gives them the versions they originally had.
|
||||
*
|
||||
* @tparam Archive Type of input archive.
|
||||
* @param archive A valid reference to an input archive.
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot_loader & destroyed(Archive &archive) const {
|
||||
static constexpr auto discard = true;
|
||||
assure(archive, discard);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -281,7 +251,7 @@ public:
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename... Component, typename Archive>
|
||||
const basic_snapshot_loader & component(Archive &archive) const {
|
||||
const basic_snapshot_loader &component(Archive &archive) const {
|
||||
(assign<Component>(archive), ...);
|
||||
return *this;
|
||||
}
|
||||
@@ -296,25 +266,25 @@ public:
|
||||
*
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
const basic_snapshot_loader & orphans() const {
|
||||
reg->orphans([this](const auto entt) {
|
||||
reg->destroy(entt);
|
||||
const basic_snapshot_loader &orphans() const {
|
||||
reg->each([this](const auto entt) {
|
||||
if(reg->orphan(entt)) {
|
||||
reg->release(entt);
|
||||
}
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
basic_registry<Entity> *reg;
|
||||
force_fn_type *force;
|
||||
registry_type *reg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class for _continuous loading_.
|
||||
*
|
||||
* A _continuous loader_ is designed to load data from a source registry to a
|
||||
* (possibly) non-empty destination. The loader can accomodate in a registry
|
||||
* (possibly) non-empty destination. The loader can accommodate in a registry
|
||||
* more than one snapshot in a sort of _continuous loading_ that updates the
|
||||
* destination one step at a time.<br/>
|
||||
* Identifiers that entities originally had are not transferred to the target.
|
||||
@@ -324,38 +294,38 @@ private:
|
||||
* the requirement of transferring somehow parts of the representation side to
|
||||
* side.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
template<typename Registry>
|
||||
class basic_continuous_loader {
|
||||
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
|
||||
using entity_traits = entt_traits<typename Registry::entity_type>;
|
||||
|
||||
void destroy(Entity entt) {
|
||||
const auto it = remloc.find(entt);
|
||||
|
||||
if(it == remloc.cend()) {
|
||||
void destroy(typename Registry::entity_type entt) {
|
||||
if(const auto it = remloc.find(entt); it == remloc.cend()) {
|
||||
const auto local = reg->create();
|
||||
remloc.emplace(entt, std::make_pair(local, true));
|
||||
reg->destroy(local);
|
||||
}
|
||||
}
|
||||
|
||||
void restore(Entity entt) {
|
||||
void restore(typename Registry::entity_type entt) {
|
||||
const auto it = remloc.find(entt);
|
||||
|
||||
if(it == remloc.cend()) {
|
||||
const auto local = reg->create();
|
||||
remloc.emplace(entt, std::make_pair(local, true));
|
||||
} else {
|
||||
remloc[entt].first = reg->valid(remloc[entt].first) ? remloc[entt].first : reg->create();
|
||||
if(!reg->valid(remloc[entt].first)) {
|
||||
remloc[entt].first = reg->create();
|
||||
}
|
||||
|
||||
// set the dirty flag
|
||||
remloc[entt].second = true;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
auto update(int, Container &container)
|
||||
-> decltype(typename Container::mapped_type{}, void()) {
|
||||
auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
|
||||
// map like container
|
||||
Container other;
|
||||
|
||||
@@ -363,35 +333,35 @@ class basic_continuous_loader {
|
||||
using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
|
||||
using second_type = typename std::decay_t<decltype(pair)>::second_type;
|
||||
|
||||
if constexpr(std::is_same_v<first_type, Entity> && std::is_same_v<second_type, Entity>) {
|
||||
if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
|
||||
other.emplace(map(pair.first), map(pair.second));
|
||||
} else if constexpr(std::is_same_v<first_type, Entity>) {
|
||||
} else if constexpr(std::is_same_v<first_type, entity_type>) {
|
||||
other.emplace(map(pair.first), std::move(pair.second));
|
||||
} else {
|
||||
static_assert(std::is_same_v<second_type, Entity>);
|
||||
static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
|
||||
other.emplace(std::move(pair.first), map(pair.second));
|
||||
}
|
||||
}
|
||||
|
||||
std::swap(container, other);
|
||||
using std::swap;
|
||||
swap(container, other);
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
auto update(char, Container &container)
|
||||
-> decltype(typename Container::value_type{}, void()) {
|
||||
auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
|
||||
// vector like container
|
||||
static_assert(std::is_same_v<typename Container::value_type, Entity>);
|
||||
static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
|
||||
|
||||
for(auto &&entt: container) {
|
||||
entt = map(entt);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Other, typename Type, typename Member>
|
||||
void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type:: *member) {
|
||||
if constexpr(!std::is_same_v<Other, Type>) {
|
||||
template<typename Component, typename Other, typename Member>
|
||||
void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) {
|
||||
if constexpr(!std::is_same_v<Component, Other>) {
|
||||
return;
|
||||
} else if constexpr(std::is_same_v<Member, Entity>) {
|
||||
} else if constexpr(std::is_same_v<Member, entity_type>) {
|
||||
instance.*member = map(instance.*member);
|
||||
} else {
|
||||
// maybe a container? let's try...
|
||||
@@ -399,68 +369,60 @@ class basic_continuous_loader {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Archive>
|
||||
void assure(Archive &archive, void(basic_continuous_loader:: *member)(Entity)) {
|
||||
typename traits_type::entity_type length{};
|
||||
archive(length);
|
||||
|
||||
while(length--) {
|
||||
Entity entt{};
|
||||
archive(entt);
|
||||
(this->*member)(entt);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Component>
|
||||
void reset() {
|
||||
void remove_if_exists() {
|
||||
for(auto &&ref: remloc) {
|
||||
const auto local = ref.second.first;
|
||||
|
||||
if(reg->valid(local)) {
|
||||
reg->template remove_if_exists<Component>(local);
|
||||
reg->template remove<Component>(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Other, typename Archive, typename... Type, typename... Member>
|
||||
void assign(Archive &archive, [[maybe_unused]] Member Type:: *... member) {
|
||||
typename traits_type::entity_type length{};
|
||||
template<typename Component, typename Archive, typename... Other, typename... Member>
|
||||
void assign(Archive &archive, [[maybe_unused]] Member Other::*...member) {
|
||||
typename entity_traits::entity_type length{};
|
||||
entity_type entt;
|
||||
|
||||
archive(length);
|
||||
|
||||
while(length--) {
|
||||
Entity entt{};
|
||||
|
||||
if constexpr(std::is_empty_v<Other>) {
|
||||
if constexpr(ignore_as_empty_v<Component>) {
|
||||
while(length--) {
|
||||
archive(entt);
|
||||
restore(entt);
|
||||
reg->template assign_or_replace<Other>(map(entt));
|
||||
} else {
|
||||
Other instance{};
|
||||
reg->template emplace_or_replace<Component>(map(entt));
|
||||
}
|
||||
} else {
|
||||
Component instance;
|
||||
|
||||
while(length--) {
|
||||
archive(entt, instance);
|
||||
(update(instance, member), ...);
|
||||
restore(entt);
|
||||
reg->template assign_or_replace<Other>(map(entt), std::as_const(instance));
|
||||
reg->template emplace_or_replace<Component>(map(entt), std::move(instance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs a loader that is bound to a given registry.
|
||||
* @brief Constructs an instance that is bound to a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
basic_continuous_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
|
||||
: reg{&source}
|
||||
{}
|
||||
basic_continuous_loader(registry_type &source) noexcept
|
||||
: reg{&source} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_continuous_loader(basic_continuous_loader &&) = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This loader. */
|
||||
basic_continuous_loader & operator=(basic_continuous_loader &&) = default;
|
||||
basic_continuous_loader &operator=(basic_continuous_loader &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Restores entities that were in use during serialization.
|
||||
@@ -473,24 +435,24 @@ public:
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
template<typename Archive>
|
||||
basic_continuous_loader & entities(Archive &archive) {
|
||||
assure(archive, &basic_continuous_loader::restore);
|
||||
return *this;
|
||||
}
|
||||
basic_continuous_loader &entities(Archive &archive) {
|
||||
typename entity_traits::entity_type length{};
|
||||
entity_type entt{};
|
||||
|
||||
archive(length);
|
||||
// discards the head of the list of destroyed entities
|
||||
archive(entt);
|
||||
|
||||
for(std::size_t pos{}, last = length - 1u; pos < last; ++pos) {
|
||||
archive(entt);
|
||||
|
||||
if(const auto entity = entity_traits::to_entity(entt); entity == pos) {
|
||||
restore(entt);
|
||||
} else {
|
||||
destroy(entt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Restores entities that were destroyed during serialization.
|
||||
*
|
||||
* This function restores the entities that were destroyed during
|
||||
* serialization and creates local counterparts for them if required.
|
||||
*
|
||||
* @tparam Archive Type of input archive.
|
||||
* @param archive A valid reference to an input archive.
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
template<typename Archive>
|
||||
basic_continuous_loader & destroyed(Archive &archive) {
|
||||
assure(archive, &basic_continuous_loader::destroy);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -507,15 +469,15 @@ public:
|
||||
*
|
||||
* @tparam Component Type of component to restore.
|
||||
* @tparam Archive Type of input archive.
|
||||
* @tparam Type Types of components to update with local counterparts.
|
||||
* @tparam Other Types of components to update with local counterparts.
|
||||
* @tparam Member Types of members to update with their local counterparts.
|
||||
* @param archive A valid reference to an input archive.
|
||||
* @param member Members to update with their local counterparts.
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
template<typename... Component, typename Archive, typename... Type, typename... Member>
|
||||
basic_continuous_loader & component(Archive &archive, Member Type:: *... member) {
|
||||
(reset<Component>(), ...);
|
||||
template<typename... Component, typename Archive, typename... Other, typename... Member>
|
||||
basic_continuous_loader &component(Archive &archive, Member Other::*...member) {
|
||||
(remove_if_exists<Component>(), ...);
|
||||
(assign<Component>(archive, member...), ...);
|
||||
return *this;
|
||||
}
|
||||
@@ -528,7 +490,7 @@ public:
|
||||
*
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
basic_continuous_loader & shrink() {
|
||||
basic_continuous_loader &shrink() {
|
||||
auto it = remloc.begin();
|
||||
|
||||
while(it != remloc.cend()) {
|
||||
@@ -560,9 +522,11 @@ public:
|
||||
*
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
basic_continuous_loader & orphans() {
|
||||
reg->orphans([this](const auto entt) {
|
||||
reg->destroy(entt);
|
||||
basic_continuous_loader &orphans() {
|
||||
reg->each([this](const auto entt) {
|
||||
if(reg->orphan(entt)) {
|
||||
reg->release(entt);
|
||||
}
|
||||
});
|
||||
|
||||
return *this;
|
||||
@@ -570,19 +534,19 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Tests if a loader knows about a given entity.
|
||||
* @param entt An entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return True if `entity` is managed by the loader, false otherwise.
|
||||
*/
|
||||
bool has(entity_type entt) const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] bool contains(entity_type entt) const noexcept {
|
||||
return (remloc.find(entt) != remloc.cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the identifier to which an entity refers.
|
||||
* @param entt An entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return The local identifier if any, the null entity otherwise.
|
||||
*/
|
||||
entity_type map(entity_type entt) const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] entity_type map(entity_type entt) const noexcept {
|
||||
const auto it = remloc.find(entt);
|
||||
entity_type other = null;
|
||||
|
||||
@@ -594,12 +558,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<entity_type, std::pair<entity_type, bool>> remloc;
|
||||
basic_registry<entity_type> *reg;
|
||||
dense_map<entity_type, std::pair<entity_type, bool>> remloc;
|
||||
registry_type *reg;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
236
src/entt/entity/storage_mixin.hpp
Normal file
236
src/entt/entity/storage_mixin.hpp
Normal file
@@ -0,0 +1,236 @@
|
||||
#ifndef ENTT_ENTITY_SIGH_STORAGE_MIXIN_HPP
|
||||
#define ENTT_ENTITY_SIGH_STORAGE_MIXIN_HPP
|
||||
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/any.hpp"
|
||||
#include "../signal/sigh.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Mixin type used to add signal support to storage types.
|
||||
*
|
||||
* The function type of a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(basic_registry<entity_type> &, entity_type);
|
||||
* @endcode
|
||||
*
|
||||
* This applies to all signals made available.
|
||||
*
|
||||
* @tparam Type The type of the underlying storage.
|
||||
*/
|
||||
template<typename Type>
|
||||
class sigh_storage_mixin final: public Type {
|
||||
using basic_registry_type = basic_registry<typename Type::entity_type, typename Type::base_type::allocator_type>;
|
||||
using sigh_type = sigh<void(basic_registry_type &, const typename Type::entity_type), typename Type::allocator_type>;
|
||||
using basic_iterator = typename Type::basic_iterator;
|
||||
|
||||
void pop(basic_iterator first, basic_iterator last) override {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
|
||||
for(; first != last; ++first) {
|
||||
const auto entt = *first;
|
||||
destruction.publish(*owner, entt);
|
||||
const auto it = Type::find(entt);
|
||||
Type::pop(it, it + 1u);
|
||||
}
|
||||
}
|
||||
|
||||
basic_iterator try_emplace(const typename basic_registry_type::entity_type entt, const bool force_back, const void *value) final {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
Type::try_emplace(entt, force_back, value);
|
||||
construction.publish(*owner, entt);
|
||||
return Type::find(entt);
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = typename Type::allocator_type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename Type::entity_type;
|
||||
/*! @brief Expected registry type. */
|
||||
using registry_type = basic_registry_type;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
sigh_storage_mixin()
|
||||
: sigh_storage_mixin{allocator_type{}} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty storage with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit sigh_storage_mixin(const allocator_type &allocator)
|
||||
: Type{allocator},
|
||||
owner{},
|
||||
construction{allocator},
|
||||
destruction{allocator},
|
||||
update{allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
sigh_storage_mixin(sigh_storage_mixin &&other) noexcept
|
||||
: Type{std::move(other)},
|
||||
owner{other.owner},
|
||||
construction{std::move(other.construction)},
|
||||
destruction{std::move(other.destruction)},
|
||||
update{std::move(other.update)} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
sigh_storage_mixin(sigh_storage_mixin &&other, const allocator_type &allocator) noexcept
|
||||
: Type{std::move(other), allocator},
|
||||
owner{other.owner},
|
||||
construction{std::move(other.construction), allocator},
|
||||
destruction{std::move(other.destruction), allocator},
|
||||
update{std::move(other.update), allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This storage.
|
||||
*/
|
||||
sigh_storage_mixin &operator=(sigh_storage_mixin &&other) noexcept {
|
||||
Type::operator=(std::move(other));
|
||||
owner = other.owner;
|
||||
construction = std::move(other.construction);
|
||||
destruction = std::move(other.destruction);
|
||||
update = std::move(other.update);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given storage.
|
||||
* @param other Storage to exchange the content with.
|
||||
*/
|
||||
void swap(sigh_storage_mixin &other) {
|
||||
using std::swap;
|
||||
Type::swap(other);
|
||||
swap(owner, other.owner);
|
||||
swap(construction, other.construction);
|
||||
swap(destruction, other.destruction);
|
||||
swap(update, other.update);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object.
|
||||
*
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever a new instance is created and assigned to an entity.<br/>
|
||||
* Listeners are invoked after the object has been assigned to the entity.
|
||||
*
|
||||
* @sa sink
|
||||
*
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
[[nodiscard]] auto on_construct() noexcept {
|
||||
return sink{construction};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object.
|
||||
*
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever an instance is explicitly updated.<br/>
|
||||
* Listeners are invoked after the object has been updated.
|
||||
*
|
||||
* @sa sink
|
||||
*
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
[[nodiscard]] auto on_update() noexcept {
|
||||
return sink{update};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object.
|
||||
*
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever an instance is removed from an entity and thus destroyed.<br/>
|
||||
* Listeners are invoked before the object has been removed from the entity.
|
||||
*
|
||||
* @sa sink
|
||||
*
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
[[nodiscard]] auto on_destroy() noexcept {
|
||||
return sink{destruction};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns entities to a storage.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param entt A valid identifier.
|
||||
* @param args Parameters to use to initialize the object.
|
||||
* @return A reference to the newly created object.
|
||||
*/
|
||||
template<typename... Args>
|
||||
decltype(auto) emplace(const entity_type entt, Args &&...args) {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
Type::emplace(entt, std::forward<Args>(args)...);
|
||||
construction.publish(*owner, entt);
|
||||
return this->get(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Patches the given instance for an entity.
|
||||
* @tparam Func Types of the function objects to invoke.
|
||||
* @param entt A valid identifier.
|
||||
* @param func Valid function objects.
|
||||
* @return A reference to the patched instance.
|
||||
*/
|
||||
template<typename... Func>
|
||||
decltype(auto) patch(const entity_type entt, Func &&...func) {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
Type::patch(entt, std::forward<Func>(func)...);
|
||||
update.publish(*owner, entt);
|
||||
return this->get(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns entities to a storage.
|
||||
* @tparam It Type of input iterator.
|
||||
* @tparam Args Types of arguments to use to construct the objects assigned
|
||||
* to the entities.
|
||||
* @param first An iterator to the first element of the range of entities.
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @param args Parameters to use to initialize the objects assigned to the
|
||||
* entities.
|
||||
*/
|
||||
template<typename It, typename... Args>
|
||||
void insert(It first, It last, Args &&...args) {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
Type::insert(first, last, std::forward<Args>(args)...);
|
||||
|
||||
for(auto it = construction.empty() ? last : first; it != last; ++it) {
|
||||
construction.publish(*owner, *it);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forwards variables to derived classes, if any.
|
||||
* @param value A variable wrapped in an opaque container.
|
||||
*/
|
||||
void bind(any value) noexcept final {
|
||||
auto *reg = any_cast<basic_registry_type>(&value);
|
||||
owner = reg ? reg : owner;
|
||||
Type::bind(std::move(value));
|
||||
}
|
||||
|
||||
private:
|
||||
basic_registry_type *owner;
|
||||
sigh_type construction;
|
||||
sigh_type destruction;
|
||||
sigh_type update;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,33 +1,64 @@
|
||||
// IWYU pragma: begin_exports
|
||||
#include "config/config.h"
|
||||
#include "config/macro.h"
|
||||
#include "config/version.h"
|
||||
#include "container/dense_map.hpp"
|
||||
#include "container/dense_set.hpp"
|
||||
#include "core/algorithm.hpp"
|
||||
#include "core/any.hpp"
|
||||
#include "core/attribute.h"
|
||||
#include "core/compressed_pair.hpp"
|
||||
#include "core/enum.hpp"
|
||||
#include "core/family.hpp"
|
||||
#include "core/hashed_string.hpp"
|
||||
#include "core/ident.hpp"
|
||||
#include "core/iterator.hpp"
|
||||
#include "core/memory.hpp"
|
||||
#include "core/monostate.hpp"
|
||||
#include "core/tuple.hpp"
|
||||
#include "core/type_info.hpp"
|
||||
#include "core/type_traits.hpp"
|
||||
#include "core/utility.hpp"
|
||||
#include "entity/actor.hpp"
|
||||
#include "entity/component.hpp"
|
||||
#include "entity/entity.hpp"
|
||||
#include "entity/group.hpp"
|
||||
#include "entity/handle.hpp"
|
||||
#include "entity/helper.hpp"
|
||||
#include "entity/observer.hpp"
|
||||
#include "entity/organizer.hpp"
|
||||
#include "entity/registry.hpp"
|
||||
#include "entity/runtime_view.hpp"
|
||||
#include "entity/snapshot.hpp"
|
||||
#include "entity/sparse_set.hpp"
|
||||
#include "entity/storage.hpp"
|
||||
#include "entity/storage_mixin.hpp"
|
||||
#include "entity/view.hpp"
|
||||
#include "graph/adjacency_matrix.hpp"
|
||||
#include "graph/dot.hpp"
|
||||
#include "graph/flow.hpp"
|
||||
#include "locator/locator.hpp"
|
||||
#include "meta/adl_pointer.hpp"
|
||||
#include "meta/container.hpp"
|
||||
#include "meta/context.hpp"
|
||||
#include "meta/factory.hpp"
|
||||
#include "meta/meta.hpp"
|
||||
#include "meta/node.hpp"
|
||||
#include "meta/pointer.hpp"
|
||||
#include "meta/policy.hpp"
|
||||
#include "meta/range.hpp"
|
||||
#include "meta/resolve.hpp"
|
||||
#include "meta/template.hpp"
|
||||
#include "meta/type_traits.hpp"
|
||||
#include "meta/utility.hpp"
|
||||
#include "platform/android-ndk-r17.hpp"
|
||||
#include "poly/poly.hpp"
|
||||
#include "process/process.hpp"
|
||||
#include "process/scheduler.hpp"
|
||||
#include "resource/cache.hpp"
|
||||
#include "resource/handle.hpp"
|
||||
#include "resource/loader.hpp"
|
||||
#include "resource/resource.hpp"
|
||||
#include "signal/delegate.hpp"
|
||||
#include "signal/dispatcher.hpp"
|
||||
#include "signal/emitter.hpp"
|
||||
#include "signal/sigh.hpp"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
// IWYU pragma: begin_exports
|
||||
#include "container/fwd.hpp"
|
||||
#include "core/fwd.hpp"
|
||||
#include "entity/fwd.hpp"
|
||||
#include "graph/fwd.hpp"
|
||||
#include "meta/fwd.hpp"
|
||||
#include "poly/fwd.hpp"
|
||||
#include "process/fwd.hpp"
|
||||
#include "resource/fwd.hpp"
|
||||
#include "signal/fwd.hpp"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
348
src/entt/graph/adjacency_matrix.hpp
Normal file
348
src/entt/graph/adjacency_matrix.hpp
Normal file
@@ -0,0 +1,348 @@
|
||||
#ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP
|
||||
#define ENTT_GRAPH_ADJACENCY_MATRIX_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
class edge_iterator {
|
||||
using size_type = std::size_t;
|
||||
|
||||
public:
|
||||
using value_type = std::pair<size_type, size_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;
|
||||
|
||||
constexpr edge_iterator() noexcept
|
||||
: it{},
|
||||
vert{},
|
||||
pos{},
|
||||
last{},
|
||||
offset{} {}
|
||||
|
||||
constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept
|
||||
: it{std::move(base)},
|
||||
vert{vertices},
|
||||
pos{from},
|
||||
last{to},
|
||||
offset{step} {
|
||||
for(; pos != last && !it[pos]; pos += offset) {}
|
||||
}
|
||||
|
||||
constexpr edge_iterator &operator++() noexcept {
|
||||
for(pos += offset; pos != last && !it[pos]; pos += offset) {}
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr edge_iterator operator++(int) noexcept {
|
||||
edge_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::make_pair<size_type>(pos / vert, pos % vert);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
friend constexpr bool operator==(const edge_iterator<Type> &, const edge_iterator<Type> &) noexcept;
|
||||
|
||||
private:
|
||||
It it;
|
||||
size_type vert;
|
||||
size_type pos;
|
||||
size_type last;
|
||||
size_type offset{};
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] inline constexpr bool operator==(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
|
||||
return lhs.pos == rhs.pos;
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] inline constexpr bool operator!=(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Basic implementation of a directed adjacency matrix.
|
||||
* @tparam Category Either a directed or undirected category tag.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Category, typename Allocator>
|
||||
class adjacency_matrix {
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_base_of_v<directed_tag, Category>, "Invalid graph category");
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, std::size_t>, "Invalid value type");
|
||||
using container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Vertex type. */
|
||||
using vertex_type = size_type;
|
||||
/*! @brief Edge type. */
|
||||
using edge_type = std::pair<vertex_type, vertex_type>;
|
||||
/*! @brief Vertex iterator type. */
|
||||
using vertex_iterator = iota_iterator<vertex_type>;
|
||||
/*! @brief Edge iterator type. */
|
||||
using edge_iterator = internal::edge_iterator<typename container_type::const_iterator>;
|
||||
/*! @brief Out edge iterator type. */
|
||||
using out_edge_iterator = edge_iterator;
|
||||
/*! @brief In edge iterator type. */
|
||||
using in_edge_iterator = edge_iterator;
|
||||
/*! @brief Graph category tag. */
|
||||
using graph_category = Category;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
adjacency_matrix() noexcept(noexcept(allocator_type{}))
|
||||
: adjacency_matrix{0u} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit adjacency_matrix(const allocator_type &allocator) noexcept
|
||||
: adjacency_matrix{0u, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator and user
|
||||
* supplied number of vertices.
|
||||
* @param vertices Number of vertices.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{})
|
||||
: matrix{vertices * vertices, allocator},
|
||||
vert{vertices} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
adjacency_matrix(const adjacency_matrix &other)
|
||||
: adjacency_matrix{other, other.get_allocator()} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator)
|
||||
: matrix{other.matrix, allocator},
|
||||
vert{other.vert} {}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
adjacency_matrix(adjacency_matrix &&other) noexcept
|
||||
: adjacency_matrix{std::move(other), other.get_allocator()} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator)
|
||||
: matrix{std::move(other.matrix), allocator},
|
||||
vert{std::exchange(other.vert, 0u)} {}
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This container.
|
||||
*/
|
||||
adjacency_matrix &operator=(const adjacency_matrix &other) {
|
||||
matrix = other.matrix;
|
||||
vert = other.vert;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This container.
|
||||
*/
|
||||
adjacency_matrix &operator=(adjacency_matrix &&other) noexcept {
|
||||
matrix = std::move(other.matrix);
|
||||
vert = std::exchange(other.vert, 0u);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return matrix.get_allocator();
|
||||
}
|
||||
|
||||
/*! @brief Clears the adjacency matrix. */
|
||||
void clear() noexcept {
|
||||
matrix.clear();
|
||||
vert = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given adjacency matrix.
|
||||
* @param other Adjacency matrix to exchange the content with.
|
||||
*/
|
||||
void swap(adjacency_matrix &other) {
|
||||
using std::swap;
|
||||
swap(matrix, other.matrix);
|
||||
swap(vert, other.vert);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of vertices.
|
||||
* @return The number of vertices.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return vert;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to visit all vertices of a matrix.
|
||||
* @return An iterable object to visit all vertices of a matrix.
|
||||
*/
|
||||
[[nodiscard]] iterable_adaptor<vertex_iterator> vertices() const noexcept {
|
||||
return {0u, vert};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to visit all edges of a matrix.
|
||||
* @return An iterable object to visit all edges of a matrix.
|
||||
*/
|
||||
[[nodiscard]] iterable_adaptor<edge_iterator> edges() const noexcept {
|
||||
const auto it = matrix.cbegin();
|
||||
const auto sz = matrix.size();
|
||||
return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to visit all out edges of a vertex.
|
||||
* @param vertex The vertex of which to return all out edges.
|
||||
* @return An iterable object to visit all out edges of a vertex.
|
||||
*/
|
||||
[[nodiscard]] iterable_adaptor<out_edge_iterator> out_edges(const vertex_type vertex) const noexcept {
|
||||
const auto it = matrix.cbegin();
|
||||
const auto from = vertex * vert;
|
||||
const auto to = vertex * vert + vert;
|
||||
return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to visit all in edges of a vertex.
|
||||
* @param vertex The vertex of which to return all in edges.
|
||||
* @return An iterable object to visit all in edges of a vertex.
|
||||
*/
|
||||
[[nodiscard]] iterable_adaptor<in_edge_iterator> in_edges(const vertex_type vertex) const noexcept {
|
||||
const auto it = matrix.cbegin();
|
||||
const auto from = vertex;
|
||||
const auto to = vert * (vert - 1u) + vertex;
|
||||
return {{it, vert, from, to, vert}, {it, vert, to, to, vert}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resizes an adjacency matrix.
|
||||
* @param vertices The new number of vertices.
|
||||
*/
|
||||
void resize(const size_type vertices) {
|
||||
adjacency_matrix other{vertices, get_allocator()};
|
||||
|
||||
for(auto [lhs, rhs]: edges()) {
|
||||
other.insert(lhs, rhs);
|
||||
}
|
||||
|
||||
other.swap(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an edge into the adjacency matrix, if it does not exist.
|
||||
* @param lhs The left hand vertex of the edge.
|
||||
* @param rhs The right hand vertex of the edge.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
std::pair<edge_iterator, bool> insert(const vertex_type lhs, const vertex_type rhs) {
|
||||
const auto pos = lhs * vert + rhs;
|
||||
|
||||
if constexpr(std::is_same_v<graph_category, undirected_tag>) {
|
||||
const auto rev = rhs * vert + lhs;
|
||||
ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
|
||||
matrix[rev] = 1u;
|
||||
}
|
||||
|
||||
const auto inserted = !std::exchange(matrix[pos], 1u);
|
||||
return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the edge associated with a pair of given vertices.
|
||||
* @param lhs The left hand vertex of the edge.
|
||||
* @param rhs The right hand vertex of the edge.
|
||||
* @return Number of elements removed (either 0 or 1).
|
||||
*/
|
||||
size_type erase(const vertex_type lhs, const vertex_type rhs) {
|
||||
const auto pos = lhs * vert + rhs;
|
||||
|
||||
if constexpr(std::is_same_v<graph_category, undirected_tag>) {
|
||||
const auto rev = rhs * vert + lhs;
|
||||
ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
|
||||
matrix[rev] = 0u;
|
||||
}
|
||||
|
||||
return std::exchange(matrix[pos], 0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if an adjacency matrix contains a given edge.
|
||||
* @param lhs The left hand vertex of the edge.
|
||||
* @param rhs The right hand vertex of the edge.
|
||||
* @return True if there is such an edge, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const {
|
||||
const auto pos = lhs * vert + rhs;
|
||||
return pos < matrix.size() && matrix[pos];
|
||||
}
|
||||
|
||||
private:
|
||||
container_type matrix;
|
||||
size_type vert;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
58
src/entt/graph/dot.hpp
Normal file
58
src/entt/graph/dot.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef ENTT_GRAPH_DOT_HPP
|
||||
#define ENTT_GRAPH_DOT_HPP
|
||||
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Outputs a graph in dot format.
|
||||
* @tparam Graph Graph type, valid as long as it exposes edges and vertices.
|
||||
* @tparam Writer Vertex decorator type.
|
||||
* @param out A standard output stream.
|
||||
* @param graph The graph to output.
|
||||
* @param writer Vertex decorator object.
|
||||
*/
|
||||
template<typename Graph, typename Writer>
|
||||
void dot(std::ostream &out, const Graph &graph, Writer writer) {
|
||||
static_assert(std::is_base_of_v<directed_tag, typename Graph::graph_category>, "Invalid graph category");
|
||||
|
||||
if constexpr(std::is_same_v<typename Graph::graph_category, undirected_tag>) {
|
||||
out << "graph{";
|
||||
} else {
|
||||
out << "digraph{";
|
||||
}
|
||||
|
||||
for(auto &&vertex: graph.vertices()) {
|
||||
out << vertex << "[";
|
||||
writer(out, vertex);
|
||||
out << "];";
|
||||
}
|
||||
|
||||
for(auto [lhs, rhs]: graph.edges()) {
|
||||
if constexpr(std::is_same_v<typename Graph::graph_category, undirected_tag>) {
|
||||
out << lhs << "--" << rhs << ";";
|
||||
} else {
|
||||
out << lhs << "->" << rhs << ";";
|
||||
}
|
||||
}
|
||||
|
||||
out << "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Outputs a graph in dot format.
|
||||
* @tparam Graph Graph type, valid as long as it exposes edges and vertices.
|
||||
* @param out A standard output stream.
|
||||
* @param graph The graph to output.
|
||||
*/
|
||||
template<typename Graph>
|
||||
void dot(std::ostream &out, const Graph &graph) {
|
||||
return dot(out, graph, [](auto &&...) {});
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
327
src/entt/graph/flow.hpp
Normal file
327
src/entt/graph/flow.hpp
Normal file
@@ -0,0 +1,327 @@
|
||||
#ifndef ENTT_GRAPH_FLOW_HPP
|
||||
#define ENTT_GRAPH_FLOW_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../container/dense_map.hpp"
|
||||
#include "../container/dense_set.hpp"
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "adjacency_matrix.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Utility class for creating task graphs.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
class basic_flow {
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, id_type>, "Invalid value type");
|
||||
using task_container_type = dense_set<id_type, identity, std::equal_to<id_type>, typename alloc_traits::template rebind_alloc<id_type>>;
|
||||
using ro_rw_container_type = std::vector<std::pair<std::size_t, bool>, typename alloc_traits::template rebind_alloc<std::pair<std::size_t, bool>>>;
|
||||
using deps_container_type = dense_map<id_type, ro_rw_container_type, identity, std::equal_to<id_type>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, ro_rw_container_type>>>;
|
||||
|
||||
void emplace(const id_type res, const bool is_rw) {
|
||||
ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
|
||||
|
||||
if(!deps.contains(res) && sync_on != vertices.size()) {
|
||||
deps[res].emplace_back(sync_on, true);
|
||||
}
|
||||
|
||||
deps[res].emplace_back(index.first(), is_rw);
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Iterable task list. */
|
||||
using iterable = iterable_adaptor<typename task_container_type::const_iterator>;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_flow()
|
||||
: basic_flow{allocator_type{}} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a flow builder with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit basic_flow(const allocator_type &allocator)
|
||||
: index{0u, allocator},
|
||||
vertices{},
|
||||
deps{},
|
||||
sync_on{} {}
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
basic_flow(const basic_flow &) = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_flow(const basic_flow &other, const allocator_type &allocator)
|
||||
: index{other.index.first(), allocator},
|
||||
vertices{other.vertices, allocator},
|
||||
deps{other.deps, allocator},
|
||||
sync_on{other.sync_on} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_flow(basic_flow &&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_flow(basic_flow &&other, const allocator_type &allocator)
|
||||
: index{other.index.first(), allocator},
|
||||
vertices{std::move(other.vertices), allocator},
|
||||
deps{std::move(other.deps), allocator},
|
||||
sync_on{other.sync_on} {}
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &operator=(const basic_flow &) = default;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &operator=(basic_flow &&) noexcept = default;
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return allocator_type{index.second()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the identifier at specified location.
|
||||
* @param pos Position of the identifier to return.
|
||||
* @return The requested identifier.
|
||||
*/
|
||||
[[nodiscard]] id_type operator[](const size_type pos) const {
|
||||
return vertices.cbegin()[pos];
|
||||
}
|
||||
|
||||
/*! @brief Clears the flow builder. */
|
||||
void clear() noexcept {
|
||||
index.first() = sync_on = {};
|
||||
vertices.clear();
|
||||
deps.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given flow builder.
|
||||
* @param other Flow builder to exchange the content with.
|
||||
*/
|
||||
void swap(basic_flow &other) {
|
||||
using std::swap;
|
||||
std::swap(index, other.index);
|
||||
std::swap(vertices, other.vertices);
|
||||
std::swap(deps, other.deps);
|
||||
std::swap(sync_on, other.sync_on);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of tasks.
|
||||
* @return The number of tasks.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return vertices.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Binds a task to a flow builder.
|
||||
* @param value Task identifier.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &bind(const id_type value) {
|
||||
sync_on += (sync_on == vertices.size());
|
||||
const auto it = vertices.emplace(value).first;
|
||||
index.first() = size_type(it - vertices.begin());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Turns the current task into a sync point.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &sync() {
|
||||
ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
|
||||
sync_on = index.first();
|
||||
|
||||
for(const auto &elem: deps) {
|
||||
elem.second.emplace_back(sync_on, true);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a resource to the current task with a given access mode.
|
||||
* @param res Resource identifier.
|
||||
* @param is_rw Access mode.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &set(const id_type res, bool is_rw = false) {
|
||||
emplace(res, is_rw);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a read-only resource to the current task.
|
||||
* @param res Resource identifier.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &ro(const id_type res) {
|
||||
emplace(res, false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a range of read-only resources to the current task.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
template<typename It>
|
||||
std::enable_if_t<std::is_same_v<std::remove_const_t<typename std::iterator_traits<It>::value_type>, id_type>, basic_flow &>
|
||||
ro(It first, It last) {
|
||||
for(; first != last; ++first) {
|
||||
emplace(*first, false);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a writable resource to the current task.
|
||||
* @param res Resource identifier.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
basic_flow &rw(const id_type res) {
|
||||
emplace(res, true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a range of writable resources to the current task.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
* @return This flow builder.
|
||||
*/
|
||||
template<typename It>
|
||||
std::enable_if_t<std::is_same_v<std::remove_const_t<typename std::iterator_traits<It>::value_type>, id_type>, basic_flow &>
|
||||
rw(It first, It last) {
|
||||
for(; first != last; ++first) {
|
||||
emplace(*first, true);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates a task graph for the current content.
|
||||
* @return The adjacency matrix of the task graph.
|
||||
*/
|
||||
[[nodiscard]] adjacency_matrix<directed_tag> graph() const {
|
||||
const auto length = vertices.size();
|
||||
adjacency_matrix<directed_tag> matrix{length};
|
||||
|
||||
// creates the adjacency matrix
|
||||
for(const auto &elem: deps) {
|
||||
const auto last = elem.second.cend();
|
||||
auto it = elem.second.cbegin();
|
||||
|
||||
while(it != last) {
|
||||
if(it->second) {
|
||||
// rw item
|
||||
if(auto curr = it++; it != last) {
|
||||
if(it->second) {
|
||||
matrix.insert(curr->first, it->first);
|
||||
} else if(const auto next = std::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
|
||||
for(; it != next; ++it) {
|
||||
matrix.insert(curr->first, it->first);
|
||||
matrix.insert(it->first, next->first);
|
||||
}
|
||||
} else {
|
||||
for(; it != next; ++it) {
|
||||
matrix.insert(curr->first, it->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ro item (first iteration only)
|
||||
if(const auto next = std::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
|
||||
for(; it != next; ++it) {
|
||||
matrix.insert(it->first, next->first);
|
||||
}
|
||||
} else {
|
||||
it = last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// computes the transitive closure
|
||||
for(std::size_t vk{}; vk < length; ++vk) {
|
||||
for(std::size_t vi{}; vi < length; ++vi) {
|
||||
for(std::size_t vj{}; vj < length; ++vj) {
|
||||
if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) {
|
||||
matrix.insert(vi, vj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// applies the transitive reduction
|
||||
for(std::size_t vert{}; vert < length; ++vert) {
|
||||
matrix.erase(vert, vert);
|
||||
}
|
||||
|
||||
for(std::size_t vj{}; vj < length; ++vj) {
|
||||
for(std::size_t vi{}; vi < length; ++vi) {
|
||||
if(matrix.contains(vi, vj)) {
|
||||
for(std::size_t vk{}; vk < length; ++vk) {
|
||||
if(matrix.contains(vj, vk)) {
|
||||
matrix.erase(vi, vk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
private:
|
||||
compressed_pair<size_type, allocator_type> index;
|
||||
task_container_type vertices;
|
||||
deps_container_type deps;
|
||||
size_type sync_on;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
27
src/entt/graph/fwd.hpp
Normal file
27
src/entt/graph/fwd.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef ENTT_GRAPH_FWD_HPP
|
||||
#define ENTT_GRAPH_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include "../core/fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @brief Undirected graph category tag. */
|
||||
struct directed_tag {};
|
||||
|
||||
/*! @brief Directed graph category tag. */
|
||||
struct undirected_tag: directed_tag {};
|
||||
|
||||
template<typename, typename = std::allocator<std::size_t>>
|
||||
class adjacency_matrix;
|
||||
|
||||
template<typename = std::allocator<id_type>>
|
||||
class basic_flow;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using flow = basic_flow<>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,111 +1,135 @@
|
||||
#ifndef ENTT_LOCATOR_LOCATOR_HPP
|
||||
#define ENTT_LOCATOR_LOCATOR_HPP
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Service locator, nothing more.
|
||||
*
|
||||
* A service locator can be used to do what it promises: locate services.<br/>
|
||||
* A service locator is used to do what it promises: locate services.<br/>
|
||||
* Usually service locators are tightly bound to the services they expose and
|
||||
* thus it's hard to define a general purpose class to do that. This template
|
||||
* based implementation tries to fill the gap and to get rid of the burden of
|
||||
* defining a different specific locator for each application.
|
||||
* thus it's hard to define a general purpose class to do that. This tiny class
|
||||
* tries to fill the gap and to get rid of the burden of defining a different
|
||||
* specific locator for each application.
|
||||
*
|
||||
* @tparam Service Type of service managed by the locator.
|
||||
* @note
|
||||
* Users shouldn't retain references to a service. The recommended way is to
|
||||
* retrieve the service implementation currently set each and every time the
|
||||
* need for it arises. The risk is to incur in unexpected behaviors otherwise.
|
||||
*
|
||||
* @tparam Service Service type.
|
||||
*/
|
||||
template<typename Service>
|
||||
struct service_locator {
|
||||
/*! @brief Type of service offered. */
|
||||
using service_type = Service;
|
||||
class locator final {
|
||||
class service_handle {
|
||||
friend class locator<Service>;
|
||||
std::shared_ptr<Service> value{};
|
||||
};
|
||||
|
||||
public:
|
||||
/*! @brief Service type. */
|
||||
using type = Service;
|
||||
/*! @brief Service node type. */
|
||||
using node_type = service_handle;
|
||||
|
||||
/*! @brief Default constructor, deleted on purpose. */
|
||||
service_locator() = delete;
|
||||
locator() = delete;
|
||||
/*! @brief Default destructor, deleted on purpose. */
|
||||
~service_locator() = delete;
|
||||
~locator() = delete;
|
||||
|
||||
/**
|
||||
* @brief Tests if a valid service implementation is set.
|
||||
* @return True if the service is set, false otherwise.
|
||||
* @brief Checks whether a service locator contains a value.
|
||||
* @return True if the service locator contains a value, false otherwise.
|
||||
*/
|
||||
static bool empty() ENTT_NOEXCEPT {
|
||||
return !static_cast<bool>(service);
|
||||
[[nodiscard]] static bool has_value() noexcept {
|
||||
return (service != nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a weak pointer to a service implementation, if any.
|
||||
*
|
||||
* Clients of a service shouldn't retain references to it. The recommended
|
||||
* way is to retrieve the service implementation currently set each and
|
||||
* every time the need of using it arises. Otherwise users can incur in
|
||||
* unexpected behaviors.
|
||||
*
|
||||
* @return A reference to the service implementation currently set, if any.
|
||||
*/
|
||||
static std::weak_ptr<Service> get() ENTT_NOEXCEPT {
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a weak reference to a service implementation, if any.
|
||||
*
|
||||
* Clients of a service shouldn't retain references to it. The recommended
|
||||
* way is to retrieve the service implementation currently set each and
|
||||
* every time the need of using it arises. Otherwise users can incur in
|
||||
* unexpected behaviors.
|
||||
* @brief Returns a reference to a valid service, if any.
|
||||
*
|
||||
* @warning
|
||||
* In case no service implementation has been set, a call to this function
|
||||
* results in undefined behavior.
|
||||
* Invoking this function can result in undefined behavior if the service
|
||||
* hasn't been set yet.
|
||||
*
|
||||
* @return A reference to the service implementation currently set, if any.
|
||||
* @return A reference to the service currently set, if any.
|
||||
*/
|
||||
static Service & ref() ENTT_NOEXCEPT {
|
||||
[[nodiscard]] static Service &value() noexcept {
|
||||
ENTT_ASSERT(has_value(), "Service not available");
|
||||
return *service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets or replaces a service.
|
||||
* @tparam Impl Type of the new service to use.
|
||||
* @tparam Args Types of arguments to use to construct the service.
|
||||
* @param args Parameters to use to construct the service.
|
||||
* @brief Returns a service if available or sets it from a fallback type.
|
||||
*
|
||||
* Arguments are used only if a service doesn't already exist. In all other
|
||||
* cases, they are discarded.
|
||||
*
|
||||
* @tparam Args Types of arguments to use to construct the fallback service.
|
||||
* @tparam Impl Fallback service type.
|
||||
* @param args Parameters to use to construct the fallback service.
|
||||
* @return A reference to a valid service.
|
||||
*/
|
||||
template<typename Impl = Service, typename... Args>
|
||||
static void set(Args &&... args) {
|
||||
service = std::make_shared<Impl>(std::forward<Args>(args)...);
|
||||
[[nodiscard]] static Service &value_or(Args &&...args) {
|
||||
return service ? *service : emplace<Impl>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets or replaces a service.
|
||||
* @param ptr Service to use to replace the current one.
|
||||
* @tparam Impl Service type.
|
||||
* @tparam Args Types of arguments to use to construct the service.
|
||||
* @param args Parameters to use to construct the service.
|
||||
* @return A reference to a valid service.
|
||||
*/
|
||||
static void set(std::shared_ptr<Service> ptr) {
|
||||
ENTT_ASSERT(static_cast<bool>(ptr));
|
||||
service = std::move(ptr);
|
||||
template<typename Impl = Service, typename... Args>
|
||||
static Service &emplace(Args &&...args) {
|
||||
service = std::make_shared<Impl>(std::forward<Args>(args)...);
|
||||
return *service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets a service.
|
||||
*
|
||||
* The service is no longer valid after a reset.
|
||||
* @brief Sets or replaces a service using a given allocator.
|
||||
* @tparam Impl Service type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the service.
|
||||
* @param alloc The allocator to use.
|
||||
* @param args Parameters to use to construct the service.
|
||||
* @return A reference to a valid service.
|
||||
*/
|
||||
static void reset() {
|
||||
service.reset();
|
||||
template<typename Impl = Service, typename Allocator, typename... Args>
|
||||
static Service &allocate_emplace(Allocator alloc, Args &&...args) {
|
||||
service = std::allocate_shared<Impl>(alloc, std::forward<Args>(args)...);
|
||||
return *service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a handle to the underlying service.
|
||||
* @return A handle to the underlying service.
|
||||
*/
|
||||
static node_type handle() noexcept {
|
||||
node_type node{};
|
||||
node.value = service;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets or replaces a service.
|
||||
* @param other Optional handle with which to replace the service.
|
||||
*/
|
||||
static void reset(const node_type &other = {}) noexcept {
|
||||
service = other.value;
|
||||
}
|
||||
|
||||
private:
|
||||
inline static std::shared_ptr<Service> service = nullptr;
|
||||
// std::shared_ptr because of its type erased allocator which is useful here
|
||||
inline static std::shared_ptr<Service> service{};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
35
src/entt/meta/adl_pointer.hpp
Normal file
35
src/entt/meta/adl_pointer.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef ENTT_META_ADL_POINTER_HPP
|
||||
#define ENTT_META_ADL_POINTER_HPP
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief ADL based lookup function for dereferencing meta pointer-like types.
|
||||
* @tparam Type Element type.
|
||||
* @param value A pointer-like object.
|
||||
* @return The value returned from the dereferenced pointer.
|
||||
*/
|
||||
template<typename Type>
|
||||
decltype(auto) dereference_meta_pointer_like(const Type &value) {
|
||||
return *value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fake ADL based lookup function for meta pointer-like types.
|
||||
* @tparam Type Element type.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct adl_meta_pointer_like {
|
||||
/**
|
||||
* @brief Uses the default ADL based lookup method to resolve the call.
|
||||
* @param value A pointer-like object.
|
||||
* @return The value returned from the dereferenced pointer.
|
||||
*/
|
||||
static decltype(auto) dereference(const Type &value) {
|
||||
return dereference_meta_pointer_like(value);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
247
src/entt/meta/container.hpp
Normal file
247
src/entt/meta/container.hpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#ifndef ENTT_META_CONTAINER_HPP
|
||||
#define ENTT_META_CONTAINER_HPP
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "../container/dense_map.hpp"
|
||||
#include "../container/dense_set.hpp"
|
||||
#include "context.hpp"
|
||||
#include "meta.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct is_dynamic_sequence_container: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct is_dynamic_sequence_container<Type, std::void_t<decltype(&Type::clear)>>: std::true_type {};
|
||||
|
||||
template<typename, typename = void>
|
||||
struct is_key_only_meta_associative_container: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct is_key_only_meta_associative_container<Type, std::void_t<typename Type::mapped_type>>: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct basic_meta_sequence_container_traits {
|
||||
using iterator = meta_sequence_container::iterator;
|
||||
using size_type = std::size_t;
|
||||
|
||||
[[nodiscard]] static size_type size(const any &container) noexcept {
|
||||
return any_cast<const Type &>(container).size();
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool resize([[maybe_unused]] any &container, [[maybe_unused]] size_type sz) {
|
||||
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
cont->resize(sz);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator iter(const meta_ctx &ctx, any &container, const bool as_end) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{ctx, as_end ? cont->end() : cont->begin()};
|
||||
}
|
||||
|
||||
const Type &as_const = any_cast<const Type &>(container);
|
||||
return iterator{ctx, as_end ? as_const.end() : as_const.begin()};
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator insert_or_erase([[maybe_unused]] const meta_ctx &ctx, [[maybe_unused]] any &container, [[maybe_unused]] const any &handle, [[maybe_unused]] meta_any &value) {
|
||||
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
typename Type::const_iterator it{};
|
||||
|
||||
if(auto *non_const = any_cast<typename Type::iterator>(&handle); non_const) {
|
||||
it = *non_const;
|
||||
} else {
|
||||
it = any_cast<const typename Type::const_iterator &>(handle);
|
||||
}
|
||||
|
||||
if(value) {
|
||||
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
|
||||
if(value.allow_cast<typename Type::const_reference>() || value.allow_cast<typename Type::value_type>()) {
|
||||
const auto *element = value.try_cast<std::remove_reference_t<typename Type::const_reference>>();
|
||||
return iterator{ctx, cont->insert(it, element ? *element : value.cast<typename Type::value_type>())};
|
||||
}
|
||||
} else {
|
||||
return iterator{ctx, cont->erase(it)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iterator{};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct basic_meta_associative_container_traits {
|
||||
using iterator = meta_associative_container::iterator;
|
||||
using size_type = std::size_t;
|
||||
|
||||
static constexpr auto key_only = is_key_only_meta_associative_container<Type>::value;
|
||||
|
||||
[[nodiscard]] static size_type size(const any &container) noexcept {
|
||||
return any_cast<const Type &>(container).size();
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool clear(any &container) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
cont->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator iter(const meta_ctx &ctx, any &container, const bool as_end) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{ctx, std::bool_constant<key_only>{}, as_end ? cont->end() : cont->begin()};
|
||||
}
|
||||
|
||||
const auto &as_const = any_cast<const Type &>(container);
|
||||
return iterator{ctx, std::bool_constant<key_only>{}, as_end ? as_const.end() : as_const.begin()};
|
||||
}
|
||||
|
||||
[[nodiscard]] static size_type insert_or_erase(any &container, meta_any &key, meta_any &value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
|
||||
if(value) {
|
||||
if constexpr(key_only) {
|
||||
return cont->insert(key.cast<const typename Type::key_type &>()).second;
|
||||
} else {
|
||||
return value.allow_cast<const typename Type::mapped_type &>() && cont->emplace(key.cast<const typename Type::key_type &>(), value.cast<const typename Type::mapped_type &>()).second;
|
||||
}
|
||||
} else {
|
||||
return cont->erase(key.cast<const typename Type::key_type &>());
|
||||
}
|
||||
}
|
||||
|
||||
return 0u;
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator find(const meta_ctx &ctx, any &container, meta_any &key) {
|
||||
if(key.allow_cast<const typename Type::key_type &>()) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{ctx, std::bool_constant<key_only>{}, cont->find(key.cast<const typename Type::key_type &>())};
|
||||
}
|
||||
|
||||
return iterator{ctx, std::bool_constant<key_only>{}, any_cast<const Type &>(container).find(key.cast<const typename Type::key_type &>())};
|
||||
}
|
||||
|
||||
return iterator{};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::vector`s of any type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_sequence_container_traits<std::vector<Args...>>
|
||||
: internal::basic_meta_sequence_container_traits<std::vector<Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::array`s of any type.
|
||||
* @tparam Type Template arguments for the container.
|
||||
* @tparam N Template arguments for the container.
|
||||
*/
|
||||
template<typename Type, auto N>
|
||||
struct meta_sequence_container_traits<std::array<Type, N>>
|
||||
: internal::basic_meta_sequence_container_traits<std::array<Type, N>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::list`s of any type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_sequence_container_traits<std::list<Args...>>
|
||||
: internal::basic_meta_sequence_container_traits<std::list<Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::deque`s of any type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_sequence_container_traits<std::deque<Args...>>
|
||||
: internal::basic_meta_sequence_container_traits<std::deque<Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `std::map`s of any type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<std::map<Args...>>
|
||||
: internal::basic_meta_associative_container_traits<std::map<Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `std::unordered_map`s of any
|
||||
* type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<std::unordered_map<Args...>>
|
||||
: internal::basic_meta_associative_container_traits<std::unordered_map<Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `std::set`s of any type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<std::set<Args...>>
|
||||
: internal::basic_meta_associative_container_traits<std::set<Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `std::unordered_set`s of any
|
||||
* type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<std::unordered_set<Args...>>
|
||||
: internal::basic_meta_associative_container_traits<std::unordered_set<Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `dense_map`s of any type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<dense_map<Args...>>
|
||||
: internal::basic_meta_associative_container_traits<dense_map<Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `dense_set`s of any type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<dense_set<Args...>>
|
||||
: internal::basic_meta_associative_container_traits<dense_set<Args...>> {};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
67
src/entt/meta/context.hpp
Normal file
67
src/entt/meta/context.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef ENTT_META_CTX_HPP
|
||||
#define ENTT_META_CTX_HPP
|
||||
|
||||
#include "../container/dense_map.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
class meta_ctx;
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct meta_type_node;
|
||||
|
||||
struct meta_context {
|
||||
dense_map<id_type, meta_type_node, identity> value{};
|
||||
|
||||
static inline meta_context &from(meta_ctx &ctx);
|
||||
static inline const meta_context &from(const meta_ctx &ctx);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/*! @brief Disambiguation tag for constructors and the like. */
|
||||
class meta_ctx_arg_t final {};
|
||||
|
||||
/*! @brief Constant of type meta_context_arg_t used to disambiguate calls. */
|
||||
inline constexpr meta_ctx_arg_t meta_ctx_arg{};
|
||||
|
||||
/*! @brief Opaque meta context type. */
|
||||
class meta_ctx: private internal::meta_context {
|
||||
/*! @brief Attorney idiom like model to access the base class. */
|
||||
friend struct internal::meta_context;
|
||||
};
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user