Compare commits
1045 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c6ed1a7c0 | ||
|
|
bd689292e9 | ||
|
|
60ada2efb7 | ||
|
|
bcbd39db35 | ||
|
|
4bfd609f69 | ||
|
|
8e313cf099 | ||
|
|
c37cc47dc8 | ||
|
|
8c2cbe88e5 | ||
|
|
2d69562088 | ||
|
|
74947434d7 | ||
|
|
5fa956395a | ||
|
|
c11e6be645 | ||
|
|
a931a83870 | ||
|
|
4c47abaca7 | ||
|
|
7d527e2633 | ||
|
|
938be3d9c5 | ||
|
|
377dde3e24 | ||
|
|
a0c7b53e67 | ||
|
|
165c6df6a2 | ||
|
|
9055a66364 | ||
|
|
625622c8ad | ||
|
|
0a62b17fce | ||
|
|
7a42ec61b3 | ||
|
|
682184ba08 | ||
|
|
dda9428140 | ||
|
|
e9bbcb6cea | ||
|
|
0c3db25cf4 | ||
|
|
04b9bcc563 | ||
|
|
18f8a103a8 | ||
|
|
576baa5c57 | ||
|
|
514521888c | ||
|
|
f0a306aa6f | ||
|
|
749411c1a9 | ||
|
|
de04de17b9 | ||
|
|
4104c7db7b | ||
|
|
490bf05f3e | ||
|
|
c0c5b81993 | ||
|
|
18477eb65b | ||
|
|
8a1940c0fa | ||
|
|
ea6b70f263 | ||
|
|
780da3c78b | ||
|
|
882cbd2251 | ||
|
|
2975d14352 | ||
|
|
b88c1903a0 | ||
|
|
f7bf2d1245 | ||
|
|
200f35130f | ||
|
|
793d4a9738 | ||
|
|
adff45e6a3 | ||
|
|
7d5b8c9a0e | ||
|
|
0a1b4f9adc | ||
|
|
c6b343ae7d | ||
|
|
b451c43058 | ||
|
|
750b450cd2 | ||
|
|
080966ad8f | ||
|
|
b5cd97f915 | ||
|
|
398a8c70a5 | ||
|
|
0ebf92f015 | ||
|
|
92a03e184d | ||
|
|
be026136db | ||
|
|
1dff52db92 | ||
|
|
685d6c643f | ||
|
|
20c21bbfd6 | ||
|
|
431556c069 | ||
|
|
3b9304480a | ||
|
|
fee356c7f9 | ||
|
|
d700f800aa | ||
|
|
e27826abc5 | ||
|
|
2f7fc36e9e | ||
|
|
d4cfc844a9 | ||
|
|
75f95b367c | ||
|
|
64a71a4e8d | ||
|
|
5623d2f9dc | ||
|
|
a039eed54e | ||
|
|
ddeea943f2 | ||
|
|
6b7513eb1a | ||
|
|
d200d8b3dc | ||
|
|
2b09786326 | ||
|
|
8ed97c2d98 | ||
|
|
04dda74792 | ||
|
|
71f3780ba7 | ||
|
|
3281239bed | ||
|
|
a5c0595896 | ||
|
|
dfb94864db | ||
|
|
879a7a301a | ||
|
|
dcf5f8fdcc | ||
|
|
43dcf712b7 | ||
|
|
94898f6083 | ||
|
|
7674036b67 | ||
|
|
e2418206da | ||
|
|
c2db759653 | ||
|
|
f16ff7071b | ||
|
|
402f040f16 | ||
|
|
9a5ad4235d | ||
|
|
3bffa25af2 | ||
|
|
80ad8de444 | ||
|
|
5f6b0c2fa1 | ||
|
|
e929304ed4 | ||
|
|
6b9f69d0e5 | ||
|
|
5cc2397069 | ||
|
|
0cd14686dd | ||
|
|
b75a7191f8 | ||
|
|
a75a608d0c | ||
|
|
2690c8af2b | ||
|
|
61a2aaa0c9 | ||
|
|
5d823e6853 | ||
|
|
0c5ca42180 | ||
|
|
213ddb74d5 | ||
|
|
0d3cecbff1 | ||
|
|
4d91f8cc5a | ||
|
|
d596ba854f | ||
|
|
03299cedad | ||
|
|
68e8b36684 | ||
|
|
9bd285bfa8 | ||
|
|
2d4324d7cb | ||
|
|
61ecf3906d | ||
|
|
9f0d0d9aeb | ||
|
|
a8fe00242a | ||
|
|
486f02dcb0 | ||
|
|
c60e076f80 | ||
|
|
8f411924b4 | ||
|
|
15f4e28205 | ||
|
|
4ac884dfd1 | ||
|
|
ed026bbc7e | ||
|
|
10bfb24bf1 | ||
|
|
50346a4cf8 | ||
|
|
69331f4796 | ||
|
|
573d982c1c | ||
|
|
257117ce8f | ||
|
|
c3a52a4f27 | ||
|
|
35435d3d82 | ||
|
|
7a672f6a1e | ||
|
|
cf7199e83e | ||
|
|
272b93c8fb | ||
|
|
9efe86621d | ||
|
|
86e2235b83 | ||
|
|
98604629c7 | ||
|
|
990eff8e73 | ||
|
|
1763f8b192 | ||
|
|
06cd683d31 | ||
|
|
bfe84b59d0 | ||
|
|
80fdab4f21 | ||
|
|
b32ec7f656 | ||
|
|
9aeffebc7b | ||
|
|
4f1897e864 | ||
|
|
8f67d4fa06 | ||
|
|
8c8949a312 | ||
|
|
17953cb28a | ||
|
|
6054e22df2 | ||
|
|
f2d89c93c9 | ||
|
|
8f3f5b99c1 | ||
|
|
8396a8c884 | ||
|
|
fc9eb2a9f2 | ||
|
|
be840ee569 | ||
|
|
fc7ca524f2 | ||
|
|
a2a72bcce6 | ||
|
|
e7be9a94e8 | ||
|
|
3652d47932 | ||
|
|
898b50a39c | ||
|
|
68f1bb1872 | ||
|
|
c7556f9245 | ||
|
|
008dd6987c | ||
|
|
1333fa5312 | ||
|
|
171700153e | ||
|
|
0ebf837e6a | ||
|
|
093bb5bd89 | ||
|
|
720dda4103 | ||
|
|
05d11b7fa0 | ||
|
|
9b94f09999 | ||
|
|
ca32a3668a | ||
|
|
060eda7586 | ||
|
|
7c463516b1 | ||
|
|
f23f923608 | ||
|
|
8cc2eb43b3 | ||
|
|
6d31b33a10 | ||
|
|
fe517b0592 | ||
|
|
06bcc770f0 | ||
|
|
75769cde27 | ||
|
|
eec10a861e | ||
|
|
e099db8e15 | ||
|
|
9905ed6cff | ||
|
|
6d6ba9b175 | ||
|
|
793ea69195 | ||
|
|
ef088a298f | ||
|
|
814a3e1404 | ||
|
|
f79c6dbde1 | ||
|
|
6ca3db7de4 | ||
|
|
9c5281c79a | ||
|
|
136b137940 | ||
|
|
1de7c8bbd2 | ||
|
|
93cb729322 | ||
|
|
7d931a8df3 | ||
|
|
e3a736a2a5 | ||
|
|
6b8fe4deff | ||
|
|
3cf061201a | ||
|
|
70d908d854 | ||
|
|
ca9a5f22d0 | ||
|
|
b7e8bb265f | ||
|
|
b5797912d3 | ||
|
|
c113dfe082 | ||
|
|
24a7cc0deb | ||
|
|
4d7fce0edc | ||
|
|
79188ad748 | ||
|
|
b1758e221b | ||
|
|
017123be3e | ||
|
|
b43bbd5e25 | ||
|
|
bb6a4abd6b | ||
|
|
3209cd854e | ||
|
|
d20fc9551f | ||
|
|
9fdc43f6f8 | ||
|
|
4e7833540c | ||
|
|
1c456e2cb6 | ||
|
|
17fc67de1f | ||
|
|
3e47fb6bbd | ||
|
|
8d4597ead0 | ||
|
|
e14033b215 | ||
|
|
41a8a7d921 | ||
|
|
3b3638ac8a | ||
|
|
34d2994cf3 | ||
|
|
011054e515 | ||
|
|
4321f5ece8 | ||
|
|
0b3827366d | ||
|
|
7cd612cc87 | ||
|
|
657f2aade4 | ||
|
|
8cfb5534ab | ||
|
|
737676f23f | ||
|
|
c6a8cf3de6 | ||
|
|
c18f1c3c07 | ||
|
|
fc4605a6b2 | ||
|
|
849852464e | ||
|
|
071febbc0c | ||
|
|
0bb54130c9 | ||
|
|
e7650e263f | ||
|
|
f93d28981f | ||
|
|
106af0f6d8 | ||
|
|
3b71902777 | ||
|
|
7b46448cd9 | ||
|
|
ed590b7ac8 | ||
|
|
bde5d86690 | ||
|
|
06491c6a0a | ||
|
|
f22c7d931b | ||
|
|
2edc59d8bf | ||
|
|
7fd8c1d2b1 | ||
|
|
4e191a95f4 | ||
|
|
a15a7653ee | ||
|
|
a77b34f929 | ||
|
|
c5ae1fc8f5 | ||
|
|
39806a525f | ||
|
|
8718ee3279 | ||
|
|
b79d78350f | ||
|
|
e08302e169 | ||
|
|
6ce08bc01d | ||
|
|
8e5b05301b | ||
|
|
0e5537e4a9 | ||
|
|
f28104bfac | ||
|
|
c7828b380d | ||
|
|
101535b666 | ||
|
|
efe67a700d | ||
|
|
7d2321efde | ||
|
|
0891adb135 | ||
|
|
222cb7b16e | ||
|
|
924cb5f9e0 | ||
|
|
392e522b62 | ||
|
|
3cc3a03c40 | ||
|
|
ebed6d8b7a | ||
|
|
e09593b44b | ||
|
|
3971113c3c | ||
|
|
e74aac0626 | ||
|
|
9509d37431 | ||
|
|
cabdc1d1e3 | ||
|
|
cf7be25ec9 | ||
|
|
75d09d6f8d | ||
|
|
413f1cba9e | ||
|
|
20263bace1 | ||
|
|
f1708811e4 | ||
|
|
a7f0371f9c | ||
|
|
9c66e7219d | ||
|
|
b00038a034 | ||
|
|
2a5f049de8 | ||
|
|
c53b9c0b30 | ||
|
|
84ba626acd | ||
|
|
9d0028e036 | ||
|
|
ad330e4c94 | ||
|
|
6ac13b140f | ||
|
|
f6e22dc4ba | ||
|
|
5c2326fa50 | ||
|
|
1000562b1c | ||
|
|
22d39a0163 | ||
|
|
272844ac90 | ||
|
|
fdbf30abc4 | ||
|
|
5e92b9113f | ||
|
|
4b43368116 | ||
|
|
c5743a6d6c | ||
|
|
d77d6fac48 | ||
|
|
b16c5c3454 | ||
|
|
ad69bec438 | ||
|
|
42c9e41c37 | ||
|
|
32dc7a37c2 | ||
|
|
c2e7139a70 | ||
|
|
778d78d98c | ||
|
|
04bf3bcbfa | ||
|
|
9173c4d2f1 | ||
|
|
0d575c9a97 | ||
|
|
4a2213ef4e | ||
|
|
c6235fc047 | ||
|
|
0cc794e921 | ||
|
|
23dc5eb501 | ||
|
|
100edffc96 | ||
|
|
f7d1a7d849 | ||
|
|
1bb590a57e | ||
|
|
80bb50c06d | ||
|
|
b8cb5de8dd | ||
|
|
beda424de1 | ||
|
|
7b456b9044 | ||
|
|
6cf91dc0e0 | ||
|
|
f69bfbb9f1 | ||
|
|
5ea023c853 | ||
|
|
9687efcaf6 | ||
|
|
5df5d165af | ||
|
|
c4cc708538 | ||
|
|
d552039b95 | ||
|
|
ee3738d5e7 | ||
|
|
80ffcda35d | ||
|
|
7d50da0463 | ||
|
|
47a6a27378 | ||
|
|
a4315a9241 | ||
|
|
7ef8da9e87 | ||
|
|
2aecdfe497 | ||
|
|
d43c5427e6 | ||
|
|
9697549749 | ||
|
|
68e64d33ec | ||
|
|
9cd81bcc37 | ||
|
|
72b2c5ac8e | ||
|
|
94d05fab2f | ||
|
|
be45cfafda | ||
|
|
f0d2f0a415 | ||
|
|
bba3722b2e | ||
|
|
5b9aa95a65 | ||
|
|
818ddc4e3e | ||
|
|
77a66812d4 | ||
|
|
5feca37a78 | ||
|
|
682f6b2392 | ||
|
|
d447f8c14a | ||
|
|
ea5deaf3c9 | ||
|
|
4793cbfd20 | ||
|
|
504768ffb3 | ||
|
|
0ed7e3163e | ||
|
|
11deba942c | ||
|
|
d13851f3b9 | ||
|
|
00729e19b4 | ||
|
|
cbeda51f8d | ||
|
|
c91b1c9155 | ||
|
|
cb499c5aea | ||
|
|
f951d5d5a7 | ||
|
|
5d9afc070e | ||
|
|
6dfd760649 | ||
|
|
439265c486 | ||
|
|
f81f34e6fa | ||
|
|
cc7d4aaeea | ||
|
|
9ac749d7b6 | ||
|
|
a2c2422fdf | ||
|
|
dc6366d6d1 | ||
|
|
5a3faa7256 | ||
|
|
4df87a007d | ||
|
|
5b5821ecc1 | ||
|
|
b3eef84102 | ||
|
|
3066d0ed5c | ||
|
|
88e5fc2609 | ||
|
|
20f395ba36 | ||
|
|
df10c0fcdc | ||
|
|
f119bff9d5 | ||
|
|
1f41b86665 | ||
|
|
5ef5d31419 | ||
|
|
86148d12ee | ||
|
|
3cae3fbb2b | ||
|
|
40109e9ae4 | ||
|
|
767013e0cb | ||
|
|
9b47f44c48 | ||
|
|
8a51b5950c | ||
|
|
e54add5eab | ||
|
|
7d4933790b | ||
|
|
ad147da839 | ||
|
|
dd5043fa81 | ||
|
|
656a2d2036 | ||
|
|
e35b698f26 | ||
|
|
cfabb3b21c | ||
|
|
ecb82e1555 | ||
|
|
9588c3cc5a | ||
|
|
f5983aa751 | ||
|
|
dd8e28a734 | ||
|
|
42acf469cf | ||
|
|
7eca5e840f | ||
|
|
fa579eea59 | ||
|
|
9e8c10a443 | ||
|
|
60a8e9dc2e | ||
|
|
c6dbcf6c5f | ||
|
|
12ec00ac28 | ||
|
|
bc93bf2f79 | ||
|
|
55a6fd65aa | ||
|
|
16a8c25bd6 | ||
|
|
d5aa3973db | ||
|
|
b3718b329d | ||
|
|
8992822fe7 | ||
|
|
32f030a346 | ||
|
|
3961aff10c | ||
|
|
f4b6b513fa | ||
|
|
deed237bbe | ||
|
|
d26a9baa1c | ||
|
|
3e9bddff98 | ||
|
|
e2044f34a8 | ||
|
|
bfd7320609 | ||
|
|
4756933039 | ||
|
|
cfdffa64a1 | ||
|
|
ed1fd2dc26 | ||
|
|
3552f45b83 | ||
|
|
8f6e1588e5 | ||
|
|
1f7efe511d | ||
|
|
9bcd14f31f | ||
|
|
37b56a535d | ||
|
|
21a9525b44 | ||
|
|
374b612c15 | ||
|
|
741fdc3810 | ||
|
|
e9d4c05825 | ||
|
|
7b273db8b8 | ||
|
|
6f2ba58e21 | ||
|
|
b3b794aef5 | ||
|
|
f2fc45dd36 | ||
|
|
c210375657 | ||
|
|
85503302cb | ||
|
|
aaeeba2167 | ||
|
|
e734078bb0 | ||
|
|
98cf280aae | ||
|
|
d14707ed3a | ||
|
|
b157dfbf86 | ||
|
|
ebb9cf017a | ||
|
|
09b9099b1c | ||
|
|
b469b2b353 | ||
|
|
93bfd66fc6 | ||
|
|
66f42d358a | ||
|
|
036196bed3 | ||
|
|
5460315b6e | ||
|
|
3ab0000b31 | ||
|
|
fbffdaf176 | ||
|
|
884f698fab | ||
|
|
5843c75b80 | ||
|
|
0a6968f3a4 | ||
|
|
c2d68e242a | ||
|
|
b69d856ee3 | ||
|
|
8dd00aea29 | ||
|
|
e40537afc2 | ||
|
|
e50ee6a956 | ||
|
|
06784b8d63 | ||
|
|
ad9ef0320b | ||
|
|
efe1e0830a | ||
|
|
16cf5b96a6 | ||
|
|
489bf2fbec | ||
|
|
b35045ac78 | ||
|
|
4f994cbec2 | ||
|
|
8e7b810a3c | ||
|
|
afc94e62f2 | ||
|
|
2f2fe11343 | ||
|
|
3390e3c563 | ||
|
|
df37ba35ac | ||
|
|
1232d7c285 | ||
|
|
3a32f18c78 | ||
|
|
e504310399 | ||
|
|
8d64106372 | ||
|
|
6b4365bec9 | ||
|
|
fc936c3e6f | ||
|
|
ff13ce5f83 | ||
|
|
cc4f7b3ab8 | ||
|
|
a6681e97c9 | ||
|
|
6d6d60d2a7 | ||
|
|
60bdaacfdf | ||
|
|
3cfd6e1739 | ||
|
|
b34131ef4b | ||
|
|
d2b00fc03a | ||
|
|
66d02050a8 | ||
|
|
9a4ffa2142 | ||
|
|
9fc1245013 | ||
|
|
aeaf6f7304 | ||
|
|
140eeae80d | ||
|
|
84646ad457 | ||
|
|
e54928794f | ||
|
|
4c2ed7380f | ||
|
|
85a042b7c9 | ||
|
|
06df4003e8 | ||
|
|
a56e19993b | ||
|
|
83dc6f4a97 | ||
|
|
9e7a31cc74 | ||
|
|
c72a42d38d | ||
|
|
f1e59c4ea4 | ||
|
|
7f397f6aa0 | ||
|
|
48dbba6c70 | ||
|
|
56b9486460 | ||
|
|
f76191d27c | ||
|
|
4a18647aa9 | ||
|
|
f4f6edbc73 | ||
|
|
d878089ecc | ||
|
|
29dba57433 | ||
|
|
46552b0663 | ||
|
|
784ba1e9cd | ||
|
|
b7040d940f | ||
|
|
494714504f | ||
|
|
f6c688d9e3 | ||
|
|
6e68159b5e | ||
|
|
c8c5905913 | ||
|
|
b90607f87b | ||
|
|
cfcee56b95 | ||
|
|
90d1a8b92d | ||
|
|
12d9660016 | ||
|
|
4cbbdf5ffb | ||
|
|
da254e1552 | ||
|
|
afad2972dd | ||
|
|
05bf0aa505 | ||
|
|
13a479eff0 | ||
|
|
52b41cfab5 | ||
|
|
be2b93549f | ||
|
|
a6638cd026 | ||
|
|
ce2c8b3b91 | ||
|
|
cd28e6269b | ||
|
|
760b2aaccf | ||
|
|
537ffb48a7 | ||
|
|
7f0caeb7bc | ||
|
|
13395a88f1 | ||
|
|
9869ab7209 | ||
|
|
0503932abf | ||
|
|
2df0073f53 | ||
|
|
311f6cac91 | ||
|
|
3bf839b89a | ||
|
|
eece255765 | ||
|
|
5ce5968d44 | ||
|
|
64982c34ad | ||
|
|
024d478409 | ||
|
|
c84ff3bcd8 | ||
|
|
e9b64a21a2 | ||
|
|
ea3de5499e | ||
|
|
de32688d46 | ||
|
|
98872fc1cc | ||
|
|
75fa927f31 | ||
|
|
dc784ba2e7 | ||
|
|
57b52a25a4 | ||
|
|
d558d06dcf | ||
|
|
db024cff7d | ||
|
|
c4904e8bcf | ||
|
|
889d6217d1 | ||
|
|
b4e58bdd36 | ||
|
|
8375ee0910 | ||
|
|
137339f48c | ||
|
|
713bcd50a3 | ||
|
|
03a45d9cca | ||
|
|
cffbf89d9b | ||
|
|
f48d16a6e6 | ||
|
|
4905da2637 | ||
|
|
558109bbe1 | ||
|
|
a505d41266 | ||
|
|
9381900b00 | ||
|
|
f6a3b09ec2 | ||
|
|
51c7533265 | ||
|
|
d502bf18da | ||
|
|
db263d2ff9 | ||
|
|
16fae2d625 | ||
|
|
4e3a1a8428 | ||
|
|
aec8a6588c | ||
|
|
3160d991f7 | ||
|
|
7359018880 | ||
|
|
17fb301636 | ||
|
|
7dac5af05d | ||
|
|
d15e514f10 | ||
|
|
fe8320c66f | ||
|
|
7111549c7c | ||
|
|
e8e5f5ee2b | ||
|
|
9caaf569e6 | ||
|
|
03bf0f90b4 | ||
|
|
5df7142f51 | ||
|
|
4d95793123 | ||
|
|
0aa503e69e | ||
|
|
02323e814a | ||
|
|
440fed990d | ||
|
|
c2dcd7257f | ||
|
|
716e3257b1 | ||
|
|
f781441bcd | ||
|
|
3c0aa4d300 | ||
|
|
a57e1a971d | ||
|
|
dc8da9e42c | ||
|
|
7eeb828980 | ||
|
|
b0d7490829 | ||
|
|
0d678442a0 | ||
|
|
2dff7c9d55 | ||
|
|
3fc5de2916 | ||
|
|
a572671947 | ||
|
|
2a6f769092 | ||
|
|
6a25c0df84 | ||
|
|
72127d699a | ||
|
|
b52d0aa133 | ||
|
|
5d006fefcc | ||
|
|
d7c58d00b4 | ||
|
|
9198a27c25 | ||
|
|
31d5d5ff1c | ||
|
|
f3fa359edf | ||
|
|
cba31e00ea | ||
|
|
d366a5ed92 | ||
|
|
d92bea4afd | ||
|
|
bbfd458d2d | ||
|
|
87a114ccc6 | ||
|
|
6852415ffc | ||
|
|
15f65bd58e | ||
|
|
54c7c47e3d | ||
|
|
5e6ccdedc8 | ||
|
|
dadf493aca | ||
|
|
3e5842a467 | ||
|
|
75ae0a10d0 | ||
|
|
e87a8e4b63 | ||
|
|
41282b0ecc | ||
|
|
030095f48d | ||
|
|
e18061bf86 | ||
|
|
38bcbf41a3 | ||
|
|
602626c840 | ||
|
|
41e359502d | ||
|
|
8e64f8accf | ||
|
|
0afab946da | ||
|
|
20d77024f7 | ||
|
|
b1bb9b4b5b | ||
|
|
978e003dbc | ||
|
|
47c65a20a1 | ||
|
|
31d845a5f5 | ||
|
|
03c5661df9 | ||
|
|
48644e568f | ||
|
|
19c0e8029d | ||
|
|
3562bec4a7 | ||
|
|
e863e4fe54 | ||
|
|
c5d89597fc | ||
|
|
091eef0e4c | ||
|
|
96b56ca630 | ||
|
|
56d78c767a | ||
|
|
1f57b2795f | ||
|
|
de054655ab | ||
|
|
bee74568e5 | ||
|
|
ebb2af1225 | ||
|
|
1487ad292b | ||
|
|
d3b8e92294 | ||
|
|
ab1d7d0126 | ||
|
|
01b21afca0 | ||
|
|
ef0056908a | ||
|
|
b021c78550 | ||
|
|
aedaa7f6a4 | ||
|
|
e15af7b500 | ||
|
|
38b34eb986 | ||
|
|
b4fc627c99 | ||
|
|
c9364d3af5 | ||
|
|
baa0d2c23c | ||
|
|
dc154a4b8a | ||
|
|
ba0e9fab45 | ||
|
|
4ab5a375e8 | ||
|
|
f63f36a411 | ||
|
|
f2b8177aaf | ||
|
|
53fab33423 | ||
|
|
4a252bdb84 | ||
|
|
cece4be1ec | ||
|
|
8f23d743ca | ||
|
|
0fa1bc5999 | ||
|
|
281276e84e | ||
|
|
f73409e9ad | ||
|
|
740cf006d9 | ||
|
|
828ecb57e6 | ||
|
|
8794888c98 | ||
|
|
dd7b96fc9e | ||
|
|
1116c33ada | ||
|
|
38fe05db85 | ||
|
|
b2d4832842 | ||
|
|
4c19d2844e | ||
|
|
6f2e5090e1 | ||
|
|
25e5123128 | ||
|
|
8c3ca20d19 | ||
|
|
ee7f24be63 | ||
|
|
a5f58ef49f | ||
|
|
ba5c4ba121 | ||
|
|
fcf455f7ef | ||
|
|
6836d5b024 | ||
|
|
8142136940 | ||
|
|
e76bbb2015 | ||
|
|
6f57622eff | ||
|
|
0c5cab164a | ||
|
|
c67a62de81 | ||
|
|
80eba8afb4 | ||
|
|
0d6615a767 | ||
|
|
fc4d18ce44 | ||
|
|
ddf28480dc | ||
|
|
f49f2331ba | ||
|
|
6526d67d16 | ||
|
|
4d90521fcf | ||
|
|
9165a1df1e | ||
|
|
a1406baf61 | ||
|
|
645b3563a9 | ||
|
|
91eecc1efd | ||
|
|
0782855880 | ||
|
|
b9bfeb9b3d | ||
|
|
0409aab6bb | ||
|
|
947d89844b | ||
|
|
ff8544f97d | ||
|
|
c777cda857 | ||
|
|
a90584f1ce | ||
|
|
4e47c535c4 | ||
|
|
84fee2848f | ||
|
|
42259fb1ce | ||
|
|
e38e88362f | ||
|
|
14be4141fa | ||
|
|
6a4ca4c4ba | ||
|
|
71e61b5270 | ||
|
|
affe6ca7b8 | ||
|
|
f0a07c4530 | ||
|
|
a003575811 | ||
|
|
be3f022445 | ||
|
|
4b5b3fec41 | ||
|
|
4debb79a60 | ||
|
|
f3b763d973 | ||
|
|
356024ed6e | ||
|
|
e8e62638fc | ||
|
|
6ecf1f35c0 | ||
|
|
05863c6a15 | ||
|
|
1a02b6ad57 | ||
|
|
5ee1f3fec1 | ||
|
|
f44c9a1c05 | ||
|
|
715e5318de | ||
|
|
211e5fddc1 | ||
|
|
9347e91db6 | ||
|
|
bebfbada68 | ||
|
|
c239821d12 | ||
|
|
293cbe2769 | ||
|
|
3587eaed9a | ||
|
|
cb9d8ac3f0 | ||
|
|
e544755bbc | ||
|
|
e2003ff17a | ||
|
|
6232c93907 | ||
|
|
6153cdcbbe | ||
|
|
89af917748 | ||
|
|
28466a7316 | ||
|
|
33efea3f03 | ||
|
|
55f1a47fcc | ||
|
|
e9b3eee6d3 | ||
|
|
b400927f02 | ||
|
|
a6d566ae4a | ||
|
|
93979e13ac | ||
|
|
a77e40093d | ||
|
|
695ac44673 | ||
|
|
1cc078e4fb | ||
|
|
94cd89a72a | ||
|
|
5497291c29 | ||
|
|
3c75f7e2fd | ||
|
|
03d8cccc86 | ||
|
|
47bfffc7cc | ||
|
|
9795f60bc1 | ||
|
|
b3b48db957 | ||
|
|
7d2b4fcf57 | ||
|
|
3af8525eb8 | ||
|
|
3306b72f87 | ||
|
|
91a239a277 | ||
|
|
fdaaeea52d | ||
|
|
d81e57daa1 | ||
|
|
ed84c6e9ff | ||
|
|
fe872f6a0d | ||
|
|
d8aa90234a | ||
|
|
28d8041da6 | ||
|
|
1f53d163b7 | ||
|
|
7f38b7668e | ||
|
|
dc70d97760 | ||
|
|
4d0d48f7d9 | ||
|
|
4ecaf18b20 | ||
|
|
30a66cf513 | ||
|
|
9bbc8ad014 | ||
|
|
626b882f26 | ||
|
|
9b44fa47d0 | ||
|
|
9170fc850b | ||
|
|
973f010d85 | ||
|
|
6241543fe2 | ||
|
|
5e99452cf3 | ||
|
|
d058ccd084 | ||
|
|
7e4694ce69 | ||
|
|
b3b7975290 | ||
|
|
5ee0a39616 | ||
|
|
27b9a25d06 | ||
|
|
9f5a6260ce | ||
|
|
b4b85c8d53 | ||
|
|
4bc11e4297 | ||
|
|
ad291d4280 | ||
|
|
f61fd4584a | ||
|
|
536dba3048 | ||
|
|
4760a09d61 | ||
|
|
47ff98e25b | ||
|
|
a638df6cae | ||
|
|
4f1626fce9 | ||
|
|
9b3965c2c9 | ||
|
|
536a43be90 | ||
|
|
09b0e7f528 | ||
|
|
76b6841c51 | ||
|
|
4507c546c1 | ||
|
|
add999d105 | ||
|
|
9cefbc3c79 | ||
|
|
22347cfbd0 | ||
|
|
6966eabd25 | ||
|
|
a32e004c92 | ||
|
|
49d9385aa4 | ||
|
|
9970ba2284 | ||
|
|
20cc85011e | ||
|
|
7f5d4fb8d2 | ||
|
|
03e046f880 | ||
|
|
436f077e0b | ||
|
|
d76cfb06f0 | ||
|
|
2bb947f6de | ||
|
|
8a8f8dfd1b | ||
|
|
15b8db6f61 | ||
|
|
05e0a22fb3 | ||
|
|
ada11c4be1 | ||
|
|
7dbb59adc9 | ||
|
|
02440e17ae | ||
|
|
fa234af36b | ||
|
|
40fdd26788 | ||
|
|
6fa668900e | ||
|
|
17e88e506c | ||
|
|
3bcbea785a | ||
|
|
3bac3d4bbe | ||
|
|
abdb293106 | ||
|
|
f4b960dc93 | ||
|
|
71c217da28 | ||
|
|
4777ca2980 | ||
|
|
4aabca2f0b | ||
|
|
5c31fda9bd | ||
|
|
eecd1dc636 | ||
|
|
998f4b45da | ||
|
|
fb0b7e2aab | ||
|
|
cbb50c1292 | ||
|
|
fcd265a6ed | ||
|
|
357ee3f994 | ||
|
|
e35eed905b | ||
|
|
7942648035 | ||
|
|
93dca93616 | ||
|
|
9f10d32b73 | ||
|
|
21e82abfa7 | ||
|
|
7b48069bd5 | ||
|
|
5721e62ed0 | ||
|
|
e140399725 | ||
|
|
7f1a2b1887 | ||
|
|
0fd70878b3 | ||
|
|
06e88ce062 | ||
|
|
b5201a56df | ||
|
|
9c05f1d8f3 | ||
|
|
093718a1c6 | ||
|
|
c07cb32ef8 | ||
|
|
04da178800 | ||
|
|
5ab8da50cb | ||
|
|
da684a4159 | ||
|
|
ba20bde250 | ||
|
|
cec550ad11 | ||
|
|
62b56e1b56 | ||
|
|
b045846579 | ||
|
|
665aa3c4cf | ||
|
|
0f49a1fe27 | ||
|
|
ad4ab9dc08 | ||
|
|
1293990605 | ||
|
|
c71bf6e8d9 | ||
|
|
716c67d3a5 | ||
|
|
33b1daafa0 | ||
|
|
2532158860 | ||
|
|
da65e347b3 | ||
|
|
c940bc8015 | ||
|
|
9c4676f4c0 | ||
|
|
3b64dae13e | ||
|
|
3126b3efbf | ||
|
|
01e12fa011 | ||
|
|
1d163ee113 | ||
|
|
f97ecd3ba4 | ||
|
|
3d66676c1b | ||
|
|
bf28bab7ba | ||
|
|
a6c2dc89ac | ||
|
|
e36ff3d50e | ||
|
|
dd4c36333b | ||
|
|
9e328ce232 | ||
|
|
624d0994ff | ||
|
|
6ec1ee6072 | ||
|
|
5642788046 | ||
|
|
e8e77bf011 | ||
|
|
964dc6ec87 | ||
|
|
a0d738215a | ||
|
|
9ae1181ca7 | ||
|
|
3b89567d77 | ||
|
|
09bb10377b | ||
|
|
ffbc5519c1 | ||
|
|
c80b634497 | ||
|
|
db6c6573af | ||
|
|
7257dd50c6 | ||
|
|
5f0af48b4c | ||
|
|
41ebe0e779 | ||
|
|
0cc95c947e | ||
|
|
991f66e1a3 | ||
|
|
d75efb9f16 | ||
|
|
3575f00bb4 | ||
|
|
f532221685 | ||
|
|
f502827e88 | ||
|
|
50c842883f | ||
|
|
2f5b25b189 | ||
|
|
fb0fedf8fc | ||
|
|
45e9c12b29 | ||
|
|
e52957fabb | ||
|
|
209f333252 | ||
|
|
aa5c0d14ed | ||
|
|
ca40a3e62f | ||
|
|
8574335fe6 | ||
|
|
9493756895 | ||
|
|
df5e57f381 | ||
|
|
62e05abc77 | ||
|
|
d7d63b09b7 | ||
|
|
ae7b3d87ee | ||
|
|
e2ef08f129 | ||
|
|
8dfa4aa677 | ||
|
|
31522ce703 | ||
|
|
25cad2543d | ||
|
|
34e50d6550 | ||
|
|
b7a06c535d | ||
|
|
bf5b188b13 | ||
|
|
20af487ea9 | ||
|
|
d037976bcd | ||
|
|
330bf8e120 | ||
|
|
7064415265 | ||
|
|
df07350a46 | ||
|
|
66e80820c9 | ||
|
|
5d3173f1b4 | ||
|
|
3b977186ed | ||
|
|
38caafd999 | ||
|
|
d7232dcf56 | ||
|
|
825f73df6b | ||
|
|
696e084b02 | ||
|
|
fcc7306407 | ||
|
|
1f182a25db | ||
|
|
995018f1a7 | ||
|
|
a6fa6f6122 | ||
|
|
1b6462a327 | ||
|
|
6054e93ecc | ||
|
|
3acf03ae1c | ||
|
|
42f4d28715 | ||
|
|
4ee86d8456 | ||
|
|
3b2adc999d | ||
|
|
87ec44d3ee | ||
|
|
182a6d5fe4 | ||
|
|
49b5b5b2b1 | ||
|
|
f984ae4930 | ||
|
|
e6ef506f2f | ||
|
|
2d1ae3d5eb | ||
|
|
d775841457 | ||
|
|
2f60398892 | ||
|
|
393a347bad | ||
|
|
6a4c594792 | ||
|
|
154c16a9d3 | ||
|
|
9536039932 | ||
|
|
cad91fd0d1 | ||
|
|
7615e55e96 | ||
|
|
0f54af1a11 | ||
|
|
a439cf476c | ||
|
|
121e5a0ca8 | ||
|
|
328e53bd7b | ||
|
|
4dd03da2e2 | ||
|
|
ebab67c314 | ||
|
|
5ddab2b9d9 | ||
|
|
265f00becf | ||
|
|
340888e4e2 | ||
|
|
f5bbc895b5 | ||
|
|
57a6c6b238 | ||
|
|
cb10854bc8 | ||
|
|
1796b18284 | ||
|
|
f505050391 | ||
|
|
b0afed4bd0 | ||
|
|
292cbd3d95 | ||
|
|
756e861346 | ||
|
|
6db98b40a1 | ||
|
|
a9852a2d2f | ||
|
|
7302b1544d | ||
|
|
491956a69e | ||
|
|
2b94080ee5 | ||
|
|
4732bd1bf7 | ||
|
|
2bdb44e3ba | ||
|
|
d805c29b73 | ||
|
|
a9187c1f45 | ||
|
|
4e76ae5cc6 | ||
|
|
54b6ee0f27 | ||
|
|
bf8c83e798 | ||
|
|
4aed49b371 | ||
|
|
c1df295845 | ||
|
|
265057be83 | ||
|
|
021fbb6c69 | ||
|
|
843480fdf6 | ||
|
|
3eb78a175e | ||
|
|
de1ae66966 | ||
|
|
ab9a62bcd8 | ||
|
|
41d9e44a23 | ||
|
|
693b85fe40 | ||
|
|
7a90e2a93b | ||
|
|
11c3ea2fdb | ||
|
|
57d604bcb2 | ||
|
|
63e38e40dd | ||
|
|
c66f116449 | ||
|
|
55fb754614 | ||
|
|
afe687e9d7 | ||
|
|
6ca9c77b26 | ||
|
|
990956980b | ||
|
|
f7f30bc5b6 | ||
|
|
81b8d01e96 | ||
|
|
7ecfe45923 | ||
|
|
5212f0c44a | ||
|
|
fa58cedd2e | ||
|
|
8b1b7a0fc9 | ||
|
|
2a37b972d9 | ||
|
|
df7ebd244b | ||
|
|
b4b1cf38a6 | ||
|
|
292d57a60b | ||
|
|
9d6850636a | ||
|
|
8879a76e88 | ||
|
|
0fa38bf0e0 | ||
|
|
36eba38f62 | ||
|
|
fe8d7d78c4 | ||
|
|
ff32d77eba | ||
|
|
84f60ea2be | ||
|
|
cc6fe33709 | ||
|
|
5b3f04c5ff | ||
|
|
dc0bf7bdd8 | ||
|
|
13f21dd942 | ||
|
|
fbe69ae90b | ||
|
|
dedad6a03e | ||
|
|
86d3d2207a | ||
|
|
9c39f76774 | ||
|
|
8c04222a40 | ||
|
|
d84a18e456 | ||
|
|
e42231fab0 | ||
|
|
d60efe04fd | ||
|
|
6e7ca646ec | ||
|
|
cac3e4c62b | ||
|
|
0e323954e4 | ||
|
|
385f5a4379 | ||
|
|
e80d20a740 | ||
|
|
9d4db9738a | ||
|
|
f54859bedf | ||
|
|
556ff733d5 | ||
|
|
4027bfff69 | ||
|
|
dbcc0baa7b | ||
|
|
d45c2aca8a | ||
|
|
fd015edb98 | ||
|
|
5ccb46383c | ||
|
|
fa6fdc4059 |
4
.bazelrc
4
.bazelrc
@@ -5,8 +5,8 @@ build --enable_runfiles
|
||||
build --incompatible_strict_action_env
|
||||
|
||||
# required for googletest
|
||||
build:linux --cxxopt=-std=c++17
|
||||
build:macos --cxxopt=-std=c++17
|
||||
build:linux --cxxopt=-std=c++20
|
||||
build:macos --cxxopt=-std=c++20
|
||||
|
||||
common:ci --announce_rc
|
||||
common:ci --verbose_failures
|
||||
|
||||
@@ -3,6 +3,7 @@ BasedOnStyle: llvm
|
||||
AccessModifierOffset: -4
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
@@ -10,6 +11,8 @@ AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeConceptDeclarations: Always
|
||||
BreakBeforeTernaryOperators: true
|
||||
ColumnLimit: 0
|
||||
DerivePointerAlignment: false
|
||||
@@ -26,17 +29,33 @@ IncludeCategories:
|
||||
Priority: 5
|
||||
IncludeIsMainRegex: "^$"
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentRequiresClause: false
|
||||
IndentWidth: 4
|
||||
InsertBraces: true
|
||||
InsertNewlineAtEOF: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
PointerAlignment: Right
|
||||
RequiresClausePosition: OwnLineWithBrace
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceAroundPointerQualifiers: After
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: Never
|
||||
SpaceBeforeParens: Custom
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: false
|
||||
AfterForeachMacros: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterIfMacros: false
|
||||
AfterOverloadedOperator: false
|
||||
AfterPlacementOperator: false
|
||||
AfterRequiresInClause: true
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
Standard: Latest
|
||||
TabWidth: 4
|
||||
|
||||
@@ -18,8 +18,10 @@ Checks: >
|
||||
performance-*,
|
||||
portability-*,
|
||||
readability-*,
|
||||
-readability-else-after-return,
|
||||
-readability-function-cognitive-complexity,
|
||||
-readability-named-parameter,
|
||||
-readability-redundant-member-init,
|
||||
-readability-uppercase-literal-suffix,
|
||||
CheckOptions:
|
||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnoreAllFloatingPointValues
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
name: tools
|
||||
name: analyzer
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- tools
|
||||
- analyzer
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -11,8 +11,8 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
|
||||
env:
|
||||
IWYU: "0.23"
|
||||
LLVM: "19"
|
||||
IWYU: "0.24"
|
||||
LLVM: "20"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
-DENTT_BUILD_EXAMPLE=ON \
|
||||
-DENTT_BUILD_LIB=ON \
|
||||
-DENTT_BUILD_SNAPSHOT=ON \
|
||||
-DENTT_BUILD_TOOLS=ON \
|
||||
-DENTT_BUILD_TESTBED=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
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
-DENTT_BUILD_EXAMPLE=ON \
|
||||
-DENTT_BUILD_LIB=ON \
|
||||
-DENTT_BUILD_SNAPSHOT=ON \
|
||||
-DENTT_BUILD_TOOLS=ON \
|
||||
-DENTT_BUILD_TESTBED=ON \
|
||||
-DENTT_USE_CLANG_TIDY=ON \
|
||||
..
|
||||
make -j4
|
||||
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@@ -40,10 +40,10 @@ jobs:
|
||||
windows:
|
||||
strategy:
|
||||
matrix:
|
||||
toolset: [default, v142, clang-cl]
|
||||
toolset: [default, v143, clang-cl]
|
||||
include:
|
||||
- toolset: v142
|
||||
toolset_option: -T"v142"
|
||||
- toolset: v143
|
||||
toolset_option: -T"v143"
|
||||
- toolset: clang-cl
|
||||
toolset_option: -T"ClangCl"
|
||||
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
matrix:
|
||||
os: [windows-latest, macOS-latest, ubuntu-latest]
|
||||
id_type: ["std::uint32_t", "std::uint64_t"]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
cxx_std: [cxx_std_20, cxx_std_23]
|
||||
|
||||
timeout-minutes: 15
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
2
.github/workflows/deploy.yml
vendored
2
.github/workflows/deploy.yml
vendored
@@ -2,7 +2,7 @@ name: deploy
|
||||
|
||||
on:
|
||||
release:
|
||||
types: published
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
|
||||
|
||||
2
.github/workflows/sanitizer.yml
vendored
2
.github/workflows/sanitizer.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
matrix:
|
||||
compiler: [clang++]
|
||||
id_type: ["std::uint32_t", "std::uint64_t"]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
cxx_std: [cxx_std_20, cxx_std_23]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
79
.github/workflows/testbed.yml
vendored
Normal file
79
.github/workflows/testbed.yml
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
name: testbed
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install required packages
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y \
|
||||
build-essential \
|
||||
git \
|
||||
make \
|
||||
pkg-config \
|
||||
cmake \
|
||||
ninja-build \
|
||||
gnome-desktop-testing \
|
||||
libasound2-dev \
|
||||
libpulse-dev \
|
||||
libaudio-dev \
|
||||
libjack-dev \
|
||||
libsndio-dev \
|
||||
libx11-dev \
|
||||
libxext-dev \
|
||||
libxrandr-dev \
|
||||
libxcursor-dev \
|
||||
libxfixes-dev \
|
||||
libxi-dev \
|
||||
libxss-dev \
|
||||
libxtst-dev \
|
||||
libxkbcommon-dev \
|
||||
libdrm-dev \
|
||||
libgbm-dev \
|
||||
libgl1-mesa-dev \
|
||||
libgles2-mesa-dev \
|
||||
libegl1-mesa-dev \
|
||||
libdbus-1-dev \
|
||||
libibus-1.0-dev \
|
||||
libudev-dev \
|
||||
libpipewire-0.3-dev \
|
||||
libwayland-dev \
|
||||
libdecor-0-dev \
|
||||
liburing-dev
|
||||
- name: Compile testbed
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTBED=ON ..
|
||||
make -j4
|
||||
|
||||
windows:
|
||||
timeout-minutes: 15
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: seanmiddleditch/gha-setup-ninja@master
|
||||
- name: Compile testbed
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTBED=ON .. -G Ninja
|
||||
cmake --build . -j 4
|
||||
|
||||
macos:
|
||||
timeout-minutes: 15
|
||||
runs-on: macOS-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile testbed
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTBED=ON ..
|
||||
make -j4
|
||||
282
CMakeLists.txt
282
CMakeLists.txt
@@ -1,6 +1,6 @@
|
||||
# EnTT
|
||||
|
||||
cmake_minimum_required(VERSION 3.15.7)
|
||||
cmake_minimum_required(VERSION 3.28)
|
||||
|
||||
# Read project version
|
||||
|
||||
@@ -22,10 +22,10 @@ project(
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
|
||||
message(VERBOSE "*")
|
||||
message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||
message(VERBOSE "* Copyright (c) 2017-2025 Michele Caini <michele.caini@gmail.com>")
|
||||
message(VERBOSE "* Copyright (c) 2017-2026 Michele Caini <michele.caini@gmail.com>")
|
||||
message(VERBOSE "*")
|
||||
|
||||
# CMake stuff
|
||||
@@ -93,7 +93,7 @@ target_include_directories(
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
target_compile_features(EnTT INTERFACE cxx_std_17)
|
||||
target_compile_features(EnTT INTERFACE cxx_std_20)
|
||||
|
||||
if(ENTT_HAS_LIBCPP)
|
||||
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
|
||||
@@ -105,14 +105,132 @@ if(ENTT_HAS_SANITIZER)
|
||||
endif()
|
||||
|
||||
if(ENTT_CLANG_TIDY_EXECUTABLE)
|
||||
set(CMAKE_CXX_CLANG_TIDY "${ENTT_CLANG_TIDY_EXECUTABLE};--config-file=${EnTT_SOURCE_DIR}/.clang-tidy;--header-filter=${EnTT_SOURCE_DIR}/src/entt/.*")
|
||||
endif()
|
||||
set(ENTT_CLANG_TIDY_OPTIONS ";--config-file=${EnTT_SOURCE_DIR}/.clang-tidy;--header-filter=${EnTT_SOURCE_DIR}/src/entt/.*")
|
||||
|
||||
if(MSVC AND NOT (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang"))
|
||||
set(ENTT_CLANG_TIDY_OPTIONS "${ENTT_CLANG_TIDY_OPTIONS};--extra-arg=/EHsc;--extra-arg=/wd4996")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_CLANG_TIDY "${ENTT_CLANG_TIDY_EXECUTABLE}${ENTT_CLANG_TIDY_OPTIONS}")
|
||||
endif()
|
||||
|
||||
# Add EnTT goodies
|
||||
|
||||
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_HEADERS)
|
||||
set(
|
||||
HEADERS_FILES
|
||||
config/config.h
|
||||
config/macro.h
|
||||
config/version.h
|
||||
container/dense_map.hpp
|
||||
container/dense_set.hpp
|
||||
container/table.hpp
|
||||
container/fwd.hpp
|
||||
core/algorithm.hpp
|
||||
core/any.hpp
|
||||
core/bit.hpp
|
||||
core/compressed_pair.hpp
|
||||
core/concepts.hpp
|
||||
core/enum.hpp
|
||||
core/family.hpp
|
||||
core/fwd.hpp
|
||||
core/hashed_string.hpp
|
||||
core/ident.hpp
|
||||
core/iterator.hpp
|
||||
core/memory.hpp
|
||||
core/monostate.hpp
|
||||
core/ranges.hpp
|
||||
core/tuple.hpp
|
||||
core/type_info.hpp
|
||||
core/type_traits.hpp
|
||||
core/utility.hpp
|
||||
entity/component.hpp
|
||||
entity/entity.hpp
|
||||
entity/fwd.hpp
|
||||
entity/group.hpp
|
||||
entity/handle.hpp
|
||||
entity/mixin.hpp
|
||||
entity/helper.hpp
|
||||
entity/organizer.hpp
|
||||
entity/ranges.hpp
|
||||
entity/registry.hpp
|
||||
entity/runtime_view.hpp
|
||||
entity/snapshot.hpp
|
||||
entity/sparse_set.hpp
|
||||
entity/storage.hpp
|
||||
entity/view.hpp
|
||||
graph/adjacency_matrix.hpp
|
||||
graph/dot.hpp
|
||||
graph/flow.hpp
|
||||
graph/fwd.hpp
|
||||
locator/locator.hpp
|
||||
meta/adl_pointer.hpp
|
||||
meta/container.hpp
|
||||
meta/context.hpp
|
||||
meta/factory.hpp
|
||||
meta/fwd.hpp
|
||||
meta/meta.hpp
|
||||
meta/node.hpp
|
||||
meta/pointer.hpp
|
||||
meta/policy.hpp
|
||||
meta/range.hpp
|
||||
meta/resolve.hpp
|
||||
meta/template.hpp
|
||||
meta/type_traits.hpp
|
||||
meta/utility.hpp
|
||||
poly/fwd.hpp
|
||||
poly/poly.hpp
|
||||
process/fwd.hpp
|
||||
process/process.hpp
|
||||
process/scheduler.hpp
|
||||
resource/cache.hpp
|
||||
resource/fwd.hpp
|
||||
resource/loader.hpp
|
||||
resource/resource.hpp
|
||||
signal/delegate.hpp
|
||||
signal/dispatcher.hpp
|
||||
signal/emitter.hpp
|
||||
signal/fwd.hpp
|
||||
signal/sigh.hpp
|
||||
stl/algorithm.hpp
|
||||
stl/array.hpp
|
||||
stl/atomic.hpp
|
||||
stl/bit.hpp
|
||||
stl/cmath.hpp
|
||||
stl/concepts.hpp
|
||||
stl/cstddef.hpp
|
||||
stl/cstdint.hpp
|
||||
stl/functional.hpp
|
||||
stl/ios.hpp
|
||||
stl/iterator.hpp
|
||||
stl/limits.hpp
|
||||
stl/memory.hpp
|
||||
stl/ostream.hpp
|
||||
stl/sstream.hpp
|
||||
stl/string.hpp
|
||||
stl/string_view.hpp
|
||||
stl/tuple.hpp
|
||||
stl/type_traits.hpp
|
||||
stl/utility.hpp
|
||||
stl/vector.hpp
|
||||
tools/davey.hpp
|
||||
entt.hpp
|
||||
fwd.hpp
|
||||
tools.hpp
|
||||
)
|
||||
|
||||
list(TRANSFORM HEADERS_FILES APPEND ">" OUTPUT_VARIABLE HEADERS_BUILD_INTERFACE)
|
||||
list(TRANSFORM HEADERS_BUILD_INTERFACE PREPEND "$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/")
|
||||
|
||||
list(TRANSFORM HEADERS_FILES APPEND ">" OUTPUT_VARIABLE HEADERS_INSTALL_INTERFACE)
|
||||
list(TRANSFORM HEADERS_INSTALL_INTERFACE PREPEND "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/entt/")
|
||||
|
||||
target_sources(EnTT INTERFACE ${HEADERS_BUILD_INTERFACE} ${HEADERS_INSTALL_INTERFACE})
|
||||
endif()
|
||||
|
||||
if(ENTT_INCLUDE_NATVIS)
|
||||
if(MSVC)
|
||||
set(ENTT_HAS_NATVIS TRUE CACHE BOOL "" FORCE)
|
||||
@@ -124,104 +242,29 @@ if(ENTT_INCLUDE_NATVIS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
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/table.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/bit.hpp>
|
||||
$<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/ranges.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/tuple.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_info.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_traits.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/utility.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/component.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/entity.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/group.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/handle.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/mixin.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/helper.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/organizer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/ranges.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/registry.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/runtime_view.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/snapshot.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/sparse_set.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/storage.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/view.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/adjacency_matrix.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/dot.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/flow.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/locator/locator.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/adl_pointer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/container.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/context.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/factory.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/meta.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/node.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/pointer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/policy.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/range.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/resolve.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/template.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/type_traits.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/utility.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/poly.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/process.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/scheduler.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/cache.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/loader.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/resource.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/delegate.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/dispatcher.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/emitter.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/sigh.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entt.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/fwd.hpp>
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENTT_HAS_NATVIS)
|
||||
target_sources(
|
||||
EnTT
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/config.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/container.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/core.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/entity.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/graph.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/locator.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/meta.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/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>
|
||||
set(
|
||||
NATVIS_FILES
|
||||
config.natvis
|
||||
container.natvis
|
||||
core.natvis
|
||||
entity.natvis
|
||||
graph.natvis
|
||||
locator.natvis
|
||||
meta.natvis
|
||||
poly.natvis
|
||||
process.natvis
|
||||
resource.natvis
|
||||
signal.natvis
|
||||
)
|
||||
|
||||
list(TRANSFORM NATVIS_FILES APPEND ">" OUTPUT_VARIABLE NATVIS_BUILD_INTERFACE)
|
||||
list(TRANSFORM NATVIS_BUILD_INTERFACE PREPEND "$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/natvis/")
|
||||
|
||||
list(TRANSFORM NATVIS_FILES APPEND ">" OUTPUT_VARIABLE NATVIS_INSTALL_INTERFACE)
|
||||
list(TRANSFORM NATVIS_INSTALL_INTERFACE PREPEND "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/entt/natvis/")
|
||||
|
||||
target_sources(EnTT INTERFACE ${NATVIS_BUILD_INTERFACE} ${NATVIS_INSTALL_INTERFACE})
|
||||
endif()
|
||||
|
||||
# Install EnTT and all related files
|
||||
@@ -296,29 +339,36 @@ if(ENTT_INSTALL)
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
PATTERN "*.hpp"
|
||||
PATTERN "*.natvis"
|
||||
)
|
||||
|
||||
export(PACKAGE EnTT)
|
||||
endif()
|
||||
|
||||
# Tests
|
||||
# Tests and testbed
|
||||
|
||||
option(ENTT_BUILD_TESTING "Enable building tests." OFF)
|
||||
option(ENTT_BUILD_TESTBED "Enable building testbed." OFF)
|
||||
|
||||
if(ENTT_BUILD_TESTING)
|
||||
option(ENTT_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
|
||||
if(ENTT_BUILD_TESTING OR ENTT_BUILD_TESTBED)
|
||||
set(ENTT_ID_TYPE std::uint32_t CACHE STRING "Type of identifiers to use for tests and testbed")
|
||||
set(ENTT_CXX_STD cxx_std_20 CACHE STRING "C++ standard revision to use for tests and testbed")
|
||||
|
||||
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)
|
||||
# Tests and tesetbed do not work together because SDL gets confused with EnTT tests
|
||||
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)
|
||||
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
elseif(ENTT_BUILD_TESTBED)
|
||||
add_subdirectory(testbed)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Documentation
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2025 Michele Caini, author of EnTT
|
||||
Copyright (c) 2017-2026 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
|
||||
|
||||
20
README.md
20
README.md
@@ -217,12 +217,12 @@ the include paths.
|
||||
## Requirements
|
||||
|
||||
To be able to use `EnTT`, users must provide a full-featured compiler that
|
||||
supports at least C++17.<br/>
|
||||
supports at least C++20.<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.
|
||||
* `CMake` version 3.28 or later.
|
||||
* `Doxygen` version 1.14 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/>
|
||||
@@ -232,7 +232,8 @@ build system of the library.
|
||||
## CMake
|
||||
|
||||
To use `EnTT` from a `CMake` project, just link an existing target to the
|
||||
`EnTT::EnTT` alias.<br/>
|
||||
`EnTT::EnTT` alias.
|
||||
|
||||
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/>
|
||||
@@ -240,12 +241,17 @@ Covering all possible cases would require a treatise 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.
|
||||
|
||||
Note that all `install` calls are guarded by the `ENTT_INSTALL` option to allow
|
||||
using `EnTT` as a submodule without conflicting with user logic.<br/>
|
||||
It is therefore necessary to set the option to true to take advantage of the
|
||||
installation logic provided by this library.
|
||||
|
||||
## Natvis support
|
||||
|
||||
When using `CMake`, just enable the option `ENTT_INCLUDE_NATVIS` and enjoy
|
||||
it.<br/>
|
||||
Otherwise, most of the tools are covered via Natvis and all files can be found
|
||||
in the `natvis` directory, divided by module.<br/>
|
||||
in the `natvis` subdirectory, divided by module.<br/>
|
||||
If you spot errors or have suggestions, any contribution is welcome!
|
||||
|
||||
## Packaging Tools
|
||||
@@ -319,7 +325,7 @@ If you spot errors or have suggestions, any contribution is welcome!
|
||||
`bazel` project, add the following to your `MODULE.bazel` file:
|
||||
|
||||
```starlark
|
||||
bazel_dep(name = "entt", version = "3.12.2")
|
||||
bazel_dep(name = "entt", version = "3.16.0")
|
||||
```
|
||||
|
||||
EnTT will now be available as `@entt` (short for `@entt//:entt`) to be used
|
||||
@@ -403,7 +409,7 @@ know who has participated so far.
|
||||
|
||||
# License
|
||||
|
||||
Code and documentation Copyright (c) 2017-2025 Michele Caini.<br/>
|
||||
Code and documentation Copyright (c) 2017-2026 Michele Caini.<br/>
|
||||
Colorful logo Copyright (c) 2018-2021 Richard Caseres.
|
||||
|
||||
Code released under
|
||||
|
||||
26
TODO
26
TODO
@@ -10,28 +10,28 @@ DOC:
|
||||
* bump entities, reserved bits on identifiers
|
||||
|
||||
TODO:
|
||||
* review all NOLINT
|
||||
* bring nested groups back in place (see bd34e7f)
|
||||
* work stealing job system (see #100) + mt scheduler based on const awareness for types
|
||||
* view: reduce inst due to/improve perf with index-based approach in dispatch_get/pick_and_each/each (single type too, define storage ::at and ::at_as_tuple)
|
||||
* view: update natvis as needed after the last rework, merge pools/filter in the same array, drop check (?) and turn view into a position
|
||||
* view: type-only view_iterator (dyn get/excl sizes), type-only basic_common_view (dyn get/excl sizes with pointer to array from derived)
|
||||
* combine version-mask-vs-version-bits tricks with reserved bits to allow things like enabling/disabling
|
||||
* self contained entity traits to avoid explicit specializations (ie enum constants)
|
||||
* auto type info data from types if present
|
||||
* test: push sharing types further
|
||||
* storage entity: fast range-push from above
|
||||
* table: pop back to support swap and pop, single column access, empty type optimization
|
||||
* review cmake warning about FetchContent_Populate (need .28 and EXCLUDE_FROM_ALL for FetchContent)
|
||||
* suppress -Wself-move on CI with g++13
|
||||
* view specializations for multi, single and filtered elements
|
||||
* don't pass reactive storage by default to callback
|
||||
* runtime types support for meta for types that aren't backed by C++ types
|
||||
* built-in no-pagination storage - no_pagination page size as limits::max
|
||||
* any cdynamic to support const ownership construction
|
||||
* allow passing arguments to meta setter/getter (we can fallback on meta invoke probably)
|
||||
* FetchContent_Populate -> FetchContent_MakeAvailable warnings
|
||||
* doc: IMPLICIT_DIR_DOCS for dir docs or \dir
|
||||
* meta non-const allow_cast overloads: (const int &) to (int &) is not allowed, but (const int &) to (double &) is allowed (support only for convertibles)
|
||||
* improve non-const allow cast with in-place switch
|
||||
* meta fixed_size could return the size directly if present
|
||||
* review build process for testbed (i.e. tests first due to SDL)
|
||||
* use unique_ptr or any for meta_custom_node
|
||||
* paged vector as a standalone class
|
||||
* resource: shared_from_this?
|
||||
* finish the imgui viewer/editor!
|
||||
* archetype-like a-là EnTT support (see my own notes)
|
||||
* organizer: view/storage only based model, no registry
|
||||
* redesign snapshot as a whole
|
||||
* explore "runtime" mode for hashed string where the source is copied internally
|
||||
* storage: shrink_to_fit does not work with reentrant destructor?
|
||||
* make meta_any buffer size configurable (propagate to any)
|
||||
* test trivially_destructible optimization
|
||||
* document stl and injections support
|
||||
|
||||
@@ -2,11 +2,11 @@ load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
|
||||
COPTS = selects.with_or({
|
||||
("//conditions:default", "@rules_cc//cc/compiler:clang", "@rules_cc//cc/compiler:gcc", "@rules_cc//cc/compiler:mingw-gcc"): [
|
||||
"-std=c++17",
|
||||
"-std=c++20",
|
||||
"-w",
|
||||
],
|
||||
("@rules_cc//cc/compiler:msvc-cl", "@rules_cc//cc/compiler:clang-cl"): [
|
||||
"/std:c++17",
|
||||
"/std:c++20",
|
||||
"/permissive-",
|
||||
"/w",
|
||||
],
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.7.2)
|
||||
cmake_minimum_required(VERSION 3.28)
|
||||
project(test_package)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE TRUE)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Doxygen configuration (documentation)
|
||||
|
||||
find_package(Doxygen 1.13)
|
||||
find_package(Doxygen 1.14)
|
||||
|
||||
if(DOXYGEN_FOUND)
|
||||
include(FetchContent)
|
||||
@@ -12,15 +12,10 @@ if(DOXYGEN_FOUND)
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
FetchContent_GetProperties(doxygen-awesome-css)
|
||||
|
||||
if(NOT doxygen-awesome-css_POPULATED)
|
||||
FetchContent_Populate(doxygen-awesome-css)
|
||||
set(doxygen-awesome-css_INCLUDE_DIR ${doxygen-awesome-css_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
FetchContent_MakeAvailable(doxygen-awesome-css)
|
||||
|
||||
set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src)
|
||||
set(DOXY_CSS_DIRECTORY ${doxygen-awesome-css_INCLUDE_DIR})
|
||||
set(DOXY_CSS_DIRECTORY ${doxygen-awesome-css_SOURCE_DIR})
|
||||
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
@@ -37,6 +32,7 @@ if(DOXYGEN_FOUND)
|
||||
md/core.md
|
||||
md/entity.md
|
||||
md/faq.md
|
||||
md/graph.md
|
||||
md/lib.md
|
||||
md/links.md
|
||||
md/locator.md
|
||||
@@ -46,7 +42,6 @@ if(DOXYGEN_FOUND)
|
||||
md/reference.md
|
||||
md/resource.md
|
||||
md/signal.md
|
||||
md/unreal.md
|
||||
doxy.in
|
||||
)
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Definitions](#definitions)
|
||||
* [ENTT_NOEXCEPTION](#entt_noexception)
|
||||
* [ENTT_USE_STL](#entt_use_stl)
|
||||
* [ENTT_NO_EXCEPTION](#entt_no_exception)
|
||||
* [ENTT_USE_ATOMIC](#entt_use_atomic)
|
||||
* [ENTT_ID_TYPE](#entt_id_type)
|
||||
* [ENTT_SPARSE_PAGE](#entt_sparse_page)
|
||||
@@ -13,7 +14,9 @@
|
||||
* [ENTT_ASSERT_CONSTEXPR](#entt_assert_constexpr)
|
||||
* [ENTT_DISABLE_ASSERT](#entt_disable_assert)
|
||||
* [ENTT_NO_ETO](#entt_no_eto)
|
||||
* [ENTT_NO_MIXIN](#entt_no_mixin)
|
||||
* [ENTT_STANDARD_CPP](#entt_standard_cpp)
|
||||
* [Configuration injection](#configuration-injection)
|
||||
|
||||
# Introduction
|
||||
|
||||
@@ -33,7 +36,14 @@ Each parameter can result in internal library definitions. It is 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
|
||||
## ENTT_USE_STL
|
||||
|
||||
Intended for testing purposes, it forces the use of built-in replacements of
|
||||
some parts of the standard library that aren't always available otherwise.<br/>
|
||||
`EnTT` _detects_ these cases on its own, and users should never define this
|
||||
variable explicitly. However, it's still possible if desired.
|
||||
|
||||
## ENTT_NO_EXCEPTION
|
||||
|
||||
Define this variable without assigning any value to it to turn off exception
|
||||
handling in `EnTT`.<br/>
|
||||
@@ -45,8 +55,9 @@ also limited to this library only.
|
||||
In general, `EnTT` does not 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 are not easily accessible to users and are made
|
||||
thread-safe by means of this definition.
|
||||
However, some internal static data shared between threads should be atomic when
|
||||
using `EnTT` from multiple threads, even when dealing with local storage. Define
|
||||
this macro without assigning any value to it to get the job done.
|
||||
|
||||
## ENTT_ID_TYPE
|
||||
|
||||
@@ -105,6 +116,13 @@ 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_NO_MIXIN
|
||||
|
||||
`EnTT` automatically assigns mixins to all storage types to support signaling
|
||||
when creating, destroying, and modifying elements.<br/>
|
||||
Mixins can have a (most likely negligible) cost in terms of performance and
|
||||
compilation time. If unwanted, this macro suppresses automatic generation.
|
||||
|
||||
## ENTT_STANDARD_CPP
|
||||
|
||||
`EnTT` mixes non-standard language features with others that are perfectly
|
||||
@@ -113,3 +131,14 @@ This definition prevents the library from using non-standard techniques, that
|
||||
is, functionalities that are not 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.
|
||||
|
||||
# Configuration injection
|
||||
|
||||
Configuration variables are provided via code or injected directly from the
|
||||
outside via a dedicated file.<br/>
|
||||
`EnTT` uses `__has_include` internally and looks for a specific path, namely
|
||||
`<entt/ext/config.h>`. This can be provided by the user by setting the include
|
||||
paths appropriately.<br/>
|
||||
For example, `CMake` allows users to _bind_ additional include directories to a
|
||||
target with `target_include_directories`. See the test suite, and in particular
|
||||
the `config_ext` test for a practical example.
|
||||
|
||||
@@ -201,19 +201,15 @@ in order to meet them.
|
||||
|
||||
# Bit
|
||||
|
||||
Finding out the population count of an unsigned integral value (`popcount`),
|
||||
whether a number is a power of two or not (`has_single_bit`) as well as the next
|
||||
power of two given a random value (`next_power_of_two`) can be useful.<br/>
|
||||
For example, it helps to allocate memory in pages having a size suitable for the
|
||||
fast modulus:
|
||||
Some general purpose utilities, such as the fast module function:
|
||||
|
||||
```cpp
|
||||
const std::size_t result = entt::fast_mod(value, modulus);
|
||||
```
|
||||
|
||||
Where `modulus` is necessarily a power of two. Perhaps not everyone knows that
|
||||
this type of operation is far superior in terms of performance to the basic
|
||||
modulus and for this reason preferred in many areas.
|
||||
Where `modulus` is necessarily a power of two. This type of operation is far
|
||||
superior in terms of performance to the basic modulus and for this reason
|
||||
preferred in many areas.
|
||||
|
||||
# Compressed pair
|
||||
|
||||
@@ -449,9 +445,9 @@ Some are geared towards simplifying the implementation of (internal or external)
|
||||
allocator aware containers. Others are designed to help the developer with
|
||||
everyday problems.
|
||||
|
||||
The former are very specific and for niche problems. These are tools designed to
|
||||
unwrap fancy or plain pointers (`to_address`) or to help forget the meaning of
|
||||
acronyms like _POCCA_, _POCMA_ or _POCS_.<br/>
|
||||
The former are very specific and for niche problems. For example, there are
|
||||
tools designed to help forget the meaning of acronyms like _POCCA_, _POCMA_ or
|
||||
_POCS_.<br/>
|
||||
I will not describe them here in detail. Instead, I recommend reading the inline
|
||||
documentation to those interested in the subject.
|
||||
|
||||
@@ -466,7 +462,7 @@ The `allocate_unique` function follows this proposal, making a virtue out of
|
||||
necessity:
|
||||
|
||||
```cpp
|
||||
std::unique_ptr<my_type, entt::allocation_deleter<my_type>> ptr = entt::allocate_unique<my_type>(allocator, arguments);
|
||||
std::unique_ptr<my_type, entt::allocation_deleter<allocator_type>> ptr = entt::allocate_unique<my_type>(allocator, arguments);
|
||||
```
|
||||
|
||||
Although the internal implementation is slightly different from what is proposed
|
||||
@@ -528,12 +524,13 @@ Basically, the whole system relies on a handful of classes. In particular:
|
||||
associative containers or for positional accesses in a vector or an array.
|
||||
|
||||
An external generator can also be used if needed. In fact, `type_index` can be
|
||||
specialized by type and is also _sfinae-friendly_ in order to allow more
|
||||
specialized by type or constrained with a concept in order to allow more
|
||||
refined specializations such as:
|
||||
|
||||
```cpp
|
||||
template<typename Type>
|
||||
struct entt::type_index<Type, std::void_d<decltype(Type::index())>> {
|
||||
requires requires { { Type::index() } -> std::same_as<entt::id_type>; }
|
||||
struct entt::type_index<Type> {
|
||||
static entt::id_type value() noexcept {
|
||||
return Type::index();
|
||||
}
|
||||
@@ -562,8 +559,8 @@ Basically, the whole system relies on a handful of classes. In particular:
|
||||
identifiers remain stable across executions. Moreover, they are generated
|
||||
at runtime and are no longer a compile-time thing.
|
||||
|
||||
As it happens with `type_index`, also `type_hash` is a _sfinae-friendly_ class
|
||||
that can be specialized in order to customize its behavior globally or on a
|
||||
As it happens with `type_index`, also `type_hash` can be specialized or
|
||||
constrained with a concept in order to customize its behavior globally or on a
|
||||
per-type or per-traits basis.
|
||||
|
||||
* The name associated with a given type:
|
||||
@@ -593,8 +590,8 @@ Basically, the whole system relies on a handful of classes. In particular:
|
||||
purposes. Users can prevent the library from using these features by means of
|
||||
the `ENTT_STANDARD_CPP` definition. In this case, the name is just empty.
|
||||
|
||||
As it happens with `type_index`, also `type_name` is a _sfinae-friendly_ class
|
||||
that can be specialized in order to customize its behavior globally or on a
|
||||
As it happens with `type_index`, also `type_name` can be specialized or
|
||||
constrained with a concept in order to customize its behavior globally or on a
|
||||
per-type or per-traits basis.
|
||||
|
||||
These are then combined into utilities that aim to offer an API that is somewhat
|
||||
@@ -639,7 +636,7 @@ These are the information made available by `type_info`:
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto idx = entt::type_index<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
|
||||
auto idx = entt::type_index<std::remove_cvref_t<a_type>>::value();
|
||||
```
|
||||
|
||||
* The hash value associated with a given type:
|
||||
@@ -651,7 +648,7 @@ These are the information made available by `type_info`:
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto hash = entt::type_hash<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
|
||||
auto hash = entt::type_hash<std::remove_cvref_t<a_type>>::value();
|
||||
```
|
||||
|
||||
* The name associated with a given type:
|
||||
@@ -663,7 +660,7 @@ These are the information made available by `type_info`:
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto name = entt::type_name<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
|
||||
auto name = entt::type_name<std::remove_cvref_t<a_type>>::value();
|
||||
```
|
||||
|
||||
Where all accessed features are available at compile-time, the `type_info` class
|
||||
@@ -919,10 +916,6 @@ It is not possible to escape the temptation to add utilities of some kind to a
|
||||
library. In fact, `EnTT` also provides a handful of tools to simplify the
|
||||
life of developers:
|
||||
|
||||
* `entt::identity`: the identity function object that will be available with
|
||||
C++20. It returns its argument unchanged and nothing more. It is useful as a
|
||||
sort of _do nothing_ function in template programming.
|
||||
|
||||
* `entt::overload`: a tool to disambiguate different overloads from their
|
||||
function type. It works with both free and member functions.<br/>
|
||||
Consider the following definition:
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
* [Vademecum](#vademecum)
|
||||
* [The Registry, the Entity and the Component](#the-registry-the-entity-and-the-component)
|
||||
* [Observe changes](#observe-changes)
|
||||
* [Auto-binding](#auto-binding)
|
||||
* [Entity lifecycle](#entity-lifecycle)
|
||||
* [Listeners disconnection](#listeners-disconnection)
|
||||
* [They call me reactive storage](#they-call-me-reactive-storage)
|
||||
@@ -409,6 +410,27 @@ There are many useful but less known functionalities that are not described
|
||||
here, such as the connection objects or the possibility to attach listeners with
|
||||
a list of parameters that is shorter than that of the signal itself.
|
||||
|
||||
### Auto-binding
|
||||
|
||||
Users don't need to create bindings manually each and every time. For managed
|
||||
types, they can have `EnTT` setup listeners automatically.<br/>
|
||||
The library searches the types for functions with specific names and signatures,
|
||||
as in the following example:
|
||||
|
||||
```cpp
|
||||
struct my_type {
|
||||
static void on_construct(entt::registry ®istry, const entt::entity entt);
|
||||
static void on_update(entt::registry ®istry, const entt::entity entt);
|
||||
static void on_destroy(entt::registry ®istry, const entt::entity entt);
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
As soon as a storage is created for such a defined type, these functions are
|
||||
associated with the respective signals. The function name is self-explanatory of
|
||||
the target signal.
|
||||
|
||||
### Entity lifecycle
|
||||
|
||||
Observing entities is also possible. In this case, the user must use the entity
|
||||
@@ -1013,9 +1035,10 @@ registry.ctx().erase<my_type>();
|
||||
registry.ctx().erase<my_type>("my_variable"_hs);
|
||||
```
|
||||
|
||||
A context variable must be both default constructible and movable. If the
|
||||
supplied type does not match that of the variable when using a _name_, the
|
||||
operation fails.<br/>
|
||||
There are no strict requirements on the type of a context variable, such as that
|
||||
it must be constructible or movable by default. However, if the supplied type
|
||||
does not match that of the variable when using a _name_, the operation
|
||||
fails.<br/>
|
||||
For all users who want to use the context but do not want to create elements,
|
||||
the `contains` and `find` functions are also available:
|
||||
|
||||
@@ -1328,7 +1351,8 @@ struct transform {
|
||||
|
||||
The `component_traits` class template takes care of _extracting_ the properties
|
||||
from the supplied type.<br/>
|
||||
Plus, it is _sfinae-friendly_ and also supports feature-based specializations.
|
||||
Plus, it can be specialized and constrained with a concept to further customize
|
||||
it on a per type or per feature basis.
|
||||
|
||||
## Empty type optimization
|
||||
|
||||
@@ -1356,7 +1380,7 @@ optimization selectively rather than globally.
|
||||
|
||||
## Void storage
|
||||
|
||||
A void storage (or `entt::storage<void>` or `entt::basic_storage<Type, void>`),
|
||||
A void storage (`entt::storage<void>` or `entt::basic_storage<void, Entity>`),
|
||||
is a fully functional storage type used to create pools not associated with a
|
||||
particular component type.<br/>
|
||||
From a technical point of view, it is in all respects similar to a storage for
|
||||
@@ -1548,7 +1572,7 @@ is not known), there is always the possibility of receiving a `type_info` object
|
||||
for the type of elements associated with the entities (if any):
|
||||
|
||||
```cpp
|
||||
if(entt::type_id<velocity>() == base.type()) {
|
||||
if(entt::type_id<velocity>() == base.info()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -1855,7 +1879,7 @@ specific _queries_.<br/>
|
||||
The type returned when combining multiple elements together is itself a view,
|
||||
more in general a multi component one.
|
||||
|
||||
Combining different elements tries to mimic C++20 ranges:
|
||||
Combining different elements tries to mimic ranges:
|
||||
|
||||
```cpp
|
||||
auto view = registry.view<position>();
|
||||
@@ -2134,13 +2158,13 @@ It means that views and groups generated by a const registry also propagate the
|
||||
constness to the types involved. As an example:
|
||||
|
||||
```cpp
|
||||
entt::view<const position, const velocity> view = std::as_const(registry).view<const position, const velocity>();
|
||||
entt::view<entt::get_t<const position, const velocity>> view = std::as_const(registry).view<const position, const velocity>();
|
||||
```
|
||||
|
||||
Consider the following definition for a non-const view instead:
|
||||
|
||||
```cpp
|
||||
entt::view<position, const velocity> view = registry.view<position, const velocity>();
|
||||
entt::view<entt::get_t<position, const velocity>> view = registry.view<position, const velocity>();
|
||||
```
|
||||
|
||||
In the example above, `view` is used to access either read-only or writable
|
||||
@@ -2345,10 +2369,10 @@ expedients.
|
||||
Finally, `EnTT` is configured via a few compile-time definitions to make some of
|
||||
its parts implicitly thread-safe, roughly speaking only the ones that really
|
||||
make sense and cannot be turned around.<br/>
|
||||
In particular, when multiple instances of objects referencing the type index
|
||||
generator (such as the `registry` class) are used in different threads, then it
|
||||
might be useful to define `ENTT_USE_ATOMIC`.<br/>
|
||||
See the relevant documentation for more information.
|
||||
When using multiple threads with `EnTT`, you should define `ENTT_USE_ATOMIC`
|
||||
unless you know exactly what you are doing. This is true even if each thread
|
||||
only uses thread local data. For more information, see
|
||||
[this section](config.md#entt_use_atomic).
|
||||
|
||||
## Iterators
|
||||
|
||||
|
||||
@@ -194,11 +194,11 @@ a solution in this case:
|
||||
```cpp
|
||||
template<>
|
||||
struct entt::type_hash<Type> final {
|
||||
[[nodiscard]] static constexpr id_type value() noexcept {
|
||||
[[nodiscard]] static consteval id_type value() noexcept {
|
||||
return hashed_string::value("Type");
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr operator id_type() const noexcept {
|
||||
[[nodiscard]] consteval operator id_type() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -28,8 +28,8 @@ The section dedicated to `type_info` contains all the details to get around the
|
||||
issue in a concise and elegant way. Please refer to the specific documentation.
|
||||
|
||||
When working with linked libraries, compile definitions `ENTT_API_EXPORT` and
|
||||
`ENTT_API_IMPORT` are to import or export symbols, so as to make everything work
|
||||
nicely across boundaries.<br/>
|
||||
`ENTT_API_IMPORT` are there 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 do not export any symbols.
|
||||
|
||||
|
||||
@@ -141,6 +141,14 @@ I hope the following lists can grow much more in the future.
|
||||
small demo game with ships and bullets flying everywhere on the screen.
|
||||
* [Lichgate](https://buas.itch.io/lichgate): step into the robes of a powerful
|
||||
mage determined to halt the relentless hordes of undead.
|
||||
* [You Are Circle](https://store.steampowered.com/app/3578190/You_Are_Circle/):
|
||||
a roguelite top-down shooter with a high-contrast vector line aesthetic.
|
||||
* [EnTT Dino](https://github.com/omgitsaheadcrab/entt_dino): a Dinosaur Game
|
||||
clone in C++ using only `SDL2` and `EnTT`.
|
||||
* [Bim!](https://github.com/j-jorge/bim): a last-man-standing arcade online
|
||||
game for Android.
|
||||
* [MonsterWar](https://github.com/WispSnow/MonsterWar): a tower defense game
|
||||
developed in C++ with `SDL3`, `EnTT`, and a few other libraries.
|
||||
|
||||
## Engines and the like:
|
||||
|
||||
@@ -241,6 +249,11 @@ I hope the following lists can grow much more in the future.
|
||||
* [Darmok](https://github.com/miguelibero/darmok): another C++ game engine.
|
||||
* [Magique](https://github.com/gk646/magique): 2D game engine for programmers
|
||||
(or those yet to be).
|
||||
* [Physecs](https://github.com/thfProjects/Physecs): real-time 3D rigid body
|
||||
physics simulation built on `EnTT`.
|
||||
* [KODZA](https://gitlab.com/arqitek/kodza/): A work in progress game engine.
|
||||
* [Omnix](https://github.com/Ace-codes-swift/Omnix): An under-development,
|
||||
multi-purpose 3D engine for `macOS`, using `EnTT` for the ECS.
|
||||
|
||||
## Articles, videos and blog posts:
|
||||
|
||||
@@ -321,6 +334,9 @@ I hope the following lists can grow much more in the future.
|
||||
[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).
|
||||
* [OneArc](https://onearc.com/): [licenses](https://onearc.com/third-party-licensors/)
|
||||
do not lie. Their products use EnTT in some way, but it is not known _what_
|
||||
way.
|
||||
* [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
|
||||
|
||||
154
docs/md/meta.md
154
docs/md/meta.md
@@ -3,10 +3,11 @@
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Names and identifiers](#names-and-identifiers)
|
||||
* [Identifiers](#identifiers)
|
||||
* [Reflection in a nutshell](#reflection-in-a-nutshell)
|
||||
* [Any to the rescue](#any-to-the-rescue)
|
||||
* [Enjoy the runtime](#enjoy-the-runtime)
|
||||
* [Tell me your name](#tell-me-your-name)
|
||||
* [Container support](#container-support)
|
||||
* [Pointer-like types](#pointer-like-types)
|
||||
* [Template information](#template-information)
|
||||
@@ -33,19 +34,19 @@ reflection system for `EnTT`. Maybe I did not do better than others or maybe
|
||||
yes, time will tell me, but at least I can model this tool around the library to
|
||||
which it belongs and not the opposite.
|
||||
|
||||
# Names and identifiers
|
||||
# Identifiers
|
||||
|
||||
The meta system does not force users to rely on the tools provided by the
|
||||
library when it comes to working with names and identifiers. It does this by
|
||||
offering an API that works with opaque identifiers that may or may not be
|
||||
generated by means of a hashed string.<br/>
|
||||
library when it comes to working with identifiers. It does this by offering an
|
||||
API that works with integral values that may or may not be generated by means of
|
||||
a hashed string.<br/>
|
||||
This means that users can assign any type of identifier to the meta objects, as
|
||||
long as they are numeric. It does not matter if they are generated at runtime,
|
||||
at compile-time or with custom functions.
|
||||
|
||||
That being said, the examples in the following sections are all based on the
|
||||
`hashed_string` class as provided by this library. Therefore, where an
|
||||
identifier is required, it is likely that a user defined literal is used as
|
||||
That being said, some of the examples in the following sections are based on the
|
||||
`hashed_string` class as provided by this library. Therefore, where an integral
|
||||
identifier is provided, it is likely that a user defined literal is used as
|
||||
follows:
|
||||
|
||||
```cpp
|
||||
@@ -82,8 +83,8 @@ However, it is also possible to assign custom identifiers to meta types:
|
||||
entt::meta_factory<my_type>{}.type("reflected_type"_hs);
|
||||
```
|
||||
|
||||
Identifiers are used to _retrieve_ meta types at runtime by _name_ other than by
|
||||
type.<br/>
|
||||
Identifiers are used instead of the type to _retrieve_ meta types at runtime, if
|
||||
necessary.<br/>
|
||||
However, users can be interested in adding features to a reflected type so that
|
||||
the reflection system can use it correctly under the hood, while they do not
|
||||
want to also make the type _searchable_. In this case, it is sufficient not to
|
||||
@@ -103,17 +104,6 @@ generally used to create the following:
|
||||
|
||||
Meta default constructors are implicitly generated, if possible.
|
||||
|
||||
* _Destructors_. Both free functions and member functions are valid destructors:
|
||||
|
||||
```cpp
|
||||
entt::meta_factory<my_type>{}.dtor<&destroy>();
|
||||
```
|
||||
|
||||
The purpose is to offer the possibility to free up resources that require
|
||||
_special treatment_ before an object is actually destroyed.<br/>
|
||||
A function should neither delete nor explicitly invoke the destructor of a
|
||||
given instance.
|
||||
|
||||
* _Data members_. Meta data members are actual data members of the underlying
|
||||
type but also static and global variables or constants of any kind. From the
|
||||
point of view of the client, all the variables associated with the reflected
|
||||
@@ -127,7 +117,7 @@ generally used to create the following:
|
||||
```
|
||||
|
||||
The `data` function requires the identifier to use for the meta data member.
|
||||
Users can then access it by _name_ at runtime.<br/>
|
||||
This is then used for runtime access.<br/>
|
||||
Data members are also defined by means of a setter and getter pair. These are
|
||||
either free functions, class members or a mix of them. This approach is also
|
||||
convenient to create read-only properties from a non-const data member:
|
||||
@@ -149,7 +139,7 @@ generally used to create the following:
|
||||
```
|
||||
|
||||
The `func` function requires the identifier to use for the meta data function.
|
||||
Users can then access it by _name_ at runtime.<br/>
|
||||
This is then used for runtime access.<br/>
|
||||
Overloading of meta functions is supported. Overloaded functions are resolved
|
||||
at runtime by the reflection system according to the types of the arguments.
|
||||
|
||||
@@ -240,7 +230,7 @@ In all cases, the returned value is an instance of `meta_type` (possibly with
|
||||
its id). These objects offer an API to know their _runtime identifiers_, to
|
||||
iterate all the meta objects associated with them and even to build instances of
|
||||
the underlying type.<br/>
|
||||
Meta data members and functions are accessed by name:
|
||||
Meta data members and functions are accessed by means of their identifiers:
|
||||
|
||||
* Meta data members:
|
||||
|
||||
@@ -268,6 +258,9 @@ Meta data members and functions are accessed by name:
|
||||
addition, a meta function object is used to invoke the underlying function and
|
||||
then get the return value in the form of a `meta_any` object.
|
||||
|
||||
Both functions search for the elements throughout the meta type hierarchy.
|
||||
However, they offer the option of passing a second boolean argument to stop the
|
||||
search at the top-level meta type.<br/>
|
||||
All the meta objects thus obtained as well as the meta types explicitly convert
|
||||
to a boolean value to check for validity:
|
||||
|
||||
@@ -292,19 +285,49 @@ type.<br/>
|
||||
In particular, the `construct` member function accepts a variable number of
|
||||
arguments and searches for a match. It then returns a `meta_any` object that may
|
||||
or may not be initialized, depending on whether a suitable constructor was found
|
||||
or not.
|
||||
|
||||
There is no object that wraps the destructor of a meta type nor a `destroy`
|
||||
member function in its API. Destructors are invoked implicitly by `meta_any`
|
||||
behind the scenes and users have not to deal with them explicitly. Furthermore,
|
||||
they have no name, cannot be searched and would not have member functions to
|
||||
expose anyway.<br/>
|
||||
Similarly, conversion functions are not directly accessible. They are used
|
||||
internally by `meta_any` and the meta objects when needed.
|
||||
or not.<br/>
|
||||
Conversion functions are not accessible instead. They are used internally by
|
||||
`meta_any` and the meta objects when needed.
|
||||
|
||||
Meta types and meta objects in general contain much more than what was said.
|
||||
Refer to the inline documentation for further details.
|
||||
|
||||
### Tell me your name
|
||||
|
||||
For meta types, data and functions, users can also provide custom _names_:
|
||||
|
||||
```cpp
|
||||
entt::meta_factory<my_type>{}
|
||||
.type("type"_hs, "my_type")
|
||||
.data<&variable>("data"_hs, "variable")
|
||||
.func<&function>("func"_hs, "function");
|
||||
```
|
||||
|
||||
The _label_ provided **should** be a string literal. The library does not make
|
||||
copies. It is up to the user to guarantee the lifetime of the name itself.<br/>
|
||||
String identifiers are returned from the meta objects via the `name` function:
|
||||
|
||||
```cpp
|
||||
const char *name = entt::resolve<my_type>().name();
|
||||
```
|
||||
|
||||
Since most of the time there is no need to differentiate the _name_ from the
|
||||
numeric identifier associated with a meta object, `EnTT` also offers a more
|
||||
compact version of these functions:
|
||||
|
||||
```cpp
|
||||
entt::meta_factory<my_type>{}
|
||||
.type("my_type")
|
||||
.data<&variable>("variable")
|
||||
.func<&function>("function");
|
||||
```
|
||||
|
||||
Again, the name provided **should** be a string literal. The string is then used
|
||||
to generate a numeric identifier with the `hashed_string` class.<br/>
|
||||
Despite support for names, there are no string-based lookup functions available.
|
||||
That is, types (`resolve`) as well as data members (`data`) and function members
|
||||
(`func`) are only _searchable_ by numeric identifiers.
|
||||
|
||||
## Container support
|
||||
|
||||
The runtime reflection system also supports containers of all types.<br/>
|
||||
@@ -312,31 +335,27 @@ Moreover, _containers_ does not necessarily mean those offered by the C++
|
||||
standard library. In fact, user defined data structures can also work with the
|
||||
meta system in many cases.
|
||||
|
||||
To make a container be recognized as such by the meta system, users are required
|
||||
to provide specializations for either the `meta_sequence_container_traits` class
|
||||
or the `meta_associative_container_traits` class, according to the actual _type_
|
||||
of the container.<br/>
|
||||
`EnTT` already exports the specializations for some common classes. In
|
||||
particular:
|
||||
Containers are automatically _detected_ based on some common _traits_.<br/>
|
||||
For example, and not limited to, a sequence container must have a `begin`/`end`
|
||||
pair that returns a forward iterator, while an associative container must also
|
||||
provide a `key_type` member and a `find` function.<br/>
|
||||
If a container is not recognized as such, it is still possible to provide an
|
||||
_adapter_ by specializing the template classes `meta_sequence_container_traits`
|
||||
and `meta_associative_container_traits`. Similarly, users can _inhibit_ the
|
||||
detection of a type as a meta container by specializing the right traits class
|
||||
but without providing any definition.
|
||||
|
||||
* `std::vector`, `std::array`, `std::deque` and `std::list` (but not
|
||||
`std::forward_list`) are supported as _sequence containers_.
|
||||
|
||||
* `std::map`, `std::set` and their unordered counterparts are supported as
|
||||
_associative containers_.
|
||||
|
||||
It is important to include the header file `container.hpp` to make these
|
||||
specializations available to the compiler when needed.<br/>
|
||||
The same file also contains many examples for the users that are interested in
|
||||
Standard library containers are generally exported as meta containers out of the
|
||||
box (with the exception of `std::string`, which is not considered a sequence
|
||||
container on purpose).<br/>
|
||||
However, it is important to include the header file `container.hpp` to make
|
||||
the right specializations available to the compiler when needed.<br/>
|
||||
The same file also contains some examples for the users that are interested in
|
||||
making their own containers available to the meta system.
|
||||
|
||||
When a specialization of the `meta_sequence_container_traits` class exists, the
|
||||
meta system treats the wrapped type as a sequence container. In a similar way,
|
||||
a type is treated as an associative container if a specialization of the
|
||||
`meta_associative_container_traits` class is found for it.<br/>
|
||||
Proxy objects are returned by dedicated members of the `meta_any` class. The
|
||||
following is a deliberately verbose example of how users can access a proxy
|
||||
object for a sequence container:
|
||||
For meta containers, the `meta_any` class returns properly initialized proxy
|
||||
objects for ease of use. The following is a deliberately verbose example of how
|
||||
users can access a proxy object for a sequence container:
|
||||
|
||||
```cpp
|
||||
std::vector<int> vec{1, 2, 3};
|
||||
@@ -349,7 +368,7 @@ if(any.type().is_sequence_container()) {
|
||||
}
|
||||
```
|
||||
|
||||
The method to use to get a proxy object for associative containers is
|
||||
Proxy object for associative containers are accessed in the same way by calling
|
||||
`as_associative_container` instead.<br/>
|
||||
It is not necessary to perform a double check actually. Instead, it is enough to
|
||||
query the meta type or verify that the proxy object is valid. In fact, proxies
|
||||
@@ -767,7 +786,7 @@ other problems.
|
||||
|
||||
There are a few alternatives available at the moment:
|
||||
|
||||
* The _as-is_ policy, associated with the type `entt::as_is_t`.<br/>
|
||||
* The _as-value_ policy, associated with the type `entt::as_value_t`.<br/>
|
||||
This is the default policy. In general, it should never be used explicitly,
|
||||
since it is implicitly selected if no other policy is specified.<br/>
|
||||
In this case, the return values of the functions as well as the properties
|
||||
@@ -805,6 +824,18 @@ There are a few alternatives available at the moment:
|
||||
`as_ref_t` _adapts_ to the constness of the passed object and to that of the
|
||||
return type if any.
|
||||
|
||||
* The _as-is_ policy, associated with the type `entt::as_is_t`.<br/>
|
||||
Useful for decoupling meta type creation code from calling code while still
|
||||
preserving the behavior of data members and member functions as defined:
|
||||
|
||||
```cpp
|
||||
entt::meta_factory<my_type>{}.func<&my_type::any_member, entt::as_is_t>("member"_hs);
|
||||
```
|
||||
|
||||
For data members or member functions that return a reference type, the value
|
||||
is returned by reference with the same constness. In all other cases, the
|
||||
value is returned by copy.
|
||||
|
||||
Some uses are rather trivial, but it is useful to note that there are some less
|
||||
obvious corner cases that can in turn be solved with the use of policies.
|
||||
|
||||
@@ -867,12 +898,9 @@ entt::meta_factory<my_type>{}.traits(my_traits::required | my_traits::hidden);
|
||||
|
||||
In the example above, `EnTT` bitmask enum support is used, but any integral
|
||||
value is fine, as long as it does not exceed 16 bits.<br/>
|
||||
It is not possible to assign traits at different times. Therefore, multiple
|
||||
calls to the `traits` function overwrite previous values. However, traits can be
|
||||
read from meta objects and used to update existing data with a factory,
|
||||
effectively extending them as needed.<br/>
|
||||
Likewise, users can also set traits on meta objects later if needed, as long as
|
||||
the factory is reset to the meta object of interest:
|
||||
Traits can be assigned at different times. Subsequent calls to the `traits`
|
||||
function do not reset previously set values. However, users must reset the
|
||||
factory to the meta object of interest:
|
||||
|
||||
```cpp
|
||||
entt::meta_factory<my_type>{}
|
||||
|
||||
@@ -230,14 +230,14 @@ For a deduced concept, inheritance is achieved in a few steps:
|
||||
```cpp
|
||||
struct DrawableAndErasable: entt::type_list<> {
|
||||
template<typename Base>
|
||||
struct type: typename Drawable::type<Base> {
|
||||
struct type: Drawable::type<Base> {
|
||||
static constexpr auto base = Drawable::impl<Drawable::type<entt::poly_inspector>>::size;
|
||||
void erase() { entt::poly_call<base + 0>(*this); }
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using impl = entt::value_list_cat_t<
|
||||
typename Drawable::impl<Type>,
|
||||
Drawable::impl<Type>,
|
||||
entt::value_list<&Type::erase>
|
||||
>;
|
||||
};
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [The process](#the-process)
|
||||
* [Adaptor](#adaptor)
|
||||
* [Continuation](#continuation)
|
||||
* [Shared process](#shared-process)
|
||||
* [The scheduler](#the-scheduler)
|
||||
|
||||
# Introduction
|
||||
@@ -17,28 +18,20 @@ to define and execute cooperative processes.
|
||||
|
||||
# The process
|
||||
|
||||
A typical task inherits from the `process` class template that stays true to the
|
||||
CRTP idiom. Moreover, derived classes specify what the intended type for elapsed
|
||||
times is.
|
||||
A typical task inherits from the `process` class template. Derived classes also
|
||||
specify what the intended type for elapsed times is.
|
||||
|
||||
A process should expose publicly the following member functions whether needed
|
||||
(note that it is not required to define a function unless the derived class
|
||||
wants to _override_ the default behavior):
|
||||
A process should implement the following member functions whether needed (note
|
||||
that it is not required to define a function unless the derived class wants to
|
||||
_override_ the default behavior):
|
||||
|
||||
* `void update(Delta, void *);`
|
||||
|
||||
This is invoked once per tick until a process is explicitly aborted or ends
|
||||
either with or without errors. Technically speaking, this member function is
|
||||
not strictly required. However, each process should at least define it to work
|
||||
either with or without errors. Each process should at least define it to work
|
||||
_properly_. The `void *` parameter is an opaque pointer to user data (if any)
|
||||
forwarded directly to the process during an update.
|
||||
|
||||
* `void init();`
|
||||
|
||||
This is invoked when the process joins the running queue of a scheduler. It
|
||||
happens usually when the process is attached to the scheduler if it is a top
|
||||
level one, or when it replaces its parent if it is a _continuation_.
|
||||
|
||||
* `void succeeded();`
|
||||
|
||||
This is invoked in case of success, immediately after an update and during the
|
||||
@@ -52,22 +45,24 @@ wants to _override_ the default behavior):
|
||||
* `void aborted();`
|
||||
|
||||
This is invoked only if a process is explicitly aborted. There is no guarantee
|
||||
that it executes in the same tick, it depends solely on whether the process is
|
||||
that it executes in the same tick. It depends solely on whether the process is
|
||||
aborted immediately or not.
|
||||
|
||||
Derived classes can also change the internal state of a process by invoking
|
||||
`succeed` and `fail`, as well as `pause` and `unpause` the process itself.<br/>
|
||||
All these are protected member functions made available to manage the life cycle
|
||||
of a process from a derived class.
|
||||
A class can also change the state of a process by invoking `succeed` and `fail`,
|
||||
as well as `pause` and `unpause` the process itself.<br/>
|
||||
All these are public member functions made available to manage the life cycle of
|
||||
a process easily.
|
||||
|
||||
Here is a minimal example for the sake of curiosity:
|
||||
|
||||
```cpp
|
||||
struct my_process: entt::process<my_process, std::uint32_t> {
|
||||
using delta_type = std::uint32_t;
|
||||
struct my_process: entt::process {
|
||||
using allocator_type = entt::process::allocator_type;
|
||||
using delta_type = entt::process::delta_type;
|
||||
|
||||
my_process(delta_type delay)
|
||||
: remaining{delay}
|
||||
my_process(const allocator_type &allocator, delta_type delay)
|
||||
: entt::process{allocator},
|
||||
remaining{delay}
|
||||
{}
|
||||
|
||||
void update(delta_type delta, void *) {
|
||||
@@ -85,33 +80,49 @@ private:
|
||||
};
|
||||
```
|
||||
|
||||
## Adaptor
|
||||
## Continuation
|
||||
|
||||
Lambdas and functors cannot be used directly with a scheduler because 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.
|
||||
|
||||
The function call operator has a signature similar to the one of the `update`
|
||||
function of a process but for the fact that it receives two extra callbacks to
|
||||
invoke whenever a process terminates with success or with an error:
|
||||
A process may be followed by other processes upon successful termination.<br/>
|
||||
This pairing can be set up at creation time, keeping the processes conceptually
|
||||
separate from each other while still combining them at runtime:
|
||||
|
||||
```cpp
|
||||
void(Delta delta, void *data, auto succeed, auto fail);
|
||||
my_process process{};
|
||||
process.then<my_other_process>();
|
||||
```
|
||||
|
||||
Parameters have the following meaning:
|
||||
This approach allows processes to be developed in isolation and combined to
|
||||
define complex actions.<br/>
|
||||
For example, a delayed operation where a parent process (such as a timer)
|
||||
_schedules_ a child process (the deferred task) once the time is over.
|
||||
|
||||
* `delta` is the elapsed time.
|
||||
* `data` is an opaque pointer to user data if any, `nullptr` otherwise.
|
||||
* `succeed` is a function to call when a process terminates with success.
|
||||
* `fail` is a function to call when a process terminates with errors.
|
||||
The `then` function also accepts lambdas, which are associated with a dedicated
|
||||
process internally:
|
||||
|
||||
Both `succeed` and `fail` accept no parameters at all.
|
||||
```cpp
|
||||
process.then([](entt::process &proc, std::uint32_t delta, void *data) {
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
Note that usually users should not worry about creating adaptors at all. A
|
||||
scheduler creates them internally, each and every time a lambda or a functor is
|
||||
used as a process.
|
||||
The lambda function is such that it accepts a reference to the process that
|
||||
manages it (to be able to terminate it, pause it and so on), plus the usual
|
||||
values also passed to the `update` function.
|
||||
|
||||
## Shared process
|
||||
|
||||
All processes inherit from `std::enable_shared_from_this` to allow sharing with
|
||||
the caller.<br/>
|
||||
The returned smart pointer was created using the allocator associated with the
|
||||
scheduler and therefore all its processes. This same allocator is available by
|
||||
invoking `get_allocator` on the process itself.
|
||||
|
||||
As far as possible, sharing a process is not intended to allow the caller to
|
||||
manage it. This could actually compromise the proper functioning of the
|
||||
scheduler and the process itself.<br/>
|
||||
Rather, the purpose is to allow the callers to save a valid reference to the
|
||||
process, allowing them to intervene in its lifecycle through calls like `pause`
|
||||
and the like.
|
||||
|
||||
# The scheduler
|
||||
|
||||
@@ -124,7 +135,7 @@ it is a good candidate to run one more time the next tick.<br/>
|
||||
A process can also have a _child_. In this case, the parent process is replaced
|
||||
with its child when it terminates and only if it returns with success. In case
|
||||
of errors, both the parent process and its child are discarded. This way, it is
|
||||
easy to create a chain of processes to run sequentially.
|
||||
easy to create a _chain of processes_ to run sequentially.
|
||||
|
||||
Using a scheduler is straightforward. To create it, users must provide only the
|
||||
type for the elapsed times and no arguments at all:
|
||||
@@ -137,7 +148,7 @@ Otherwise, the `scheduler` alias is also available for the most common cases. It
|
||||
uses `std::uint32_t` as a default type:
|
||||
|
||||
```cpp
|
||||
entt::scheduler scheduler;
|
||||
entt::scheduler scheduler{};
|
||||
```
|
||||
|
||||
The class has member functions to query its internal data structures, like
|
||||
@@ -154,34 +165,33 @@ entt::scheduler::size_type size = scheduler.size();
|
||||
scheduler.clear();
|
||||
```
|
||||
|
||||
To attach a process to a scheduler, there are mainly two ways:
|
||||
To attach a process to a scheduler, invoke the `attach` function with a process
|
||||
type and the arguments to use to construct it:
|
||||
|
||||
* If the process inherits from the `process` class template, it is enough to
|
||||
indicate its type and submit all the parameters required to construct it to
|
||||
the `attach` member function:
|
||||
```cpp
|
||||
scheduler.attach<my_process>(_1000u);
|
||||
```
|
||||
|
||||
```cpp
|
||||
scheduler.attach<my_process>(1000u);
|
||||
```
|
||||
The scheduler will also provide the process with its allocator as the first
|
||||
argument.<br>
|
||||
In case of lambdas or functors, the required signature is the one already seen
|
||||
for the `then` function of a process:
|
||||
|
||||
* Otherwise, in case of a lambda or a functor, it is enough to provide an
|
||||
instance of the class to the `attach` member function:
|
||||
```cpp
|
||||
scheduler.attach([](entt::process &, std::uint32_t, void *){ /* ... */ });
|
||||
```
|
||||
|
||||
```cpp
|
||||
scheduler.attach([](auto...){ /* ... */ });
|
||||
```
|
||||
|
||||
In both cases, the scheduler is returned and its `then` member function can be
|
||||
used to create chains of processes to run sequentially.<br/>
|
||||
In both cases, the newly created process is returned by reference and its `then`
|
||||
member function is used to create chains of processes to run sequentially.<br/>
|
||||
As a minimal example of use:
|
||||
|
||||
```cpp
|
||||
// schedules a task in the form of a lambda function
|
||||
scheduler.attach([](auto delta, void *, auto succeed, auto fail) {
|
||||
scheduler.attach([](entt::process &, std::uint32_t, void *) {
|
||||
// ...
|
||||
})
|
||||
// appends a child in the form of another lambda function
|
||||
.then([](auto delta, void *, auto succeed, auto fail) {
|
||||
.then([](entt::process &, std::uint32_t, void *) {
|
||||
// ...
|
||||
})
|
||||
// appends a child in the form of a process class
|
||||
@@ -209,3 +219,6 @@ scheduler.abort(true);
|
||||
// ... or gracefully during the next tick
|
||||
scheduler.abort();
|
||||
```
|
||||
|
||||
The argument passed to the `abort` function indicates whether execution should
|
||||
be stopped immediately or processes should be notified on the next tick.
|
||||
|
||||
@@ -112,13 +112,13 @@ struct my_loader {
|
||||
struct from_disk_tag{};
|
||||
struct from_network_tag{};
|
||||
|
||||
template<typename Args>
|
||||
template<typename... Args>
|
||||
result_type operator()(from_disk_tag, Args&&... args) {
|
||||
// ...
|
||||
return std::make_shared<my_resource>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Args>
|
||||
template<typename... Args>
|
||||
result_type operator()(from_network_tag, Args&&... args) {
|
||||
// ...
|
||||
return std::make_shared<my_resource>(std::forward<Args>(args)...);
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* [Raw access](#raw-access)
|
||||
* [Signals](#signals)
|
||||
* [Event dispatcher](#event-dispatcher)
|
||||
* [Connect, disconnect, publish](#connect-disconnect-publish)]
|
||||
* [Named queues](#named-queues)
|
||||
* [Event emitter](#event-emitter)
|
||||
|
||||
@@ -382,34 +383,45 @@ signal.collect(std::ref(collector));
|
||||
# Event dispatcher
|
||||
|
||||
The event dispatcher class allows users to trigger immediate events or to queue
|
||||
and publish them all together later.<br/>
|
||||
This class lazily instantiates its queues. Therefore, it is not necessary to
|
||||
_announce_ the event types in advance:
|
||||
and publish them all together later:
|
||||
|
||||
```cpp
|
||||
// define a general purpose dispatcher
|
||||
entt::dispatcher dispatcher{};
|
||||
```
|
||||
|
||||
A listener registered with a dispatcher is such that its type offers one or more
|
||||
member functions that take arguments of type `Event &` for any type of event,
|
||||
regardless of the return value.<br/>
|
||||
These functions are linked directly via `connect` to a _sink_:
|
||||
This class lazily instantiates its queues. Therefore, it is not necessary to
|
||||
_announce_ the event types in advance.
|
||||
|
||||
## Connect, disconnect, publish
|
||||
|
||||
Listeners registered with a dispatcher are mainly of two types: free and member
|
||||
functions. Lambdas as template functions are also accepted and belong to the
|
||||
first group.<br/>
|
||||
In all cases, a listener accepts an argument of type `Event &` for any type
|
||||
of event, regardless of the return value.
|
||||
|
||||
Listeners are linked directly via `connect` to a _sink_ object:
|
||||
|
||||
```cpp
|
||||
struct an_event { int value; };
|
||||
struct another_event {};
|
||||
|
||||
void on_event(const an_event &event) { /* ... */ }
|
||||
|
||||
struct listener {
|
||||
void receive(const an_event &) { /* ... */ }
|
||||
void method(const another_event &) { /* ... */ }
|
||||
// Member function listener
|
||||
void on_event(const another_event &) { /* ... */ }
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
// free function listener
|
||||
dispatcher.sink<an_event>().connect<&on_event>();
|
||||
|
||||
listener listener;
|
||||
dispatcher.sink<an_event>().connect<&listener::receive>(listener);
|
||||
dispatcher.sink<another_event>().connect<&listener::method>(listener);
|
||||
// member function listener
|
||||
dispatcher.sink<another_event>().connect<&listener::on_event>(listener);
|
||||
```
|
||||
|
||||
Note that connecting listeners within event handlers can result in undefined
|
||||
@@ -418,7 +430,13 @@ 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);
|
||||
// disconnects a free function
|
||||
dispatcher.sink<an_event>().disconnect<&on_event>();
|
||||
|
||||
// disconnect a member function of an instance
|
||||
dispatcher.sink<another_event>().disconnect<&listener::on_event>(listener);
|
||||
|
||||
// disconnect all member functions of an instance, if any
|
||||
dispatcher.sink<another_event>().disconnect(&listener);
|
||||
```
|
||||
|
||||
@@ -427,7 +445,7 @@ to all the listeners registered so far:
|
||||
|
||||
```cpp
|
||||
dispatcher.trigger(an_event{42});
|
||||
dispatcher.trigger<another_event>();
|
||||
dispatcher.trigger(another_event{});
|
||||
```
|
||||
|
||||
Listeners are invoked immediately, order of execution is not guaranteed. This
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
# EnTT and Unreal Engine
|
||||
|
||||
# Table of Contents
|
||||
|
||||
* [Enable Cpp17](#enable-cpp17)
|
||||
* [EnTT as a third party module](#entt-as-a-third-party-module)
|
||||
* [Include EnTT](#include-entt)
|
||||
|
||||
## Enable Cpp17
|
||||
|
||||
> Skip this part if you are working with UE5, Since UE5 uses cpp17 by default.
|
||||
|
||||
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 does not already contain a file of this type, it is 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 does not 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 does
|
||||
not 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.
|
||||
@@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,46 +1,47 @@
|
||||
#ifndef ENTT_CONFIG_CONFIG_H
|
||||
#define ENTT_CONFIG_CONFIG_H
|
||||
|
||||
#if __has_include(<entt/ext/config.h>)
|
||||
# include <entt/ext/config.h>
|
||||
#endif
|
||||
|
||||
#include <version>
|
||||
#include "version.h"
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
|
||||
|
||||
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
|
||||
# define ENTT_CONSTEXPR
|
||||
#ifdef ENTT_USE_STL
|
||||
# define ENTT_FORCE_STL
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION)
|
||||
# define ENTT_THROW throw
|
||||
# define ENTT_TRY try
|
||||
# define ENTT_CATCH catch(...)
|
||||
#else
|
||||
# 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
|
||||
|
||||
#if __has_include(<version>)
|
||||
# include <version>
|
||||
#
|
||||
# if defined(__cpp_consteval)
|
||||
# define ENTT_CONSTEVAL consteval
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_CONSTEVAL
|
||||
#if defined(__cpp_consteval)
|
||||
# define ENTT_CONSTEVAL consteval
|
||||
#else
|
||||
# define ENTT_CONSTEVAL constexpr
|
||||
#endif
|
||||
|
||||
#ifdef ENTT_USE_ATOMIC
|
||||
# include <atomic>
|
||||
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
||||
# include "../stl/atomic.hpp"
|
||||
# define ENTT_MAYBE_ATOMIC(Type) stl::atomic<Type>
|
||||
#else
|
||||
# define ENTT_MAYBE_ATOMIC(Type) Type
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_ID_TYPE
|
||||
# include <cstdint>
|
||||
# define ENTT_ID_TYPE std::uint32_t
|
||||
# include "../stl/cstdint.hpp"
|
||||
# define ENTT_ID_TYPE stl::uint32_t
|
||||
#else
|
||||
# include <cstdint> // provides coverage for types in the std namespace
|
||||
# include "../stl/cstdint.hpp" // provides coverage for types in the std namespace
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_SPARSE_PAGE
|
||||
@@ -95,6 +96,32 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#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
|
||||
#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
|
||||
#endif
|
||||
|
||||
#if defined _MSC_VER
|
||||
# pragma detect_mismatch("entt.version", ENTT_VERSION)
|
||||
# pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY))
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*)
|
||||
|
||||
#define ENTT_VERSION_MAJOR 3
|
||||
#define ENTT_VERSION_MINOR 15
|
||||
#define ENTT_VERSION_MAJOR 4
|
||||
#define ENTT_VERSION_MINOR 0
|
||||
#define ENTT_VERSION_PATCH 0
|
||||
|
||||
#define ENTT_VERSION \
|
||||
|
||||
@@ -1,54 +1,57 @@
|
||||
#ifndef ENTT_CONTAINER_DENSE_MAP_HPP
|
||||
#define ENTT_CONTAINER_DENSE_MAP_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <compare>
|
||||
#include "../config/config.h"
|
||||
#include "../core/bit.hpp"
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/memory.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/bit.hpp"
|
||||
#include "../stl/cmath.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/limits.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits<stl::size_t>::max)();
|
||||
|
||||
template<typename Key, typename Type>
|
||||
struct dense_map_node final {
|
||||
using value_type = std::pair<Key, Type>;
|
||||
using value_type = stl::pair<Key, Type>;
|
||||
|
||||
template<typename... Args>
|
||||
dense_map_node(const std::size_t pos, Args &&...args)
|
||||
dense_map_node(const stl::size_t pos, Args &&...args)
|
||||
: next{pos},
|
||||
element{std::forward<Args>(args)...} {}
|
||||
element{stl::forward<Args>(args)...} {}
|
||||
|
||||
template<typename Allocator, typename... Args>
|
||||
dense_map_node(std::allocator_arg_t, const Allocator &allocator, const std::size_t pos, Args &&...args)
|
||||
template<typename... Args>
|
||||
dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args)
|
||||
: next{pos},
|
||||
element{entt::make_obj_using_allocator<value_type>(allocator, std::forward<Args>(args)...)} {}
|
||||
element{entt::make_obj_using_allocator<value_type>(allocator, stl::forward<Args>(args)...)} {}
|
||||
|
||||
template<typename Allocator>
|
||||
dense_map_node(std::allocator_arg_t, const Allocator &allocator, const dense_map_node &other)
|
||||
dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other)
|
||||
: next{other.next},
|
||||
element{entt::make_obj_using_allocator<value_type>(allocator, other.element)} {}
|
||||
|
||||
template<typename Allocator>
|
||||
dense_map_node(std::allocator_arg_t, const Allocator &allocator, dense_map_node &&other)
|
||||
dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other)
|
||||
: next{other.next},
|
||||
element{entt::make_obj_using_allocator<value_type>(allocator, std::move(other.element))} {}
|
||||
element{entt::make_obj_using_allocator<value_type>(allocator, stl::move(other.element))} {}
|
||||
|
||||
std::size_t next;
|
||||
stl::size_t next;
|
||||
value_type element;
|
||||
};
|
||||
|
||||
@@ -57,16 +60,17 @@ class dense_map_iterator final {
|
||||
template<typename>
|
||||
friend class dense_map_iterator;
|
||||
|
||||
using first_type = decltype(std::as_const(std::declval<It>()->element.first));
|
||||
using second_type = decltype((std::declval<It>()->element.second));
|
||||
static_assert(stl::is_pointer_v<It>, "Not a pointer type");
|
||||
using first_type = decltype(stl::as_const(stl::declval<It>()->element.first));
|
||||
using second_type = decltype((stl::declval<It>()->element.second));
|
||||
|
||||
public:
|
||||
using value_type = std::pair<first_type, second_type>;
|
||||
using value_type = stl::pair<first_type, second_type>;
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::random_access_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::random_access_iterator_tag;
|
||||
|
||||
constexpr dense_map_iterator() noexcept
|
||||
: it{} {}
|
||||
@@ -74,7 +78,8 @@ public:
|
||||
constexpr dense_map_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>>>
|
||||
template<typename Other>
|
||||
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
|
||||
constexpr dense_map_iterator(const dense_map_iterator<Other> &other) noexcept
|
||||
: it{other.it} {}
|
||||
|
||||
@@ -126,85 +131,56 @@ public:
|
||||
return operator[](0);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr std::ptrdiff_t operator-(const dense_map_iterator<Lhs> &, const dense_map_iterator<Rhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator<Other> &other) const noexcept {
|
||||
return it - other.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr bool operator==(const dense_map_iterator<Lhs> &, const dense_map_iterator<Rhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_map_iterator<Other> &other) const noexcept {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr bool operator<(const dense_map_iterator<Lhs> &, const dense_map_iterator<Rhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr auto operator<=>(const dense_map_iterator<Other> &other) const noexcept {
|
||||
return it <=> other.it;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
};
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it - rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator<(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it < rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator>(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator<=(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator>=(const dense_map_iterator<Lhs> &lhs, const dense_map_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
class dense_map_local_iterator final {
|
||||
template<typename>
|
||||
friend class dense_map_local_iterator;
|
||||
|
||||
using first_type = decltype(std::as_const(std::declval<It>()->element.first));
|
||||
using second_type = decltype((std::declval<It>()->element.second));
|
||||
static_assert(stl::is_pointer_v<It>, "Not a pointer type");
|
||||
using first_type = decltype(stl::as_const(stl::declval<It>()->element.first));
|
||||
using second_type = decltype((stl::declval<It>()->element.second));
|
||||
|
||||
public:
|
||||
using value_type = std::pair<first_type, second_type>;
|
||||
using value_type = stl::pair<first_type, second_type>;
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::forward_iterator_tag;
|
||||
|
||||
constexpr dense_map_local_iterator() noexcept
|
||||
: it{},
|
||||
offset{} {}
|
||||
constexpr dense_map_local_iterator() noexcept = default;
|
||||
|
||||
constexpr dense_map_local_iterator(It iter, const std::size_t pos) noexcept
|
||||
constexpr dense_map_local_iterator(It iter, const stl::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>>>
|
||||
template<typename Other>
|
||||
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
|
||||
constexpr dense_map_local_iterator(const dense_map_local_iterator<Other> &other) noexcept
|
||||
: it{other.it},
|
||||
offset{other.offset} {}
|
||||
|
||||
constexpr dense_map_local_iterator &operator++() noexcept {
|
||||
return (offset = it[static_cast<typename It::difference_type>(offset)].next), *this;
|
||||
return (offset = it[static_cast<difference_type>(offset)].next), *this;
|
||||
}
|
||||
|
||||
constexpr dense_map_local_iterator operator++(int) noexcept {
|
||||
@@ -217,29 +193,24 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
const auto idx = static_cast<typename It::difference_type>(offset);
|
||||
const auto idx = static_cast<difference_type>(offset);
|
||||
return {it[idx].element.first, it[idx].element.second};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t index() const noexcept {
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_map_local_iterator<Other> &other) const noexcept {
|
||||
return offset == other.offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr stl::size_t index() const noexcept {
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
std::size_t offset;
|
||||
It it{};
|
||||
stl::size_t offset{dense_map_placeholder_position};
|
||||
};
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_map_local_iterator<Lhs> &lhs, const dense_map_local_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.index() == rhs.index();
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const dense_map_local_iterator<Lhs> &lhs, const dense_map_local_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
@@ -259,36 +230,34 @@ template<typename Lhs, typename Rhs>
|
||||
template<typename Key, typename Type, typename Hash, typename KeyEqual, typename Allocator>
|
||||
class dense_map {
|
||||
static constexpr float default_threshold = 0.875f;
|
||||
static constexpr std::size_t minimum_capacity = 8u;
|
||||
static constexpr stl::size_t minimum_capacity = 8u;
|
||||
static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position;
|
||||
|
||||
using node_type = internal::dense_map_node<Key, Type>;
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, std::pair<const Key, 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>>;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, stl::pair<const Key, Type>>, "Invalid value type");
|
||||
using sparse_container_type = stl::vector<stl::size_t, typename alloc_traits::template rebind_alloc<stl::size_t>>;
|
||||
using packed_container_type = stl::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::size_t key_to_bucket(const Other &key) const noexcept {
|
||||
[[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
|
||||
return fast_mod(static_cast<size_type>(sparse.second()(key)), bucket_count());
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &key, std::size_t bucket) {
|
||||
for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
|
||||
if(packed.second()(it->first, key)) {
|
||||
return begin() + static_cast<difference_type>(it.index());
|
||||
[[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) {
|
||||
for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) {
|
||||
if(packed.second()(packed.first()[offset].element.first, key)) {
|
||||
return begin() + static_cast<iterator::difference_type>(offset);
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &key, std::size_t bucket) const {
|
||||
for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
|
||||
if(packed.second()(it->first, key)) {
|
||||
return cbegin() + static_cast<difference_type>(it.index());
|
||||
[[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const {
|
||||
for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) {
|
||||
if(packed.second()(packed.first()[offset].element.first, key)) {
|
||||
return cbegin() + static_cast<const_iterator::difference_type>(offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,14 +269,14 @@ class dense_map {
|
||||
const auto index = key_to_bucket(key);
|
||||
|
||||
if(auto it = constrained_find(key, index); it != end()) {
|
||||
return std::make_pair(it, false);
|
||||
return stl::make_pair(it, false);
|
||||
}
|
||||
|
||||
packed.first().emplace_back(sparse.first()[index], std::piecewise_construct, std::forward_as_tuple(std::forward<Other>(key)), std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward<Other>(key)), stl::forward_as_tuple(stl::forward<Args>(args)...));
|
||||
sparse.first()[index] = packed.first().size() - 1u;
|
||||
rehash_if_required();
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
return stl::make_pair(--end(), true);
|
||||
}
|
||||
|
||||
template<typename Other, typename Arg>
|
||||
@@ -315,21 +284,21 @@ class dense_map {
|
||||
const auto index = key_to_bucket(key);
|
||||
|
||||
if(auto it = constrained_find(key, index); it != end()) {
|
||||
it->second = std::forward<Arg>(value);
|
||||
return std::make_pair(it, false);
|
||||
it->second = stl::forward<Arg>(value);
|
||||
return stl::make_pair(it, false);
|
||||
}
|
||||
|
||||
packed.first().emplace_back(sparse.first()[index], std::forward<Other>(key), std::forward<Arg>(value));
|
||||
packed.first().emplace_back(sparse.first()[index], stl::forward<Other>(key), stl::forward<Arg>(value));
|
||||
sparse.first()[index] = packed.first().size() - 1u;
|
||||
rehash_if_required();
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
return stl::make_pair(--end(), true);
|
||||
}
|
||||
|
||||
void move_and_pop(const std::size_t pos) {
|
||||
void move_and_pop(const stl::size_t pos) {
|
||||
if(const auto last = size() - 1u; pos != last) {
|
||||
size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)];
|
||||
packed.first()[pos] = std::move(packed.first().back());
|
||||
packed.first()[pos] = stl::move(packed.first().back());
|
||||
for(; *curr != last; curr = &packed.first()[*curr].next) {}
|
||||
*curr = pos;
|
||||
}
|
||||
@@ -351,23 +320,23 @@ public:
|
||||
/*! @brief Mapped type of the container. */
|
||||
using mapped_type = Type;
|
||||
/*! @brief Key-value type of the container. */
|
||||
using value_type = std::pair<const Key, Type>;
|
||||
using value_type = stl::pair<const Key, Type>;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Type of function to use to hash the keys. */
|
||||
using hasher = Hash;
|
||||
/*! @brief Type of function to use to compare the keys for equality. */
|
||||
using key_equal = KeyEqual;
|
||||
/*! @brief Input iterator type. */
|
||||
using iterator = internal::dense_map_iterator<typename packed_container_type::iterator>;
|
||||
using iterator = internal::dense_map_iterator<typename packed_container_type::pointer>;
|
||||
/*! @brief Constant input iterator type. */
|
||||
using const_iterator = internal::dense_map_iterator<typename packed_container_type::const_iterator>;
|
||||
using const_iterator = internal::dense_map_iterator<typename packed_container_type::const_pointer>;
|
||||
/*! @brief Input iterator type. */
|
||||
using local_iterator = internal::dense_map_local_iterator<typename packed_container_type::iterator>;
|
||||
using local_iterator = internal::dense_map_local_iterator<typename packed_container_type::pointer>;
|
||||
/*! @brief Constant input iterator type. */
|
||||
using const_local_iterator = internal::dense_map_local_iterator<typename packed_container_type::const_iterator>;
|
||||
using const_local_iterator = internal::dense_map_local_iterator<typename packed_container_type::const_pointer>;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
dense_map()
|
||||
@@ -422,8 +391,8 @@ public:
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_map(const dense_map &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())},
|
||||
: sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())},
|
||||
packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
@@ -435,8 +404,8 @@ public:
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_map(dense_map &&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()))},
|
||||
: sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))},
|
||||
packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
@@ -459,7 +428,7 @@ public:
|
||||
* @param other Container to exchange the content with.
|
||||
*/
|
||||
void swap(dense_map &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(sparse, other.sparse);
|
||||
swap(packed, other.packed);
|
||||
swap(threshold, other.threshold);
|
||||
@@ -481,7 +450,7 @@ public:
|
||||
* @return An iterator to the first instance of the internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cbegin() const noexcept {
|
||||
return packed.first().begin();
|
||||
return packed.first().data();
|
||||
}
|
||||
|
||||
/*! @copydoc cbegin */
|
||||
@@ -491,7 +460,7 @@ public:
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] iterator begin() noexcept {
|
||||
return packed.first().begin();
|
||||
return packed.first().data();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,7 +469,7 @@ public:
|
||||
* internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cend() const noexcept {
|
||||
return packed.first().end();
|
||||
return packed.first().data() + packed.first().size();
|
||||
}
|
||||
|
||||
/*! @copydoc cend */
|
||||
@@ -510,7 +479,7 @@ public:
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] iterator end() noexcept {
|
||||
return packed.first().end();
|
||||
return packed.first().data() + packed.first().size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -551,13 +520,13 @@ public:
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
std::pair<iterator, bool> insert(const value_type &value) {
|
||||
stl::pair<iterator, bool> insert(const value_type &value) {
|
||||
return insert_or_do_nothing(value.first, value.second);
|
||||
}
|
||||
|
||||
/*! @copydoc insert */
|
||||
std::pair<iterator, bool> insert(value_type &&value) {
|
||||
return insert_or_do_nothing(std::move(value.first), std::move(value.second));
|
||||
stl::pair<iterator, bool> insert(value_type &&value) {
|
||||
return insert_or_do_nothing(stl::move(value.first), stl::move(value.second));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -565,19 +534,17 @@ public:
|
||||
* @tparam Arg Type of the key-value pair to insert into the container.
|
||||
*/
|
||||
template<typename Arg>
|
||||
std::enable_if_t<std::is_constructible_v<value_type, Arg &&>, std::pair<iterator, bool>>
|
||||
insert(Arg &&value) {
|
||||
return insert_or_do_nothing(std::forward<Arg>(value).first, std::forward<Arg>(value).second);
|
||||
requires stl::constructible_from<value_type, Arg &&>
|
||||
stl::pair<iterator, bool> insert(Arg &&value) {
|
||||
return insert_or_do_nothing(stl::forward<Arg>(value).first, stl::forward<Arg>(value).second);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts elements into the container, if their keys 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) {
|
||||
void insert(stl::input_iterator auto first, stl::input_iterator auto last) {
|
||||
for(; first != last; ++first) {
|
||||
insert(*first);
|
||||
}
|
||||
@@ -593,14 +560,14 @@ public:
|
||||
* denoting whether the insertion took place.
|
||||
*/
|
||||
template<typename Arg>
|
||||
std::pair<iterator, bool> insert_or_assign(const key_type &key, Arg &&value) {
|
||||
return insert_or_overwrite(key, std::forward<Arg>(value));
|
||||
stl::pair<iterator, bool> insert_or_assign(const key_type &key, Arg &&value) {
|
||||
return insert_or_overwrite(key, stl::forward<Arg>(value));
|
||||
}
|
||||
|
||||
/*! @copydoc insert_or_assign */
|
||||
template<typename Arg>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type &&key, Arg &&value) {
|
||||
return insert_or_overwrite(std::move(key), std::forward<Arg>(value));
|
||||
stl::pair<iterator, bool> insert_or_assign(key_type &&key, Arg &&value) {
|
||||
return insert_or_overwrite(stl::move(key), stl::forward<Arg>(value));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -617,26 +584,26 @@ public:
|
||||
* insertion took place.
|
||||
*/
|
||||
template<typename... Args>
|
||||
std::pair<iterator, bool> emplace([[maybe_unused]] Args &&...args) {
|
||||
stl::pair<iterator, bool> emplace([[maybe_unused]] Args &&...args) {
|
||||
if constexpr(sizeof...(Args) == 0u) {
|
||||
return insert_or_do_nothing(key_type{});
|
||||
} else if constexpr(sizeof...(Args) == 1u) {
|
||||
return insert_or_do_nothing(std::forward<Args>(args).first..., std::forward<Args>(args).second...);
|
||||
return insert_or_do_nothing(stl::forward<Args>(args).first..., stl::forward<Args>(args).second...);
|
||||
} else if constexpr(sizeof...(Args) == 2u) {
|
||||
return insert_or_do_nothing(std::forward<Args>(args)...);
|
||||
return insert_or_do_nothing(stl::forward<Args>(args)...);
|
||||
} else {
|
||||
auto &node = packed.first().emplace_back(packed.first().size(), std::forward<Args>(args)...);
|
||||
auto &node = packed.first().emplace_back(packed.first().size(), stl::forward<Args>(args)...);
|
||||
const auto index = key_to_bucket(node.element.first);
|
||||
|
||||
if(auto it = constrained_find(node.element.first, index); it != end()) {
|
||||
packed.first().pop_back();
|
||||
return std::make_pair(it, false);
|
||||
return stl::make_pair(it, false);
|
||||
}
|
||||
|
||||
std::swap(node.next, sparse.first()[index]);
|
||||
stl::swap(node.next, sparse.first()[index]);
|
||||
rehash_if_required();
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
return stl::make_pair(--end(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,14 +619,14 @@ public:
|
||||
* insertion took place.
|
||||
*/
|
||||
template<typename... Args>
|
||||
std::pair<iterator, bool> try_emplace(const key_type &key, Args &&...args) {
|
||||
return insert_or_do_nothing(key, std::forward<Args>(args)...);
|
||||
stl::pair<iterator, bool> try_emplace(const key_type &key, Args &&...args) {
|
||||
return insert_or_do_nothing(key, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! @copydoc try_emplace */
|
||||
template<typename... Args>
|
||||
std::pair<iterator, bool> try_emplace(key_type &&key, Args &&...args) {
|
||||
return insert_or_do_nothing(std::move(key), std::forward<Args>(args)...);
|
||||
stl::pair<iterator, bool> try_emplace(key_type &&key, Args &&...args) {
|
||||
return insert_or_do_nothing(stl::move(key), stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -695,7 +662,7 @@ public:
|
||||
* @return Number of elements removed (either 0 or 1).
|
||||
*/
|
||||
size_type erase(const key_type &key) {
|
||||
for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].next) {
|
||||
for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) {
|
||||
if(packed.second()(packed.first()[*curr].element.first, key)) {
|
||||
const auto index = *curr;
|
||||
*curr = packed.first()[*curr].next;
|
||||
@@ -725,6 +692,26 @@ public:
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accesses a given element with bounds checking.
|
||||
* @param key A key of an element to find.
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
[[nodiscard]] mapped_type const &at(const auto &key) const
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
auto it = find(key);
|
||||
ENTT_ASSERT(it != cend(), "Invalid key");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/*! @copydoc at */
|
||||
[[nodiscard]] mapped_type &at(const auto &key)
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
auto it = find(key);
|
||||
ENTT_ASSERT(it != end(), "Invalid key");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accesses or inserts a given element.
|
||||
* @param key A key of an element to find or insert.
|
||||
@@ -740,7 +727,7 @@ public:
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
[[nodiscard]] mapped_type &operator[](key_type &&key) {
|
||||
return insert_or_do_nothing(std::move(key)).first->second;
|
||||
return insert_or_do_nothing(stl::move(key)).first->second;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -754,13 +741,11 @@ public:
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
[[nodiscard]] size_type count(const auto &key) const
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
return find(key) != end();
|
||||
}
|
||||
|
||||
@@ -782,21 +767,18 @@ public:
|
||||
/**
|
||||
* @brief Finds an element with a key that compares _equivalent_ to a given
|
||||
* key.
|
||||
* @tparam Other Type of the key value of an element to search for.
|
||||
* @param key Key value of an element to search for.
|
||||
* @return An iterator to an element with the given key. 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 &key) {
|
||||
[[nodiscard]] iterator find(const auto &key)
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
return constrained_find(key, key_to_bucket(key));
|
||||
}
|
||||
|
||||
/*! @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 &key) const {
|
||||
[[nodiscard]] const_iterator find(const auto &key) const
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
return constrained_find(key, key_to_bucket(key));
|
||||
}
|
||||
|
||||
@@ -806,13 +788,13 @@ public:
|
||||
* @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 key_type &key) {
|
||||
[[nodiscard]] stl::pair<iterator, iterator> equal_range(const key_type &key) {
|
||||
const auto it = find(key);
|
||||
return {it, it + !(it == end())};
|
||||
}
|
||||
|
||||
/*! @copydoc equal_range */
|
||||
[[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const key_type &key) const {
|
||||
[[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const key_type &key) const {
|
||||
const auto it = find(key);
|
||||
return {it, it + !(it == cend())};
|
||||
}
|
||||
@@ -820,22 +802,19 @@ public:
|
||||
/**
|
||||
* @brief Returns a range containing all elements that compare _equivalent_
|
||||
* to a given key.
|
||||
* @tparam Other Type of an element to search for.
|
||||
* @param key Key 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 &key) {
|
||||
[[nodiscard]] stl::pair<iterator, iterator> equal_range(const auto &key)
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
const auto it = find(key);
|
||||
return {it, it + !(it == end())};
|
||||
}
|
||||
|
||||
/*! @copydoc equal_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<const_iterator, const_iterator>>>
|
||||
equal_range(const Other &key) const {
|
||||
[[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const auto &key) const
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
const auto it = find(key);
|
||||
return {it, it + !(it == cend())};
|
||||
}
|
||||
@@ -852,13 +831,11 @@ public:
|
||||
/**
|
||||
* @brief Checks if the container contains an element with a key that
|
||||
* compares _equivalent_ to a given value.
|
||||
* @tparam Other Type of the key value of an element to search for.
|
||||
* @param key Key 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 &key) const {
|
||||
[[nodiscard]] bool contains(const auto &key) const
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
return (find(key) != cend());
|
||||
}
|
||||
|
||||
@@ -868,7 +845,7 @@ public:
|
||||
* @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]};
|
||||
return {packed.first().data(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -886,7 +863,7 @@ public:
|
||||
* @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]};
|
||||
return {packed.first().data(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -895,7 +872,7 @@ public:
|
||||
* @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)()};
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -913,7 +890,7 @@ public:
|
||||
* @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)()};
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -938,7 +915,7 @@ public:
|
||||
* @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)));
|
||||
return static_cast<size_type>(stl::distance(begin(index), end(index)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -986,16 +963,16 @@ public:
|
||||
const auto cap = static_cast<size_type>(static_cast<float>(size()) / max_load_factor());
|
||||
value = value > cap ? value : cap;
|
||||
|
||||
if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
|
||||
if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) {
|
||||
sparse.first().resize(sz);
|
||||
|
||||
for(auto &&elem: sparse.first()) {
|
||||
elem = (std::numeric_limits<size_type>::max)();
|
||||
elem = placeholder_position;
|
||||
}
|
||||
|
||||
for(size_type pos{}, last = size(); pos < last; ++pos) {
|
||||
const auto index = key_to_bucket(packed.first()[pos].element.first);
|
||||
packed.first()[pos].next = std::exchange(sparse.first()[index], pos);
|
||||
packed.first()[pos].next = stl::exchange(sparse.first()[index], pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1007,7 +984,7 @@ public:
|
||||
*/
|
||||
void reserve(const size_type cnt) {
|
||||
packed.first().reserve(cnt);
|
||||
rehash(static_cast<size_type>(std::ceil(static_cast<float>(cnt) / max_load_factor())));
|
||||
rehash(static_cast<size_type>(stl::ceil(static_cast<float>(cnt) / max_load_factor())));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1034,12 +1011,14 @@ private:
|
||||
|
||||
} // namespace entt
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
#include <utility>
|
||||
|
||||
namespace std {
|
||||
|
||||
template<typename Key, typename Value, typename Allocator>
|
||||
struct uses_allocator<entt::internal::dense_map_node<Key, Value>, Allocator>
|
||||
: std::true_type {};
|
||||
: entt::stl::true_type {};
|
||||
|
||||
} // namespace std
|
||||
/*! @endcond */
|
||||
|
||||
@@ -1,38 +1,45 @@
|
||||
#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 <compare>
|
||||
#include "../config/config.h"
|
||||
#include "../core/bit.hpp"
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/bit.hpp"
|
||||
#include "../stl/cmath.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/limits.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
static constexpr stl::size_t dense_set_placeholder_position = (stl::numeric_limits<stl::size_t>::max)();
|
||||
|
||||
template<typename It>
|
||||
class dense_set_iterator final {
|
||||
template<typename>
|
||||
friend class dense_set_iterator;
|
||||
|
||||
static_assert(stl::is_pointer_v<It>, "Not a pointer type");
|
||||
|
||||
public:
|
||||
using value_type = typename It::value_type::second_type;
|
||||
using value_type = stl::remove_const_t<stl::remove_pointer_t<It>>::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;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::random_access_iterator_tag;
|
||||
|
||||
constexpr dense_set_iterator() noexcept
|
||||
: it{} {}
|
||||
@@ -40,7 +47,8 @@ public:
|
||||
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>>>
|
||||
template<typename Other>
|
||||
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
|
||||
constexpr dense_set_iterator(const dense_set_iterator<Other> &other) noexcept
|
||||
: it{other.it} {}
|
||||
|
||||
@@ -85,88 +93,60 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::addressof(operator[](0));
|
||||
return stl::addressof(operator[](0));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return operator[](0);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_set_iterator<Other> &other) const noexcept {
|
||||
return it - other.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr bool operator==(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_set_iterator<Other> &other) const noexcept {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr bool operator<(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr auto operator<=>(const dense_set_iterator<Other> &other) const noexcept {
|
||||
return it <=> other.it;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
};
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it - rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator<(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it < rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator>(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator<=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator>=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
class dense_set_local_iterator final {
|
||||
template<typename>
|
||||
friend class dense_set_local_iterator;
|
||||
|
||||
static_assert(stl::is_pointer_v<It>, "Not a pointer type");
|
||||
|
||||
public:
|
||||
using value_type = typename It::value_type::second_type;
|
||||
using value_type = stl::remove_const_t<stl::remove_pointer_t<It>>::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;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::forward_iterator_tag;
|
||||
|
||||
constexpr dense_set_local_iterator() noexcept
|
||||
: it{},
|
||||
offset{} {}
|
||||
constexpr dense_set_local_iterator() noexcept = default;
|
||||
|
||||
constexpr dense_set_local_iterator(It iter, const std::size_t pos) noexcept
|
||||
constexpr dense_set_local_iterator(It iter, const stl::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>>>
|
||||
template<typename Other>
|
||||
requires (!stl::same_as<It, Other> && stl::constructible_from<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[static_cast<typename It::difference_type>(offset)].first, *this;
|
||||
return offset = it[static_cast<difference_type>(offset)].first, *this;
|
||||
}
|
||||
|
||||
constexpr dense_set_local_iterator operator++(int) noexcept {
|
||||
@@ -175,32 +155,27 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::addressof(it[static_cast<typename It::difference_type>(offset)].second);
|
||||
return stl::addressof(it[static_cast<difference_type>(offset)].second);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t index() const noexcept {
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<Other> &other) const noexcept {
|
||||
return offset == other.offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr stl::size_t index() const noexcept {
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
std::size_t offset;
|
||||
It it{};
|
||||
stl::size_t offset{dense_set_placeholder_position};
|
||||
};
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.index() == rhs.index();
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
@@ -219,35 +194,33 @@ template<typename Lhs, typename Rhs>
|
||||
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;
|
||||
static constexpr stl::size_t minimum_capacity = 8u;
|
||||
static constexpr stl::size_t placeholder_position = internal::dense_set_placeholder_position;
|
||||
|
||||
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>>;
|
||||
using node_type = stl::pair<stl::size_t, Type>;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
|
||||
using sparse_container_type = stl::vector<stl::size_t, typename alloc_traits::template rebind_alloc<stl::size_t>>;
|
||||
using packed_container_type = stl::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 {
|
||||
[[nodiscard]] stl::size_t value_to_bucket(const auto &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<difference_type>(it.index());
|
||||
[[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) {
|
||||
for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) {
|
||||
if(packed.second()(packed.first()[offset].second, value)) {
|
||||
return begin() + static_cast<iterator::difference_type>(offset);
|
||||
}
|
||||
}
|
||||
|
||||
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<difference_type>(it.index());
|
||||
[[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) const {
|
||||
for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) {
|
||||
if(packed.second()(packed.first()[offset].second, value)) {
|
||||
return cbegin() + static_cast<const_iterator::difference_type>(offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,20 +232,20 @@ class dense_set {
|
||||
const auto index = value_to_bucket(value);
|
||||
|
||||
if(auto it = constrained_find(value, index); it != end()) {
|
||||
return std::make_pair(it, false);
|
||||
return stl::make_pair(it, false);
|
||||
}
|
||||
|
||||
packed.first().emplace_back(sparse.first()[index], std::forward<Other>(value));
|
||||
packed.first().emplace_back(sparse.first()[index], stl::forward<Other>(value));
|
||||
sparse.first()[index] = packed.first().size() - 1u;
|
||||
rehash_if_required();
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
return stl::make_pair(--end(), true);
|
||||
}
|
||||
|
||||
void move_and_pop(const std::size_t pos) {
|
||||
void move_and_pop(const stl::size_t pos) {
|
||||
if(const auto last = size() - 1u; pos != last) {
|
||||
size_type *curr = &sparse.first()[value_to_bucket(packed.first().back().second)];
|
||||
packed.first()[pos] = std::move(packed.first().back());
|
||||
packed.first()[pos] = stl::move(packed.first().back());
|
||||
for(; *curr != last; curr = &packed.first()[*curr].first) {}
|
||||
*curr = pos;
|
||||
}
|
||||
@@ -294,25 +267,25 @@ public:
|
||||
/*! @brief Value type of the container. */
|
||||
using value_type = Type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_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 Random access iterator type. */
|
||||
using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>;
|
||||
using iterator = internal::dense_set_iterator<typename packed_container_type::pointer>;
|
||||
/*! @brief Constant random access iterator type. */
|
||||
using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_iterator>;
|
||||
using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_pointer>;
|
||||
/*! @brief Reverse iterator type. */
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using reverse_iterator = stl::reverse_iterator<iterator>;
|
||||
/*! @brief Constant reverse iterator type. */
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using const_reverse_iterator = stl::reverse_iterator<const_iterator>;
|
||||
/*! @brief Forward iterator type. */
|
||||
using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>;
|
||||
using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::pointer>;
|
||||
/*! @brief Constant forward iterator type. */
|
||||
using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_iterator>;
|
||||
using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_pointer>;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
dense_set()
|
||||
@@ -367,8 +340,8 @@ public:
|
||||
* @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())},
|
||||
: sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())},
|
||||
packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
@@ -380,8 +353,8 @@ public:
|
||||
* @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()))},
|
||||
: sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))},
|
||||
packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
@@ -404,7 +377,7 @@ public:
|
||||
* @param other Container to exchange the content with.
|
||||
*/
|
||||
void swap(dense_set &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(sparse, other.sparse);
|
||||
swap(packed, other.packed);
|
||||
swap(threshold, other.threshold);
|
||||
@@ -426,7 +399,7 @@ public:
|
||||
* @return An iterator to the first instance of the internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cbegin() const noexcept {
|
||||
return packed.first().begin();
|
||||
return packed.first().data();
|
||||
}
|
||||
|
||||
/*! @copydoc cbegin */
|
||||
@@ -436,7 +409,7 @@ public:
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] iterator begin() noexcept {
|
||||
return packed.first().begin();
|
||||
return packed.first().data();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -445,7 +418,7 @@ public:
|
||||
* internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cend() const noexcept {
|
||||
return packed.first().end();
|
||||
return packed.first().data() + packed.first().size();
|
||||
}
|
||||
|
||||
/*! @copydoc cend */
|
||||
@@ -455,7 +428,7 @@ public:
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] iterator end() noexcept {
|
||||
return packed.first().end();
|
||||
return packed.first().data() + packed.first().size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -466,7 +439,7 @@ public:
|
||||
* @return An iterator to the first instance of the reversed internal array.
|
||||
*/
|
||||
[[nodiscard]] const_reverse_iterator crbegin() const noexcept {
|
||||
return std::make_reverse_iterator(cend());
|
||||
return stl::make_reverse_iterator(cend());
|
||||
}
|
||||
|
||||
/*! @copydoc crbegin */
|
||||
@@ -476,7 +449,7 @@ public:
|
||||
|
||||
/*! @copydoc rbegin */
|
||||
[[nodiscard]] reverse_iterator rbegin() noexcept {
|
||||
return std::make_reverse_iterator(end());
|
||||
return stl::make_reverse_iterator(end());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,7 +458,7 @@ public:
|
||||
* reversed internal array.
|
||||
*/
|
||||
[[nodiscard]] const_reverse_iterator crend() const noexcept {
|
||||
return std::make_reverse_iterator(cbegin());
|
||||
return stl::make_reverse_iterator(cbegin());
|
||||
}
|
||||
|
||||
/*! @copydoc crend */
|
||||
@@ -495,7 +468,7 @@ public:
|
||||
|
||||
/*! @copydoc rend */
|
||||
[[nodiscard]] reverse_iterator rend() noexcept {
|
||||
return std::make_reverse_iterator(begin());
|
||||
return stl::make_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -536,23 +509,21 @@ public:
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
std::pair<iterator, bool> insert(const value_type &value) {
|
||||
stl::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));
|
||||
stl::pair<iterator, bool> insert(value_type &&value) {
|
||||
return insert_or_do_nothing(stl::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) {
|
||||
void insert(stl::input_iterator auto first, stl::input_iterator auto last) {
|
||||
for(; first != last; ++first) {
|
||||
insert(*first);
|
||||
}
|
||||
@@ -572,22 +543,22 @@ public:
|
||||
* 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)...);
|
||||
stl::pair<iterator, bool> emplace(Args &&...args) {
|
||||
if constexpr(((sizeof...(Args) == 1u) && ... && stl::is_same_v<stl::decay_t<Args>, value_type>)) {
|
||||
return insert_or_do_nothing(stl::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)...));
|
||||
auto &node = packed.first().emplace_back(stl::piecewise_construct, stl::make_tuple(packed.first().size()), stl::forward_as_tuple(stl::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);
|
||||
return stl::make_pair(it, false);
|
||||
}
|
||||
|
||||
std::swap(node.first, sparse.first()[index]);
|
||||
stl::swap(node.first, sparse.first()[index]);
|
||||
rehash_if_required();
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
return stl::make_pair(--end(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,7 +595,7 @@ public:
|
||||
* @return Number of elements removed (either 0 or 1).
|
||||
*/
|
||||
size_type erase(const value_type &value) {
|
||||
for(size_type *curr = &sparse.first()[value_to_bucket(value)]; *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].first) {
|
||||
for(size_type *curr = &sparse.first()[value_to_bucket(value)]; *curr != placeholder_position; curr = &packed.first()[*curr].first) {
|
||||
if(packed.second()(packed.first()[*curr].second, value)) {
|
||||
const auto index = *curr;
|
||||
*curr = packed.first()[*curr].first;
|
||||
@@ -647,13 +618,11 @@ public:
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
[[nodiscard]] size_type count(const auto &key) const
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
return find(key) != end();
|
||||
}
|
||||
|
||||
@@ -674,21 +643,18 @@ public:
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
[[nodiscard]] iterator find(const auto &value)
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
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 {
|
||||
[[nodiscard]] const_iterator find(const auto &value) const
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
return constrained_find(value, value_to_bucket(value));
|
||||
}
|
||||
|
||||
@@ -698,13 +664,13 @@ public:
|
||||
* @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) {
|
||||
[[nodiscard]] stl::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 {
|
||||
[[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const value_type &value) const {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == cend())};
|
||||
}
|
||||
@@ -712,22 +678,19 @@ public:
|
||||
/**
|
||||
* @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) {
|
||||
[[nodiscard]] stl::pair<iterator, iterator> equal_range(const auto &value)
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == end())};
|
||||
}
|
||||
|
||||
/*! @copydoc equal_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<const_iterator, const_iterator>>>
|
||||
equal_range(const Other &value) const {
|
||||
[[nodiscard]] stl::pair<const_iterator, const_iterator> equal_range(const auto &value) const
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == cend())};
|
||||
}
|
||||
@@ -744,13 +707,11 @@ public:
|
||||
/**
|
||||
* @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 {
|
||||
[[nodiscard]] bool contains(const auto &value) const
|
||||
requires is_transparent_v<hasher> && is_transparent_v<key_equal> {
|
||||
return (find(value) != cend());
|
||||
}
|
||||
|
||||
@@ -760,7 +721,7 @@ public:
|
||||
* @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]};
|
||||
return {packed.first().data(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -778,7 +739,7 @@ public:
|
||||
* @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]};
|
||||
return {packed.first().data(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -787,7 +748,7 @@ public:
|
||||
* @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)()};
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -805,7 +766,7 @@ public:
|
||||
* @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)()};
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -830,7 +791,7 @@ public:
|
||||
* @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)));
|
||||
return static_cast<size_type>(stl::distance(begin(index), end(index)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -878,16 +839,16 @@ public:
|
||||
const auto cap = static_cast<size_type>(static_cast<float>(size()) / max_load_factor());
|
||||
value = value > cap ? value : cap;
|
||||
|
||||
if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
|
||||
if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) {
|
||||
sparse.first().resize(sz);
|
||||
|
||||
for(auto &&elem: sparse.first()) {
|
||||
elem = (std::numeric_limits<size_type>::max)();
|
||||
elem = placeholder_position;
|
||||
}
|
||||
|
||||
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);
|
||||
packed.first()[pos].first = stl::exchange(sparse.first()[index], pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -899,7 +860,7 @@ public:
|
||||
*/
|
||||
void reserve(const size_type cnt) {
|
||||
packed.first().reserve(cnt);
|
||||
rehash(static_cast<size_type>(std::ceil(static_cast<float>(cnt) / max_load_factor())));
|
||||
rehash(static_cast<size_type>(stl::ceil(static_cast<float>(cnt) / max_load_factor())));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
#ifndef ENTT_CONTAINER_FWD_HPP
|
||||
#define ENTT_CONTAINER_FWD_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<
|
||||
typename Key,
|
||||
typename Type,
|
||||
typename = std::hash<Key>,
|
||||
typename = std::equal_to<>,
|
||||
typename = std::allocator<std::pair<const Key, Type>>>
|
||||
typename = stl::hash<Key>,
|
||||
typename = stl::equal_to<>,
|
||||
typename = stl::allocator<stl::pair<const Key, Type>>>
|
||||
class dense_map;
|
||||
|
||||
template<
|
||||
typename Type,
|
||||
typename = std::hash<Type>,
|
||||
typename = std::equal_to<>,
|
||||
typename = std::allocator<Type>>
|
||||
typename = stl::hash<Type>,
|
||||
typename = stl::equal_to<>,
|
||||
typename = stl::allocator<Type>>
|
||||
class dense_set;
|
||||
|
||||
template<typename...>
|
||||
@@ -31,7 +31,7 @@ class basic_table;
|
||||
* @tparam Type Element types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
using table = basic_table<std::vector<Type>...>;
|
||||
using table = basic_table<stl::vector<Type>...>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#ifndef ENTT_CONTAINER_TABLE_HPP
|
||||
#define ENTT_CONTAINER_TABLE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename... It>
|
||||
@@ -21,12 +21,12 @@ class table_iterator {
|
||||
friend class table_iterator;
|
||||
|
||||
public:
|
||||
using value_type = decltype(std::forward_as_tuple(*std::declval<It>()...));
|
||||
using value_type = decltype(stl::forward_as_tuple(*stl::declval<It>()...));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::random_access_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::random_access_iterator_tag;
|
||||
|
||||
constexpr table_iterator() noexcept
|
||||
: it{} {}
|
||||
@@ -34,12 +34,13 @@ public:
|
||||
constexpr table_iterator(It... from) noexcept
|
||||
: it{from...} {}
|
||||
|
||||
template<typename... Other, typename = std::enable_if_t<(std::is_constructible_v<It, Other> && ...)>>
|
||||
template<typename... Other>
|
||||
requires (stl::constructible_from<It, Other> && ...)
|
||||
constexpr table_iterator(const table_iterator<Other...> &other) noexcept
|
||||
: table_iterator{std::get<Other>(other.it)...} {}
|
||||
: table_iterator{stl::get<Other>(other.it)...} {}
|
||||
|
||||
constexpr table_iterator &operator++() noexcept {
|
||||
return (++std::get<It>(it), ...), *this;
|
||||
return (++stl::get<It>(it), ...), *this;
|
||||
}
|
||||
|
||||
constexpr table_iterator operator++(int) noexcept {
|
||||
@@ -48,7 +49,7 @@ public:
|
||||
}
|
||||
|
||||
constexpr table_iterator &operator--() noexcept {
|
||||
return (--std::get<It>(it), ...), *this;
|
||||
return (--stl::get<It>(it), ...), *this;
|
||||
}
|
||||
|
||||
constexpr table_iterator operator--(int) noexcept {
|
||||
@@ -57,7 +58,7 @@ public:
|
||||
}
|
||||
|
||||
constexpr table_iterator &operator+=(const difference_type value) noexcept {
|
||||
return ((std::get<It>(it) += value), ...), *this;
|
||||
return ((stl::get<It>(it) += value), ...), *this;
|
||||
}
|
||||
|
||||
constexpr table_iterator operator+(const difference_type value) const noexcept {
|
||||
@@ -74,7 +75,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
|
||||
return std::forward_as_tuple(std::get<It>(it)[value]...);
|
||||
return stl::forward_as_tuple(stl::get<It>(it)[value]...);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
@@ -85,54 +86,25 @@ public:
|
||||
return operator[](0);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
friend constexpr std::ptrdiff_t operator-(const table_iterator<Lhs...> &, const table_iterator<Rhs...> &) noexcept;
|
||||
template<typename... Other>
|
||||
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const table_iterator<Other...> &other) const noexcept {
|
||||
return stl::get<0>(it) - stl::get<0>(other.it);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
friend constexpr bool operator==(const table_iterator<Lhs...> &, const table_iterator<Rhs...> &) noexcept;
|
||||
template<typename... Other>
|
||||
[[nodiscard]] constexpr bool operator==(const table_iterator<Other...> &other) const noexcept {
|
||||
return stl::get<0>(it) == stl::get<0>(other.it);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
friend constexpr bool operator<(const table_iterator<Lhs...> &, const table_iterator<Rhs...> &) noexcept;
|
||||
template<typename... Other>
|
||||
[[nodiscard]] constexpr auto operator<=>(const table_iterator<Other...> &other) const noexcept {
|
||||
return stl::get<0>(it) <=> stl::get<0>(other.it);
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<It...> it;
|
||||
stl::tuple<It...> it;
|
||||
};
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr std::ptrdiff_t operator-(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
|
||||
return std::get<0>(lhs.it) - std::get<0>(rhs.it);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
|
||||
return std::get<0>(lhs.it) == std::get<0>(rhs.it);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator<(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
|
||||
return std::get<0>(lhs.it) < std::get<0>(rhs.it);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator>(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator<=(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator>=(const table_iterator<Lhs...> &lhs, const table_iterator<Rhs...> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
@@ -147,13 +119,13 @@ template<typename... Lhs, typename... Rhs>
|
||||
*/
|
||||
template<typename... Container>
|
||||
class basic_table {
|
||||
using container_type = std::tuple<Container...>;
|
||||
using container_type = stl::tuple<Container...>;
|
||||
|
||||
public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Input iterator type. */
|
||||
using iterator = internal::table_iterator<typename Container::iterator...>;
|
||||
/*! @brief Constant input iterator type. */
|
||||
@@ -174,7 +146,7 @@ public:
|
||||
*/
|
||||
explicit basic_table(const Container &...container) noexcept
|
||||
: payload{container...} {
|
||||
ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
||||
ENTT_ASSERT((((stl::get<Container>(payload).size() * sizeof...(Container)) == (stl::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,8 +154,8 @@ public:
|
||||
* @param container The containers to move from.
|
||||
*/
|
||||
explicit basic_table(Container &&...container) noexcept
|
||||
: payload{std::move(container)...} {
|
||||
ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
||||
: payload{stl::move(container)...} {
|
||||
ENTT_ASSERT((((stl::get<Container>(payload).size() * sizeof...(Container)) == (stl::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
||||
}
|
||||
|
||||
/*! @brief Default copy constructor, deleted on purpose. */
|
||||
@@ -194,15 +166,13 @@ public:
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_table(basic_table &&other) noexcept
|
||||
: payload{std::move(other.payload)} {}
|
||||
: payload{stl::move(other.payload)} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs the underlying containers using a given allocator.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param allocator A valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
explicit basic_table(const Allocator &allocator)
|
||||
explicit basic_table(const auto &allocator)
|
||||
: payload{Container{allocator}...} {}
|
||||
|
||||
/**
|
||||
@@ -214,7 +184,7 @@ public:
|
||||
template<class Allocator>
|
||||
basic_table(const Container &...container, const Allocator &allocator) noexcept
|
||||
: payload{Container{container, allocator}...} {
|
||||
ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
||||
ENTT_ASSERT((((stl::get<Container>(payload).size() * sizeof...(Container)) == (stl::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,8 +195,8 @@ public:
|
||||
*/
|
||||
template<class Allocator>
|
||||
basic_table(Container &&...container, const Allocator &allocator) noexcept
|
||||
: payload{Container{std::move(container), allocator}...} {
|
||||
ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
||||
: payload{Container{stl::move(container), allocator}...} {
|
||||
ENTT_ASSERT((((stl::get<Container>(payload).size() * sizeof...(Container)) == (stl::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -237,7 +207,7 @@ public:
|
||||
*/
|
||||
template<class Allocator>
|
||||
basic_table(basic_table &&other, const Allocator &allocator)
|
||||
: payload{Container{std::move(std::get<Container>(other.payload)), allocator}...} {}
|
||||
: payload{Container{stl::move(stl::get<Container>(other.payload)), allocator}...} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~basic_table() = default;
|
||||
@@ -263,7 +233,7 @@ public:
|
||||
* @param other Table to exchange the content with.
|
||||
*/
|
||||
void swap(basic_table &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(payload, other.payload);
|
||||
}
|
||||
|
||||
@@ -276,7 +246,7 @@ public:
|
||||
* @param cap Desired capacity.
|
||||
*/
|
||||
void reserve(const size_type cap) {
|
||||
(std::get<Container>(payload).reserve(cap), ...);
|
||||
(stl::get<Container>(payload).reserve(cap), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,12 +255,12 @@ public:
|
||||
* @return Capacity of the table.
|
||||
*/
|
||||
[[nodiscard]] size_type capacity() const noexcept {
|
||||
return std::get<0>(payload).capacity();
|
||||
return stl::get<0>(payload).capacity();
|
||||
}
|
||||
|
||||
/*! @brief Requests the removal of unused capacity. */
|
||||
void shrink_to_fit() {
|
||||
(std::get<Container>(payload).shrink_to_fit(), ...);
|
||||
(stl::get<Container>(payload).shrink_to_fit(), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,7 +268,7 @@ public:
|
||||
* @return Number of rows.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return std::get<0>(payload).size();
|
||||
return stl::get<0>(payload).size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -306,7 +276,7 @@ public:
|
||||
* @return True if the table is empty, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept {
|
||||
return std::get<0>(payload).empty();
|
||||
return stl::get<0>(payload).empty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,7 +287,7 @@ public:
|
||||
* @return An iterator to the first row of the table.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cbegin() const noexcept {
|
||||
return {std::get<Container>(payload).cbegin()...};
|
||||
return {stl::get<Container>(payload).cbegin()...};
|
||||
}
|
||||
|
||||
/*! @copydoc cbegin */
|
||||
@@ -327,7 +297,7 @@ public:
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] iterator begin() noexcept {
|
||||
return {std::get<Container>(payload).begin()...};
|
||||
return {stl::get<Container>(payload).begin()...};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,7 +305,7 @@ public:
|
||||
* @return An iterator to the element following the last row of the table.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cend() const noexcept {
|
||||
return {std::get<Container>(payload).cend()...};
|
||||
return {stl::get<Container>(payload).cend()...};
|
||||
}
|
||||
|
||||
/*! @copydoc cend */
|
||||
@@ -345,7 +315,7 @@ public:
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] iterator end() noexcept {
|
||||
return {std::get<Container>(payload).end()...};
|
||||
return {stl::get<Container>(payload).end()...};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,7 +326,7 @@ public:
|
||||
* @return An iterator to the first row of the reversed table.
|
||||
*/
|
||||
[[nodiscard]] const_reverse_iterator crbegin() const noexcept {
|
||||
return {std::get<Container>(payload).crbegin()...};
|
||||
return {stl::get<Container>(payload).crbegin()...};
|
||||
}
|
||||
|
||||
/*! @copydoc crbegin */
|
||||
@@ -366,7 +336,7 @@ public:
|
||||
|
||||
/*! @copydoc rbegin */
|
||||
[[nodiscard]] reverse_iterator rbegin() noexcept {
|
||||
return {std::get<Container>(payload).rbegin()...};
|
||||
return {stl::get<Container>(payload).rbegin()...};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -375,7 +345,7 @@ public:
|
||||
* table.
|
||||
*/
|
||||
[[nodiscard]] const_reverse_iterator crend() const noexcept {
|
||||
return {std::get<Container>(payload).crend()...};
|
||||
return {stl::get<Container>(payload).crend()...};
|
||||
}
|
||||
|
||||
/*! @copydoc crend */
|
||||
@@ -385,7 +355,7 @@ public:
|
||||
|
||||
/*! @copydoc rend */
|
||||
[[nodiscard]] reverse_iterator rend() noexcept {
|
||||
return {std::get<Container>(payload).rend()...};
|
||||
return {stl::get<Container>(payload).rend()...};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,11 +365,11 @@ public:
|
||||
* @return A reference to the newly created row data.
|
||||
*/
|
||||
template<typename... Args>
|
||||
std::tuple<typename Container::value_type &...> emplace(Args &&...args) {
|
||||
stl::tuple<typename Container::value_type &...> emplace(Args &&...args) {
|
||||
if constexpr(sizeof...(Args) == 0u) {
|
||||
return std::forward_as_tuple(std::get<Container>(payload).emplace_back()...);
|
||||
return stl::forward_as_tuple(stl::get<Container>(payload).emplace_back()...);
|
||||
} else {
|
||||
return std::forward_as_tuple(std::get<Container>(payload).emplace_back(std::forward<Args>(args))...);
|
||||
return stl::forward_as_tuple(stl::get<Container>(payload).emplace_back(stl::forward<Args>(args))...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +380,7 @@ public:
|
||||
*/
|
||||
iterator erase(const_iterator pos) {
|
||||
const auto diff = pos - begin();
|
||||
return {std::get<Container>(payload).erase(std::get<Container>(payload).begin() + diff)...};
|
||||
return {stl::get<Container>(payload).erase(stl::get<Container>(payload).begin() + diff)...};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -427,20 +397,20 @@ public:
|
||||
* @param pos The row for which to return the data.
|
||||
* @return The row data at specified location.
|
||||
*/
|
||||
[[nodiscard]] std::tuple<const typename Container::value_type &...> operator[](const size_type pos) const {
|
||||
[[nodiscard]] stl::tuple<const typename Container::value_type &...> operator[](const size_type pos) const {
|
||||
ENTT_ASSERT(pos < size(), "Index out of bounds");
|
||||
return std::forward_as_tuple(std::get<Container>(payload)[pos]...);
|
||||
return stl::forward_as_tuple(stl::get<Container>(payload)[pos]...);
|
||||
}
|
||||
|
||||
/*! @copydoc operator[] */
|
||||
[[nodiscard]] std::tuple<typename Container::value_type &...> operator[](const size_type pos) {
|
||||
[[nodiscard]] stl::tuple<typename Container::value_type &...> operator[](const size_type pos) {
|
||||
ENTT_ASSERT(pos < size(), "Index out of bounds");
|
||||
return std::forward_as_tuple(std::get<Container>(payload)[pos]...);
|
||||
return stl::forward_as_tuple(stl::get<Container>(payload)[pos]...);
|
||||
}
|
||||
|
||||
/*! @brief Clears a table. */
|
||||
void clear() {
|
||||
(std::get<Container>(payload).clear(), ...);
|
||||
(stl::get<Container>(payload).clear(), ...);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -449,12 +419,14 @@ private:
|
||||
|
||||
} // namespace entt
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
#include <utility>
|
||||
|
||||
namespace std {
|
||||
|
||||
template<typename... Container, typename Allocator>
|
||||
struct uses_allocator<entt::basic_table<Container...>, Allocator>
|
||||
: std::bool_constant<(std::uses_allocator_v<Container, Allocator> && ...)> {};
|
||||
: entt::stl::bool_constant<(entt::stl::uses_allocator_v<Container, Allocator> && ...)> {};
|
||||
|
||||
} // namespace std
|
||||
/*! @endcond */
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
#ifndef ENTT_CORE_ALGORITHM_HPP
|
||||
#define ENTT_CORE_ALGORITHM_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "utility.hpp"
|
||||
#include "../stl/algorithm.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Function object to wrap `std::sort` in a class type.
|
||||
* @brief Function object to wrap `stl::sort` in a class type.
|
||||
*
|
||||
* Unfortunately, `std::sort` cannot be passed as template argument to a class
|
||||
* Unfortunately, `stl::sort` cannot be passed as template argument to a class
|
||||
* template or a function template.<br/>
|
||||
* This class fills the gap by wrapping some flavors of `std::sort` in a
|
||||
* This class fills the gap by wrapping some flavors of `stl::sort` in a
|
||||
* function object.
|
||||
*/
|
||||
struct std_sort {
|
||||
@@ -24,7 +25,6 @@ struct std_sort {
|
||||
*
|
||||
* Sorts the elements in a range using the given binary comparison function.
|
||||
*
|
||||
* @tparam It Type of random access iterator.
|
||||
* @tparam Compare Type of comparison function object.
|
||||
* @tparam Args Types of arguments to forward to the sort function.
|
||||
* @param first An iterator to the first element of the range to sort.
|
||||
@@ -32,9 +32,9 @@ struct std_sort {
|
||||
* @param compare A valid comparison function object.
|
||||
* @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 {
|
||||
std::sort(std::forward<Args>(args)..., std::move(first), std::move(last), std::move(compare));
|
||||
template<typename Compare = stl::less<>, typename... Args>
|
||||
void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}, Args &&...args) const {
|
||||
stl::sort(stl::forward<Args>(args)..., stl::move(first), stl::move(last), stl::move(compare));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -45,26 +45,25 @@ struct insertion_sort {
|
||||
*
|
||||
* Sorts the elements in a range using the given binary comparison function.
|
||||
*
|
||||
* @tparam It Type of random access iterator.
|
||||
* @tparam Compare Type of comparison function object.
|
||||
* @param first An iterator to the first element of the range to sort.
|
||||
* @param last An iterator past the last element of the range to sort.
|
||||
* @param compare A valid comparison function object.
|
||||
*/
|
||||
template<typename It, typename Compare = std::less<>>
|
||||
void operator()(It first, It last, Compare compare = Compare{}) const {
|
||||
template<typename Compare = stl::less<>>
|
||||
void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}) const {
|
||||
if(first < last) {
|
||||
for(auto it = first + 1; it < last; ++it) {
|
||||
auto value = std::move(*it);
|
||||
auto value = stl::move(*it);
|
||||
auto pre = it;
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
for(; pre > first && compare(value, *(pre - 1)); --pre) {
|
||||
*pre = std::move(*(pre - 1));
|
||||
*pre = stl::move(*(pre - 1));
|
||||
}
|
||||
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
|
||||
*pre = std::move(value);
|
||||
*pre = stl::move(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,10 +74,9 @@ struct insertion_sort {
|
||||
* @tparam Bit Number of bits processed per pass.
|
||||
* @tparam N Maximum number of bits to sort.
|
||||
*/
|
||||
template<std::size_t Bit, std::size_t N>
|
||||
template<stl::size_t Bit, stl::size_t N>
|
||||
requires ((N % Bit) == 0) // The maximum number of bits to sort must be a multiple of the number of bits processed per pass
|
||||
struct radix_sort {
|
||||
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.
|
||||
*
|
||||
@@ -94,47 +92,47 @@ struct radix_sort {
|
||||
* @param last An iterator past the last element of the range to sort.
|
||||
* @param getter A valid _getter_ function object.
|
||||
*/
|
||||
template<typename It, typename Getter = identity>
|
||||
template<stl::random_access_iterator It, typename Getter = stl::identity>
|
||||
void operator()(It first, It last, Getter getter = Getter{}) const {
|
||||
if(first < last) {
|
||||
constexpr auto passes = N / Bit;
|
||||
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
using difference_type = typename std::iterator_traits<It>::difference_type;
|
||||
std::vector<value_type> aux(static_cast<std::size_t>(std::distance(first, last)));
|
||||
using value_type = stl::iterator_traits<It>::value_type;
|
||||
using difference_type = stl::iterator_traits<It>::difference_type;
|
||||
stl::vector<value_type> aux(static_cast<stl::size_t>(stl::distance(first, last)));
|
||||
|
||||
auto part = [getter = std::move(getter)](auto from, auto to, auto out, auto start) {
|
||||
auto part = [getter = stl::move(getter)](auto from, auto to, auto out, auto start) {
|
||||
constexpr auto mask = (1 << Bit) - 1;
|
||||
constexpr auto buckets = 1 << Bit;
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays, misc-const-correctness)
|
||||
std::size_t count[buckets]{};
|
||||
stl::size_t count[buckets]{};
|
||||
|
||||
for(auto it = from; it != to; ++it) {
|
||||
++count[(getter(*it) >> start) & mask];
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
std::size_t index[buckets]{};
|
||||
stl::size_t index[buckets]{};
|
||||
|
||||
for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
|
||||
for(stl::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
|
||||
index[pos + 1u] = index[pos] + count[pos];
|
||||
}
|
||||
|
||||
for(auto it = from; it != to; ++it) {
|
||||
const auto pos = index[(getter(*it) >> start) & mask]++;
|
||||
out[static_cast<difference_type>(pos)] = std::move(*it);
|
||||
out[static_cast<difference_type>(pos)] = stl::move(*it);
|
||||
}
|
||||
};
|
||||
|
||||
for(std::size_t pass = 0; pass < (passes & ~1u); pass += 2) {
|
||||
for(stl::size_t pass = 0; pass < (passes & ~1u); pass += 2) {
|
||||
part(first, last, aux.begin(), pass * Bit);
|
||||
part(aux.begin(), aux.end(), first, (pass + 1) * Bit);
|
||||
}
|
||||
|
||||
if constexpr(passes & 1) {
|
||||
part(first, last, aux.begin(), (passes - 1) * Bit);
|
||||
std::move(aux.begin(), aux.end(), first);
|
||||
stl::move(aux.begin(), aux.end(), first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +1,193 @@
|
||||
#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 "../core/concepts.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/cstdint.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "type_traits.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
enum class any_request : std::uint8_t {
|
||||
enum class any_request : stl::uint8_t {
|
||||
info,
|
||||
transfer,
|
||||
assign,
|
||||
destroy,
|
||||
compare,
|
||||
copy,
|
||||
move,
|
||||
get
|
||||
move
|
||||
};
|
||||
|
||||
template<stl::size_t Len, stl::size_t Align>
|
||||
struct basic_any_storage {
|
||||
static constexpr bool has_buffer = true;
|
||||
union {
|
||||
const void *instance{};
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
alignas(Align) stl::byte buffer[Len];
|
||||
};
|
||||
};
|
||||
|
||||
template<stl::size_t Align>
|
||||
struct basic_any_storage<0u, Align> {
|
||||
static constexpr bool has_buffer = false;
|
||||
const void *instance{};
|
||||
};
|
||||
|
||||
template<typename Type, stl::size_t Len, stl::size_t Align>
|
||||
// NOLINTNEXTLINE(bugprone-sizeof-expression)
|
||||
struct in_situ: stl::bool_constant<(Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && stl::is_nothrow_move_constructible_v<Type>> {};
|
||||
|
||||
template<stl::size_t Len, stl::size_t Align>
|
||||
struct in_situ<void, Len, Align>: stl::false_type {};
|
||||
|
||||
} // namespace internal
|
||||
/*! @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 Len Size of the buffer reserved for the small buffer optimization.
|
||||
* @tparam Align Optional alignment requirement.
|
||||
*/
|
||||
template<std::size_t Len, std::size_t Align>
|
||||
class basic_any {
|
||||
template<stl::size_t Len, stl::size_t Align>
|
||||
class basic_any: private internal::basic_any_storage<Len, Align> {
|
||||
using request = internal::any_request;
|
||||
using base_type = internal::basic_any_storage<Len, Align>;
|
||||
using vtable_type = const void *(const request, const basic_any &, const void *);
|
||||
|
||||
struct storage_type {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
alignas(Align) std::byte data[Len + static_cast<std::size_t>(Len == 0u)];
|
||||
};
|
||||
using deleter_type = void(const basic_any &);
|
||||
|
||||
template<typename Type>
|
||||
// NOLINTNEXTLINE(bugprone-sizeof-expression)
|
||||
static constexpr bool in_situ = (Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && std::is_nothrow_move_constructible_v<Type>;
|
||||
static constexpr bool in_situ_v = internal::in_situ<Type, Len, Align>::value;
|
||||
|
||||
template<typename Type>
|
||||
template<cvref_unqualified Type>
|
||||
static const void *basic_vtable(const request req, const basic_any &value, const void *other) {
|
||||
static_assert(!std::is_void_v<Type> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
|
||||
const Type *elem = nullptr;
|
||||
|
||||
if constexpr(in_situ<Type>) {
|
||||
elem = (value.mode == any_policy::embedded) ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance);
|
||||
} else {
|
||||
elem = static_cast<const Type *>(value.instance);
|
||||
}
|
||||
|
||||
switch(req) {
|
||||
case request::transfer:
|
||||
if constexpr(std::is_move_assignable_v<Type>) {
|
||||
switch(const auto *elem = static_cast<const Type *>(value.data()); req) {
|
||||
using enum internal::any_request;
|
||||
case info:
|
||||
return &type_id<Type>();
|
||||
case transfer:
|
||||
if constexpr(stl::is_move_assignable_v<Type>) {
|
||||
// NOLINTNEXTLINE(bugprone-casting-through-void)
|
||||
*const_cast<Type *>(elem) = std::move(*static_cast<Type *>(const_cast<void *>(other)));
|
||||
*const_cast<Type *>(elem) = stl::move(*static_cast<Type *>(const_cast<void *>(other)));
|
||||
return other;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case request::assign:
|
||||
if constexpr(std::is_copy_assignable_v<Type>) {
|
||||
case assign:
|
||||
if constexpr(stl::is_copy_assignable_v<Type>) {
|
||||
*const_cast<Type *>(elem) = *static_cast<const Type *>(other);
|
||||
return other;
|
||||
}
|
||||
break;
|
||||
case request::destroy:
|
||||
if constexpr(in_situ<Type>) {
|
||||
(value.mode == any_policy::embedded) ? elem->~Type() : (delete elem);
|
||||
} else if constexpr(std::is_array_v<Type>) {
|
||||
delete[] elem;
|
||||
} else {
|
||||
delete elem;
|
||||
}
|
||||
break;
|
||||
case request::compare:
|
||||
if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
|
||||
case compare:
|
||||
if constexpr(!stl::is_function_v<Type> && !stl::is_array_v<Type> && is_equality_comparable_v<Type>) {
|
||||
return (*elem == *static_cast<const Type *>(other)) ? other : nullptr;
|
||||
} else {
|
||||
return (elem == other) ? other : nullptr;
|
||||
}
|
||||
case request::copy:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
case copy:
|
||||
if constexpr(stl::is_copy_constructible_v<Type>) {
|
||||
// NOLINTNEXTLINE(bugprone-casting-through-void)
|
||||
static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*elem);
|
||||
}
|
||||
break;
|
||||
case request::move:
|
||||
case move:
|
||||
ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy");
|
||||
if constexpr(in_situ<Type>) {
|
||||
if constexpr(in_situ_v<Type>) {
|
||||
// NOLINTNEXTLINE(bugprone-casting-through-void, bugprone-multi-level-implicit-pointer-conversion)
|
||||
return ::new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(elem))};
|
||||
}
|
||||
[[fallthrough]];
|
||||
case request::get:
|
||||
ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy");
|
||||
if constexpr(in_situ<Type>) {
|
||||
// NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
|
||||
return elem;
|
||||
return ::new(&static_cast<basic_any *>(const_cast<void *>(other))->buffer) Type{stl::move(*const_cast<Type *>(elem))};
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<cvref_unqualified Type>
|
||||
static void basic_deleter(const basic_any &value) {
|
||||
ENTT_ASSERT((value.mode == any_policy::dynamic) || ((value.mode == any_policy::embedded) && !stl::is_trivially_destructible_v<Type>), "Unexpected policy");
|
||||
|
||||
const auto *elem = static_cast<const Type *>(value.data());
|
||||
|
||||
if constexpr(in_situ_v<Type>) {
|
||||
(value.mode == any_policy::embedded) ? elem->~Type() : (delete elem);
|
||||
} else if constexpr(stl::is_array_v<Type>) {
|
||||
delete[] elem;
|
||||
} else {
|
||||
delete elem;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args>
|
||||
void initialize([[maybe_unused]] Args &&...args) {
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
using plain_type = std::remove_cv_t<std::remove_reference_t<Type>>;
|
||||
using plain_type = stl::remove_cvref_t<Type>;
|
||||
|
||||
info = &type_id<plain_type>();
|
||||
vtable = basic_vtable<plain_type>;
|
||||
vtable = basic_vtable<plain_type>;
|
||||
underlying_type = type_hash<plain_type>::value();
|
||||
|
||||
if constexpr(std::is_lvalue_reference_v<Type>) {
|
||||
static_assert((std::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "Invalid arguments");
|
||||
mode = std::is_const_v<std::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
|
||||
// NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
|
||||
instance = (std::addressof(args), ...);
|
||||
} else if constexpr(in_situ<plain_type>) {
|
||||
mode = any_policy::embedded;
|
||||
|
||||
if constexpr(std::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
|
||||
::new(&storage) plain_type{std::forward<Args>(args)...};
|
||||
} else {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
|
||||
::new(&storage) plain_type(std::forward<Args>(args)...);
|
||||
}
|
||||
if constexpr(stl::is_void_v<Type>) {
|
||||
deleter = nullptr;
|
||||
mode = any_policy::empty;
|
||||
this->instance = nullptr;
|
||||
} else if constexpr(stl::is_lvalue_reference_v<Type>) {
|
||||
deleter = nullptr;
|
||||
mode = stl::is_const_v<stl::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
|
||||
static_assert((stl::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "Invalid arguments");
|
||||
// NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion)
|
||||
this->instance = (stl::addressof(args), ...);
|
||||
} else if constexpr(in_situ_v<plain_type>) {
|
||||
if constexpr(stl::is_trivially_destructible_v<plain_type>) {
|
||||
deleter = nullptr;
|
||||
} else {
|
||||
mode = any_policy::dynamic;
|
||||
deleter = &basic_deleter<plain_type>;
|
||||
}
|
||||
|
||||
if constexpr(std::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
|
||||
instance = new plain_type{std::forward<Args>(args)...};
|
||||
} else if constexpr(std::is_array_v<plain_type>) {
|
||||
static_assert(sizeof...(Args) == 0u, "Invalid arguments");
|
||||
instance = new plain_type[std::extent_v<plain_type>]();
|
||||
} else {
|
||||
instance = new plain_type(std::forward<Args>(args)...);
|
||||
}
|
||||
mode = any_policy::embedded;
|
||||
|
||||
if constexpr(stl::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !stl::is_default_constructible_v<plain_type>)) {
|
||||
::new(&this->buffer) plain_type{stl::forward<Args>(args)...};
|
||||
} else {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
|
||||
::new(&this->buffer) plain_type(stl::forward<Args>(args)...);
|
||||
}
|
||||
} else {
|
||||
deleter = &basic_deleter<plain_type>;
|
||||
mode = any_policy::dynamic;
|
||||
|
||||
if constexpr(stl::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !stl::is_default_constructible_v<plain_type>)) {
|
||||
this->instance = new plain_type{stl::forward<Args>(args)...};
|
||||
} else if constexpr(stl::is_array_v<plain_type>) {
|
||||
static_assert(sizeof...(Args) == 0u, "Invalid arguments");
|
||||
this->instance = new plain_type[stl::extent_v<plain_type>]();
|
||||
} else {
|
||||
this->instance = new plain_type(stl::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
basic_any(const basic_any &other, const any_policy pol) noexcept
|
||||
: instance{other.data()},
|
||||
info{other.info},
|
||||
vtable{other.vtable},
|
||||
mode{pol} {}
|
||||
void invoke_deleter_if_exists() {
|
||||
if(deleter != nullptr) {
|
||||
deleter(*this);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Size of the internal storage. */
|
||||
/*! @brief Size of the internal buffer. */
|
||||
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>} {}
|
||||
: basic_any{stl::in_place_type<void>} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a wrapper by directly initializing the new object.
|
||||
@@ -172,9 +196,9 @@ public:
|
||||
* @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{} {
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
explicit basic_any(stl::in_place_type_t<Type>, Args &&...args)
|
||||
: base_type{} {
|
||||
initialize<Type>(stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -183,12 +207,14 @@ public:
|
||||
* @param value A pointer to an object to take ownership of.
|
||||
*/
|
||||
template<typename Type>
|
||||
explicit basic_any(std::in_place_t, Type *value)
|
||||
: instance{} {
|
||||
static_assert(!std::is_const_v<Type> && !std::is_void_v<Type>, "Non-const non-void pointer required");
|
||||
|
||||
if(value != nullptr) {
|
||||
requires (!stl::is_const_v<Type> && !stl::is_void_v<Type>)
|
||||
explicit basic_any(stl::in_place_t, Type *value)
|
||||
: base_type{} {
|
||||
if(value == nullptr) {
|
||||
initialize<void>();
|
||||
} else {
|
||||
initialize<Type &>(*value);
|
||||
deleter = &basic_deleter<Type>;
|
||||
mode = any_policy::dynamic;
|
||||
}
|
||||
}
|
||||
@@ -198,9 +224,10 @@ public:
|
||||
* @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>>>
|
||||
template<typename Type>
|
||||
requires (!stl::same_as<stl::remove_cvref_t<Type>, basic_any>)
|
||||
basic_any(Type &&value)
|
||||
: basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
|
||||
: basic_any{stl::in_place_type<stl::decay_t<Type>>, stl::forward<Type>(value)} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
@@ -208,9 +235,7 @@ public:
|
||||
*/
|
||||
basic_any(const basic_any &other)
|
||||
: basic_any{} {
|
||||
if(other.vtable) {
|
||||
other.vtable(request::copy, other, this);
|
||||
}
|
||||
other.vtable(request::copy, other, this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,22 +243,21 @@ public:
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_any(basic_any &&other) noexcept
|
||||
: instance{},
|
||||
info{other.info},
|
||||
: base_type{},
|
||||
vtable{other.vtable},
|
||||
deleter{other.deleter},
|
||||
underlying_type{other.underlying_type},
|
||||
mode{other.mode} {
|
||||
if(other.mode == any_policy::embedded) {
|
||||
other.vtable(request::move, other, this);
|
||||
} else if(other.mode != any_policy::empty) {
|
||||
instance = std::exchange(other.instance, nullptr);
|
||||
this->instance = stl::exchange(other.instance, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Frees the internal storage, whatever it means. */
|
||||
/*! @brief Frees the internal buffer, whatever it means. */
|
||||
~basic_any() {
|
||||
if(owner()) {
|
||||
vtable(request::destroy, *this, nullptr);
|
||||
}
|
||||
invoke_deleter_if_exists();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,10 +267,12 @@ public:
|
||||
*/
|
||||
basic_any &operator=(const basic_any &other) {
|
||||
if(this != &other) {
|
||||
reset();
|
||||
invoke_deleter_if_exists();
|
||||
|
||||
if(other.vtable) {
|
||||
if(other) {
|
||||
other.vtable(request::copy, other, this);
|
||||
} else {
|
||||
initialize<void>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,26 +281,25 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
*
|
||||
* @warning
|
||||
* Self-moving puts objects in a safe but unspecified state.
|
||||
*
|
||||
* @param other The instance to move from.
|
||||
* @return This any object.
|
||||
*/
|
||||
basic_any &operator=(basic_any &&other) noexcept {
|
||||
reset();
|
||||
if(this != &other) {
|
||||
invoke_deleter_if_exists();
|
||||
|
||||
if(other.mode == any_policy::embedded) {
|
||||
other.vtable(request::move, other, this);
|
||||
} else if(other.mode != any_policy::empty) {
|
||||
instance = std::exchange(other.instance, nullptr);
|
||||
if(other.mode == any_policy::embedded) {
|
||||
other.vtable(request::move, other, this);
|
||||
} else if(other.mode != any_policy::empty) {
|
||||
this->instance = stl::exchange(other.instance, nullptr);
|
||||
}
|
||||
|
||||
vtable = other.vtable;
|
||||
deleter = other.deleter;
|
||||
underlying_type = other.underlying_type;
|
||||
mode = other.mode;
|
||||
}
|
||||
|
||||
info = other.info;
|
||||
vtable = other.vtable;
|
||||
mode = other.mode;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -284,18 +309,50 @@ public:
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
* @return This any object.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
|
||||
template<typename Type>
|
||||
requires (!stl::same_as<stl::remove_cvref_t<Type>, basic_any>)
|
||||
basic_any &operator=(Type &&value) {
|
||||
emplace<std::decay_t<Type>>(std::forward<Type>(value));
|
||||
emplace<stl::decay_t<Type>>(stl::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.
|
||||
* @brief Returns false if a wrapper is empty, true otherwise.
|
||||
* @return False if the wrapper is empty, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] const type_info &type() const noexcept {
|
||||
return (info == nullptr) ? type_id<void>() : *info;
|
||||
[[nodiscard]] bool has_value() const noexcept {
|
||||
return (mode != any_policy::empty);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns false if the wrapper does not contain the expected type,
|
||||
* true otherwise.
|
||||
* @param req Expected type.
|
||||
* @return False if the wrapper does not contain the expected type, true
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool has_value(const type_info &req) const noexcept {
|
||||
return (underlying_type == req.hash());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns false if the wrapper does not contain the expected type,
|
||||
* true otherwise.
|
||||
* @tparam Type Expected type.
|
||||
* @return False if the wrapper does not contain the expected type, true
|
||||
* otherwise.
|
||||
*/
|
||||
template<cvref_unqualified Type>
|
||||
[[nodiscard]] bool has_value() const noexcept {
|
||||
return (underlying_type == type_hash<Type>::value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the object type info if any, `type_id<void>()` otherwise.
|
||||
* @return The object type info if any, `type_id<void>()` otherwise.
|
||||
*/
|
||||
[[nodiscard]] const type_info &info() const noexcept {
|
||||
return *static_cast<const type_info *>(vtable(request::info, *this, nullptr));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,7 +360,11 @@ public:
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] const void *data() const noexcept {
|
||||
return (mode == any_policy::embedded) ? vtable(request::get, *this, nullptr) : instance;
|
||||
if constexpr(base_type::has_buffer) {
|
||||
return (mode == any_policy::embedded) ? &this->buffer : this->instance;
|
||||
} else {
|
||||
return this->instance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -312,7 +373,17 @@ public:
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] const void *data(const type_info &req) const noexcept {
|
||||
return (type() == req) ? data() : nullptr;
|
||||
return has_value(req) ? data() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @tparam Type Expected type.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] const Type *data() const noexcept {
|
||||
return has_value<stl::remove_const_t<Type>>() ? static_cast<const Type *>(data()) : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -320,7 +391,7 @@ public:
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data() noexcept {
|
||||
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data());
|
||||
return (mode == any_policy::cref) ? nullptr : const_cast<void *>(stl::as_const(*this).data());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -329,7 +400,21 @@ public:
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data(const type_info &req) noexcept {
|
||||
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
|
||||
return (mode == any_policy::cref) ? nullptr : const_cast<void *>(stl::as_const(*this).data(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @tparam Type Expected type.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] Type *data() noexcept {
|
||||
if constexpr(stl::is_const_v<Type>) {
|
||||
return stl::as_const(*this).template data<stl::remove_const_t<Type>>();
|
||||
} else {
|
||||
return (mode == any_policy::cref) ? nullptr : const_cast<Type *>(stl::as_const(*this).template data<stl::remove_const_t<Type>>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,8 +425,8 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
void emplace(Args &&...args) {
|
||||
reset();
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
invoke_deleter_if_exists();
|
||||
initialize<Type>(stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,7 +435,7 @@ public:
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool assign(const basic_any &other) {
|
||||
if(vtable && mode != any_policy::cref && *info == other.type()) {
|
||||
if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) {
|
||||
return (vtable(request::assign, *this, other.data()) != nullptr);
|
||||
}
|
||||
|
||||
@@ -360,12 +445,8 @@ public:
|
||||
/*! @copydoc assign */
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
bool assign(basic_any &&other) {
|
||||
if(vtable && mode != any_policy::cref && *info == other.type()) {
|
||||
if(auto *val = other.data(); val) {
|
||||
return (vtable(request::transfer, *this, val) != nullptr);
|
||||
}
|
||||
|
||||
return (vtable(request::assign, *this, std::as_const(other).data()) != nullptr);
|
||||
if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) {
|
||||
return (other.mode == any_policy::cref) ? (vtable(request::assign, *this, stl::as_const(other).data()) != nullptr) : (vtable(request::transfer, *this, other.data()) != nullptr);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -373,14 +454,8 @@ public:
|
||||
|
||||
/*! @brief Destroys contained object */
|
||||
void reset() {
|
||||
if(owner()) {
|
||||
vtable(request::destroy, *this, nullptr);
|
||||
}
|
||||
|
||||
instance = nullptr;
|
||||
info = nullptr;
|
||||
vtable = nullptr;
|
||||
mode = any_policy::empty;
|
||||
invoke_deleter_if_exists();
|
||||
initialize<void>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -388,7 +463,7 @@ public:
|
||||
* @return False if the wrapper is empty, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] explicit operator bool() const noexcept {
|
||||
return vtable != nullptr;
|
||||
return has_value();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -397,20 +472,11 @@ public:
|
||||
* @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.type()) {
|
||||
if(other && (underlying_type == other.underlying_type)) {
|
||||
return (vtable(request::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);
|
||||
return (!*this && !other);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -418,12 +484,30 @@ public:
|
||||
* @return A wrapper that shares a reference to an unmanaged object.
|
||||
*/
|
||||
[[nodiscard]] basic_any as_ref() noexcept {
|
||||
return basic_any{*this, (mode == any_policy::cref ? any_policy::cref : any_policy::ref)};
|
||||
basic_any other = stl::as_const(*this).as_ref();
|
||||
|
||||
switch(mode) {
|
||||
using enum any_policy;
|
||||
case cref:
|
||||
case empty:
|
||||
other.mode = mode;
|
||||
break;
|
||||
default:
|
||||
other.mode = any_policy::ref;
|
||||
break;
|
||||
}
|
||||
|
||||
return other;
|
||||
}
|
||||
|
||||
/*! @copydoc as_ref */
|
||||
[[nodiscard]] basic_any as_ref() const noexcept {
|
||||
return basic_any{*this, any_policy::cref};
|
||||
basic_any other{};
|
||||
other.instance = data();
|
||||
other.vtable = vtable;
|
||||
other.underlying_type = underlying_type;
|
||||
other.mode = any_policy::cref;
|
||||
return other;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -443,100 +527,95 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
const void *instance;
|
||||
storage_type storage;
|
||||
};
|
||||
const type_info *info{};
|
||||
vtable_type *vtable{};
|
||||
any_policy mode{any_policy::empty};
|
||||
deleter_type *deleter{};
|
||||
id_type underlying_type{};
|
||||
any_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 Len Size of the buffer 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>
|
||||
[[nodiscard]] std::remove_const_t<Type> any_cast(const basic_any<Len, Align> &data) noexcept {
|
||||
const auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
|
||||
template<typename Type, stl::size_t Len, stl::size_t Align>
|
||||
[[nodiscard]] stl::remove_const_t<Type> any_cast(const basic_any<Len, Align> &data) noexcept {
|
||||
const auto *const instance = any_cast<stl::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>
|
||||
[[nodiscard]] std::remove_const_t<Type> any_cast(basic_any<Len, Align> &data) noexcept {
|
||||
template<typename Type, stl::size_t Len, stl::size_t Align>
|
||||
[[nodiscard]] stl::remove_const_t<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);
|
||||
auto *const instance = any_cast<stl::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>
|
||||
template<typename Type, stl::size_t Len, stl::size_t Align>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
[[nodiscard]] std::remove_const_t<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));
|
||||
[[nodiscard]] stl::remove_const_t<Type> any_cast(basic_any<Len, Align> &&data) noexcept {
|
||||
if constexpr(stl::is_copy_constructible_v<stl::remove_cvref_t<Type>>) {
|
||||
if(auto *const instance = any_cast<stl::remove_reference_t<Type>>(&data); instance) {
|
||||
return static_cast<Type>(stl::move(*instance));
|
||||
}
|
||||
|
||||
return any_cast<Type>(data);
|
||||
} else {
|
||||
auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
|
||||
auto *const instance = any_cast<stl::remove_reference_t<Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(std::move(*instance));
|
||||
return static_cast<Type>(stl::move(*instance));
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
template<typename Type, stl::size_t Len, stl::size_t Align>
|
||||
[[nodiscard]] 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));
|
||||
return data->template data<stl::remove_const_t<Type>>();
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
template<typename Type, stl::size_t Len, stl::size_t Align>
|
||||
[[nodiscard]] Type *any_cast(basic_any<Len, Align> *data) noexcept {
|
||||
if constexpr(std::is_const_v<Type>) {
|
||||
if constexpr(stl::is_const_v<Type>) {
|
||||
// last attempt to make wrappers for const references return their values
|
||||
return any_cast<Type>(&std::as_const(*data));
|
||||
return any_cast<Type>(&stl::as_const(*data));
|
||||
} else {
|
||||
const auto &info = type_id<std::remove_cv_t<Type>>();
|
||||
return static_cast<Type *>(data->data(info));
|
||||
return data->template data<Type>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 Len Size of the buffer 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>
|
||||
template<typename Type, stl::size_t Len = basic_any<>::length, stl::size_t Align = basic_any<Len>::alignment, typename... Args>
|
||||
[[nodiscard]] basic_any<Len, Align> make_any(Args &&...args) {
|
||||
return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...};
|
||||
return basic_any<Len, Align>{stl::in_place_type<Type>, stl::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 Len Size of the buffer 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>
|
||||
template<stl::size_t Len = basic_any<>::length, stl::size_t Align = basic_any<Len>::alignment, typename Type>
|
||||
[[nodiscard]] basic_any<Len, Align> forward_as_any(Type &&value) {
|
||||
return basic_any<Len, Align>{std::in_place_type<Type &&>, std::forward<Type>(value)};
|
||||
return basic_any<Len, Align>{stl::in_place_type<Type &&>, stl::forward<Type>(value)};
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#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
|
||||
#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
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,57 +1,13 @@
|
||||
#ifndef ENTT_CORE_BIT_HPP
|
||||
#define ENTT_CORE_BIT_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../stl/bit.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Returns the number of set bits in a value (waiting for C++20 and
|
||||
* `std::popcount`).
|
||||
* @tparam Type Unsigned integer type.
|
||||
* @param value A value of unsigned integer type.
|
||||
* @return The number of set bits in the value.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, int> popcount(const Type value) noexcept {
|
||||
return value ? (int(value & 1) + popcount(static_cast<Type>(value >> 1))) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a value is a power of two or not (waiting for C++20 and
|
||||
* `std::has_single_bit`).
|
||||
* @tparam Type Unsigned integer type.
|
||||
* @param value A value of unsigned integer type.
|
||||
* @return True if the value is a power of two, false otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, bool> has_single_bit(const Type value) noexcept {
|
||||
return value && ((value & (value - 1)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the smallest power of two greater than or equal to a value
|
||||
* (waiting for C++20 and `std::bit_ceil`).
|
||||
* @tparam Type Unsigned integer type.
|
||||
* @param value A value of unsigned integer type.
|
||||
* @return The smallest power of two greater than or equal to the given value.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, Type> next_power_of_two(const Type value) noexcept {
|
||||
// NOLINTNEXTLINE(bugprone-assert-side-effect)
|
||||
ENTT_ASSERT_CONSTEXPR(value < (Type{1u} << (std::numeric_limits<Type>::digits - 1)), "Numeric limits exceeded");
|
||||
Type curr = value - (value != 0u);
|
||||
|
||||
for(int next = 1; next < std::numeric_limits<Type>::digits; next = next * 2) {
|
||||
curr |= (curr >> next);
|
||||
}
|
||||
|
||||
return ++curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fast module utility function (powers of two only).
|
||||
* @tparam Type Unsigned integer type.
|
||||
@@ -59,9 +15,9 @@ template<typename Type>
|
||||
* @param mod _Modulus_, it must be a power of two.
|
||||
* @return The common remainder.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, Type> fast_mod(const Type value, const std::size_t mod) noexcept {
|
||||
ENTT_ASSERT_CONSTEXPR(has_single_bit(mod), "Value must be a power of two");
|
||||
template<stl::unsigned_integral Type>
|
||||
[[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept {
|
||||
ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two");
|
||||
return static_cast<Type>(value & (mod - 1u));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
#ifndef ENTT_CORE_COMPRESSED_PAIR_HPP
|
||||
#define ENTT_CORE_COMPRESSED_PAIR_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, std::size_t, typename = void>
|
||||
template<typename Type, stl::size_t>
|
||||
struct compressed_pair_element {
|
||||
using reference = Type &;
|
||||
using const_reference = const Type &;
|
||||
|
||||
template<typename Dummy = Type, typename = std::enable_if_t<std::is_default_constructible_v<Dummy>>>
|
||||
// NOLINTNEXTLINE(modernize-use-equals-default)
|
||||
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<Type>) {}
|
||||
constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v<Type>)
|
||||
requires stl::default_initializable<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<Type, Arg>)
|
||||
: value{std::forward<Arg>(arg)} {}
|
||||
template<typename Arg>
|
||||
constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v<Type, Arg>)
|
||||
requires (!stl::same_as<stl::remove_cvref_t<Arg>, compressed_pair_element>)
|
||||
: value{stl::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))...} {}
|
||||
template<typename... Args, stl::size_t... Index>
|
||||
constexpr compressed_pair_element(stl::tuple<Args...> args, stl::index_sequence<Index...>) noexcept(stl::is_nothrow_constructible_v<Type, Args...>)
|
||||
: value{stl::forward<Args>(stl::get<Index>(args))...} {}
|
||||
|
||||
[[nodiscard]] constexpr reference get() noexcept {
|
||||
return value;
|
||||
@@ -42,23 +44,25 @@ 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 {
|
||||
template<typename Type, stl::size_t Tag>
|
||||
requires is_ebco_eligible_v<Type>
|
||||
struct compressed_pair_element<Type, Tag>: Type {
|
||||
using reference = Type &;
|
||||
using const_reference = const Type &;
|
||||
using base_type = Type;
|
||||
|
||||
template<typename Dummy = Type, typename = std::enable_if_t<std::is_default_constructible_v<Dummy>>>
|
||||
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<base_type>)
|
||||
constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v<base_type>)
|
||||
requires stl::default_initializable<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 Arg>
|
||||
constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v<base_type, Arg>)
|
||||
requires (!stl::same_as<stl::remove_cvref_t<Arg>, compressed_pair_element>)
|
||||
: base_type{stl::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))...} {}
|
||||
template<typename... Args, stl::size_t... Index>
|
||||
constexpr compressed_pair_element(stl::tuple<Args...> args, stl::index_sequence<Index...>) noexcept(stl::is_nothrow_constructible_v<base_type, Args...>)
|
||||
: base_type{stl::forward<Args>(stl::get<Index>(args))...} {}
|
||||
|
||||
[[nodiscard]] constexpr reference get() noexcept {
|
||||
return *this;
|
||||
@@ -99,11 +103,9 @@ public:
|
||||
*
|
||||
* 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>)
|
||||
constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v<first_base> && stl::is_nothrow_default_constructible_v<second_base>)
|
||||
requires stl::default_initializable<first_type> && stl::default_initializable<second_type>
|
||||
: first_base{},
|
||||
second_base{} {}
|
||||
|
||||
@@ -127,9 +129,9 @@ public:
|
||||
* @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)} {}
|
||||
constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v<first_base, Arg> && stl::is_nothrow_constructible_v<second_base, Other>)
|
||||
: first_base{stl::forward<Arg>(arg)},
|
||||
second_base{stl::forward<Other>(other)} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a pair by forwarding the arguments to its parts.
|
||||
@@ -139,9 +141,9 @@ public:
|
||||
* @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...>{}} {}
|
||||
constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple<Args...> args, stl::tuple<Other...> other) noexcept(stl::is_nothrow_constructible_v<first_base, Args...> && stl::is_nothrow_constructible_v<second_base, Other...>)
|
||||
: first_base{stl::move(args), stl::index_sequence_for<Args...>{}},
|
||||
second_base{stl::move(other), stl::index_sequence_for<Other...>{}} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~compressed_pair() = default;
|
||||
@@ -191,7 +193,7 @@ public:
|
||||
* @param other The compressed pair to swap with.
|
||||
*/
|
||||
constexpr void swap(compressed_pair &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(first(), other.first());
|
||||
swap(second(), other.second());
|
||||
}
|
||||
@@ -202,23 +204,23 @@ public:
|
||||
* @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>
|
||||
template<stl::size_t Index>
|
||||
requires (Index <= 1u)
|
||||
[[nodiscard]] 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>
|
||||
template<stl::size_t Index>
|
||||
requires (Index <= 1u)
|
||||
[[nodiscard]] constexpr decltype(auto) get() const noexcept {
|
||||
if constexpr(Index == 0u) {
|
||||
return first();
|
||||
} else {
|
||||
static_assert(Index == 1u, "Index out of bounds");
|
||||
return second();
|
||||
}
|
||||
}
|
||||
@@ -230,7 +232,7 @@ public:
|
||||
* @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>>;
|
||||
compressed_pair(Type &&, Other &&) -> compressed_pair<stl::decay_t<Type>, stl::decay_t<Other>>;
|
||||
|
||||
/**
|
||||
* @brief Swaps two compressed pair objects.
|
||||
@@ -246,27 +248,19 @@ constexpr void swap(compressed_pair<First, Second> &lhs, compressed_pair<First,
|
||||
|
||||
} // namespace entt
|
||||
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
#include <utility>
|
||||
|
||||
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> {};
|
||||
struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<entt::stl::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");
|
||||
};
|
||||
template<entt::stl::size_t Index, typename First, typename Second>
|
||||
requires (Index <= 1u)
|
||||
struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {};
|
||||
|
||||
} // namespace std
|
||||
/*! @endcond */
|
||||
|
||||
#endif
|
||||
|
||||
17
src/entt/core/concepts.hpp
Normal file
17
src/entt/core/concepts.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef ENTT_CORE_CONCEPTS_HPP
|
||||
#define ENTT_CORE_CONCEPTS_HPP
|
||||
|
||||
#include "../stl/type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Specifies that a type is not a cv-qualified reference.
|
||||
* @tparam Type Type to check.
|
||||
*/
|
||||
template<typename Type>
|
||||
concept cvref_unqualified = stl::is_same_v<stl::remove_cvref_t<Type>, Type>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef ENTT_CORE_ENUM_HPP
|
||||
#define ENTT_CORE_ENUM_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
@@ -9,12 +10,16 @@ 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 {};
|
||||
template<typename Type>
|
||||
struct enum_as_bitmask: stl::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> {};
|
||||
requires requires {
|
||||
requires stl::is_enum_v<Type>;
|
||||
{ Type::_entt_enum_as_bitmask } -> stl::same_as<Type>;
|
||||
}
|
||||
struct enum_as_bitmask<Type>: stl::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -23,6 +28,14 @@ struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>
|
||||
template<typename Type>
|
||||
inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Specifies that an enum class supports bitmask operations.
|
||||
* @tparam Type Enum class type.
|
||||
*/
|
||||
template<typename Type>
|
||||
// check again that it is an enum to deal with incorrect specializations
|
||||
concept enum_bitmask = stl::is_enum_v<Type> && enum_as_bitmask_v<Type>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
/**
|
||||
@@ -33,24 +46,21 @@ inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value;
|
||||
* @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));
|
||||
template<entt::enum_bitmask Type>
|
||||
[[nodiscard]] constexpr Type operator|(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<entt::stl::underlying_type_t<Type>>(lhs) | static_cast<entt::stl::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));
|
||||
template<entt::enum_bitmask Type>
|
||||
[[nodiscard]] constexpr Type operator&(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<entt::stl::underlying_type_t<Type>>(lhs) & static_cast<entt::stl::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));
|
||||
template<entt::enum_bitmask Type>
|
||||
[[nodiscard]] constexpr Type operator^(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<entt::stl::underlying_type_t<Type>>(lhs) ^ static_cast<entt::stl::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,37 +70,32 @@ operator^(const Type lhs, const Type rhs) noexcept {
|
||||
* @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));
|
||||
template<entt::enum_bitmask Type>
|
||||
[[nodiscard]] constexpr Type operator~(const Type value) noexcept {
|
||||
return static_cast<Type>(~static_cast<entt::stl::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);
|
||||
template<entt::enum_bitmask Type>
|
||||
[[nodiscard]] constexpr bool operator!(const Type value) noexcept {
|
||||
return !static_cast<entt::stl::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 {
|
||||
template<entt::enum_bitmask Type>
|
||||
constexpr 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 {
|
||||
template<entt::enum_bitmask Type>
|
||||
constexpr 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 {
|
||||
template<entt::enum_bitmask Type>
|
||||
constexpr Type &operator^=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs ^ rhs));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,10 @@ namespace entt {
|
||||
*/
|
||||
template<typename...>
|
||||
class family {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
inline static ENTT_MAYBE_ATOMIC(id_type) identifier{};
|
||||
static auto identifier() noexcept {
|
||||
static ENTT_MAYBE_ATOMIC(id_type) value{};
|
||||
return value++;
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
@@ -24,8 +26,8 @@ public:
|
||||
|
||||
/*! @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 value_type value = identifier++;
|
||||
// at the time I'm writing, clang crashes during compilation if auto is used instead of value_type
|
||||
inline static const value_type value = identifier();
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
#ifndef ENTT_CORE_FWD_HPP
|
||||
#define ENTT_CORE_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "../config/config.h"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/cstdint.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @brief Possible modes of an any object. */
|
||||
enum class any_policy : std::uint8_t {
|
||||
/*! @brief Default mode, the object does not own any elements. */
|
||||
enum class any_policy : stl::uint8_t {
|
||||
/*! @brief Default mode, no element available. */
|
||||
empty,
|
||||
/*! @brief Owning mode, the object owns a dynamically allocated element. */
|
||||
/*! @brief Owning mode, dynamically allocated element. */
|
||||
dynamic,
|
||||
/*! @brief Owning mode, the object owns an embedded element. */
|
||||
/*! @brief Owning mode, embedded element. */
|
||||
embedded,
|
||||
/*! @brief Aliasing mode, the object _points_ to a non-const element. */
|
||||
/*! @brief Aliasing mode, non-const reference. */
|
||||
ref,
|
||||
/*! @brief Const aliasing mode, the object _points_ to a const element. */
|
||||
/*! @brief Const aliasing mode, const reference. */
|
||||
cref
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(double[2])>
|
||||
template<stl::size_t Len = sizeof(double[2]), stl::size_t = alignof(double[2])>
|
||||
class basic_any;
|
||||
|
||||
/*! @brief Alias declaration for type identifiers. */
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
#ifndef ENTT_CORE_HASHED_STRING_HPP
|
||||
#define ENTT_CORE_HASHED_STRING_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/cstdint.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename = id_type>
|
||||
struct fnv_1a_params;
|
||||
|
||||
template<>
|
||||
struct fnv_1a_params<std::uint32_t> {
|
||||
struct fnv_1a_params<stl::uint32_t> {
|
||||
static constexpr auto offset = 2166136261;
|
||||
static constexpr auto prime = 16777619;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct fnv_1a_params<std::uint64_t> {
|
||||
struct fnv_1a_params<stl::uint64_t> {
|
||||
static constexpr auto offset = 14695981039346656037ull;
|
||||
static constexpr auto prime = 1099511628211ull;
|
||||
};
|
||||
@@ -29,12 +28,12 @@ struct fnv_1a_params<std::uint64_t> {
|
||||
template<typename Char>
|
||||
struct basic_hashed_string {
|
||||
using value_type = Char;
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
using hash_type = id_type;
|
||||
|
||||
const value_type *repr;
|
||||
size_type length;
|
||||
hash_type hash;
|
||||
const value_type *repr{};
|
||||
hash_type hash{fnv_1a_params<>::offset};
|
||||
size_type length{};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
@@ -62,30 +61,19 @@ class basic_hashed_string: internal::basic_hashed_string<Char> {
|
||||
|
||||
struct const_wrapper {
|
||||
// non-explicit constructor on purpose
|
||||
constexpr const_wrapper(const Char *str) noexcept
|
||||
constexpr const_wrapper(const base_type::value_type *str) noexcept
|
||||
: repr{str} {}
|
||||
|
||||
const Char *repr;
|
||||
const base_type::value_type *repr;
|
||||
};
|
||||
|
||||
// Fowler–Noll–Vo hash function v. 1a - the good
|
||||
[[nodiscard]] static constexpr auto helper(const std::basic_string_view<Char> view) noexcept {
|
||||
base_type base{view.data(), view.size(), params::offset};
|
||||
|
||||
for(auto &&curr: view) {
|
||||
base.hash = (base.hash ^ static_cast<id_type>(curr)) * params::prime;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Character type. */
|
||||
using value_type = typename base_type::value_type;
|
||||
using value_type = base_type::value_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename base_type::size_type;
|
||||
using size_type = base_type::size_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using hash_type = typename base_type::hash_type;
|
||||
using hash_type = base_type::hash_type;
|
||||
|
||||
/**
|
||||
* @brief Returns directly the numeric representation of a string view.
|
||||
@@ -103,7 +91,7 @@ public:
|
||||
* @param str Human-readable identifier.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
template<stl::size_t N>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
[[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept {
|
||||
return basic_hashed_string{str};
|
||||
@@ -128,17 +116,29 @@ public:
|
||||
* @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})} {}
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
|
||||
: base_type{str} {
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
for(; base_type::length < len; ++base_type::length) {
|
||||
base_type::hash = (base_type::hash ^ static_cast<id_type>(str[base_type::length])) * params::prime;
|
||||
}
|
||||
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a hashed string from an array of const characters.
|
||||
* @tparam N Number of characters of the identifier.
|
||||
* @param str Human-readable identifier.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
template<stl::size_t N>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept
|
||||
: base_type{helper({static_cast<const value_type *>(str)})} {}
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
|
||||
: base_type{str} {
|
||||
for(; str[base_type::length]; ++base_type::length) {
|
||||
base_type::hash = (base_type::hash ^ static_cast<id_type>(str[base_type::length])) * params::prime;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Explicit constructor on purpose to avoid constructing a hashed
|
||||
@@ -150,10 +150,16 @@ public:
|
||||
* @param wrapper Helps achieving the purpose by relying on overloading.
|
||||
*/
|
||||
explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept
|
||||
: base_type{helper({wrapper.repr})} {}
|
||||
: base_type{wrapper.repr} {
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
for(; wrapper.repr[base_type::length]; ++base_type::length) {
|
||||
base_type::hash = (base_type::hash ^ static_cast<id_type>(wrapper.repr[base_type::length])) * params::prime;
|
||||
}
|
||||
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the size a hashed string.
|
||||
* @brief Returns the size of a hashed string.
|
||||
* @return The size of the hashed string.
|
||||
*/
|
||||
[[nodiscard]] constexpr size_type size() const noexcept {
|
||||
@@ -177,7 +183,7 @@ public:
|
||||
}
|
||||
|
||||
/*! @copydoc data */
|
||||
[[nodiscard]] constexpr operator const value_type *() const noexcept {
|
||||
[[nodiscard]] explicit constexpr operator const value_type *() const noexcept {
|
||||
return data();
|
||||
}
|
||||
|
||||
@@ -188,6 +194,24 @@ public:
|
||||
[[nodiscard]] constexpr operator hash_type() const noexcept {
|
||||
return value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @param other A valid hashed string.
|
||||
* @return True if the two hashed strings are identical, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept {
|
||||
return value() == other.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lexicographically compares two hashed strings.
|
||||
* @param other A valid hashed string.
|
||||
* @return The relative order between the two hashed strings.
|
||||
*/
|
||||
[[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept {
|
||||
return value() <=> other.value();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -197,7 +221,7 @@ public:
|
||||
* @param len Length of the string to hash.
|
||||
*/
|
||||
template<typename Char>
|
||||
basic_hashed_string(const Char *str, std::size_t len) -> basic_hashed_string<Char>;
|
||||
basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string<Char>;
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
@@ -205,85 +229,10 @@ basic_hashed_string(const Char *str, std::size_t len) -> basic_hashed_string<Cha
|
||||
* @tparam N Number of characters of the identifier.
|
||||
* @param str Human-readable identifier.
|
||||
*/
|
||||
template<typename Char, std::size_t N>
|
||||
template<typename Char, stl::size_t N>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>;
|
||||
|
||||
/**
|
||||
* @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 are identical, 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 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);
|
||||
}
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
/**
|
||||
@@ -291,7 +240,7 @@ inline namespace literals {
|
||||
* @param str The literal without its suffix.
|
||||
* @return A properly initialized hashed string.
|
||||
*/
|
||||
[[nodiscard]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, std::size_t) noexcept {
|
||||
[[nodiscard]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept {
|
||||
return hashed_string{str};
|
||||
}
|
||||
|
||||
@@ -300,7 +249,7 @@ inline namespace literals {
|
||||
* @param str The literal without its suffix.
|
||||
* @return A properly initialized hashed wstring.
|
||||
*/
|
||||
[[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, std::size_t) noexcept {
|
||||
[[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept {
|
||||
return hashed_wstring{str};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef ENTT_CORE_IDENT_HPP
|
||||
#define ENTT_CORE_IDENT_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
@@ -15,10 +15,9 @@ namespace entt {
|
||||
*/
|
||||
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{}));
|
||||
template<typename Curr, stl::size_t... Index>
|
||||
[[nodiscard]] static ENTT_CONSTEVAL id_type get(stl::index_sequence<Index...>) noexcept {
|
||||
return (0 + ... + (stl::is_same_v<Curr, type_list_element_t<Index, type_list<stl::decay_t<Type>...>>> ? id_type{Index} : id_type{}));
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -27,7 +26,8 @@ public:
|
||||
|
||||
/*! @brief Statically generated unique identifier for the given type. */
|
||||
template<typename Curr>
|
||||
static constexpr value_type value = get<std::decay_t<Curr>>(std::index_sequence_for<Type...>{});
|
||||
requires (stl::is_same_v<stl::remove_cvref_t<Curr>, Type> || ...)
|
||||
static constexpr value_type value = get<stl::remove_cvref_t<Curr>>(stl::index_sequence_for<Type...>{});
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#ifndef ENTT_CORE_ITERATOR_HPP
|
||||
#define ENTT_CORE_ITERATOR_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
@@ -25,15 +27,15 @@ struct input_iterator_pointer final {
|
||||
* @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)} {}
|
||||
constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v<value_type>)
|
||||
: value{stl::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);
|
||||
return stl::addressof(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,11 +54,8 @@ private:
|
||||
* @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:
|
||||
template<stl::integral Type>
|
||||
struct iota_iterator final {
|
||||
/*! @brief Value type, likely an integral one. */
|
||||
using value_type = Type;
|
||||
/*! @brief Invalid pointer type. */
|
||||
@@ -64,9 +63,9 @@ public:
|
||||
/*! @brief Non-reference type, same as value type. */
|
||||
using reference = value_type;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Iterator category. */
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
constexpr iota_iterator() noexcept
|
||||
@@ -104,50 +103,35 @@ public:
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Comparison operator.
|
||||
* @param other A properly initialized iota iterator.
|
||||
* @return True if the two iterators are identical, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept {
|
||||
return current == other.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>
|
||||
template<stl::input_or_output_iterator It, stl::sentinel_for<It> Sentinel = It>
|
||||
struct iterable_adaptor final {
|
||||
/*! @brief Value type. */
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
using value_type = stl::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>)
|
||||
constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v<iterator> && stl::is_nothrow_default_constructible_v<sentinel>)
|
||||
: first{},
|
||||
last{} {}
|
||||
|
||||
@@ -156,9 +140,9 @@ struct iterable_adaptor final {
|
||||
* @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)} {}
|
||||
constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v<iterator> && stl::is_nothrow_move_constructible_v<sentinel>)
|
||||
: first{stl::move(from)},
|
||||
last{stl::move(to)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning.
|
||||
|
||||
@@ -1,30 +1,15 @@
|
||||
#ifndef ENTT_CORE_MEMORY_HPP
|
||||
#define ENTT_CORE_MEMORY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @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.
|
||||
@@ -33,7 +18,7 @@ template<typename Type>
|
||||
*/
|
||||
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) {
|
||||
if constexpr(stl::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
|
||||
lhs = rhs;
|
||||
}
|
||||
}
|
||||
@@ -46,8 +31,8 @@ constexpr void propagate_on_container_copy_assignment([[maybe_unused]] 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);
|
||||
if constexpr(stl::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
|
||||
lhs = stl::move(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +44,8 @@ constexpr void propagate_on_container_move_assignment([[maybe_unused]] 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;
|
||||
if constexpr(stl::allocator_traits<Allocator>::propagate_on_container_swap::value) {
|
||||
using stl::swap;
|
||||
swap(lhs, rhs);
|
||||
} else {
|
||||
ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers");
|
||||
@@ -76,28 +61,28 @@ struct allocation_deleter: private Allocator {
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Pointer type. */
|
||||
using pointer = typename std::allocator_traits<Allocator>::pointer;
|
||||
using pointer = stl::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>)
|
||||
constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::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 = std::allocator_traits<Allocator>;
|
||||
alloc_traits::destroy(*this, to_address(ptr));
|
||||
constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v<typename allocator_type::value_type>) {
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
alloc_traits::destroy(*this, stl::to_address(ptr));
|
||||
alloc_traits::deallocate(*this, ptr, 1u);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Allows `std::unique_ptr` to use allocators (waiting for C++20).
|
||||
* @brief Allows `stl::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.
|
||||
@@ -106,78 +91,77 @@ struct allocation_deleter: private Allocator {
|
||||
* @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");
|
||||
constexpr auto allocate_unique(Allocator &allocator, Args &&...args) {
|
||||
static_assert(!stl::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;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>::template rebind_traits<Type>;
|
||||
using allocator_type = 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)...);
|
||||
alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward<Args>(args)...);
|
||||
}
|
||||
ENTT_CATCH {
|
||||
alloc_traits::deallocate(alloc, ptr, 1u);
|
||||
ENTT_THROW;
|
||||
}
|
||||
|
||||
return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
|
||||
return stl::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
|
||||
}
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
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)...);
|
||||
if constexpr(!stl::uses_allocator_v<Type, Allocator> && stl::is_constructible_v<Type, Params...>) {
|
||||
return stl::forward_as_tuple(stl::forward<Params>(params)...);
|
||||
} else {
|
||||
static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request");
|
||||
static_assert(stl::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)...};
|
||||
if constexpr(stl::is_constructible_v<Type, stl::allocator_arg_t, const Allocator &, Params...>) {
|
||||
return stl::tuple<stl::allocator_arg_t, const Allocator &, Params &&...>{stl::allocator_arg, allocator, stl::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);
|
||||
static_assert(stl::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
|
||||
return stl::forward_as_tuple(stl::forward<Params>(params)..., allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type, typename Other>
|
||||
struct uses_allocator_construction<std::pair<Type, Other>> {
|
||||
using type = std::pair<Type, Other>;
|
||||
struct uses_allocator_construction<stl::pair<Type, Other>> {
|
||||
using type = stl::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 First, typename Second>
|
||||
static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept {
|
||||
return stl::make_tuple(
|
||||
stl::piecewise_construct,
|
||||
stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, stl::forward<decltype(curr)>(curr)...); }, stl::forward<First>(first)),
|
||||
stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, stl::forward<decltype(curr)>(curr)...); }, stl::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<>{});
|
||||
static constexpr auto args(const auto &allocator) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::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 First, typename Second>
|
||||
static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward<First>(first)), stl::forward_as_tuple(stl::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 First, typename Second>
|
||||
static constexpr auto args(const auto &allocator, const stl::pair<First, Second> &value) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::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)));
|
||||
template<typename First, typename Second>
|
||||
static constexpr auto args(const auto &allocator, stl::pair<First, Second> &&value) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -191,15 +175,14 @@ struct uses_allocator_construction<std::pair<Type, Other>> {
|
||||
* 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)...);
|
||||
template<typename Type, typename... Args>
|
||||
constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept {
|
||||
return internal::uses_allocator_construction<Type>::args(allocator, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,15 +192,14 @@ constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args
|
||||
* 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)...));
|
||||
template<typename Type, typename... Args>
|
||||
constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) {
|
||||
return stl::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, stl::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,16 +209,15 @@ constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...ar
|
||||
* 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)...));
|
||||
template<typename Type, typename... Args>
|
||||
constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) {
|
||||
return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, stl::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
#ifndef ENTT_CORE_RANGES_HPP
|
||||
#define ENTT_CORE_RANGES_HPP
|
||||
|
||||
#if __has_include(<version>)
|
||||
# include <version>
|
||||
#
|
||||
# if defined(__cpp_lib_ranges)
|
||||
# include <ranges>
|
||||
# include "iterator.hpp"
|
||||
#include <version>
|
||||
|
||||
#if defined(__cpp_lib_ranges)
|
||||
# include <ranges>
|
||||
# include "iterator.hpp"
|
||||
|
||||
namespace std::ranges {
|
||||
|
||||
template<class... Args>
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<entt::iterable_adaptor<Args...>>{true};
|
||||
inline constexpr bool enable_borrowed_range<entt::iterable_adaptor<Args...>>{true};
|
||||
|
||||
template<class... Args>
|
||||
inline constexpr bool std::ranges::enable_view<entt::iterable_adaptor<Args...>>{true};
|
||||
inline constexpr bool enable_view<entt::iterable_adaptor<Args...>>{true};
|
||||
|
||||
} // namespace std::ranges
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef ENTT_CORE_TUPLE_HPP
|
||||
#define ENTT_CORE_TUPLE_HPP
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
@@ -13,14 +13,14 @@ namespace entt {
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_tuple: std::false_type {};
|
||||
struct is_tuple: stl::false_type {};
|
||||
|
||||
/**
|
||||
* @copybrief is_tuple
|
||||
* @tparam Args Tuple template arguments.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct is_tuple<std::tuple<Args...>>: std::true_type {};
|
||||
struct is_tuple<stl::tuple<Args...>>: stl::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -38,10 +38,10 @@ inline constexpr bool is_tuple_v = is_tuple<Type>::value;
|
||||
*/
|
||||
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));
|
||||
if constexpr(stl::tuple_size_v<stl::remove_reference_t<Type>> == 1u) {
|
||||
return stl::get<0>(stl::forward<Type>(value));
|
||||
} else {
|
||||
return std::forward<Type>(value);
|
||||
return stl::forward<Type>(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ struct forward_apply: private Func {
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename... Args>
|
||||
constexpr forward_apply(Args &&...args) noexcept(std::is_nothrow_constructible_v<Func, Args...>)
|
||||
: Func{std::forward<Args>(args)...} {}
|
||||
constexpr forward_apply(Args &&...args) noexcept(stl::is_nothrow_constructible_v<Func, Args...>)
|
||||
: Func{stl::forward<Args>(args)...} {}
|
||||
|
||||
/**
|
||||
* @brief Forwards and applies the arguments with the underlying function.
|
||||
@@ -67,14 +67,14 @@ struct forward_apply: private Func {
|
||||
* @return Return value of the underlying function, if any.
|
||||
*/
|
||||
template<typename 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));
|
||||
constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(stl::apply(stl::declval<Func &>(), args))) {
|
||||
return stl::apply(static_cast<Func &>(*this), stl::forward<Type>(args));
|
||||
}
|
||||
|
||||
/*! @copydoc operator()() */
|
||||
template<typename 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));
|
||||
constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(stl::apply(stl::declval<const Func &>(), args))) {
|
||||
return stl::apply(static_cast<const Func &>(*this), stl::forward<Type>(args));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -83,7 +83,7 @@ struct forward_apply: private Func {
|
||||
* @tparam Func Type of underlying invocable object.
|
||||
*/
|
||||
template<typename Func>
|
||||
forward_apply(Func) -> forward_apply<std::remove_reference_t<std::remove_cv_t<Func>>>;
|
||||
forward_apply(Func) -> forward_apply<stl::remove_cvref_t<Func>>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
#ifndef ENTT_CORE_TYPE_INFO_HPP
|
||||
#define ENTT_CORE_TYPE_INFO_HPP
|
||||
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <compare>
|
||||
#include "../config/config.h"
|
||||
#include "../core/attribute.h"
|
||||
#include "../stl/string_view.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "hashed_string.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
struct ENTT_API type_index final {
|
||||
@@ -21,32 +21,41 @@ struct ENTT_API type_index final {
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr const char *pretty_function() noexcept {
|
||||
#if defined ENTT_PRETTY_FUNCTION
|
||||
return static_cast<const char *>(ENTT_PRETTY_FUNCTION);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto stripped_type_name() noexcept {
|
||||
#if defined ENTT_PRETTY_FUNCTION
|
||||
const std::string_view pretty_function{static_cast<const char *>(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);
|
||||
const stl::string_view full_name{pretty_function<Type>()};
|
||||
auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1);
|
||||
auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first);
|
||||
return value;
|
||||
#else
|
||||
return std::string_view{""};
|
||||
return stl::string_view{};
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
|
||||
[[nodiscard]] constexpr std::string_view type_name(int) noexcept {
|
||||
[[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept {
|
||||
constexpr auto value = stripped_type_name<Type>();
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] std::string_view type_name(char) noexcept {
|
||||
[[nodiscard]] stl::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]] constexpr id_type type_hash(int) noexcept {
|
||||
[[nodiscard]] ENTT_CONSTEVAL 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;
|
||||
@@ -67,7 +76,7 @@ template<typename Type>
|
||||
* @brief Type sequential identifier.
|
||||
* @tparam Type Type for which to generate a sequential identifier.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
template<typename Type>
|
||||
struct ENTT_API type_index final {
|
||||
/**
|
||||
* @brief Returns the sequential identifier of a given type.
|
||||
@@ -88,7 +97,7 @@ struct ENTT_API type_index final {
|
||||
* @brief Type hash.
|
||||
* @tparam Type Type for which to generate a hash value.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
template<typename Type>
|
||||
struct type_hash final {
|
||||
/**
|
||||
* @brief Returns the numeric representation of a given type.
|
||||
@@ -113,18 +122,18 @@ struct type_hash final {
|
||||
* @brief Type name.
|
||||
* @tparam Type Type for which to generate a name.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
template<typename Type>
|
||||
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 {
|
||||
[[nodiscard]] static constexpr stl::string_view value() noexcept {
|
||||
return internal::type_name<Type>(0);
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator std::string_view() const noexcept {
|
||||
[[nodiscard]] constexpr operator stl::string_view() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
@@ -137,10 +146,10 @@ struct type_info final {
|
||||
*/
|
||||
template<typename Type>
|
||||
// NOLINTBEGIN(modernize-use-transparent-functors)
|
||||
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()} {}
|
||||
constexpr type_info(stl::in_place_type_t<Type>) noexcept
|
||||
: seq{type_index<stl::remove_cvref_t<Type>>::value()},
|
||||
identifier{type_hash<stl::remove_cvref_t<Type>>::value()},
|
||||
alias{type_name<stl::remove_cvref_t<Type>>::value()} {}
|
||||
// NOLINTEND(modernize-use-transparent-functors)
|
||||
|
||||
/**
|
||||
@@ -163,79 +172,34 @@ struct type_info final {
|
||||
* @brief Type name.
|
||||
* @return Type name.
|
||||
*/
|
||||
[[nodiscard]] constexpr std::string_view name() const noexcept {
|
||||
[[nodiscard]] constexpr stl::string_view name() const noexcept {
|
||||
return alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param other A type info object.
|
||||
* @return True if the two type info objects are identical, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept {
|
||||
return identifier == other.identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Lexicographically compares two type info objects.
|
||||
* @param other A type info object.
|
||||
* @return The relative order between the two type info objects.
|
||||
*/
|
||||
[[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept {
|
||||
return seq <=> other.seq;
|
||||
}
|
||||
|
||||
private:
|
||||
id_type seq;
|
||||
id_type identifier;
|
||||
std::string_view alias;
|
||||
stl::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]] 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]] 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.
|
||||
*
|
||||
@@ -249,19 +213,18 @@ private:
|
||||
*/
|
||||
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 const type_info instance{std::in_place_type<Type>};
|
||||
if constexpr(stl::is_same_v<Type, stl::remove_cvref_t<Type>>) {
|
||||
static const type_info instance{stl::in_place_type<Type>};
|
||||
return instance;
|
||||
} else {
|
||||
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
return type_id<stl::remove_cvref_t<Type>>();
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc type_id */
|
||||
template<typename Type>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
|
||||
[[nodiscard]] const type_info &type_id(Type &&) noexcept {
|
||||
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
[[nodiscard]] const type_info &type_id(const Type &) noexcept {
|
||||
return type_id<stl::remove_cvref_t<Type>>();
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#ifndef ENTT_CORE_TYPE_TRAITS_HPP
|
||||
#define ENTT_CORE_TYPE_TRAITS_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
@@ -15,10 +16,10 @@ namespace entt {
|
||||
* @brief Utility class to disambiguate overloaded functions.
|
||||
* @tparam N Number of choices available.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
template<stl::size_t N>
|
||||
struct choice_t
|
||||
// unfortunately, doxygen cannot parse such a construct
|
||||
: /*! @cond TURN_OFF_DOXYGEN */ choice_t<N - 1> /*! @endcond */
|
||||
: /*! @cond ENTT_INTERNAL */ choice_t<N - 1> /*! @endcond */
|
||||
{};
|
||||
|
||||
/*! @copybrief choice_t */
|
||||
@@ -29,49 +30,29 @@ struct choice_t<0> {};
|
||||
* @brief Variable template for the choice trick.
|
||||
* @tparam N Number of choices available.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
template<stl::size_t N>
|
||||
inline constexpr choice_t<N> choice{};
|
||||
|
||||
/**
|
||||
* @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.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct size_of: std::integral_constant<std::size_t, 0u> {};
|
||||
template<typename Type>
|
||||
struct size_of: stl::integral_constant<stl::size_t, 0u> {};
|
||||
|
||||
/*! @copydoc size_of */
|
||||
template<typename Type>
|
||||
struct size_of<Type, std::void_t<decltype(sizeof(Type))>>
|
||||
requires requires { sizeof(Type); }
|
||||
struct size_of<Type>
|
||||
// NOLINTNEXTLINE(bugprone-sizeof-expression)
|
||||
: std::integral_constant<std::size_t, sizeof(Type)> {};
|
||||
: stl::integral_constant<stl::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;
|
||||
inline constexpr stl::size_t size_of_v = size_of<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Using declaration to be used to _repeat_ the same type a number of
|
||||
@@ -94,7 +75,7 @@ inline constexpr auto unpack_as_value = Value;
|
||||
* @tparam Value A static constant.
|
||||
*/
|
||||
template<auto Value>
|
||||
using integral_constant = std::integral_constant<decltype(Value), Value>;
|
||||
using integral_constant = stl::integral_constant<decltype(Value), Value>;
|
||||
|
||||
/**
|
||||
* @brief Alias template to facilitate the creation of named values.
|
||||
@@ -116,7 +97,7 @@ struct type_list {
|
||||
};
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<std::size_t, typename>
|
||||
template<stl::size_t, typename>
|
||||
struct type_list_element;
|
||||
|
||||
/**
|
||||
@@ -125,7 +106,7 @@ struct type_list_element;
|
||||
* @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>
|
||||
template<stl::size_t Index, typename First, typename... Other>
|
||||
struct type_list_element<Index, type_list<First, Other...>>
|
||||
: type_list_element<Index - 1u, type_list<Other...>> {};
|
||||
|
||||
@@ -145,8 +126,8 @@ struct type_list_element<0u, type_list<First, Other...>> {
|
||||
* @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;
|
||||
template<stl::size_t Index, typename List>
|
||||
using type_list_element_t = type_list_element<Index, List>::type;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename, typename>
|
||||
@@ -161,7 +142,7 @@ struct type_list_index;
|
||||
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;
|
||||
using value_type = stl::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;
|
||||
};
|
||||
@@ -175,7 +156,7 @@ 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;
|
||||
using value_type = stl::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
@@ -187,7 +168,7 @@ struct type_list_index<Type, type_list<Type, Other...>> {
|
||||
template<typename Type>
|
||||
struct type_list_index<Type, type_list<>> {
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
using value_type = stl::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
@@ -198,7 +179,7 @@ struct type_list_index<Type, type_list<>> {
|
||||
* @tparam Type Type to look for and for which to return the index.
|
||||
*/
|
||||
template<typename Type, typename List>
|
||||
inline constexpr std::size_t type_list_index_v = type_list_index<Type, List>::value;
|
||||
inline constexpr stl::size_t type_list_index_v = type_list_index<Type, List>::value;
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
@@ -207,7 +188,7 @@ inline constexpr std::size_t type_list_index_v = type_list_index<Type, List>::va
|
||||
* @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...>) {
|
||||
ENTT_CONSTEVAL type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -231,7 +212,7 @@ struct type_list_cat<> {
|
||||
template<typename... Type, typename... Other, typename... List>
|
||||
struct type_list_cat<type_list<Type...>, type_list<Other...>, List...> {
|
||||
/*! @brief A type list composed by the types of all the type lists. */
|
||||
using type = typename type_list_cat<type_list<Type..., Other...>, List...>::type;
|
||||
using type = type_list_cat<type_list<Type..., Other...>, List...>::type;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -249,9 +230,9 @@ struct type_list_cat<type_list<Type...>> {
|
||||
* @tparam List Type lists to concatenate.
|
||||
*/
|
||||
template<typename... List>
|
||||
using type_list_cat_t = typename type_list_cat<List...>::type;
|
||||
using type_list_cat_t = type_list_cat<List...>::type;
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename...>
|
||||
@@ -259,7 +240,7 @@ struct type_list_unique;
|
||||
|
||||
template<typename First, typename... Other, typename... Type>
|
||||
struct type_list_unique<type_list<First, Other...>, Type...>
|
||||
: std::conditional_t<(std::is_same_v<First, Type> || ...), type_list_unique<type_list<Other...>, Type...>, type_list_unique<type_list<Other...>, Type..., First>> {};
|
||||
: stl::conditional_t<(stl::is_same_v<First, Type> || ...), type_list_unique<type_list<Other...>, Type...>, type_list_unique<type_list<Other...>, Type..., First>> {};
|
||||
|
||||
template<typename... Type>
|
||||
struct type_list_unique<type_list<>, Type...> {
|
||||
@@ -276,7 +257,7 @@ struct type_list_unique<type_list<>, Type...> {
|
||||
template<typename List>
|
||||
struct type_list_unique {
|
||||
/*! @brief A type list without duplicate types. */
|
||||
using type = typename internal::type_list_unique<List>::type;
|
||||
using type = internal::type_list_unique<List>::type;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -284,7 +265,7 @@ struct type_list_unique {
|
||||
* @tparam List Type list.
|
||||
*/
|
||||
template<typename List>
|
||||
using type_list_unique_t = typename type_list_unique<List>::type;
|
||||
using type_list_unique_t = type_list_unique<List>::type;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a type list contains a
|
||||
@@ -302,7 +283,7 @@ struct type_list_contains;
|
||||
*/
|
||||
template<typename... Type, typename Other>
|
||||
struct type_list_contains<type_list<Type...>, Other>
|
||||
: std::bool_constant<(std::is_same_v<Type, Other> || ...)> {};
|
||||
: stl::bool_constant<(stl::is_same_v<Type, Other> || ...)> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -324,7 +305,7 @@ struct type_list_diff;
|
||||
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>>...>;
|
||||
using type = type_list_cat_t<stl::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -332,7 +313,7 @@ struct type_list_diff<type_list<Type...>, type_list<Other...>> {
|
||||
* @tparam List Type lists between which to compute the difference.
|
||||
*/
|
||||
template<typename... List>
|
||||
using type_list_diff_t = typename type_list_diff<List...>::type;
|
||||
using type_list_diff_t = type_list_diff<List...>::type;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename, template<typename...> class>
|
||||
@@ -356,7 +337,7 @@ struct type_list_transform<type_list<Type...>, Op> {
|
||||
* @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;
|
||||
using type_list_transform_t = type_list_transform<List, Op>::type;
|
||||
|
||||
/**
|
||||
* @brief A class to use to push around lists of constant values, nothing more.
|
||||
@@ -371,7 +352,7 @@ struct value_list {
|
||||
};
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<std::size_t, typename>
|
||||
template<stl::size_t, typename>
|
||||
struct value_list_element;
|
||||
|
||||
/**
|
||||
@@ -380,7 +361,7 @@ struct value_list_element;
|
||||
* @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>
|
||||
template<stl::size_t Index, auto Value, auto... Other>
|
||||
struct value_list_element<Index, value_list<Value, Other...>>
|
||||
: value_list_element<Index - 1u, value_list<Other...>> {};
|
||||
|
||||
@@ -402,15 +383,15 @@ struct value_list_element<0u, value_list<Value, Other...>> {
|
||||
* @tparam Index Index of the type to return.
|
||||
* @tparam List Value list to search into.
|
||||
*/
|
||||
template<std::size_t Index, typename List>
|
||||
using value_list_element_t = typename value_list_element<Index, List>::type;
|
||||
template<stl::size_t Index, typename List>
|
||||
using value_list_element_t = value_list_element<Index, List>::type;
|
||||
|
||||
/**
|
||||
* @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>
|
||||
template<stl::size_t Index, typename List>
|
||||
inline constexpr auto value_list_element_v = value_list_element<Index, List>::value;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
@@ -426,7 +407,7 @@ struct value_list_index;
|
||||
template<auto Value, auto First, auto... Other>
|
||||
struct value_list_index<Value, value_list<First, Other...>> {
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
using value_type = stl::size_t;
|
||||
/*! @brief Compile-time position of the given value in the sublist. */
|
||||
static constexpr value_type value = 1u + value_list_index<Value, value_list<Other...>>::value;
|
||||
};
|
||||
@@ -440,7 +421,7 @@ template<auto Value, auto... Other>
|
||||
struct value_list_index<Value, value_list<Value, Other...>> {
|
||||
static_assert(value_list_index<Value, value_list<Other...>>::value == sizeof...(Other), "Non-unique type");
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
using value_type = stl::size_t;
|
||||
/*! @brief Compile-time position of the given value in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
@@ -452,7 +433,7 @@ struct value_list_index<Value, value_list<Value, Other...>> {
|
||||
template<auto Value>
|
||||
struct value_list_index<Value, value_list<>> {
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
using value_type = stl::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
@@ -463,7 +444,7 @@ struct value_list_index<Value, value_list<>> {
|
||||
* @tparam Value Value to look for and for which to return the index.
|
||||
*/
|
||||
template<auto Value, typename List>
|
||||
inline constexpr std::size_t value_list_index_v = value_list_index<Value, List>::value;
|
||||
inline constexpr stl::size_t value_list_index_v = value_list_index<Value, List>::value;
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
@@ -472,7 +453,7 @@ inline constexpr std::size_t value_list_index_v = value_list_index<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...>) {
|
||||
ENTT_CONSTEVAL value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -496,7 +477,7 @@ struct value_list_cat<> {
|
||||
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;
|
||||
using type = value_list_cat<value_list<Value..., Other...>, List...>::type;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -514,7 +495,7 @@ struct value_list_cat<value_list<Value...>> {
|
||||
* @tparam List Value lists to concatenate.
|
||||
*/
|
||||
template<typename... List>
|
||||
using value_list_cat_t = typename value_list_cat<List...>::type;
|
||||
using value_list_cat_t = value_list_cat<List...>::type;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename>
|
||||
@@ -528,7 +509,7 @@ struct value_list_unique;
|
||||
template<auto Value, auto... Other>
|
||||
struct value_list_unique<value_list<Value, Other...>> {
|
||||
/*! @brief A value list without duplicate types. */
|
||||
using type = std::conditional_t<
|
||||
using type = stl::conditional_t<
|
||||
((Value == Other) || ...),
|
||||
typename value_list_unique<value_list<Other...>>::type,
|
||||
value_list_cat_t<value_list<Value>, typename value_list_unique<value_list<Other...>>::type>>;
|
||||
@@ -546,7 +527,7 @@ struct value_list_unique<value_list<>> {
|
||||
* @tparam Type A value list.
|
||||
*/
|
||||
template<typename Type>
|
||||
using value_list_unique_t = typename value_list_unique<Type>::type;
|
||||
using value_list_unique_t = value_list_unique<Type>::type;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a value list contains
|
||||
@@ -564,7 +545,7 @@ struct value_list_contains;
|
||||
*/
|
||||
template<auto... Value, auto Other>
|
||||
struct value_list_contains<value_list<Value...>, Other>
|
||||
: std::bool_constant<((Value == Other) || ...)> {};
|
||||
: stl::bool_constant<((Value == Other) || ...)> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -586,7 +567,7 @@ struct value_list_diff;
|
||||
template<auto... Value, auto... Other>
|
||||
struct value_list_diff<value_list<Value...>, value_list<Other...>> {
|
||||
/*! @brief A value list that is the difference between the two value lists. */
|
||||
using type = value_list_cat_t<std::conditional_t<value_list_contains_v<value_list<Other...>, Value>, value_list<>, value_list<Value>>...>;
|
||||
using type = value_list_cat_t<stl::conditional_t<value_list_contains_v<value_list<Other...>, Value>, value_list<>, value_list<Value>>...>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -594,11 +575,11 @@ struct value_list_diff<value_list<Value...>, value_list<Other...>> {
|
||||
* @tparam List Value lists between which to compute the difference.
|
||||
*/
|
||||
template<typename... List>
|
||||
using value_list_diff_t = typename value_list_diff<List...>::type;
|
||||
using value_list_diff_t = value_list_diff<List...>::type;
|
||||
|
||||
/*! @brief Same as std::is_invocable, but with tuples. */
|
||||
/*! @brief Same as stl::is_invocable, but with tuples. */
|
||||
template<typename, typename>
|
||||
struct is_applicable: std::false_type {};
|
||||
struct is_applicable: stl::false_type {};
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable
|
||||
@@ -607,7 +588,7 @@ struct is_applicable: std::false_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...> {};
|
||||
struct is_applicable<Func, Tuple<Args...>>: stl::is_invocable<Func, Args...> {};
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable
|
||||
@@ -616,7 +597,7 @@ struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
|
||||
* @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...> {};
|
||||
struct is_applicable<Func, const Tuple<Args...>>: stl::is_invocable<Func, Args...> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -626,9 +607,9 @@ struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args..
|
||||
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. */
|
||||
/*! @brief Same as stl::is_invocable_r, but with tuples for arguments. */
|
||||
template<typename, typename, typename>
|
||||
struct is_applicable_r: std::false_type {};
|
||||
struct is_applicable_r: stl::false_type {};
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable_r
|
||||
@@ -638,7 +619,7 @@ struct is_applicable_r: std::false_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...> {};
|
||||
struct is_applicable_r<Ret, Func, stl::tuple<Args...>>: stl::is_invocable_r<Ret, Func, Args...> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -655,12 +636,13 @@ inline constexpr bool is_applicable_r_v = is_applicable_r<Ret, Func, Args>::valu
|
||||
* complete, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_complete: std::false_type {};
|
||||
template<typename Type>
|
||||
struct is_complete: stl::false_type {};
|
||||
|
||||
/*! @copydoc is_complete */
|
||||
template<typename Type>
|
||||
struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {};
|
||||
requires requires { sizeof(Type); }
|
||||
struct is_complete<Type>: stl::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -674,25 +656,26 @@ inline constexpr bool is_complete_v = is_complete<Type>::value;
|
||||
* iterator, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_iterator: std::false_type {};
|
||||
template<typename Type>
|
||||
struct is_iterator: stl::false_type {};
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_iterator_category: std::false_type {};
|
||||
template<typename>
|
||||
struct has_iterator_category: stl::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
|
||||
requires requires { typename stl::iterator_traits<Type>::iterator_category; }
|
||||
struct has_iterator_category<Type>: stl::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/*! @copydoc is_iterator */
|
||||
template<typename Type>
|
||||
struct is_iterator<Type, std::enable_if_t<!std::is_void_v<std::remove_cv_t<std::remove_pointer_t<Type>>>>>
|
||||
: internal::has_iterator_category<Type> {};
|
||||
requires (!stl::is_void_v<stl::remove_const_t<stl::remove_pointer_t<Type>>>)
|
||||
struct is_iterator<Type>: internal::has_iterator_category<Type> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -707,8 +690,7 @@ inline constexpr bool is_iterator_v = is_iterator<Type>::value;
|
||||
* @tparam Type The type to test
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_ebco_eligible
|
||||
: std::bool_constant<std::is_empty_v<Type> && !std::is_final_v<Type>> {};
|
||||
struct is_ebco_eligible: stl::bool_constant<stl::is_empty_v<Type> && !stl::is_final_v<Type>> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -722,12 +704,13 @@ inline constexpr bool is_ebco_eligible_v = is_ebco_eligible<Type>::value;
|
||||
* 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 {};
|
||||
template<typename Type>
|
||||
struct is_transparent: stl::false_type {};
|
||||
|
||||
/*! @copydoc is_transparent */
|
||||
template<typename Type>
|
||||
struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::true_type {};
|
||||
requires requires { typename Type::is_transparent; }
|
||||
struct is_transparent<Type>: stl::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -736,52 +719,54 @@ struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::tr
|
||||
template<typename Type>
|
||||
inline constexpr bool is_transparent_v = is_transparent<Type>::value;
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_tuple_size_value: std::false_type {};
|
||||
template<typename>
|
||||
struct has_tuple_size_value: stl::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, typename = void>
|
||||
struct has_value_type: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct has_value_type<Type, std::void_t<typename Type::value_type>>: std::true_type {};
|
||||
requires is_complete_v<stl::tuple_size<const Type>>
|
||||
struct has_tuple_size_value<Type>: stl::true_type {};
|
||||
|
||||
template<typename>
|
||||
[[nodiscard]] constexpr bool dispatch_is_equality_comparable();
|
||||
struct has_value_type: stl::false_type {};
|
||||
|
||||
template<typename Type, std::size_t... Index>
|
||||
[[nodiscard]] constexpr bool unpack_maybe_equality_comparable(std::index_sequence<Index...>) {
|
||||
return (dispatch_is_equality_comparable<std::tuple_element_t<Index, Type>>() && ...);
|
||||
template<typename Type>
|
||||
requires requires { typename Type::value_type; }
|
||||
struct has_value_type<Type>: stl::true_type {};
|
||||
|
||||
template<typename>
|
||||
[[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable();
|
||||
|
||||
template<typename Type, stl::size_t... Index>
|
||||
[[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence<Index...>) {
|
||||
return (dispatch_is_equality_comparable<stl::tuple_element_t<Index, Type>>() && ...);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
[[nodiscard]] constexpr bool maybe_equality_comparable(char) {
|
||||
[[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto maybe_equality_comparable(int) -> decltype(std::declval<Type>() == std::declval<Type>()) {
|
||||
[[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval<Type>() == stl::declval<Type>()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr bool dispatch_is_equality_comparable() {
|
||||
[[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() {
|
||||
// NOLINTBEGIN(modernize-use-transparent-functors)
|
||||
if constexpr(std::is_array_v<Type>) {
|
||||
if constexpr(stl::is_array_v<Type>) {
|
||||
return false;
|
||||
} else if constexpr(is_complete_v<std::tuple_size<std::remove_cv_t<Type>>>) {
|
||||
} else if constexpr(is_complete_v<stl::tuple_size<stl::remove_const_t<Type>>>) {
|
||||
if constexpr(has_tuple_size_value<Type>::value) {
|
||||
return maybe_equality_comparable<Type>(0) && unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
|
||||
return maybe_equality_comparable<Type>(0) && unpack_maybe_equality_comparable<Type>(stl::make_index_sequence<stl::tuple_size<Type>::value>{});
|
||||
} else {
|
||||
return maybe_equality_comparable<Type>(0);
|
||||
}
|
||||
} else if constexpr(has_value_type<Type>::value) {
|
||||
if constexpr(is_iterator_v<Type> || std::is_same_v<typename Type::value_type, Type> || dispatch_is_equality_comparable<typename Type::value_type>()) {
|
||||
if constexpr(is_iterator_v<Type> || stl::is_same_v<typename Type::value_type, Type> || dispatch_is_equality_comparable<typename Type::value_type>()) {
|
||||
return maybe_equality_comparable<Type>(0);
|
||||
} else {
|
||||
return false;
|
||||
@@ -801,7 +786,7 @@ template<typename Type>
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_equality_comparable: std::bool_constant<internal::dispatch_is_equality_comparable<Type>()> {};
|
||||
struct is_equality_comparable: stl::bool_constant<internal::dispatch_is_equality_comparable<Type>()> {};
|
||||
|
||||
/*! @copydoc is_equality_comparable */
|
||||
template<typename Type>
|
||||
@@ -822,7 +807,7 @@ inline constexpr bool is_equality_comparable_v = is_equality_comparable<Type>::v
|
||||
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>;
|
||||
using type = stl::remove_const_t<To>;
|
||||
};
|
||||
|
||||
/*! @copydoc constness_as */
|
||||
@@ -838,7 +823,7 @@ struct constness_as<To, const From> {
|
||||
* @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;
|
||||
using constness_as_t = constness_as<To, From>::type;
|
||||
|
||||
/**
|
||||
* @brief Extracts the class of a non-static member object or function.
|
||||
@@ -846,7 +831,7 @@ using constness_as_t = typename constness_as<To, From>::type;
|
||||
*/
|
||||
template<typename Member>
|
||||
class member_class {
|
||||
static_assert(std::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function");
|
||||
static_assert(stl::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...));
|
||||
@@ -859,7 +844,7 @@ class member_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>()))>;
|
||||
using type = stl::remove_pointer_t<decltype(clazz(stl::declval<Member>()))>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -867,33 +852,33 @@ public:
|
||||
* @tparam Member A pointer to a non-static member object or function.
|
||||
*/
|
||||
template<typename Member>
|
||||
using member_class_t = typename member_class<Member>::type;
|
||||
using member_class_t = member_class<Member>::type;
|
||||
|
||||
/**
|
||||
* @brief Extracts the n-th argument of a _callable_ type.
|
||||
* @tparam Index The index of the argument to extract.
|
||||
* @tparam Candidate A valid _callable_ type.
|
||||
*/
|
||||
template<std::size_t Index, typename Candidate>
|
||||
template<stl::size_t Index, typename Candidate>
|
||||
class nth_argument {
|
||||
template<typename Ret, typename... Args>
|
||||
static constexpr type_list<Args...> pick_up(Ret (*)(Args...));
|
||||
static ENTT_CONSTEVAL type_list<Args...> pick_up(Ret (*)(Args...));
|
||||
|
||||
template<typename Ret, typename Class, typename... Args>
|
||||
static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...));
|
||||
static ENTT_CONSTEVAL 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);
|
||||
static ENTT_CONSTEVAL type_list<Args...> pick_up(Ret (Class ::*)(Args...) const);
|
||||
|
||||
template<typename Type, typename Class>
|
||||
static constexpr type_list<Type> pick_up(Type Class ::*);
|
||||
static ENTT_CONSTEVAL type_list<Type> pick_up(Type Class ::*);
|
||||
|
||||
template<typename Type>
|
||||
static constexpr decltype(pick_up(&Type::operator())) pick_up(Type &&);
|
||||
static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&);
|
||||
|
||||
public:
|
||||
/*! @brief N-th argument of the _callable_ type. */
|
||||
using type = type_list_element_t<Index, decltype(pick_up(std::declval<Candidate>()))>;
|
||||
using type = type_list_element_t<Index, decltype(pick_up(stl::declval<Candidate>()))>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -901,21 +886,21 @@ public:
|
||||
* @tparam Index The index of the argument to extract.
|
||||
* @tparam Candidate A valid function, member function or data member type.
|
||||
*/
|
||||
template<std::size_t Index, typename Candidate>
|
||||
using nth_argument_t = typename nth_argument<Index, Candidate>::type;
|
||||
template<stl::size_t Index, typename Candidate>
|
||||
using nth_argument_t = nth_argument<Index, Candidate>::type;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
template<typename... Type>
|
||||
struct std::tuple_size<entt::type_list<Type...>>: std::integral_constant<std::size_t, entt::type_list<Type...>::size> {};
|
||||
struct entt::stl::tuple_size<entt::type_list<Type...>>: entt::stl::integral_constant<entt::stl::size_t, entt::type_list<Type...>::size> {};
|
||||
|
||||
template<std::size_t Index, typename... Type>
|
||||
struct std::tuple_element<Index, entt::type_list<Type...>>: entt::type_list_element<Index, entt::type_list<Type...>> {};
|
||||
template<entt::stl::size_t Index, typename... Type>
|
||||
struct entt::stl::tuple_element<Index, entt::type_list<Type...>>: entt::type_list_element<Index, entt::type_list<Type...>> {};
|
||||
|
||||
template<auto... Value>
|
||||
struct std::tuple_size<entt::value_list<Value...>>: std::integral_constant<std::size_t, entt::value_list<Value...>::size> {};
|
||||
struct entt::stl::tuple_size<entt::value_list<Value...>>: entt::stl::integral_constant<entt::stl::size_t, entt::value_list<Value...>::size> {};
|
||||
|
||||
template<std::size_t Index, auto... Value>
|
||||
struct std::tuple_element<Index, entt::value_list<Value...>>: entt::value_list_element<Index, entt::value_list<Value...>> {};
|
||||
template<entt::stl::size_t Index, auto... Value>
|
||||
struct entt::stl::tuple_element<Index, entt::value_list<Value...>>: entt::value_list_element<Index, entt::value_list<Value...>> {};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,28 +1,11 @@
|
||||
#ifndef ENTT_CORE_UTILITY_HPP
|
||||
#define ENTT_CORE_UTILITY_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
|
||||
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.
|
||||
* @param value The actual argument.
|
||||
* @return The submitted value as-is.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[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.
|
||||
@@ -72,8 +55,8 @@ struct y_combinator {
|
||||
* @brief Constructs a y-combinator from a given function.
|
||||
* @param recursive A potentially recursive function.
|
||||
*/
|
||||
constexpr y_combinator(Func recursive) noexcept(std::is_nothrow_move_constructible_v<Func>)
|
||||
: func{std::move(recursive)} {}
|
||||
constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v<Func>)
|
||||
: func{stl::move(recursive)} {}
|
||||
|
||||
/**
|
||||
* @brief Invokes a y-combinator and therefore its underlying function.
|
||||
@@ -82,14 +65,14 @@ struct y_combinator {
|
||||
* @return Return value of the underlying function, if any.
|
||||
*/
|
||||
template<typename... 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)...);
|
||||
constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v<Func, const y_combinator &, Args...>) {
|
||||
return func(*this, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! @copydoc operator()() */
|
||||
template<typename... Args>
|
||||
constexpr decltype(auto) operator()(Args &&...args) noexcept(std::is_nothrow_invocable_v<Func, y_combinator &, Args...>) {
|
||||
return func(*this, std::forward<Args>(args)...);
|
||||
constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v<Func, y_combinator &, Args...>) {
|
||||
return func(*this, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,35 +1,37 @@
|
||||
#ifndef ENTT_ENTITY_COMPONENT_HPP
|
||||
#define ENTT_ENTITY_COMPONENT_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/concepts.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
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: stl::bool_constant<!(stl::is_move_constructible_v<Type> && stl::is_move_assignable_v<Type>)> {};
|
||||
|
||||
template<>
|
||||
struct in_place_delete<void>: std::false_type {};
|
||||
struct in_place_delete<void>: stl::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>>
|
||||
: std::true_type {};
|
||||
requires Type::in_place_delete
|
||||
struct in_place_delete<Type>: stl::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: stl::integral_constant<stl::size_t, !stl::is_empty_v<ENTT_ETO_TYPE(Type)> * ENTT_PACKED_PAGE> {};
|
||||
|
||||
template<>
|
||||
struct page_size<void>: std::integral_constant<std::size_t, 0u> {};
|
||||
struct page_size<void>: stl::integral_constant<stl::size_t, 0u> {};
|
||||
|
||||
template<typename Type>
|
||||
struct page_size<Type, std::void_t<decltype(Type::page_size)>>
|
||||
: std::integral_constant<std::size_t, Type::page_size> {};
|
||||
requires stl::is_convertible_v<decltype(Type::page_size), stl::size_t>
|
||||
struct page_size<Type>: stl::integral_constant<stl::size_t, Type::page_size> {};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
@@ -39,10 +41,8 @@ struct page_size<Type, std::void_t<decltype(Type::page_size)>>
|
||||
* @tparam Type Element type.
|
||||
* @tparam Entity A valid entity type.
|
||||
*/
|
||||
template<typename Type, typename Entity, typename>
|
||||
template<cvref_unqualified Type, typename Entity>
|
||||
struct component_traits {
|
||||
static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
|
||||
|
||||
/*! @brief Element type. */
|
||||
using element_type = Type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
@@ -51,7 +51,7 @@ struct component_traits {
|
||||
/*! @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;
|
||||
static constexpr stl::size_t page_size = internal::page_size<Type>::value;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -1,50 +1,56 @@
|
||||
#ifndef ENTT_ENTITY_ENTITY_HPP
|
||||
#define ENTT_ENTITY_ENTITY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/bit.hpp"
|
||||
#include "../stl/bit.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/cstdint.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
template<typename>
|
||||
struct entt_traits;
|
||||
|
||||
template<typename Type>
|
||||
struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>>
|
||||
: entt_traits<std::underlying_type_t<Type>> {
|
||||
requires requires {
|
||||
requires stl::is_enum_v<Type>;
|
||||
typename internal::entt_traits<stl::underlying_type_t<Type>>::value_type;
|
||||
}
|
||||
struct entt_traits<Type>: entt_traits<stl::underlying_type_t<Type>> {
|
||||
using value_type = Type;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>>
|
||||
requires requires { typename Type::entity_type; }
|
||||
struct entt_traits<Type>
|
||||
: entt_traits<typename Type::entity_type> {
|
||||
using value_type = Type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct entt_traits<std::uint32_t> {
|
||||
using value_type = std::uint32_t;
|
||||
struct entt_traits<stl::uint32_t> {
|
||||
using value_type = stl::uint32_t;
|
||||
|
||||
using entity_type = std::uint32_t;
|
||||
using version_type = std::uint16_t;
|
||||
using entity_type = stl::uint32_t;
|
||||
using version_type = stl::uint16_t;
|
||||
|
||||
static constexpr entity_type entity_mask = 0xFFFFF;
|
||||
static constexpr entity_type version_mask = 0xFFF;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct entt_traits<std::uint64_t> {
|
||||
using value_type = std::uint64_t;
|
||||
struct entt_traits<stl::uint64_t> {
|
||||
using value_type = stl::uint64_t;
|
||||
|
||||
using entity_type = std::uint64_t;
|
||||
using version_type = std::uint32_t;
|
||||
using entity_type = stl::uint64_t;
|
||||
using version_type = stl::uint32_t;
|
||||
|
||||
static constexpr entity_type entity_mask = 0xFFFFFFFF;
|
||||
static constexpr entity_type version_mask = 0xFFFFFFFF;
|
||||
@@ -53,24 +59,33 @@ struct entt_traits<std::uint64_t> {
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Specifies that a type is an entity-like type.
|
||||
* @tparam Type Type to check.
|
||||
*/
|
||||
template<typename Type>
|
||||
concept entity_like = requires {
|
||||
typename internal::entt_traits<Type>::value_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Common basic entity traits implementation.
|
||||
* @tparam Traits Actual entity traits to use.
|
||||
*/
|
||||
template<typename Traits>
|
||||
class basic_entt_traits {
|
||||
static constexpr auto length = popcount(Traits::entity_mask);
|
||||
static constexpr auto length = stl::popcount(Traits::entity_mask);
|
||||
|
||||
static_assert(Traits::entity_mask && ((Traits::entity_mask & (Traits::entity_mask + 1)) == 0), "Invalid entity mask");
|
||||
static_assert((Traits::version_mask & (Traits::version_mask + 1)) == 0, "Invalid version mask");
|
||||
|
||||
public:
|
||||
/*! @brief Value type. */
|
||||
using value_type = typename Traits::value_type;
|
||||
using value_type = Traits::value_type;
|
||||
/*! @brief Underlying entity type. */
|
||||
using entity_type = typename Traits::entity_type;
|
||||
using entity_type = Traits::entity_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename Traits::version_type;
|
||||
using version_type = Traits::version_type;
|
||||
|
||||
/*! @brief Entity mask size. */
|
||||
static constexpr entity_type entity_mask = Traits::entity_mask;
|
||||
@@ -159,12 +174,12 @@ public:
|
||||
* @brief Entity traits.
|
||||
* @tparam Type Type of identifier.
|
||||
*/
|
||||
template<typename Type>
|
||||
template<entity_like Type>
|
||||
struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> {
|
||||
/*! @brief Base type. */
|
||||
using base_type = basic_entt_traits<internal::entt_traits<Type>>;
|
||||
/*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */
|
||||
static constexpr std::size_t page_size = ENTT_SPARSE_PAGE;
|
||||
static constexpr stl::size_t page_size = ENTT_SPARSE_PAGE;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -174,7 +189,7 @@ struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> {
|
||||
* @return The integral representation of the given value.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept {
|
||||
[[nodiscard]] constexpr entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept {
|
||||
return entt_traits<Entity>::to_integral(value);
|
||||
}
|
||||
|
||||
@@ -185,7 +200,7 @@ template<typename Entity>
|
||||
* @return The integral representation of the entity part.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept {
|
||||
[[nodiscard]] constexpr entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept {
|
||||
return entt_traits<Entity>::to_entity(value);
|
||||
}
|
||||
|
||||
@@ -196,7 +211,7 @@ template<typename Entity>
|
||||
* @return The integral representation of the version part.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::version_type to_version(const Entity value) noexcept {
|
||||
[[nodiscard]] constexpr entt_traits<Entity>::version_type to_version(const Entity value) noexcept {
|
||||
return entt_traits<Entity>::to_version(value);
|
||||
}
|
||||
|
||||
@@ -207,11 +222,10 @@ struct null_t {
|
||||
* @tparam Entity Type of identifier.
|
||||
* @return The null representation for the given type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
template<entity_like Entity>
|
||||
[[nodiscard]] constexpr operator Entity() const noexcept {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
|
||||
return value;
|
||||
return traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,63 +237,19 @@ struct null_t {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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>
|
||||
template<entity_like Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
return traits_type::to_entity(entity) == traits_type::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>
|
||||
[[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 lhs Identifier with which to compare.
|
||||
* @param rhs A null object yet to be converted.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity lhs, const null_t rhs) noexcept {
|
||||
return rhs.operator==(lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param lhs Identifier with which to compare.
|
||||
* @param rhs 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 lhs, const null_t rhs) noexcept {
|
||||
return !(rhs == lhs);
|
||||
}
|
||||
|
||||
/*! @brief Tombstone object for all identifiers. */
|
||||
struct tombstone_t {
|
||||
/**
|
||||
@@ -287,11 +257,10 @@ struct tombstone_t {
|
||||
* @tparam Entity Type of identifier.
|
||||
* @return The tombstone representation for the given type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
template<entity_like Entity>
|
||||
[[nodiscard]] constexpr operator Entity() const noexcept {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
|
||||
return value;
|
||||
return traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,22 +272,13 @@ struct tombstone_t {
|
||||
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>
|
||||
template<entity_like Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
|
||||
@@ -328,43 +288,8 @@ struct tombstone_t {
|
||||
return (traits_type::to_version(entity) == traits_type::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 lhs Identifier with which to compare.
|
||||
* @param rhs 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 lhs, const tombstone_t rhs) noexcept {
|
||||
return rhs.operator==(lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param lhs Identifier with which to compare.
|
||||
* @param rhs 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 lhs, const tombstone_t rhs) noexcept {
|
||||
return !(rhs == lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compile-time constant for null entities.
|
||||
*
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#ifndef ENTT_ENTITY_FWD_HPP
|
||||
#define ENTT_ENTITY_FWD_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/concepts.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/cstdint.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
@@ -14,7 +15,7 @@ namespace entt {
|
||||
enum class entity : id_type {};
|
||||
|
||||
/*! @brief Storage deletion policy. */
|
||||
enum class deletion_policy : std::uint8_t {
|
||||
enum class deletion_policy : stl::uint8_t {
|
||||
/*! @brief Swap-and-pop deletion policy. */
|
||||
swap_and_pop = 0u,
|
||||
/*! @brief In-place deletion policy. */
|
||||
@@ -25,13 +26,13 @@ enum class deletion_policy : std::uint8_t {
|
||||
unspecified = swap_and_pop
|
||||
};
|
||||
|
||||
template<typename Type, typename Entity = entity, typename = void>
|
||||
template<cvref_unqualified Type, typename Entity = entity>
|
||||
struct component_traits;
|
||||
|
||||
template<typename Entity = entity, typename = std::allocator<Entity>>
|
||||
template<typename Entity = entity, typename = stl::allocator<Entity>>
|
||||
class basic_sparse_set;
|
||||
|
||||
template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
|
||||
template<typename Type, typename = entity, typename = stl::allocator<Type>>
|
||||
class basic_storage;
|
||||
|
||||
template<typename, typename>
|
||||
@@ -40,13 +41,13 @@ class basic_sigh_mixin;
|
||||
template<typename, typename>
|
||||
class basic_reactive_mixin;
|
||||
|
||||
template<typename Entity = entity, typename = std::allocator<Entity>>
|
||||
template<typename Entity = entity, typename = stl::allocator<Entity>>
|
||||
class basic_registry;
|
||||
|
||||
template<typename, typename, typename = void>
|
||||
template<typename, typename>
|
||||
class basic_view;
|
||||
|
||||
template<typename Type, typename = std::allocator<Type *>>
|
||||
template<typename Type, typename = stl::allocator<Type *>>
|
||||
class basic_runtime_view;
|
||||
|
||||
template<typename, typename, typename>
|
||||
@@ -139,7 +140,7 @@ using const_runtime_view = basic_runtime_view<const sparse_set>;
|
||||
template<typename... Type>
|
||||
struct exclude_t final: type_list<Type...> {
|
||||
/*! @brief Default constructor. */
|
||||
explicit constexpr exclude_t() = default;
|
||||
explicit ENTT_CONSTEVAL exclude_t() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -156,7 +157,7 @@ inline constexpr exclude_t<Type...> exclude{};
|
||||
template<typename... Type>
|
||||
struct get_t final: type_list<Type...> {
|
||||
/*! @brief Default constructor. */
|
||||
explicit constexpr get_t() = default;
|
||||
explicit ENTT_CONSTEVAL get_t() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -173,7 +174,7 @@ inline constexpr get_t<Type...> get{};
|
||||
template<typename... Type>
|
||||
struct owned_t final: type_list<Type...> {
|
||||
/*! @brief Default constructor. */
|
||||
explicit constexpr owned_t() = default;
|
||||
explicit ENTT_CONSTEVAL owned_t() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -222,7 +223,7 @@ struct type_list_transform<owned_t<Type...>, Op> {
|
||||
* @tparam Entity A valid entity type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
|
||||
template<typename Type, typename Entity = entity, typename Allocator = stl::allocator<Type>>
|
||||
struct storage_type {
|
||||
/*! @brief Type-to-storage conversion result. */
|
||||
using type = ENTT_STORAGE(sigh_mixin, basic_storage<Type, Entity, Allocator>);
|
||||
@@ -247,7 +248,7 @@ struct storage_type<reactive, Entity, Allocator> {
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using storage_type_t = typename storage_type<Args...>::type;
|
||||
using storage_type_t = storage_type<Args...>::type;
|
||||
|
||||
/**
|
||||
* Type-to-storage conversion utility that preserves constness.
|
||||
@@ -255,10 +256,10 @@ using storage_type_t = typename storage_type<Args...>::type;
|
||||
* @tparam Entity A valid entity type.
|
||||
* @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>>>
|
||||
template<typename Type, typename Entity = entity, typename Allocator = stl::allocator<stl::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>;
|
||||
using type = constness_as_t<storage_type_t<stl::remove_const_t<Type>, Entity, Allocator>, Type>;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -266,7 +267,7 @@ struct storage_for {
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using storage_for_t = typename storage_for<Args...>::type;
|
||||
using storage_for_t = storage_for<Args...>::type;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
#ifndef ENTT_ENTITY_GROUP_HPP
|
||||
#define ENTT_ENTITY_GROUP_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/algorithm.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/array.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename, typename>
|
||||
@@ -28,29 +29,29 @@ template<typename It, typename... Owned, typename... Get>
|
||||
class extended_group_iterator<It, owned_t<Owned...>, get_t<Get...>> {
|
||||
template<typename Type>
|
||||
[[nodiscard]] auto index_to_element([[maybe_unused]] Type &cpool) const {
|
||||
if constexpr(std::is_void_v<typename Type::value_type>) {
|
||||
return std::make_tuple();
|
||||
if constexpr(stl::is_void_v<typename Type::value_type>) {
|
||||
return stl::make_tuple();
|
||||
} else {
|
||||
return std::forward_as_tuple(cpool.rbegin()[it.index()]);
|
||||
return stl::forward_as_tuple(cpool.rbegin()[it.index()]);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
using iterator_type = It;
|
||||
using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Owned>().get_as_tuple({})..., std::declval<Get>().get_as_tuple({})...));
|
||||
using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval<It>()), stl::declval<Owned>().get_as_tuple({})..., stl::declval<Get>().get_as_tuple({})...));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::forward_iterator_tag;
|
||||
|
||||
constexpr extended_group_iterator()
|
||||
: it{},
|
||||
pools{} {}
|
||||
|
||||
extended_group_iterator(iterator_type from, std::tuple<Owned *..., Get *...> cpools)
|
||||
extended_group_iterator(iterator_type from, stl::tuple<Owned *..., Get *...> cpools)
|
||||
: it{from},
|
||||
pools{std::move(cpools)} {}
|
||||
pools{stl::move(cpools)} {}
|
||||
|
||||
extended_group_iterator &operator++() noexcept {
|
||||
return ++it, *this;
|
||||
@@ -62,7 +63,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const noexcept {
|
||||
return std::tuple_cat(std::make_tuple(*it), index_to_element(*std::get<Owned *>(pools))..., std::get<Get *>(pools)->get_as_tuple(*it)...);
|
||||
return stl::tuple_cat(stl::make_tuple(*it), index_to_element(*stl::get<Owned *>(pools))..., stl::get<Get *>(pools)->get_as_tuple(*it)...);
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const noexcept {
|
||||
@@ -73,52 +74,44 @@ public:
|
||||
return it;
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
friend constexpr bool operator==(const extended_group_iterator<Lhs...> &, const extended_group_iterator<Rhs...> &) noexcept;
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator==(const extended_group_iterator<Args...> &other) const noexcept {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
std::tuple<Owned *..., Get *...> pools;
|
||||
stl::tuple<Owned *..., Get *...> pools;
|
||||
};
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const extended_group_iterator<Lhs...> &lhs, const extended_group_iterator<Rhs...> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
struct group_descriptor {
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
virtual ~group_descriptor() = default;
|
||||
[[nodiscard]] virtual bool owned(const id_type) const noexcept {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type, std::size_t Owned, std::size_t Get, std::size_t Exclude>
|
||||
template<typename Type, stl::size_t Owned, stl::size_t Get, stl::size_t Exclude>
|
||||
class group_handler final: public group_descriptor {
|
||||
using entity_type = typename Type::entity_type;
|
||||
using entity_type = Type::entity_type;
|
||||
|
||||
void swap_elements(const std::size_t pos, const entity_type entt) {
|
||||
void swap_elements(const stl::size_t pos, const entity_type entt) {
|
||||
for(size_type next{}; next < Owned; ++next) {
|
||||
pools[next]->swap_elements((*pools[next])[pos], entt);
|
||||
}
|
||||
}
|
||||
|
||||
void push_on_construct(const entity_type entt) {
|
||||
if(std::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
|
||||
&& std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
|
||||
if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
|
||||
&& stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
|
||||
swap_elements(len++, entt);
|
||||
}
|
||||
}
|
||||
|
||||
void push_on_destroy(const entity_type entt) {
|
||||
if(std::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
|
||||
&& std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
|
||||
if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools)
|
||||
&& stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
|
||||
swap_elements(len++, entt);
|
||||
}
|
||||
}
|
||||
@@ -131,27 +124,27 @@ class group_handler final: public group_descriptor {
|
||||
|
||||
void common_setup() {
|
||||
// we cannot iterate backwards because we want to leave behind valid entities in case of owned types
|
||||
for(auto first = pools[0u]->rbegin(), last = first + static_cast<typename decltype(pools)::difference_type>(pools[0u]->size()); first != last; ++first) {
|
||||
for(auto first = pools[0u]->rbegin(), last = first + static_cast<decltype(pools)::difference_type>(pools[0u]->size()); first != last; ++first) {
|
||||
push_on_construct(*first);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
using common_type = Type;
|
||||
using size_type = typename Type::size_type;
|
||||
using size_type = Type::size_type;
|
||||
|
||||
template<typename... OGType, typename... EType>
|
||||
group_handler(std::tuple<OGType &...> ogpool, std::tuple<EType &...> epool)
|
||||
: pools{std::apply([](auto &&...cpool) { return std::array<common_type *, (Owned + Get)>{&cpool...}; }, ogpool)},
|
||||
filter{std::apply([](auto &&...cpool) { return std::array<common_type *, Exclude>{&cpool...}; }, epool)} {
|
||||
std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, ogpool);
|
||||
std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
|
||||
group_handler(stl::tuple<OGType &...> ogpool, stl::tuple<EType &...> epool)
|
||||
: pools{stl::apply([](auto &&...cpool) { return stl::array<common_type *, (Owned + Get)>{&cpool...}; }, ogpool)},
|
||||
filter{stl::apply([](auto &&...cpool) { return stl::array<common_type *, Exclude>{&cpool...}; }, epool)} {
|
||||
stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, ogpool);
|
||||
stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
|
||||
common_setup();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool owned(const id_type hash) const noexcept override {
|
||||
for(size_type pos{}; pos < Owned; ++pos) {
|
||||
if(pools[pos]->type().hash() == hash) {
|
||||
if(pools[pos]->info().hash() == hash) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -163,7 +156,7 @@ public:
|
||||
return len;
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
template<stl::size_t Index>
|
||||
[[nodiscard]] common_type *storage() const noexcept {
|
||||
if constexpr(Index < (Owned + Get)) {
|
||||
return pools[Index];
|
||||
@@ -173,27 +166,27 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<common_type *, (Owned + Get)> pools;
|
||||
std::array<common_type *, Exclude> filter;
|
||||
std::size_t len{};
|
||||
stl::array<common_type *, (Owned + Get)> pools;
|
||||
stl::array<common_type *, Exclude> filter;
|
||||
stl::size_t len{};
|
||||
};
|
||||
|
||||
template<typename Type, std::size_t Get, std::size_t Exclude>
|
||||
template<typename Type, stl::size_t Get, stl::size_t Exclude>
|
||||
class group_handler<Type, 0u, Get, Exclude> final: public group_descriptor {
|
||||
using entity_type = typename Type::entity_type;
|
||||
using entity_type = Type::entity_type;
|
||||
|
||||
void push_on_construct(const entity_type entt) {
|
||||
if(!elem.contains(entt)
|
||||
&& std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
|
||||
&& std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
|
||||
&& stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
|
||||
&& stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
|
||||
elem.push(entt);
|
||||
}
|
||||
}
|
||||
|
||||
void push_on_destroy(const entity_type entt) {
|
||||
if(!elem.contains(entt)
|
||||
&& std::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
|
||||
&& std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
|
||||
&& stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools)
|
||||
&& stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
|
||||
elem.push(entt);
|
||||
}
|
||||
}
|
||||
@@ -212,12 +205,12 @@ public:
|
||||
using common_type = Type;
|
||||
|
||||
template<typename Allocator, typename... GType, typename... EType>
|
||||
group_handler(const Allocator &allocator, std::tuple<GType &...> gpool, std::tuple<EType &...> epool)
|
||||
: pools{std::apply([](auto &&...cpool) { return std::array<common_type *, Get>{&cpool...}; }, gpool)},
|
||||
filter{std::apply([](auto &&...cpool) { return std::array<common_type *, Exclude>{&cpool...}; }, epool)},
|
||||
group_handler(const Allocator &allocator, stl::tuple<GType &...> gpool, stl::tuple<EType &...> epool)
|
||||
: pools{stl::apply([](auto &&...cpool) { return stl::array<common_type *, Get>{&cpool...}; }, gpool)},
|
||||
filter{stl::apply([](auto &&...cpool) { return stl::array<common_type *, Exclude>{&cpool...}; }, epool)},
|
||||
elem{allocator} {
|
||||
std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, gpool);
|
||||
std::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
|
||||
stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, gpool);
|
||||
stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool);
|
||||
common_setup();
|
||||
}
|
||||
|
||||
@@ -229,7 +222,7 @@ public:
|
||||
return elem;
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
template<stl::size_t Index>
|
||||
[[nodiscard]] common_type *storage() const noexcept {
|
||||
if constexpr(Index < Get) {
|
||||
return pools[Index];
|
||||
@@ -239,8 +232,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<common_type *, Get> pools;
|
||||
std::array<common_type *, Exclude> filter;
|
||||
stl::array<common_type *, Get> pools;
|
||||
stl::array<common_type *, Exclude> filter;
|
||||
common_type elem;
|
||||
};
|
||||
|
||||
@@ -280,15 +273,15 @@ class basic_group;
|
||||
*/
|
||||
template<typename... Get, typename... Exclude>
|
||||
class basic_group<owned_t<>, get_t<Get...>, exclude_t<Exclude...>> {
|
||||
using base_type = std::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
|
||||
using underlying_type = typename base_type::entity_type;
|
||||
using base_type = stl::common_type_t<typename Get::base_type..., typename Exclude::base_type...>;
|
||||
using underlying_type = base_type::entity_type;
|
||||
|
||||
template<typename Type>
|
||||
static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
|
||||
static constexpr stl::size_t index_of = type_list_index_v<stl::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
|
||||
|
||||
template<std::size_t... Index>
|
||||
[[nodiscard]] auto pools_for(std::index_sequence<Index...>) const noexcept {
|
||||
using return_type = std::tuple<Get *...>;
|
||||
template<stl::size_t... Index>
|
||||
[[nodiscard]] auto pools_for(stl::index_sequence<Index...>) const noexcept {
|
||||
using return_type = stl::tuple<Get *...>;
|
||||
return descriptor ? return_type{static_cast<Get *>(descriptor->template storage<Index>())...} : return_type{};
|
||||
}
|
||||
|
||||
@@ -296,15 +289,15 @@ public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = underlying_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = base_type;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename common_type::iterator;
|
||||
using iterator = common_type::iterator;
|
||||
/*! @brief Reverse iterator type. */
|
||||
using reverse_iterator = typename common_type::reverse_iterator;
|
||||
using reverse_iterator = common_type::reverse_iterator;
|
||||
/*! @brief Iterable group type. */
|
||||
using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<>, get_t<Get...>>>;
|
||||
/*! @brief Group handler type. */
|
||||
@@ -315,7 +308,7 @@ public:
|
||||
* @return Group opaque identifier.
|
||||
*/
|
||||
static id_type group_id() noexcept {
|
||||
return type_hash<basic_group<owned_t<>, get_t<std::remove_const_t<Get>...>, exclude_t<std::remove_const_t<Exclude>...>>>::value();
|
||||
return type_hash<basic_group<owned_t<>, get_t<stl::remove_const_t<Get>...>, exclude_t<stl::remove_const_t<Exclude>...>>>::value();
|
||||
}
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid groups. */
|
||||
@@ -352,7 +345,7 @@ public:
|
||||
* @tparam Index Index of the storage to return.
|
||||
* @return The storage for the given index.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
template<stl::size_t Index>
|
||||
[[nodiscard]] auto *storage() const noexcept {
|
||||
using type = type_list_element_t<Index, type_list<Get..., Exclude...>>;
|
||||
return *this ? static_cast<type *>(descriptor->template storage<Index>()) : nullptr;
|
||||
@@ -505,16 +498,16 @@ public:
|
||||
* @param entt A valid identifier.
|
||||
* @return The elements assigned to the entity.
|
||||
*/
|
||||
template<std::size_t... Index>
|
||||
template<stl::size_t... Index>
|
||||
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
|
||||
const auto cpools = pools_for(std::index_sequence_for<Get...>{});
|
||||
const auto cpools = pools_for(stl::index_sequence_for<Get...>{});
|
||||
|
||||
if constexpr(sizeof...(Index) == 0) {
|
||||
return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
|
||||
return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
|
||||
} else if constexpr(sizeof...(Index) == 1) {
|
||||
return (std::get<Index>(cpools)->get(entt), ...);
|
||||
return (stl::get<Index>(cpools)->get(entt), ...);
|
||||
} else {
|
||||
return std::tuple_cat(std::get<Index>(cpools)->get_as_tuple(entt)...);
|
||||
return stl::tuple_cat(stl::get<Index>(cpools)->get_as_tuple(entt)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,10 +536,10 @@ public:
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
for(const auto entt: *this) {
|
||||
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
|
||||
std::apply(func, std::tuple_cat(std::make_tuple(entt), get(entt)));
|
||||
if constexpr(is_applicable_v<Func, decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_group>().get({})))>) {
|
||||
stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), get(entt)));
|
||||
} else {
|
||||
std::apply(func, get(entt));
|
||||
stl::apply(func, get(entt));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -565,7 +558,7 @@ public:
|
||||
* @return An iterable object to use to _visit_ the group.
|
||||
*/
|
||||
[[nodiscard]] iterable each() const noexcept {
|
||||
const auto cpools = pools_for(std::index_sequence_for<Get...>{});
|
||||
const auto cpools = pools_for(stl::index_sequence_for<Get...>{});
|
||||
return iterable{{begin(), cpools}, {end(), cpools}};
|
||||
}
|
||||
|
||||
@@ -577,7 +570,7 @@ public:
|
||||
* comparison function should be equivalent to one of the following:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* bool(std::tuple<Type &...>, std::tuple<Type &...>);
|
||||
* bool(stl::tuple<Type &...>, stl::tuple<Type &...>);
|
||||
* bool(const Type &..., const Type &...);
|
||||
* bool(const Entity, const Entity);
|
||||
* @endcode
|
||||
@@ -604,7 +597,7 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Other, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
|
||||
sort<index_of<Type>, index_of<Other>...>(std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
sort<index_of<Type>, index_of<Other>...>(stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -620,22 +613,22 @@ public:
|
||||
* @param algo A valid sort function object.
|
||||
* @param args Arguments to forward to the sort function object, if any.
|
||||
*/
|
||||
template<std::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
template<stl::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
|
||||
if(*this) {
|
||||
if constexpr(sizeof...(Index) == 0) {
|
||||
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
|
||||
descriptor->handle().sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
static_assert(stl::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
|
||||
descriptor->handle().sort(stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
|
||||
} else {
|
||||
auto comp = [&compare, cpools = pools_for(std::index_sequence_for<Get...>{})](const entity_type lhs, const entity_type rhs) {
|
||||
auto comp = [&compare, cpools = pools_for(stl::index_sequence_for<Get...>{})](const entity_type lhs, const entity_type rhs) {
|
||||
if constexpr(sizeof...(Index) == 1) {
|
||||
return compare((std::get<Index>(cpools)->get(lhs), ...), (std::get<Index>(cpools)->get(rhs), ...));
|
||||
return compare((stl::get<Index>(cpools)->get(lhs), ...), (stl::get<Index>(cpools)->get(rhs), ...));
|
||||
} else {
|
||||
return compare(std::forward_as_tuple(std::get<Index>(cpools)->get(lhs)...), std::forward_as_tuple(std::get<Index>(cpools)->get(rhs)...));
|
||||
return compare(stl::forward_as_tuple(stl::get<Index>(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get<Index>(cpools)->get(rhs)...));
|
||||
}
|
||||
};
|
||||
|
||||
descriptor->handle().sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
|
||||
descriptor->handle().sort(stl::move(comp), stl::move(algo), stl::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -646,12 +639,10 @@ public:
|
||||
* The shared pool of entities and thus its order is affected by the changes
|
||||
* to each and every pool that it tracks.
|
||||
*
|
||||
* @tparam It Type of input iterator.
|
||||
* @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.
|
||||
*/
|
||||
template<typename It>
|
||||
void sort_as(It first, It last) const {
|
||||
void sort_as(stl::input_iterator auto first, stl::input_iterator auto last) const {
|
||||
if(*this) {
|
||||
descriptor->handle().sort_as(first, last);
|
||||
}
|
||||
@@ -696,15 +687,15 @@ template<typename... Owned, typename... Get, typename... Exclude>
|
||||
class basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> {
|
||||
static_assert(((Owned::storage_policy != deletion_policy::in_place) && ...), "Groups do not support in-place delete");
|
||||
|
||||
using base_type = std::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
|
||||
using underlying_type = typename base_type::entity_type;
|
||||
using base_type = stl::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
|
||||
using underlying_type = base_type::entity_type;
|
||||
|
||||
template<typename Type>
|
||||
static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Owned::element_type..., typename Get::element_type..., typename Exclude::element_type...>>;
|
||||
static constexpr stl::size_t index_of = type_list_index_v<stl::remove_const_t<Type>, type_list<typename Owned::element_type..., typename Get::element_type..., typename Exclude::element_type...>>;
|
||||
|
||||
template<std::size_t... Index, std::size_t... Other>
|
||||
[[nodiscard]] auto pools_for(std::index_sequence<Index...>, std::index_sequence<Other...>) const noexcept {
|
||||
using return_type = std::tuple<Owned *..., Get *...>;
|
||||
template<stl::size_t... Index, stl::size_t... Other>
|
||||
[[nodiscard]] auto pools_for(stl::index_sequence<Index...>, stl::index_sequence<Other...>) const noexcept {
|
||||
using return_type = stl::tuple<Owned *..., Get *...>;
|
||||
return descriptor ? return_type{static_cast<Owned *>(descriptor->template storage<Index>())..., static_cast<Get *>(descriptor->template storage<sizeof...(Owned) + Other>())...} : return_type{};
|
||||
}
|
||||
|
||||
@@ -712,15 +703,15 @@ public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = underlying_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = base_type;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename common_type::iterator;
|
||||
using iterator = common_type::iterator;
|
||||
/*! @brief Reverse iterator type. */
|
||||
using reverse_iterator = typename common_type::reverse_iterator;
|
||||
using reverse_iterator = common_type::reverse_iterator;
|
||||
/*! @brief Iterable group type. */
|
||||
using iterable = iterable_adaptor<internal::extended_group_iterator<iterator, owned_t<Owned...>, get_t<Get...>>>;
|
||||
/*! @brief Group handler type. */
|
||||
@@ -731,7 +722,7 @@ public:
|
||||
* @return Group opaque identifier.
|
||||
*/
|
||||
static id_type group_id() noexcept {
|
||||
return type_hash<basic_group<owned_t<std::remove_const_t<Owned>...>, get_t<std::remove_const_t<Get>...>, exclude_t<std::remove_const_t<Exclude>...>>>::value();
|
||||
return type_hash<basic_group<owned_t<stl::remove_const_t<Owned>...>, get_t<stl::remove_const_t<Get>...>, exclude_t<stl::remove_const_t<Exclude>...>>>::value();
|
||||
}
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid groups. */
|
||||
@@ -768,7 +759,7 @@ public:
|
||||
* @tparam Index Index of the storage to return.
|
||||
* @return The storage for the given index.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
template<stl::size_t Index>
|
||||
[[nodiscard]] auto *storage() const noexcept {
|
||||
using type = type_list_element_t<Index, type_list<Owned..., Get..., Exclude...>>;
|
||||
return *this ? static_cast<type *>(descriptor->template storage<Index>()) : nullptr;
|
||||
@@ -906,16 +897,16 @@ public:
|
||||
* @param entt A valid identifier.
|
||||
* @return The elements assigned to the entity.
|
||||
*/
|
||||
template<std::size_t... Index>
|
||||
template<stl::size_t... Index>
|
||||
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
|
||||
const auto cpools = pools_for(std::index_sequence_for<Owned...>{}, std::index_sequence_for<Get...>{});
|
||||
const auto cpools = pools_for(stl::index_sequence_for<Owned...>{}, stl::index_sequence_for<Get...>{});
|
||||
|
||||
if constexpr(sizeof...(Index) == 0) {
|
||||
return std::apply([entt](auto *...curr) { return std::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
|
||||
return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools);
|
||||
} else if constexpr(sizeof...(Index) == 1) {
|
||||
return (std::get<Index>(cpools)->get(entt), ...);
|
||||
return (stl::get<Index>(cpools)->get(entt), ...);
|
||||
} else {
|
||||
return std::tuple_cat(std::get<Index>(cpools)->get_as_tuple(entt)...);
|
||||
return stl::tuple_cat(stl::get<Index>(cpools)->get_as_tuple(entt)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -944,10 +935,10 @@ public:
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
for(auto args: each()) {
|
||||
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
|
||||
std::apply(func, args);
|
||||
if constexpr(is_applicable_v<Func, decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_group>().get({})))>) {
|
||||
stl::apply(func, args);
|
||||
} else {
|
||||
std::apply([&func](auto, auto &&...less) { func(std::forward<decltype(less)>(less)...); }, args);
|
||||
stl::apply([&func](auto, auto &&...less) { func(stl::forward<decltype(less)>(less)...); }, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -966,7 +957,7 @@ public:
|
||||
* @return An iterable object to use to _visit_ the group.
|
||||
*/
|
||||
[[nodiscard]] iterable each() const noexcept {
|
||||
const auto cpools = pools_for(std::index_sequence_for<Owned...>{}, std::index_sequence_for<Get...>{});
|
||||
const auto cpools = pools_for(stl::index_sequence_for<Owned...>{}, stl::index_sequence_for<Get...>{});
|
||||
return iterable{{begin(), cpools}, {end(), cpools}};
|
||||
}
|
||||
|
||||
@@ -978,7 +969,7 @@ public:
|
||||
* comparison function should be equivalent to one of the following:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* bool(std::tuple<Type &...>, std::tuple<Type &...>);
|
||||
* bool(stl::tuple<Type &...>, stl::tuple<Type &...>);
|
||||
* bool(const Type &, const Type &);
|
||||
* bool(const Entity, const Entity);
|
||||
* @endcode
|
||||
@@ -1006,7 +997,7 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Other, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
|
||||
sort<index_of<Type>, index_of<Other>...>(std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
sort<index_of<Type>, index_of<Other>...>(stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1022,23 +1013,23 @@ public:
|
||||
* @param algo A valid sort function object.
|
||||
* @param args Arguments to forward to the sort function object, if any.
|
||||
*/
|
||||
template<std::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
template<stl::size_t... Index, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
|
||||
const auto cpools = pools_for(std::index_sequence_for<Owned...>{}, std::index_sequence_for<Get...>{});
|
||||
const auto cpools = pools_for(stl::index_sequence_for<Owned...>{}, stl::index_sequence_for<Get...>{});
|
||||
|
||||
if constexpr(sizeof...(Index) == 0) {
|
||||
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
|
||||
storage<0>()->sort_n(descriptor->length(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
static_assert(stl::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
|
||||
storage<0>()->sort_n(descriptor->length(), stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
|
||||
} else {
|
||||
auto comp = [&compare, &cpools](const entity_type lhs, const entity_type rhs) {
|
||||
if constexpr(sizeof...(Index) == 1) {
|
||||
return compare((std::get<Index>(cpools)->get(lhs), ...), (std::get<Index>(cpools)->get(rhs), ...));
|
||||
return compare((stl::get<Index>(cpools)->get(lhs), ...), (stl::get<Index>(cpools)->get(rhs), ...));
|
||||
} else {
|
||||
return compare(std::forward_as_tuple(std::get<Index>(cpools)->get(lhs)...), std::forward_as_tuple(std::get<Index>(cpools)->get(rhs)...));
|
||||
return compare(stl::forward_as_tuple(stl::get<Index>(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get<Index>(cpools)->get(rhs)...));
|
||||
}
|
||||
};
|
||||
|
||||
storage<0>()->sort_n(descriptor->length(), std::move(comp), std::move(algo), std::forward<Args>(args)...);
|
||||
storage<0>()->sort_n(descriptor->length(), stl::move(comp), stl::move(algo), stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
auto cb = [this](auto *head, auto *...other) {
|
||||
@@ -1049,7 +1040,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
std::apply(cb, cpools);
|
||||
stl::apply(cb, cpools);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
#ifndef ENTT_ENTITY_HANDLE_HPP
|
||||
#define ENTT_ENTITY_HANDLE_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
class handle_storage_iterator final {
|
||||
template<typename Other>
|
||||
template<typename>
|
||||
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;
|
||||
using underlying_type = stl::remove_reference_t<typename It::value_type::second_type>;
|
||||
using entity_type = underlying_type::entity_type;
|
||||
|
||||
public:
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
using value_type = stl::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;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::forward_iterator_tag;
|
||||
|
||||
constexpr handle_storage_iterator() noexcept
|
||||
: entt{null},
|
||||
@@ -64,8 +64,10 @@ public:
|
||||
return operator*();
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend constexpr bool operator==(const handle_storage_iterator<ILhs> &, const handle_storage_iterator<IRhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr bool operator==(const handle_storage_iterator<Other> &other) const noexcept {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
private:
|
||||
entity_type entt;
|
||||
@@ -73,16 +75,6 @@ private:
|
||||
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
|
||||
/*! @endcond */
|
||||
|
||||
@@ -107,13 +99,13 @@ public:
|
||||
/*! @brief Type of registry accepted by the handle. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename traits_type::value_type;
|
||||
using entity_type = traits_type::value_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename traits_type::version_type;
|
||||
using version_type = traits_type::version_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Iterable handle type. */
|
||||
using iterable = iterable_adaptor<internal::handle_storage_iterator<typename decltype(std::declval<registry_type>().storage())::iterator>>;
|
||||
using iterable = iterable_adaptor<internal::handle_storage_iterator<typename decltype(stl::declval<registry_type>().storage())::iterator>>;
|
||||
|
||||
/*! @brief Constructs an invalid handle. */
|
||||
basic_handle() noexcept
|
||||
@@ -181,7 +173,7 @@ public:
|
||||
|
||||
/*! @brief Destroys the entity associated with a handle. */
|
||||
void destroy() {
|
||||
owner_or_assert().destroy(std::exchange(entt, null));
|
||||
owner_or_assert().destroy(stl::exchange(entt, null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,7 +181,7 @@ public:
|
||||
* @param version A desired version upon destruction.
|
||||
*/
|
||||
void destroy(const version_type version) {
|
||||
owner_or_assert().destroy(std::exchange(entt, null), version);
|
||||
owner_or_assert().destroy(stl::exchange(entt, null), version);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,8 +194,8 @@ public:
|
||||
template<typename Type, typename... Args>
|
||||
// NOLINTNEXTLINE(modernize-use-nodiscard)
|
||||
decltype(auto) emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template emplace<Type>(entt, std::forward<Args>(args)...);
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template emplace<Type>(entt, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,8 +207,8 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
decltype(auto) emplace_or_replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template emplace_or_replace<Type>(entt, std::forward<Args>(args)...);
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template emplace_or_replace<Type>(entt, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,8 +220,8 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Func>
|
||||
decltype(auto) patch(Func &&...func) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template patch<Type>(entt, std::forward<Func>(func)...);
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template patch<Type>(entt, stl::forward<Func>(func)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -241,8 +233,8 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
decltype(auto) replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template replace<Type>(entt, std::forward<Args>(args)...);
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template replace<Type>(entt, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,8 +300,8 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
[[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template get_or_emplace<Type>(entt, std::forward<Args>(args)...);
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v<Type, Scope>), "Invalid type");
|
||||
return owner_or_assert().template get_or_emplace<Type>(entt, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -331,6 +323,27 @@ public:
|
||||
return owner_or_assert().orphan(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two handles.
|
||||
* @tparam Other Scope of the other handle.
|
||||
* @param other A valid handle.
|
||||
* @return True if both handles refer to the same registry and the same
|
||||
* entity, false otherwise.
|
||||
*/
|
||||
template<typename... Other>
|
||||
[[nodiscard]] bool operator==(const basic_handle<Other...> &other) const noexcept {
|
||||
return owner == other.registry() && entt == other.entity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a handle with the null object.
|
||||
* @param other A null object yet to be converted.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==(const null_t other) const noexcept {
|
||||
return (entt == other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a const handle from a non-const one.
|
||||
* @tparam Other A valid entity type.
|
||||
@@ -340,7 +353,7 @@ public:
|
||||
*/
|
||||
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(stl::is_same_v<Other, Registry> || stl::is_same_v<stl::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 owner ? basic_handle<Other, Args...>{*owner, entt} : basic_handle<Other, Args...>{};
|
||||
}
|
||||
@@ -350,82 +363,6 @@ private:
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a handle with the null object.
|
||||
* @tparam Args Scope of the handle.
|
||||
* @param lhs A valid handle.
|
||||
* @param rhs A null object yet to be converted.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator==(const basic_handle<Args...> &lhs, const null_t rhs) noexcept {
|
||||
return (lhs.entity() == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a handle with the null object.
|
||||
* @tparam Args Scope of the handle.
|
||||
* @param lhs A null object yet to be converted.
|
||||
* @param rhs A valid handle.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator==(const null_t lhs, const basic_handle<Args...> &rhs) noexcept {
|
||||
return (rhs == lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a handle with the null object.
|
||||
* @tparam Args Scope of the handle.
|
||||
* @param lhs A valid handle.
|
||||
* @param rhs A null object yet to be converted.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator!=(const basic_handle<Args...> &lhs, const null_t rhs) noexcept {
|
||||
return (lhs.entity() != rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a handle with the null object.
|
||||
* @tparam Args Scope of the handle.
|
||||
* @param lhs A null object yet to be converted.
|
||||
* @param rhs A valid handle.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator!=(const null_t lhs, const basic_handle<Args...> &rhs) noexcept {
|
||||
return (rhs != lhs);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#ifndef ENTT_ENTITY_HELPER_HPP
|
||||
#define ENTT_ENTITY_HELPER_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "component.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "group.hpp"
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
/*! @brief Type of registry to convert. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
using entity_type = registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs a converter for a given registry.
|
||||
@@ -61,7 +61,7 @@ template<typename Registry>
|
||||
class as_group {
|
||||
template<typename... Owned, typename... Get, typename... Exclude>
|
||||
[[nodiscard]] auto dispatch(owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>) const {
|
||||
if constexpr(std::is_const_v<registry_type>) {
|
||||
if constexpr(stl::is_const_v<registry_type>) {
|
||||
return reg->template group_if_exists<typename Owned::element_type...>(get_t<typename Get::element_type...>{}, exclude_t<typename Exclude::element_type...>{});
|
||||
} else {
|
||||
return reg->template group<constness_as_t<typename Owned::element_type, Owned>...>(get_t<constness_as_t<typename Get::element_type, Get>...>{}, exclude_t<constness_as_t<typename Exclude::element_type, Exclude>...>{});
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
/*! @brief Type of registry to convert. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
using entity_type = registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs a converter for a given registry.
|
||||
@@ -104,9 +104,9 @@ private:
|
||||
* @param reg A registry that contains the given entity and its elements.
|
||||
* @param entt Entity from which to get the element.
|
||||
*/
|
||||
template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, decltype(Member)>>>
|
||||
template<auto Member, typename Registry = stl::decay_t<nth_argument_t<0u, decltype(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");
|
||||
static_assert(stl::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
|
||||
(reg.template get<member_class_t<decltype(Member)>>(entt).*Member)(reg, entt);
|
||||
}
|
||||
|
||||
@@ -123,15 +123,15 @@ void invoke(Registry ®, const typename Registry::entity_type entt) {
|
||||
* @return The entity associated with the given element.
|
||||
*/
|
||||
template<typename... Args>
|
||||
typename basic_storage<Args...>::entity_type to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) {
|
||||
basic_storage<Args...>::entity_type to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) {
|
||||
using traits_type = component_traits<typename basic_storage<Args...>::value_type, typename basic_storage<Args...>::entity_type>;
|
||||
static_assert(traits_type::page_size != 0u, "Unexpected page size");
|
||||
const auto *page = storage.raw();
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
for(std::size_t pos{}, count = storage.size(); pos < count; pos += traits_type::page_size, ++page) {
|
||||
if(const auto dist = (std::addressof(instance) - *page); dist >= 0 && dist < static_cast<decltype(dist)>(traits_type::page_size)) {
|
||||
return *(static_cast<const typename basic_storage<Args...>::base_type &>(storage).rbegin() + static_cast<decltype(dist)>(pos) + dist);
|
||||
for(stl::size_t pos{}, count = storage.size(); pos < count; pos += traits_type::page_size, ++page) {
|
||||
if(const auto dist = (stl::addressof(instance) - *page); dist >= 0 && dist < static_cast<decltype(dist)>(traits_type::page_size)) {
|
||||
return *(static_cast<const basic_storage<Args...>::base_type &>(storage).rbegin() + static_cast<decltype(dist)>(pos) + dist);
|
||||
}
|
||||
}
|
||||
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
@@ -210,7 +210,7 @@ struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
|
||||
*/
|
||||
template<auto Candidate, typename... Args>
|
||||
auto on_construct(Args &&...args) {
|
||||
this->registry().template on_construct<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
|
||||
this->registry().template on_construct<Type>(name).template connect<Candidate>(stl::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -223,7 +223,7 @@ struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
|
||||
*/
|
||||
template<auto Candidate, typename... Args>
|
||||
auto on_update(Args &&...args) {
|
||||
this->registry().template on_update<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
|
||||
this->registry().template on_update<Type>(name).template connect<Candidate>(stl::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
|
||||
*/
|
||||
template<auto Candidate, typename... Args>
|
||||
auto on_destroy(Args &&...args) {
|
||||
this->registry().template on_destroy<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
|
||||
this->registry().template on_destroy<Type>(name).template connect<Candidate>(stl::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,43 @@
|
||||
#ifndef ENTT_ENTITY_MIXIN_HPP
|
||||
#define ENTT_ENTITY_MIXIN_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/any.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../signal/sigh.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename, typename = void>
|
||||
struct has_on_construct final: std::false_type {};
|
||||
template<typename, typename>
|
||||
struct has_on_construct final: stl::false_type {};
|
||||
|
||||
template<typename Type, typename Registry>
|
||||
struct has_on_construct<Type, Registry, std::void_t<decltype(Type::on_construct(std::declval<Registry &>(), std::declval<Registry>().create()))>>
|
||||
: std::true_type {};
|
||||
requires stl::invocable<decltype(&Type::on_construct), Registry &, typename Registry::entity_type>
|
||||
struct has_on_construct<Type, Registry>: stl::true_type {};
|
||||
|
||||
template<typename, typename, typename = void>
|
||||
struct has_on_update final: std::false_type {};
|
||||
template<typename, typename>
|
||||
struct has_on_update final: stl::false_type {};
|
||||
|
||||
template<typename Type, typename Registry>
|
||||
struct has_on_update<Type, Registry, std::void_t<decltype(Type::on_update(std::declval<Registry &>(), std::declval<Registry>().create()))>>
|
||||
: std::true_type {};
|
||||
requires stl::invocable<decltype(&Type::on_update), Registry &, typename Registry::entity_type>
|
||||
struct has_on_update<Type, Registry>: stl::true_type {};
|
||||
|
||||
template<typename, typename, typename = void>
|
||||
struct has_on_destroy final: std::false_type {};
|
||||
template<typename, typename>
|
||||
struct has_on_destroy final: stl::false_type {};
|
||||
|
||||
template<typename Type, typename Registry>
|
||||
struct has_on_destroy<Type, Registry, std::void_t<decltype(Type::on_destroy(std::declval<Registry &>(), std::declval<Registry>().create()))>>
|
||||
: std::true_type {};
|
||||
requires stl::invocable<decltype(&Type::on_destroy), Registry &, typename Registry::entity_type>
|
||||
struct has_on_destroy<Type, Registry>: stl::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
@@ -60,9 +63,9 @@ class basic_sigh_mixin final: public Type {
|
||||
|
||||
using basic_registry_type = basic_registry<typename owner_type::entity_type, typename owner_type::allocator_type>;
|
||||
using sigh_type = sigh<void(owner_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
|
||||
using underlying_iterator = typename underlying_type::base_type::basic_iterator;
|
||||
using underlying_iterator = underlying_type::base_type::basic_iterator;
|
||||
|
||||
static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
|
||||
static_assert(stl::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
|
||||
|
||||
[[nodiscard]] auto &owner_or_assert() const noexcept {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
@@ -85,12 +88,12 @@ private:
|
||||
|
||||
void pop_all() final {
|
||||
if(auto ® = owner_or_assert(); !destruction.empty()) {
|
||||
if constexpr(std::is_same_v<typename underlying_type::element_type, entity_type>) {
|
||||
if constexpr(stl::is_same_v<typename underlying_type::element_type, entity_type>) {
|
||||
for(typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) {
|
||||
destruction.publish(reg, underlying_type::base_type::operator[](pos));
|
||||
}
|
||||
} else {
|
||||
for(auto entt: static_cast<typename underlying_type::base_type &>(*this)) {
|
||||
for(auto entt: static_cast<underlying_type::base_type &>(*this)) {
|
||||
if constexpr(underlying_type::storage_policy == deletion_policy::in_place) {
|
||||
if(entt != tombstone) {
|
||||
destruction.publish(reg, entt);
|
||||
@@ -105,7 +108,7 @@ private:
|
||||
underlying_type::pop_all();
|
||||
}
|
||||
|
||||
underlying_iterator try_emplace(const typename underlying_type::entity_type entt, const bool force_back, const void *value) final {
|
||||
underlying_iterator try_emplace(const underlying_type::entity_type entt, const bool force_back, const void *value) final {
|
||||
const auto it = underlying_type::try_emplace(entt, force_back, value);
|
||||
|
||||
if(auto ® = owner_or_assert(); it != underlying_type::base_type::end()) {
|
||||
@@ -118,20 +121,20 @@ private:
|
||||
void bind_any(any value) noexcept final {
|
||||
owner = any_cast<basic_registry_type>(&value);
|
||||
|
||||
if constexpr(!std::is_same_v<registry_type, basic_registry_type>) {
|
||||
if constexpr(!stl::is_same_v<registry_type, basic_registry_type>) {
|
||||
if(owner == nullptr) {
|
||||
owner = any_cast<registry_type>(&value);
|
||||
}
|
||||
}
|
||||
|
||||
underlying_type::bind_any(std::move(value));
|
||||
underlying_type::bind_any(stl::move(value));
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = typename underlying_type::allocator_type;
|
||||
using allocator_type = underlying_type::allocator_type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename underlying_type::entity_type;
|
||||
using entity_type = underlying_type::entity_type;
|
||||
/*! @brief Expected registry type. */
|
||||
using registry_type = owner_type;
|
||||
|
||||
@@ -150,15 +153,15 @@ public:
|
||||
destruction{allocator},
|
||||
update{allocator} {
|
||||
if constexpr(internal::has_on_construct<typename underlying_type::element_type, Registry>::value) {
|
||||
entt::sink{construction}.template connect<&underlying_type::element_type::on_construct>();
|
||||
sink{construction}.template connect<&underlying_type::element_type::on_construct>();
|
||||
}
|
||||
|
||||
if constexpr(internal::has_on_update<typename underlying_type::element_type, Registry>::value) {
|
||||
entt::sink{update}.template connect<&underlying_type::element_type::on_update>();
|
||||
sink{update}.template connect<&underlying_type::element_type::on_update>();
|
||||
}
|
||||
|
||||
if constexpr(internal::has_on_destroy<typename underlying_type::element_type, Registry>::value) {
|
||||
entt::sink{destruction}.template connect<&underlying_type::element_type::on_destroy>();
|
||||
sink{destruction}.template connect<&underlying_type::element_type::on_destroy>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,28 +172,24 @@ public:
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
// NOLINTBEGIN(bugprone-use-after-move)
|
||||
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
|
||||
: underlying_type{std::move(other)},
|
||||
: underlying_type{static_cast<underlying_type &&>(other)},
|
||||
owner{other.owner},
|
||||
construction{std::move(other.construction)},
|
||||
destruction{std::move(other.destruction)},
|
||||
update{std::move(other.update)} {}
|
||||
// NOLINTEND(bugprone-use-after-move)
|
||||
construction{stl::move(other.construction)},
|
||||
destruction{stl::move(other.destruction)},
|
||||
update{stl::move(other.update)} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
// NOLINTBEGIN(bugprone-use-after-move)
|
||||
basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator)
|
||||
: underlying_type{std::move(other), allocator},
|
||||
: underlying_type{static_cast<underlying_type &&>(other), allocator},
|
||||
owner{other.owner},
|
||||
construction{std::move(other.construction), allocator},
|
||||
destruction{std::move(other.destruction), allocator},
|
||||
update{std::move(other.update), allocator} {}
|
||||
// NOLINTEND(bugprone-use-after-move)
|
||||
construction{stl::move(other.construction), allocator},
|
||||
destruction{stl::move(other.destruction), allocator},
|
||||
update{stl::move(other.update), allocator} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~basic_sigh_mixin() override = default;
|
||||
@@ -216,7 +215,7 @@ public:
|
||||
* @param other Storage to exchange the content with.
|
||||
*/
|
||||
void swap(basic_sigh_mixin &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(owner, other.owner);
|
||||
swap(construction, other.construction);
|
||||
swap(destruction, other.destruction);
|
||||
@@ -313,11 +312,11 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Assigns each element in a range an identifier.
|
||||
* @tparam It Type of mutable forward iterator.
|
||||
* @tparam It Type of output iterator.
|
||||
* @param first An iterator to the first element of the range to generate.
|
||||
* @param last An iterator past the last element of the range to generate.
|
||||
*/
|
||||
template<typename It>
|
||||
template<stl::output_iterator<entity_type> It>
|
||||
void generate(It first, It last) {
|
||||
underlying_type::generate(first, last);
|
||||
|
||||
@@ -337,7 +336,7 @@ public:
|
||||
*/
|
||||
template<typename... Args>
|
||||
decltype(auto) emplace(const entity_type entt, Args &&...args) {
|
||||
underlying_type::emplace(entt, std::forward<Args>(args)...);
|
||||
underlying_type::emplace(entt, stl::forward<Args>(args)...);
|
||||
construction.publish(owner_or_assert(), entt);
|
||||
return this->get(entt);
|
||||
}
|
||||
@@ -351,7 +350,7 @@ public:
|
||||
*/
|
||||
template<typename... Func>
|
||||
decltype(auto) patch(const entity_type entt, Func &&...func) {
|
||||
underlying_type::patch(entt, std::forward<Func>(func)...);
|
||||
underlying_type::patch(entt, stl::forward<Func>(func)...);
|
||||
update.publish(owner_or_assert(), entt);
|
||||
return this->get(entt);
|
||||
}
|
||||
@@ -359,16 +358,15 @@ public:
|
||||
/**
|
||||
* @brief Assigns one or more entities to a storage and constructs their
|
||||
* objects from a given instance.
|
||||
* @tparam It Type of input iterator.
|
||||
* @tparam Args Types of arguments to forward to the underlying storage.
|
||||
* @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 forward to the underlying storage.
|
||||
*/
|
||||
template<typename It, typename... Args>
|
||||
void insert(It first, It last, Args &&...args) {
|
||||
template<typename... Args>
|
||||
void insert(stl::input_iterator auto first, stl::input_iterator auto last, Args &&...args) {
|
||||
auto from = underlying_type::size();
|
||||
underlying_type::insert(first, last, std::forward<Args>(args)...);
|
||||
underlying_type::insert(first, last, stl::forward<Args>(args)...);
|
||||
|
||||
if(auto ® = owner_or_assert(); !construction.empty()) {
|
||||
// fine as long as insert passes force_back true to try_emplace
|
||||
@@ -395,18 +393,18 @@ class basic_reactive_mixin final: public Type {
|
||||
using underlying_type = Type;
|
||||
using owner_type = Registry;
|
||||
|
||||
using alloc_traits = std::allocator_traits<typename underlying_type::allocator_type>;
|
||||
using alloc_traits = stl::allocator_traits<typename underlying_type::allocator_type>;
|
||||
using basic_registry_type = basic_registry<typename owner_type::entity_type, typename owner_type::allocator_type>;
|
||||
using container_type = std::vector<connection, typename alloc_traits::template rebind_alloc<connection>>;
|
||||
using container_type = stl::vector<connection, typename alloc_traits::template rebind_alloc<connection>>;
|
||||
|
||||
static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
|
||||
static_assert(stl::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
|
||||
|
||||
[[nodiscard]] auto &owner_or_assert() const noexcept {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
return static_cast<owner_type &>(*owner);
|
||||
}
|
||||
|
||||
void emplace_element(const Registry &, typename underlying_type::entity_type entity) {
|
||||
void emplace_element(const Registry &, underlying_type::entity_type entity) {
|
||||
if(!underlying_type::contains(entity)) {
|
||||
underlying_type::emplace(entity);
|
||||
}
|
||||
@@ -416,20 +414,20 @@ private:
|
||||
void bind_any(any value) noexcept final {
|
||||
owner = any_cast<basic_registry_type>(&value);
|
||||
|
||||
if constexpr(!std::is_same_v<registry_type, basic_registry_type>) {
|
||||
if constexpr(!stl::is_same_v<registry_type, basic_registry_type>) {
|
||||
if(owner == nullptr) {
|
||||
owner = any_cast<registry_type>(&value);
|
||||
}
|
||||
}
|
||||
|
||||
underlying_type::bind_any(std::move(value));
|
||||
underlying_type::bind_any(stl::move(value));
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = typename underlying_type::allocator_type;
|
||||
using allocator_type = underlying_type::allocator_type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename underlying_type::entity_type;
|
||||
using entity_type = underlying_type::entity_type;
|
||||
/*! @brief Expected registry type. */
|
||||
using registry_type = owner_type;
|
||||
|
||||
@@ -454,26 +452,22 @@ public:
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
// NOLINTBEGIN(bugprone-use-after-move)
|
||||
basic_reactive_mixin(basic_reactive_mixin &&other) noexcept
|
||||
: underlying_type{std::move(other)},
|
||||
: underlying_type{static_cast<underlying_type &&>(other)},
|
||||
owner{other.owner},
|
||||
conn{} {
|
||||
conn{stl::move(other.conn)} {
|
||||
}
|
||||
// NOLINTEND(bugprone-use-after-move)
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
// NOLINTBEGIN(bugprone-use-after-move)
|
||||
basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator)
|
||||
: underlying_type{std::move(other), allocator},
|
||||
: underlying_type{static_cast<underlying_type &&>(other), allocator},
|
||||
owner{other.owner},
|
||||
conn{allocator} {
|
||||
conn{stl::move(other.conn), allocator} {
|
||||
}
|
||||
// NOLINTEND(bugprone-use-after-move)
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~basic_reactive_mixin() override = default;
|
||||
@@ -504,7 +498,7 @@ public:
|
||||
template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
|
||||
basic_reactive_mixin &on_construct(const id_type id = type_hash<Clazz>::value()) {
|
||||
auto curr = owner_or_assert().template storage<Clazz>(id).on_construct().template connect<Candidate>(*this);
|
||||
conn.push_back(std::move(curr));
|
||||
conn.push_back(stl::move(curr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -518,7 +512,7 @@ public:
|
||||
template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
|
||||
basic_reactive_mixin &on_update(const id_type id = type_hash<Clazz>::value()) {
|
||||
auto curr = owner_or_assert().template storage<Clazz>(id).on_update().template connect<Candidate>(*this);
|
||||
conn.push_back(std::move(curr));
|
||||
conn.push_back(stl::move(curr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -532,7 +526,7 @@ public:
|
||||
template<typename Clazz, auto Candidate = &basic_reactive_mixin::emplace_element>
|
||||
basic_reactive_mixin &on_destroy(const id_type id = type_hash<Clazz>::value()) {
|
||||
auto curr = owner_or_assert().template storage<Clazz>(id).on_destroy().template connect<Candidate>(*this);
|
||||
conn.push_back(std::move(curr));
|
||||
conn.push_back(stl::move(curr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -568,7 +562,7 @@ public:
|
||||
view(exclude_t<Exclude...> = exclude_t{}) const {
|
||||
const owner_type &parent = owner_or_assert();
|
||||
basic_view<get_t<const basic_reactive_mixin, typename basic_registry_type::template storage_for_type<const Get>...>, exclude_t<typename basic_registry_type::template storage_for_type<const Exclude>...>> elem{};
|
||||
[&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(parent.template storage<std::remove_const_t<Exclude>>()..., parent.template storage<std::remove_const_t<Get>>()..., this);
|
||||
[&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(parent.template storage<stl::remove_const_t<Exclude>>()..., parent.template storage<stl::remove_const_t<Get>>()..., this);
|
||||
return elem;
|
||||
}
|
||||
|
||||
@@ -576,8 +570,8 @@ public:
|
||||
template<typename... Get, typename... Exclude>
|
||||
[[nodiscard]] basic_view<get_t<const basic_reactive_mixin, typename basic_registry_type::template storage_for_type<Get>...>, exclude_t<typename basic_registry_type::template storage_for_type<Exclude>...>>
|
||||
view(exclude_t<Exclude...> = exclude_t{}) {
|
||||
std::conditional_t<((std::is_const_v<Get> && ...) && (std::is_const_v<Exclude> && ...)), const owner_type, owner_type> &parent = owner_or_assert();
|
||||
return {*this, parent.template storage<std::remove_const_t<Get>>()..., parent.template storage<std::remove_const_t<Exclude>>()...};
|
||||
stl::conditional_t<((stl::is_const_v<Get> && ...) && (stl::is_const_v<Exclude> && ...)), const owner_type, owner_type> &parent = owner_or_assert();
|
||||
return {*this, parent.template storage<stl::remove_const_t<Get>>()..., parent.template storage<stl::remove_const_t<Exclude>>()...};
|
||||
}
|
||||
|
||||
/*! @brief Releases all connections to the underlying registry, if any. */
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
#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 "../stl/cstddef.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "helper.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename>
|
||||
struct is_view: std::false_type {};
|
||||
struct is_view: stl::false_type {};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_view<basic_view<Args...>>: std::true_type {};
|
||||
struct is_view<basic_view<Args...>>: stl::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool is_view_v = is_view<Type>::value;
|
||||
|
||||
template<typename>
|
||||
struct is_group: std::false_type {};
|
||||
struct is_group: stl::false_type {};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_group<basic_group<Args...>>: std::true_type {};
|
||||
struct is_group<basic_group<Args...>>: stl::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool is_group_v = is_group<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>>,
|
||||
using ro = stl::conditional_t<
|
||||
type_list_contains_v<Override, const Type> || (stl::is_const_v<Type> && !type_list_contains_v<Override, stl::remove_const_t<Type>>),
|
||||
type_list<stl::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>),
|
||||
using rw = stl::conditional_t<
|
||||
type_list_contains_v<Override, stl::remove_const_t<Type>> || (!stl::is_const_v<Type> && !type_list_contains_v<Override, const Type>),
|
||||
type_list<Type>,
|
||||
type_list<>>;
|
||||
};
|
||||
@@ -79,27 +79,28 @@ template<typename... Owned, typename... Get, typename... Exclude, typename... Ov
|
||||
struct unpack_type<const basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>>
|
||||
: unpack_type<basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {};
|
||||
|
||||
template<typename, typename>
|
||||
template<typename, 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>...>;
|
||||
template<typename Registry, typename... Args, typename... Req>
|
||||
struct resource_traits<Registry, type_list<Args...>, type_list<Req...>> {
|
||||
using args = type_list<stl::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...>;
|
||||
static constexpr auto sync_point = (stl::is_same_v<Args, Registry> || ...);
|
||||
};
|
||||
|
||||
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 Registry, typename... Req, typename Ret, typename... Args>
|
||||
resource_traits<Registry, type_list<stl::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 Registry, typename... Req, typename Ret, typename Type, typename... Args>
|
||||
resource_traits<Registry, type_list<stl::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 Registry, typename... Req, typename Ret, typename Class, typename... Args>
|
||||
resource_traits<Registry, type_list<stl::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);
|
||||
template<typename Registry, typename... Req, typename Ret, typename Class, typename... Args>
|
||||
resource_traits<Registry, type_list<stl::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
@@ -119,11 +120,11 @@ 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);
|
||||
using dependency_type = stl::size_t(const bool, const type_info **, const stl::size_t);
|
||||
|
||||
struct vertex_data final {
|
||||
std::size_t ro_count{};
|
||||
std::size_t rw_count{};
|
||||
stl::size_t ro_count{};
|
||||
stl::size_t rw_count{};
|
||||
const char *name{};
|
||||
const void *payload{};
|
||||
callback_type *callback{};
|
||||
@@ -134,24 +135,24 @@ class basic_organizer final {
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static decltype(auto) extract(Registry ®) {
|
||||
if constexpr(std::is_same_v<Type, Registry>) {
|
||||
if constexpr(stl::is_same_v<Type, Registry>) {
|
||||
return reg;
|
||||
} else if constexpr(internal::is_view_v<Type>) {
|
||||
return static_cast<Type>(as_view{reg});
|
||||
} else if constexpr(internal::is_group_v<Type>) {
|
||||
return static_cast<Type>(as_group{reg});
|
||||
} else {
|
||||
return reg.ctx().template emplace<std::remove_reference_t<Type>>();
|
||||
return reg.ctx().template emplace<stl::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)...);
|
||||
return stl::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
|
||||
}
|
||||
|
||||
template<typename... Type>
|
||||
[[nodiscard]] static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const std::size_t count) {
|
||||
[[nodiscard]] static stl::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const stl::size_t count) {
|
||||
if constexpr(sizeof...(Type) == 0u) {
|
||||
return {};
|
||||
} else {
|
||||
@@ -159,7 +160,7 @@ class basic_organizer final {
|
||||
const type_info *info[]{&type_id<Type>()...};
|
||||
const auto length = count < sizeof...(Type) ? count : sizeof...(Type);
|
||||
|
||||
for(std::size_t pos{}; pos < length; ++pos) {
|
||||
for(stl::size_t pos{}; pos < length; ++pos) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
buffer[pos] = info[pos];
|
||||
}
|
||||
@@ -169,9 +170,9 @@ class basic_organizer final {
|
||||
}
|
||||
|
||||
template<typename... RO, typename... RW>
|
||||
void track_dependencies(std::size_t index, const bool requires_registry, type_list<RO...>, type_list<RW...>) {
|
||||
void track_dependencies(stl::size_t index, const bool sync_point, 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.set(type_hash<Registry>::value(), sync_point || (sizeof...(RO) + sizeof...(RW) == 0u));
|
||||
(builder.ro(type_hash<RO>::value()), ...);
|
||||
(builder.rw(type_hash<RW>::value()), ...);
|
||||
}
|
||||
@@ -180,9 +181,9 @@ public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
using entity_type = registry_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Raw task function type. */
|
||||
using function_type = callback_type;
|
||||
|
||||
@@ -194,10 +195,10 @@ public:
|
||||
* @param from List of in-edges of the vertex.
|
||||
* @param to List of out-edges of the vertex.
|
||||
*/
|
||||
vertex(vertex_data data, std::vector<std::size_t> from, std::vector<std::size_t> to)
|
||||
: node{std::move(data)},
|
||||
in{std::move(from)},
|
||||
out{std::move(to)} {}
|
||||
vertex(vertex_data data, stl::vector<stl::size_t> from, stl::vector<stl::size_t> to)
|
||||
: node{stl::move(data)},
|
||||
in{stl::move(from)},
|
||||
out{stl::move(to)} {}
|
||||
|
||||
/**
|
||||
* @brief Fills a buffer with the type info objects for the writable
|
||||
@@ -206,7 +207,7 @@ public:
|
||||
* @param length The length of the user-supplied buffer.
|
||||
* @return The number of type info objects written to the buffer.
|
||||
*/
|
||||
[[nodiscard]] size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept {
|
||||
[[nodiscard]] size_type ro_dependency(const type_info **buffer, const stl::size_t length) const noexcept {
|
||||
return node.dependency(false, buffer, length);
|
||||
}
|
||||
|
||||
@@ -217,7 +218,7 @@ public:
|
||||
* @param length The length of the user-supplied buffer.
|
||||
* @return The number of type info objects written to the buffer.
|
||||
*/
|
||||
[[nodiscard]] size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept {
|
||||
[[nodiscard]] size_type rw_dependency(const type_info **buffer, const stl::size_t length) const noexcept {
|
||||
return node.dependency(true, buffer, length);
|
||||
}
|
||||
|
||||
@@ -281,7 +282,7 @@ public:
|
||||
* @brief Returns the list of in-edges of a vertex.
|
||||
* @return The list of in-edges of a vertex.
|
||||
*/
|
||||
[[nodiscard]] const std::vector<std::size_t> &in_edges() const noexcept {
|
||||
[[nodiscard]] const stl::vector<stl::size_t> &in_edges() const noexcept {
|
||||
return in;
|
||||
}
|
||||
|
||||
@@ -289,7 +290,7 @@ public:
|
||||
* @brief Returns the list of out-edges of a vertex.
|
||||
* @return The list of out-edges of a vertex.
|
||||
*/
|
||||
[[nodiscard]] const std::vector<std::size_t> &out_edges() const noexcept {
|
||||
[[nodiscard]] const stl::vector<stl::size_t> &out_edges() const noexcept {
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -304,8 +305,8 @@ public:
|
||||
|
||||
private:
|
||||
vertex_data node;
|
||||
std::vector<std::size_t> in;
|
||||
std::vector<std::size_t> out;
|
||||
stl::vector<stl::size_t> in;
|
||||
stl::vector<stl::size_t> out;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -316,11 +317,10 @@ public:
|
||||
*/
|
||||
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>;
|
||||
using resource_type = decltype(internal::free_function_to_resource_traits<registry_type, Req...>(Candidate));
|
||||
|
||||
callback_type *callback = +[](const void *, registry_type ®) {
|
||||
std::apply(Candidate, to_args(reg, typename resource_type::args{}));
|
||||
stl::apply(Candidate, to_args(reg, typename resource_type::args{}));
|
||||
};
|
||||
|
||||
vertex_data vdata{
|
||||
@@ -329,12 +329,12 @@ public:
|
||||
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); },
|
||||
+[](const bool rw, const type_info **buffer, const stl::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>>()};
|
||||
&type_id<stl::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));
|
||||
track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
vertices.push_back(stl::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,12 +348,11 @@ public:
|
||||
*/
|
||||
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>;
|
||||
using resource_type = decltype(internal::constrained_function_to_resource_traits<registry_type, Req...>(Candidate));
|
||||
|
||||
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{})));
|
||||
stl::apply(Candidate, stl::tuple_cat(stl::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
|
||||
};
|
||||
|
||||
vertex_data vdata{
|
||||
@@ -362,12 +361,12 @@ public:
|
||||
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); },
|
||||
+[](const bool rw, const type_info **buffer, const stl::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>>()};
|
||||
&type_id<stl::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));
|
||||
track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
vertices.push_back(stl::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -380,7 +379,7 @@ public:
|
||||
*/
|
||||
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...>>;
|
||||
using resource_type = internal::resource_traits<registry_type, type_list<>, type_list<Req...>>;
|
||||
track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
|
||||
vertex_data vdata{
|
||||
@@ -389,25 +388,24 @@ public:
|
||||
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); },
|
||||
+[](const bool rw, const type_info **buffer, const stl::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));
|
||||
vertices.push_back(stl::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates a task graph for the current content.
|
||||
* @return The adjacency list of the task graph.
|
||||
*/
|
||||
[[nodiscard]] std::vector<vertex> graph() {
|
||||
std::vector<vertex> adjacency_list{};
|
||||
[[nodiscard]] stl::vector<vertex> graph() const {
|
||||
stl::vector<vertex> adjacency_list{};
|
||||
adjacency_list.reserve(vertices.size());
|
||||
auto adjacency_matrix = builder.graph();
|
||||
|
||||
for(auto curr: adjacency_matrix.vertices()) {
|
||||
std::vector<std::size_t> in{};
|
||||
std::vector<std::size_t> out{};
|
||||
for(auto adjacency_matrix = builder.graph(); auto curr: adjacency_matrix.vertices()) {
|
||||
stl::vector<stl::size_t> in{};
|
||||
stl::vector<stl::size_t> out{};
|
||||
|
||||
for(auto &&edge: adjacency_matrix.in_edges(curr)) {
|
||||
in.push_back(edge.first);
|
||||
@@ -417,7 +415,7 @@ public:
|
||||
out.push_back(edge.second);
|
||||
}
|
||||
|
||||
adjacency_list.emplace_back(vertices[curr], std::move(in), std::move(out));
|
||||
adjacency_list.emplace_back(vertices[curr], stl::move(in), stl::move(out));
|
||||
}
|
||||
|
||||
return adjacency_list;
|
||||
@@ -430,7 +428,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<vertex_data> vertices;
|
||||
stl::vector<vertex_data> vertices;
|
||||
flow builder;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
#ifndef ENTT_ENTITY_RANGES_HPP
|
||||
#define ENTT_ENTITY_RANGES_HPP
|
||||
|
||||
#if __has_include(<version>)
|
||||
# include <version>
|
||||
#
|
||||
# if defined(__cpp_lib_ranges)
|
||||
# include <ranges>
|
||||
# include "fwd.hpp"
|
||||
#include <version>
|
||||
|
||||
#if defined(__cpp_lib_ranges)
|
||||
# include <ranges>
|
||||
# include "fwd.hpp"
|
||||
|
||||
namespace std::ranges {
|
||||
|
||||
template<class... Args>
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<entt::basic_view<Args...>>{true};
|
||||
inline constexpr bool enable_borrowed_range<entt::basic_view<Args...>>{true};
|
||||
|
||||
template<class... Args>
|
||||
inline constexpr bool std::ranges::enable_borrowed_range<entt::basic_group<Args...>>{true};
|
||||
inline constexpr bool enable_borrowed_range<entt::basic_group<Args...>>{true};
|
||||
|
||||
template<class... Args>
|
||||
inline constexpr bool std::ranges::enable_view<entt::basic_view<Args...>>{true};
|
||||
inline constexpr bool enable_view<entt::basic_view<Args...>>{true};
|
||||
|
||||
template<class... Args>
|
||||
inline constexpr bool std::ranges::enable_view<entt::basic_group<Args...>>{true};
|
||||
inline constexpr bool enable_view<entt::basic_group<Args...>>{true};
|
||||
|
||||
} // namespace std::ranges
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
#ifndef ENTT_ENTITY_REGISTRY_HPP
|
||||
#define ENTT_ENTITY_REGISTRY_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <compare>
|
||||
#include "../config/config.h"
|
||||
#include "../container/dense_map.hpp"
|
||||
#include "../core/algorithm.hpp"
|
||||
#include "../core/any.hpp"
|
||||
#include "../core/concepts.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/memory.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "../stl/algorithm.hpp"
|
||||
#include "../stl/array.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "group.hpp"
|
||||
@@ -31,23 +32,23 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
class registry_storage_iterator final {
|
||||
template<typename Other>
|
||||
template<typename>
|
||||
friend class registry_storage_iterator;
|
||||
|
||||
using mapped_type = std::remove_reference_t<decltype(std::declval<It>()->second)>;
|
||||
using mapped_type = stl::remove_reference_t<decltype(stl::declval<It>()->second)>;
|
||||
|
||||
public:
|
||||
using value_type = std::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_type> &>;
|
||||
using value_type = stl::pair<id_type, constness_as_t<typename mapped_type::element_type, mapped_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;
|
||||
using iterator_concept = std::random_access_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::random_access_iterator_tag;
|
||||
|
||||
constexpr registry_storage_iterator() noexcept
|
||||
: it{} {}
|
||||
@@ -55,7 +56,8 @@ public:
|
||||
constexpr registry_storage_iterator(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>>>
|
||||
template<typename Other>
|
||||
requires (!stl::same_as<It, Other> && stl::constructible_from<It, Other>)
|
||||
constexpr registry_storage_iterator(const registry_storage_iterator<Other> &other) noexcept
|
||||
: registry_storage_iterator{other.it} {}
|
||||
|
||||
@@ -107,87 +109,62 @@ public:
|
||||
return operator*();
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const registry_storage_iterator<Other> &other) const noexcept {
|
||||
return it - other.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr bool operator==(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr bool operator==(const registry_storage_iterator<Other> &other) const noexcept {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr bool operator<(const registry_storage_iterator<Lhs> &, const registry_storage_iterator<Rhs> &) noexcept;
|
||||
template<typename Other>
|
||||
[[nodiscard]] constexpr auto operator<=>(const registry_storage_iterator<Other> &other) const noexcept {
|
||||
return it <=> other.it;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
};
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr std::ptrdiff_t operator-(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it - rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator<(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it < rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator>(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator<=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator>=(const registry_storage_iterator<Lhs> &lhs, const registry_storage_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
class registry_context {
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
using allocator_type = typename alloc_traits::template rebind_alloc<std::pair<const id_type, basic_any<0u>>>;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
using allocator_type = alloc_traits::template rebind_alloc<stl::pair<const id_type, basic_any<0u>>>;
|
||||
|
||||
public:
|
||||
explicit registry_context(const allocator_type &allocator)
|
||||
: ctx{allocator} {}
|
||||
|
||||
void clear() noexcept {
|
||||
ctx.clear();
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args>
|
||||
Type &emplace_as(const id_type id, Args &&...args) {
|
||||
return any_cast<Type &>(ctx.try_emplace(id, std::in_place_type<Type>, std::forward<Args>(args)...).first->second);
|
||||
return any_cast<Type &>(ctx.try_emplace(id, stl::in_place_type<Type>, stl::forward<Args>(args)...).first->second);
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args>
|
||||
Type &emplace(Args &&...args) {
|
||||
return emplace_as<Type>(type_id<Type>().hash(), std::forward<Args>(args)...);
|
||||
return emplace_as<Type>(type_id<Type>().hash(), stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
Type &insert_or_assign(const id_type id, Type &&value) {
|
||||
return any_cast<std::remove_cv_t<std::remove_reference_t<Type>> &>(ctx.insert_or_assign(id, std::forward<Type>(value)).first->second);
|
||||
return any_cast<stl::remove_cvref_t<Type> &>(ctx.insert_or_assign(id, stl::forward<Type>(value)).first->second);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
Type &insert_or_assign(Type &&value) {
|
||||
return insert_or_assign(type_id<Type>().hash(), std::forward<Type>(value));
|
||||
return insert_or_assign(type_id<Type>().hash(), stl::forward<Type>(value));
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
bool erase(const id_type id = type_id<Type>().hash()) {
|
||||
const auto it = ctx.find(id);
|
||||
return it != ctx.end() && it->second.type() == type_id<Type>() ? (ctx.erase(it), true) : false;
|
||||
return it != ctx.end() && it->second.info() == type_id<Type>() ? (ctx.erase(it), true) : false;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
@@ -215,11 +192,11 @@ public:
|
||||
template<typename Type>
|
||||
[[nodiscard]] bool contains(const id_type id = type_id<Type>().hash()) const {
|
||||
const auto it = ctx.find(id);
|
||||
return it != ctx.cend() && it->second.type() == type_id<Type>();
|
||||
return it != ctx.cend() && it->second.info() == type_id<Type>();
|
||||
}
|
||||
|
||||
private:
|
||||
dense_map<id_type, basic_any<0u>, identity, std::equal_to<>, allocator_type> ctx;
|
||||
dense_map<id_type, basic_any<0u>, stl::identity, stl::equal_to<>, allocator_type> ctx;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
@@ -233,38 +210,27 @@ private:
|
||||
template<typename Entity, typename Allocator>
|
||||
class basic_registry {
|
||||
using base_type = basic_sparse_set<Entity, Allocator>;
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
|
||||
// std::shared_ptr because of its type erased allocator which is useful here
|
||||
using pool_container_type = dense_map<id_type, std::shared_ptr<base_type>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<base_type>>>>;
|
||||
using group_container_type = dense_map<id_type, std::shared_ptr<internal::group_descriptor>, identity, std::equal_to<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, std::shared_ptr<internal::group_descriptor>>>>;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
|
||||
// stl::shared_ptr because of its type erased allocator which is useful here
|
||||
using pool_container_type = dense_map<id_type, stl::shared_ptr<base_type>, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<stl::pair<const id_type, stl::shared_ptr<base_type>>>>;
|
||||
using group_container_type = dense_map<id_type, stl::shared_ptr<internal::group_descriptor>, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<stl::pair<const id_type, stl::shared_ptr<internal::group_descriptor>>>>;
|
||||
using traits_type = entt_traits<Entity>;
|
||||
|
||||
template<typename Type>
|
||||
template<cvref_unqualified Type>
|
||||
[[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) {
|
||||
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
|
||||
|
||||
if constexpr(std::is_same_v<Type, entity_type>) {
|
||||
if constexpr(stl::is_same_v<Type, entity_type>) {
|
||||
ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
|
||||
return entities;
|
||||
} else {
|
||||
using storage_type = storage_for_type<Type>;
|
||||
|
||||
if(auto it = pools.find(id); it != pools.cend()) {
|
||||
ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
|
||||
ENTT_ASSERT(it->second->info() == type_id<Type>(), "Unexpected type");
|
||||
return static_cast<storage_type &>(*it->second);
|
||||
}
|
||||
|
||||
using alloc_type = typename storage_type::allocator_type;
|
||||
typename pool_container_type::mapped_type cpool{};
|
||||
|
||||
if constexpr(std::is_void_v<Type> && !std::is_constructible_v<alloc_type, allocator_type>) {
|
||||
// std::allocator<void> has no cross constructors (waiting for C++20)
|
||||
cpool = std::allocate_shared<storage_type>(get_allocator(), alloc_type{});
|
||||
} else {
|
||||
cpool = std::allocate_shared<storage_type>(get_allocator(), get_allocator());
|
||||
}
|
||||
|
||||
typename pool_container_type::mapped_type cpool = stl::allocate_shared<storage_type>(get_allocator(), get_allocator());
|
||||
pools.emplace(id, cpool);
|
||||
cpool->bind(*this);
|
||||
|
||||
@@ -272,16 +238,14 @@ class basic_registry {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
template<cvref_unqualified Type>
|
||||
[[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) const {
|
||||
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
|
||||
|
||||
if constexpr(std::is_same_v<Type, entity_type>) {
|
||||
if constexpr(stl::is_same_v<Type, entity_type>) {
|
||||
ENTT_ASSERT(id == type_hash<Type>::value(), "User entity storage not allowed");
|
||||
return &entities;
|
||||
} else {
|
||||
if(const auto it = pools.find(id); it != pools.cend()) {
|
||||
ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
|
||||
ENTT_ASSERT(it->second->info() == type_id<Type>(), "Unexpected type");
|
||||
return static_cast<const storage_for_type<Type> *>(it->second.get());
|
||||
}
|
||||
|
||||
@@ -301,11 +265,11 @@ public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename traits_type::value_type;
|
||||
using entity_type = traits_type::value_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename traits_type::version_type;
|
||||
using version_type = traits_type::version_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = base_type;
|
||||
/*! @brief Context type. */
|
||||
@@ -320,7 +284,7 @@ public:
|
||||
* @tparam Type Storage value type, eventually const.
|
||||
*/
|
||||
template<typename Type>
|
||||
using storage_for_type = typename storage_for<Type, Entity, typename alloc_traits::template rebind_alloc<std::remove_const_t<Type>>>::type;
|
||||
using storage_for_type = storage_for<Type, Entity, typename alloc_traits::template rebind_alloc<stl::remove_const_t<Type>>>::type;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_registry()
|
||||
@@ -355,10 +319,10 @@ public:
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_registry(basic_registry &&other) noexcept
|
||||
: vars{std::move(other.vars)},
|
||||
pools{std::move(other.pools)},
|
||||
groups{std::move(other.groups)},
|
||||
entities{std::move(other.entities)} {
|
||||
: vars{stl::move(other.vars)},
|
||||
pools{stl::move(other.pools)},
|
||||
groups{stl::move(other.groups)},
|
||||
entities{stl::move(other.entities)} {
|
||||
rebind();
|
||||
}
|
||||
|
||||
@@ -386,7 +350,7 @@ public:
|
||||
* @param other Registry to exchange the content with.
|
||||
*/
|
||||
void swap(basic_registry &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
|
||||
swap(vars, other.vars);
|
||||
swap(pools, other.pools);
|
||||
@@ -428,7 +392,7 @@ public:
|
||||
* @return A pointer to the storage if it exists, a null pointer otherwise.
|
||||
*/
|
||||
[[nodiscard]] common_type *storage(const id_type id) {
|
||||
return const_cast<common_type *>(std::as_const(*this).storage(id));
|
||||
return const_cast<common_type *>(stl::as_const(*this).storage(id));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,7 +413,7 @@ public:
|
||||
*/
|
||||
template<typename Type>
|
||||
storage_for_type<Type> &storage(const id_type id = type_hash<Type>::value()) {
|
||||
return assure<std::remove_const_t<Type>>(id);
|
||||
return assure<stl::remove_const_t<Type>>(id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -460,7 +424,7 @@ public:
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] const storage_for_type<Type> *storage(const id_type id = type_hash<Type>::value()) const {
|
||||
return assure<std::remove_const_t<Type>>(id);
|
||||
return assure<stl::remove_const_t<Type>>(id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,13 +482,13 @@ public:
|
||||
*
|
||||
* @sa create
|
||||
*
|
||||
* @tparam It Type of forward iterator.
|
||||
* @tparam It Type of output iterator.
|
||||
* @param first An iterator to the first element of the range to generate.
|
||||
* @param last An iterator past the last element of the range to generate.
|
||||
*/
|
||||
template<typename It>
|
||||
template<stl::output_iterator<entity_type> It>
|
||||
void create(It first, It last) {
|
||||
entities.generate(std::move(first), std::move(last));
|
||||
entities.generate(stl::move(first), stl::move(last));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -539,7 +503,7 @@ public:
|
||||
*/
|
||||
version_type destroy(const entity_type entt) {
|
||||
for(size_type pos = pools.size(); pos != 0u; --pos) {
|
||||
pools.begin()[static_cast<typename pool_container_type::difference_type>(pos - 1u)].second->remove(entt);
|
||||
pools.begin()[static_cast<pool_container_type::difference_type>(pos - 1u)].second->remove(entt);
|
||||
}
|
||||
|
||||
entities.erase(entt);
|
||||
@@ -569,14 +533,12 @@ public:
|
||||
*
|
||||
* @sa destroy
|
||||
*
|
||||
* @tparam It Type of input iterator.
|
||||
* @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.
|
||||
*/
|
||||
template<typename It>
|
||||
void destroy(It first, It last) {
|
||||
void destroy(stl::input_iterator auto first, stl::input_iterator auto last) {
|
||||
const auto to = entities.sort_as(first, last);
|
||||
const auto from = entities.cend() - static_cast<typename common_type::difference_type>(entities.free_list());
|
||||
const auto from = entities.cend() - static_cast<common_type::difference_type>(entities.free_list());
|
||||
|
||||
for(auto &&curr: pools) {
|
||||
curr.second->remove(from, to);
|
||||
@@ -603,7 +565,7 @@ public:
|
||||
template<typename Type, typename... Args>
|
||||
decltype(auto) emplace(const entity_type entt, Args &&...args) {
|
||||
ENTT_ASSERT(valid(entt), "Invalid entity");
|
||||
return assure<Type>().emplace(entt, std::forward<Args>(args)...);
|
||||
return assure<Type>().emplace(entt, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -612,15 +574,14 @@ public:
|
||||
* @sa emplace
|
||||
*
|
||||
* @tparam Type Type of element to create.
|
||||
* @tparam It Type of input iterator.
|
||||
* @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 value An instance of the element to assign.
|
||||
*/
|
||||
template<typename Type, typename It>
|
||||
void insert(It first, It last, const Type &value = {}) {
|
||||
ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
|
||||
assure<Type>().insert(std::move(first), std::move(last), value);
|
||||
template<typename Type>
|
||||
void insert(stl::input_iterator auto first, stl::input_iterator auto last, const Type &value = {}) {
|
||||
ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
|
||||
assure<Type>().insert(stl::move(first), stl::move(last), value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -635,9 +596,10 @@ public:
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @param from An iterator to the first element of the range of elements.
|
||||
*/
|
||||
template<typename Type, typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, Type>>>
|
||||
template<typename Type, typename EIt, typename CIt>
|
||||
requires stl::same_as<typename stl::iterator_traits<CIt>::value_type, Type>
|
||||
void insert(EIt first, EIt last, CIt from) {
|
||||
ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
|
||||
ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity");
|
||||
assure<Type>().insert(first, last, from);
|
||||
}
|
||||
|
||||
@@ -657,7 +619,7 @@ public:
|
||||
decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) {
|
||||
auto &cpool = assure<Type>();
|
||||
ENTT_ASSERT(valid(entt), "Invalid entity");
|
||||
return cpool.contains(entt) ? cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); }) : cpool.emplace(entt, std::forward<Args>(args)...);
|
||||
return cpool.contains(entt) ? cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward<Args>(args)...}), ...); }) : cpool.emplace(entt, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -681,7 +643,7 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Func>
|
||||
decltype(auto) patch(const entity_type entt, Func &&...func) {
|
||||
return assure<Type>().patch(entt, std::forward<Func>(func)...);
|
||||
return assure<Type>().patch(entt, stl::forward<Func>(func)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -701,7 +663,7 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
decltype(auto) replace(const entity_type entt, Args &&...args) {
|
||||
return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{std::forward<Args>(args)...}), ...); });
|
||||
return patch<Type>(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward<Args>(args)...}), ...); });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -728,17 +690,17 @@ public:
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @return The number of elements actually removed.
|
||||
*/
|
||||
template<typename Type, typename... Other, typename It>
|
||||
template<typename Type, typename... Other, stl::input_iterator It>
|
||||
size_type remove(It first, It last) {
|
||||
size_type count{};
|
||||
|
||||
if constexpr(std::is_same_v<It, typename common_type::iterator>) {
|
||||
std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
|
||||
if constexpr(stl::is_same_v<It, typename common_type::iterator>) {
|
||||
stl::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
|
||||
|
||||
for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
|
||||
if constexpr(sizeof...(Other) != 0u) {
|
||||
if((*from)->data() == first.data()) {
|
||||
std::swap((*from), cpools.back());
|
||||
stl::swap((*from), cpools.back());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -746,8 +708,8 @@ public:
|
||||
}
|
||||
|
||||
} else {
|
||||
for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
|
||||
count += std::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
|
||||
for(auto cpools = stl::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
|
||||
count += stl::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,23 +743,23 @@ public:
|
||||
* @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.
|
||||
*/
|
||||
template<typename Type, typename... Other, typename It>
|
||||
template<typename Type, typename... Other, stl::input_iterator It>
|
||||
void erase(It first, It last) {
|
||||
if constexpr(std::is_same_v<It, typename common_type::iterator>) {
|
||||
std::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
|
||||
if constexpr(stl::is_same_v<It, typename common_type::iterator>) {
|
||||
stl::array cpools{static_cast<common_type *>(&assure<Type>()), static_cast<common_type *>(&assure<Other>())...};
|
||||
|
||||
for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) {
|
||||
if constexpr(sizeof...(Other) != 0u) {
|
||||
if((*from)->data() == first.data()) {
|
||||
std::swap(*from, cpools.back());
|
||||
stl::swap(*from, cpools.back());
|
||||
}
|
||||
}
|
||||
|
||||
(*from)->erase(first, last);
|
||||
}
|
||||
} else {
|
||||
for(auto cpools = std::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
|
||||
std::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
|
||||
for(auto cpools = stl::forward_as_tuple(assure<Type>(), assure<Other>()...); first != last; ++first) {
|
||||
stl::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -820,7 +782,7 @@ public:
|
||||
template<typename Func>
|
||||
void erase_if(const entity_type entt, Func func) {
|
||||
for(auto [id, cpool]: storage()) {
|
||||
if(cpool.contains(entt) && func(id, std::as_const(cpool))) {
|
||||
if(cpool.contains(entt) && func(id, stl::as_const(cpool))) {
|
||||
cpool.erase(entt);
|
||||
}
|
||||
}
|
||||
@@ -851,7 +813,7 @@ public:
|
||||
template<typename... Type>
|
||||
[[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
|
||||
if constexpr(sizeof...(Type) == 1u) {
|
||||
auto *cpool = assure<std::remove_const_t<Type>...>();
|
||||
auto *cpool = assure<stl::remove_const_t<Type>...>();
|
||||
return cpool && cpool->contains(entt);
|
||||
} else {
|
||||
return (all_of<Type>(entt) && ...);
|
||||
@@ -884,9 +846,9 @@ public:
|
||||
template<typename... Type>
|
||||
[[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const {
|
||||
if constexpr(sizeof...(Type) == 1u) {
|
||||
return (assure<std::remove_const_t<Type>>()->get(entt), ...);
|
||||
return (assure<stl::remove_const_t<Type>>()->get(entt), ...);
|
||||
} else {
|
||||
return std::forward_as_tuple(get<Type>(entt)...);
|
||||
return stl::forward_as_tuple(get<Type>(entt)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -894,9 +856,9 @@ public:
|
||||
template<typename... Type>
|
||||
[[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) {
|
||||
if constexpr(sizeof...(Type) == 1u) {
|
||||
return (static_cast<storage_for_type<Type> &>(assure<std::remove_const_t<Type>>()).get(entt), ...);
|
||||
return (static_cast<storage_for_type<Type> &>(assure<stl::remove_const_t<Type>>()).get(entt), ...);
|
||||
} else {
|
||||
return std::forward_as_tuple(get<Type>(entt)...);
|
||||
return stl::forward_as_tuple(get<Type>(entt)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -919,7 +881,7 @@ public:
|
||||
[[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) {
|
||||
auto &cpool = assure<Type>();
|
||||
ENTT_ASSERT(valid(entt), "Invalid entity");
|
||||
return cpool.contains(entt) ? cpool.get(entt) : cpool.emplace(entt, std::forward<Args>(args)...);
|
||||
return cpool.contains(entt) ? cpool.get(entt) : cpool.emplace(entt, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -935,10 +897,10 @@ public:
|
||||
template<typename... Type>
|
||||
[[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const {
|
||||
if constexpr(sizeof...(Type) == 1u) {
|
||||
const auto *cpool = assure<std::remove_const_t<Type>...>();
|
||||
return (cpool && cpool->contains(entt)) ? std::addressof(cpool->get(entt)) : nullptr;
|
||||
const auto *cpool = assure<stl::remove_const_t<Type>...>();
|
||||
return (cpool && cpool->contains(entt)) ? stl::addressof(cpool->get(entt)) : nullptr;
|
||||
} else {
|
||||
return std::make_tuple(try_get<Type>(entt)...);
|
||||
return stl::make_tuple(try_get<Type>(entt)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -946,9 +908,9 @@ public:
|
||||
template<typename... Type>
|
||||
[[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
|
||||
if constexpr(sizeof...(Type) == 1u) {
|
||||
return (const_cast<Type *>(std::as_const(*this).template try_get<Type>(entt)), ...);
|
||||
return (const_cast<Type *>(stl::as_const(*this).template try_get<Type>(entt)), ...);
|
||||
} else {
|
||||
return std::make_tuple(try_get<Type>(entt)...);
|
||||
return stl::make_tuple(try_get<Type>(entt)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -960,7 +922,7 @@ public:
|
||||
void clear() {
|
||||
if constexpr(sizeof...(Type) == 0u) {
|
||||
for(size_type pos = pools.size(); pos; --pos) {
|
||||
pools.begin()[static_cast<typename pool_container_type::difference_type>(pos - 1u)].second->clear();
|
||||
pools.begin()[static_cast<pool_container_type::difference_type>(pos - 1u)].second->clear();
|
||||
}
|
||||
|
||||
const auto elem = entities.each();
|
||||
@@ -976,7 +938,7 @@ public:
|
||||
* @return True if the entity has no elements assigned, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool orphan(const entity_type entt) const {
|
||||
return std::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
|
||||
return stl::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1062,7 +1024,7 @@ public:
|
||||
[[nodiscard]] basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>>
|
||||
view(exclude_t<Exclude...> = exclude_t{}) const {
|
||||
basic_view<get_t<storage_for_type<const Type>, storage_for_type<const Other>...>, exclude_t<storage_for_type<const Exclude>...>> elem{};
|
||||
[&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(assure<std::remove_const_t<Exclude>>()..., assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Type>>());
|
||||
[&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(assure<stl::remove_const_t<Exclude>>()..., assure<stl::remove_const_t<Other>>()..., assure<stl::remove_const_t<Type>>());
|
||||
return elem;
|
||||
}
|
||||
|
||||
@@ -1070,7 +1032,7 @@ public:
|
||||
template<typename Type, typename... Other, typename... Exclude>
|
||||
[[nodiscard]] basic_view<get_t<storage_for_type<Type>, storage_for_type<Other>...>, exclude_t<storage_for_type<Exclude>...>>
|
||||
view(exclude_t<Exclude...> = exclude_t{}) {
|
||||
return {assure<std::remove_const_t<Type>>(), assure<std::remove_const_t<Other>>()..., assure<std::remove_const_t<Exclude>>()...};
|
||||
return {assure<stl::remove_const_t<Type>>(), assure<stl::remove_const_t<Other>>()..., assure<stl::remove_const_t<Exclude>>()...};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1084,19 +1046,19 @@ public:
|
||||
basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>
|
||||
group(get_t<Get...> = get_t{}, exclude_t<Exclude...> = exclude_t{}) {
|
||||
using group_type = basic_group<owned_t<storage_for_type<Owned>...>, get_t<storage_for_type<Get>...>, exclude_t<storage_for_type<Exclude>...>>;
|
||||
using handler_type = typename group_type::handler;
|
||||
using handler_type = group_type::handler;
|
||||
|
||||
if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
|
||||
return {*std::static_pointer_cast<handler_type>(it->second)};
|
||||
return {*stl::static_pointer_cast<handler_type>(it->second)};
|
||||
}
|
||||
|
||||
std::shared_ptr<handler_type> handler{};
|
||||
stl::shared_ptr<handler_type> handler{};
|
||||
|
||||
if constexpr(sizeof...(Owned) == 0u) {
|
||||
handler = std::allocate_shared<handler_type>(get_allocator(), get_allocator(), std::forward_as_tuple(assure<std::remove_const_t<Get>>()...), std::forward_as_tuple(assure<std::remove_const_t<Exclude>>()...));
|
||||
handler = stl::allocate_shared<handler_type>(get_allocator(), get_allocator(), stl::forward_as_tuple(assure<stl::remove_const_t<Get>>()...), stl::forward_as_tuple(assure<stl::remove_const_t<Exclude>>()...));
|
||||
} else {
|
||||
handler = std::allocate_shared<handler_type>(get_allocator(), std::forward_as_tuple(assure<std::remove_const_t<Owned>>()..., assure<std::remove_const_t<Get>>()...), std::forward_as_tuple(assure<std::remove_const_t<Exclude>>()...));
|
||||
ENTT_ASSERT(std::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id<Owned>().hash()) || ...); }), "Conflicting groups");
|
||||
handler = stl::allocate_shared<handler_type>(get_allocator(), stl::forward_as_tuple(assure<stl::remove_const_t<Owned>>()..., assure<stl::remove_const_t<Get>>()...), stl::forward_as_tuple(assure<stl::remove_const_t<Exclude>>()...));
|
||||
ENTT_ASSERT(stl::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id<Owned>().hash()) || ...); }), "Conflicting groups");
|
||||
}
|
||||
|
||||
groups.emplace(group_type::group_id(), handler);
|
||||
@@ -1108,10 +1070,10 @@ public:
|
||||
[[nodiscard]] basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>
|
||||
group_if_exists(get_t<Get...> = get_t{}, exclude_t<Exclude...> = exclude_t{}) const {
|
||||
using group_type = basic_group<owned_t<storage_for_type<const Owned>...>, get_t<storage_for_type<const Get>...>, exclude_t<storage_for_type<const Exclude>...>>;
|
||||
using handler_type = typename group_type::handler;
|
||||
using handler_type = group_type::handler;
|
||||
|
||||
if(auto it = groups.find(group_type::group_id()); it != groups.cend()) {
|
||||
return {*std::static_pointer_cast<handler_type>(it->second)};
|
||||
return {*stl::static_pointer_cast<handler_type>(it->second)};
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -1125,7 +1087,7 @@ public:
|
||||
*/
|
||||
template<typename... Type>
|
||||
[[nodiscard]] bool owned() const {
|
||||
return std::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id<Type>().hash()) || ...); });
|
||||
return stl::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id<Type>().hash()) || ...); });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1166,11 +1128,11 @@ public:
|
||||
ENTT_ASSERT(!owned<Type>(), "Cannot sort owned storage");
|
||||
auto &cpool = assure<Type>();
|
||||
|
||||
if constexpr(std::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
|
||||
auto comp = [&cpool, compare = std::move(compare)](const auto lhs, const auto rhs) { return compare(std::as_const(cpool.get(lhs)), std::as_const(cpool.get(rhs))); };
|
||||
cpool.sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
|
||||
if constexpr(stl::is_invocable_v<Compare, decltype(cpool.get({})), decltype(cpool.get({}))>) {
|
||||
auto comp = [&cpool, compare = stl::move(compare)](const auto lhs, const auto rhs) { return compare(stl::as_const(cpool.get(lhs)), stl::as_const(cpool.get(rhs))); };
|
||||
cpool.sort(stl::move(comp), stl::move(algo), stl::forward<Args>(args)...);
|
||||
} else {
|
||||
cpool.sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
cpool.sort(stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
|
||||
#define ENTT_ENTITY_RUNTIME_VIEW_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../stl/algorithm.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename Set>
|
||||
class runtime_view_iterator final {
|
||||
using iterator_type = typename Set::iterator;
|
||||
using iterator_traits = std::iterator_traits<iterator_type>;
|
||||
using iterator_type = Set::iterator;
|
||||
using iterator_traits = stl::iterator_traits<iterator_type>;
|
||||
|
||||
[[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); });
|
||||
&& stl::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
|
||||
&& stl::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = typename iterator_traits::value_type;
|
||||
using pointer = typename iterator_traits::pointer;
|
||||
using reference = typename iterator_traits::reference;
|
||||
using difference_type = typename iterator_traits::difference_type;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = iterator_traits::value_type;
|
||||
using pointer = iterator_traits::pointer;
|
||||
using reference = iterator_traits::reference;
|
||||
using difference_type = iterator_traits::difference_type;
|
||||
using iterator_category = stl::bidirectional_iterator_tag;
|
||||
|
||||
constexpr runtime_view_iterator() noexcept
|
||||
: pools{},
|
||||
@@ -38,8 +38,7 @@ public:
|
||||
it{},
|
||||
tombstone_check{} {}
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
runtime_view_iterator(const std::vector<Set *> &cpools, const std::vector<Set *> &ignore, iterator_type curr) noexcept
|
||||
runtime_view_iterator(const stl::vector<Set *> &cpools, iterator_type curr, const stl::vector<Set *> &ignore) noexcept
|
||||
: pools{&cpools},
|
||||
filter{&ignore},
|
||||
it{curr},
|
||||
@@ -83,13 +82,9 @@ public:
|
||||
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;
|
||||
const stl::vector<Set *> *pools;
|
||||
const stl::vector<Set *> *filter;
|
||||
iterator_type it;
|
||||
bool tombstone_check;
|
||||
};
|
||||
@@ -122,17 +117,25 @@ private:
|
||||
*/
|
||||
template<typename Type, typename Allocator>
|
||||
class basic_runtime_view {
|
||||
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>;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type");
|
||||
using container_type = stl::vector<Type *, Allocator>;
|
||||
|
||||
[[nodiscard]] auto offset() const noexcept {
|
||||
ENTT_ASSERT(!pools.empty(), "Invalid view");
|
||||
const auto &leading = *pools.front();
|
||||
return (leading.policy() == deletion_policy::swap_only) ? leading.free_list() : leading.size();
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename Type::entity_type;
|
||||
using entity_type = Type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = Type;
|
||||
/*! @brief Bidirectional iterator type. */
|
||||
@@ -171,8 +174,8 @@ public:
|
||||
* @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} {}
|
||||
: pools{stl::move(other.pools), allocator},
|
||||
filter{stl::move(other.filter), allocator} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~basic_runtime_view() = default;
|
||||
@@ -194,7 +197,7 @@ public:
|
||||
* @param other View to exchange the content with.
|
||||
*/
|
||||
void swap(basic_runtime_view &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(pools, other.pools);
|
||||
swap(filter, other.filter);
|
||||
}
|
||||
@@ -219,10 +222,10 @@ public:
|
||||
* @return This runtime view.
|
||||
*/
|
||||
basic_runtime_view &iterate(common_type &base) {
|
||||
if(pools.empty() || !(base.size() < pools[0u]->size())) {
|
||||
if(pools.empty() || !(base.size() < pools.front()->size())) {
|
||||
pools.push_back(&base);
|
||||
} else {
|
||||
pools.push_back(std::exchange(pools[0u], &base));
|
||||
pools.push_back(stl::exchange(pools.front(), &base));
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -243,7 +246,7 @@ public:
|
||||
* @return Estimated number of entities iterated by the view.
|
||||
*/
|
||||
[[nodiscard]] size_type size_hint() const {
|
||||
return pools.empty() ? size_type{} : pools.front()->size();
|
||||
return pools.empty() ? size_type{} : offset();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,7 +258,7 @@ public:
|
||||
* @return An iterator to the first entity that has the given elements.
|
||||
*/
|
||||
[[nodiscard]] iterator begin() const {
|
||||
return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->begin()};
|
||||
return pools.empty() ? iterator{} : iterator{pools, pools.front()->end() - static_cast<difference_type>(offset()), filter};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,7 +268,7 @@ public:
|
||||
* given elements.
|
||||
*/
|
||||
[[nodiscard]] iterator end() const {
|
||||
return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->end()};
|
||||
return pools.empty() ? iterator{} : iterator{pools, pools.front()->end(), filter};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,8 +286,9 @@ public:
|
||||
*/
|
||||
[[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); });
|
||||
&& stl::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
|
||||
&& stl::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); })
|
||||
&& pools.front()->index(entt) < offset();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
#ifndef ENTT_ENTITY_SNAPSHOT_HPP
|
||||
#define ENTT_ENTITY_SNAPSHOT_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../container/dense_map.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "view.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename Registry>
|
||||
void orphans(Registry ®istry) {
|
||||
auto &storage = registry.template storage<typename Registry::entity_type>();
|
||||
|
||||
for(auto entt: storage) {
|
||||
for(auto &storage = registry.template storage<typename Registry::entity_type>(); auto entt: storage) {
|
||||
if(registry.orphan(entt)) {
|
||||
storage.erase(entt);
|
||||
}
|
||||
@@ -45,14 +43,14 @@ void orphans(Registry ®istry) {
|
||||
*/
|
||||
template<typename Registry>
|
||||
class basic_snapshot {
|
||||
static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
|
||||
static_assert(!stl::is_const_v<Registry>, "Non-const registry type required");
|
||||
using traits_type = entt_traits<typename Registry::entity_type>;
|
||||
|
||||
public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
using entity_type = registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs an instance that is bound to a given registry.
|
||||
@@ -95,10 +93,10 @@ public:
|
||||
if(const auto *storage = reg->template storage<Type>(id); storage) {
|
||||
const typename registry_type::common_type &base = *storage;
|
||||
|
||||
archive(static_cast<typename traits_type::entity_type>(storage->size()));
|
||||
archive(static_cast<traits_type::entity_type>(storage->size()));
|
||||
|
||||
if constexpr(std::is_same_v<Type, entity_type>) {
|
||||
archive(static_cast<typename traits_type::entity_type>(storage->free_list()));
|
||||
if constexpr(stl::is_same_v<Type, entity_type>) {
|
||||
archive(static_cast<traits_type::entity_type>(storage->free_list()));
|
||||
|
||||
for(auto first = base.rbegin(), last = base.rend(); first != last; ++first) {
|
||||
archive(*first);
|
||||
@@ -109,12 +107,12 @@ public:
|
||||
archive(static_cast<entity_type>(null));
|
||||
} else {
|
||||
archive(entt);
|
||||
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
|
||||
stl::apply([&archive](auto &&...args) { (archive(stl::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(auto elem: storage->reach()) {
|
||||
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, elem);
|
||||
stl::apply([&archive](auto &&...args) { (archive(stl::forward<decltype(args)>(args)), ...); }, elem);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -129,24 +127,23 @@ public:
|
||||
* the entities in a range.
|
||||
* @tparam Type Type of elements to serialize.
|
||||
* @tparam Archive Type of output archive.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param archive A valid reference to an output archive.
|
||||
* @param first An iterator to the first element of the range to serialize.
|
||||
* @param last An iterator past the last element of the range to serialize.
|
||||
* @param id Optional name used to map the storage within the registry.
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename Type, typename Archive, typename It>
|
||||
const basic_snapshot &get(Archive &archive, It first, It last, const id_type id = type_hash<Type>::value()) const {
|
||||
static_assert(!std::is_same_v<Type, entity_type>, "Entity types not supported");
|
||||
template<typename Type, typename Archive>
|
||||
const basic_snapshot &get(Archive &archive, stl::input_iterator auto first, stl::input_iterator auto last, const id_type id = type_hash<Type>::value()) const {
|
||||
static_assert(!stl::is_same_v<Type, entity_type>, "Entity types not supported");
|
||||
|
||||
if(const auto *storage = reg->template storage<Type>(id); storage && !storage->empty()) {
|
||||
archive(static_cast<typename traits_type::entity_type>(std::distance(first, last)));
|
||||
archive(static_cast<traits_type::entity_type>(stl::distance(first, last)));
|
||||
|
||||
for(; first != last; ++first) {
|
||||
if(const auto entt = *first; storage->contains(entt)) {
|
||||
archive(entt);
|
||||
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
|
||||
stl::apply([&archive](auto &&...args) { (archive(stl::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
|
||||
} else {
|
||||
archive(static_cast<entity_type>(null));
|
||||
}
|
||||
@@ -174,14 +171,14 @@ private:
|
||||
*/
|
||||
template<typename Registry>
|
||||
class basic_snapshot_loader {
|
||||
static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
|
||||
static_assert(!stl::is_const_v<Registry>, "Non-const registry type required");
|
||||
using traits_type = entt_traits<typename Registry::entity_type>;
|
||||
|
||||
public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
using entity_type = registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs an instance that is bound to a given registry.
|
||||
@@ -229,7 +226,7 @@ public:
|
||||
|
||||
archive(length);
|
||||
|
||||
if constexpr(std::is_same_v<Type, entity_type>) {
|
||||
if constexpr(stl::is_same_v<Type, entity_type>) {
|
||||
typename traits_type::entity_type count{};
|
||||
entity_type placeholder{};
|
||||
|
||||
@@ -253,12 +250,12 @@ public:
|
||||
const auto entity = other.contains(entt) ? entt : other.generate(entt);
|
||||
ENTT_ASSERT(entity == entt, "Entity not available for use");
|
||||
|
||||
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
|
||||
if constexpr(stl::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
|
||||
storage.emplace(entity);
|
||||
} else {
|
||||
Type elem{};
|
||||
archive(elem);
|
||||
storage.emplace(entity, std::move(elem));
|
||||
storage.emplace(entity, stl::move(elem));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,16 +301,16 @@ private:
|
||||
*/
|
||||
template<typename Registry>
|
||||
class basic_continuous_loader {
|
||||
static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
|
||||
static_assert(!stl::is_const_v<Registry>, "Non-const registry type required");
|
||||
using traits_type = entt_traits<typename Registry::entity_type>;
|
||||
|
||||
void restore(typename Registry::entity_type entt) {
|
||||
void restore(Registry::entity_type entt) {
|
||||
if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) {
|
||||
if(!reg->valid(remloc[entity].second)) {
|
||||
remloc[entity].second = reg->create();
|
||||
}
|
||||
} else {
|
||||
remloc.insert_or_assign(entity, std::make_pair(entt, reg->create()));
|
||||
remloc.insert_or_assign(entity, stl::make_pair(entt, reg->create()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,27 +320,27 @@ class basic_continuous_loader {
|
||||
Container other;
|
||||
|
||||
for(auto &&pair: container) {
|
||||
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;
|
||||
using first_type = stl::remove_const_t<typename stl::decay_t<decltype(pair)>::first_type>;
|
||||
using second_type = stl::decay_t<decltype(pair)>::second_type;
|
||||
|
||||
if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
|
||||
if constexpr(stl::is_same_v<first_type, entity_type> && stl::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_type>) {
|
||||
other.emplace(map(pair.first), std::move(pair.second));
|
||||
} else if constexpr(stl::is_same_v<first_type, entity_type>) {
|
||||
other.emplace(map(pair.first), stl::move(pair.second));
|
||||
} else {
|
||||
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));
|
||||
static_assert(stl::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
|
||||
other.emplace(stl::move(pair.first), map(pair.second));
|
||||
}
|
||||
}
|
||||
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(container, other);
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
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_type>, "Invalid value type");
|
||||
static_assert(stl::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
|
||||
|
||||
for(auto &&entt: container) {
|
||||
entt = map(entt);
|
||||
@@ -352,9 +349,9 @@ class basic_continuous_loader {
|
||||
|
||||
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>) {
|
||||
if constexpr(!stl::is_same_v<Component, Other>) {
|
||||
return;
|
||||
} else if constexpr(std::is_same_v<Member, entity_type>) {
|
||||
} else if constexpr(stl::is_same_v<Member, entity_type>) {
|
||||
instance.*member = map(instance.*member);
|
||||
} else {
|
||||
// maybe a container? let's try...
|
||||
@@ -366,7 +363,7 @@ public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
using entity_type = registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs an instance that is bound to a given registry.
|
||||
@@ -419,18 +416,18 @@ public:
|
||||
|
||||
archive(length);
|
||||
|
||||
if constexpr(std::is_same_v<Type, entity_type>) {
|
||||
if constexpr(stl::is_same_v<Type, entity_type>) {
|
||||
typename traits_type::entity_type in_use{};
|
||||
|
||||
storage.reserve(length);
|
||||
archive(in_use);
|
||||
|
||||
for(std::size_t pos{}; pos < in_use; ++pos) {
|
||||
for(stl::size_t pos{}; pos < in_use; ++pos) {
|
||||
archive(entt);
|
||||
restore(entt);
|
||||
}
|
||||
|
||||
for(std::size_t pos = in_use; pos < length; ++pos) {
|
||||
for(stl::size_t pos = in_use; pos < length; ++pos) {
|
||||
archive(entt);
|
||||
|
||||
if(const auto entity = to_entity(entt); remloc.contains(entity)) {
|
||||
@@ -450,12 +447,12 @@ public:
|
||||
if(archive(entt); entt != null) {
|
||||
restore(entt);
|
||||
|
||||
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
|
||||
if constexpr(stl::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
|
||||
storage.emplace(map(entt));
|
||||
} else {
|
||||
Type elem{};
|
||||
archive(elem);
|
||||
storage.emplace(map(entt), std::move(elem));
|
||||
storage.emplace(map(entt), stl::move(elem));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,7 +500,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
dense_map<typename traits_type::entity_type, std::pair<entity_type, entity_type>> remloc;
|
||||
dense_map<typename traits_type::entity_type, stl::pair<entity_type, entity_type>> remloc;
|
||||
registry_type *reg;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,32 +1,34 @@
|
||||
#ifndef ENTT_ENTITY_SPARSE_SET_HPP
|
||||
#define ENTT_ENTITY_SPARSE_SET_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <compare>
|
||||
#include "../config/config.h"
|
||||
#include "../core/algorithm.hpp"
|
||||
#include "../core/any.hpp"
|
||||
#include "../core/bit.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename Container>
|
||||
struct sparse_set_iterator final {
|
||||
using value_type = typename Container::value_type;
|
||||
using pointer = typename Container::const_pointer;
|
||||
using reference = typename Container::const_reference;
|
||||
using difference_type = typename Container::difference_type;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = Container::value_type;
|
||||
using pointer = Container::const_pointer;
|
||||
using reference = Container::const_reference;
|
||||
using difference_type = Container::difference_type;
|
||||
using iterator_category = stl::random_access_iterator_tag;
|
||||
|
||||
constexpr sparse_set_iterator() noexcept
|
||||
: packed{},
|
||||
@@ -73,17 +75,31 @@ struct sparse_set_iterator final {
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
|
||||
return (*packed)[static_cast<typename Container::size_type>(index() - value)];
|
||||
return (*packed)[static_cast<Container::size_type>(index() - value)];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::addressof(operator[](0));
|
||||
return stl::addressof(operator[](0));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return operator[](0);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const sparse_set_iterator &other) const noexcept {
|
||||
// intentionally reversed due to backward iteration
|
||||
return other.offset - offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const sparse_set_iterator &other) const noexcept {
|
||||
return offset == other.offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator<=>(const sparse_set_iterator &other) const noexcept {
|
||||
// intentionally reversed due to backward iteration
|
||||
return other.offset <=> offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer data() const noexcept {
|
||||
return packed ? packed->data() : nullptr;
|
||||
}
|
||||
@@ -97,41 +113,6 @@ private:
|
||||
difference_type offset;
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] constexpr std::ptrdiff_t operator-(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
|
||||
return rhs.index() - lhs.index();
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] constexpr bool operator==(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
|
||||
return lhs.index() == rhs.index();
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] constexpr bool operator!=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] constexpr bool operator<(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
|
||||
return lhs.index() > rhs.index();
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] constexpr bool operator>(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] constexpr bool operator<=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] constexpr bool operator>=(const sparse_set_iterator<Container> &lhs, const sparse_set_iterator<Container> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
@@ -156,24 +137,24 @@ template<typename Container>
|
||||
*/
|
||||
template<typename Entity, typename Allocator>
|
||||
class basic_sparse_set {
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
|
||||
using sparse_container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
|
||||
using packed_container_type = std::vector<Entity, Allocator>;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
|
||||
using sparse_container_type = stl::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
|
||||
using packed_container_type = stl::vector<Entity, Allocator>;
|
||||
using traits_type = entt_traits<Entity>;
|
||||
|
||||
static constexpr auto max_size = static_cast<std::size_t>(traits_type::to_entity(null));
|
||||
static constexpr auto max_size = static_cast<stl::size_t>(traits_type::to_entity(null));
|
||||
|
||||
// it could be auto but gcc complains and emits a warning due to a false positive
|
||||
[[nodiscard]] std::size_t policy_to_head() const noexcept {
|
||||
return static_cast<size_type>(max_size * static_cast<std::remove_const_t<decltype(max_size)>>(mode != deletion_policy::swap_only));
|
||||
[[nodiscard]] stl::size_t policy_to_head() const noexcept {
|
||||
return static_cast<size_type>(max_size * static_cast<stl::remove_const_t<decltype(max_size)>>(mode != deletion_policy::swap_only));
|
||||
}
|
||||
|
||||
[[nodiscard]] auto entity_to_pos(const Entity entt) const noexcept {
|
||||
return static_cast<size_type>(traits_type::to_entity(entt));
|
||||
}
|
||||
|
||||
[[nodiscard]] auto pos_to_page(const std::size_t pos) const noexcept {
|
||||
[[nodiscard]] auto pos_to_page(const stl::size_t pos) const noexcept {
|
||||
return static_cast<size_type>(pos / traits_type::page_size);
|
||||
}
|
||||
|
||||
@@ -205,40 +186,38 @@ class basic_sparse_set {
|
||||
constexpr entity_type init = null;
|
||||
auto page_allocator{packed.get_allocator()};
|
||||
sparse[page] = alloc_traits::allocate(page_allocator, traits_type::page_size);
|
||||
std::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init);
|
||||
stl::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init);
|
||||
}
|
||||
|
||||
return sparse[page][fast_mod(pos, traits_type::page_size)];
|
||||
}
|
||||
|
||||
void release_sparse_pages() {
|
||||
auto page_allocator{packed.get_allocator()};
|
||||
|
||||
for(auto &&page: sparse) {
|
||||
for(auto page_allocator{packed.get_allocator()}; auto &&page: sparse) {
|
||||
if(page != nullptr) {
|
||||
std::destroy(page, page + traits_type::page_size);
|
||||
stl::destroy(page, page + traits_type::page_size);
|
||||
alloc_traits::deallocate(page_allocator, page, traits_type::page_size);
|
||||
page = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void swap_at(const std::size_t lhs, const std::size_t rhs) {
|
||||
void swap_at(const stl::size_t lhs, const stl::size_t rhs) {
|
||||
auto &from = packed[lhs];
|
||||
auto &to = packed[rhs];
|
||||
|
||||
sparse_ref(from) = traits_type::combine(static_cast<typename traits_type::entity_type>(rhs), traits_type::to_integral(from));
|
||||
sparse_ref(to) = traits_type::combine(static_cast<typename traits_type::entity_type>(lhs), traits_type::to_integral(to));
|
||||
sparse_ref(from) = traits_type::combine(static_cast<traits_type::entity_type>(rhs), traits_type::to_integral(from));
|
||||
sparse_ref(to) = traits_type::combine(static_cast<traits_type::entity_type>(lhs), traits_type::to_integral(to));
|
||||
|
||||
std::swap(from, to);
|
||||
stl::swap(from, to);
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] virtual const void *get_at(const std::size_t) const {
|
||||
[[nodiscard]] virtual const void *get_at(const stl::size_t) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void swap_or_move([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {
|
||||
virtual void swap_or_move([[maybe_unused]] const stl::size_t lhs, [[maybe_unused]] const stl::size_t rhs) {
|
||||
ENTT_ASSERT((mode != deletion_policy::swap_only) || ((lhs < head) == (rhs < head)), "Cross swapping is not supported");
|
||||
}
|
||||
|
||||
@@ -248,25 +227,25 @@ protected:
|
||||
|
||||
/**
|
||||
* @brief Erases an entity from a sparse set.
|
||||
* @param it An iterator to the element to pop.
|
||||
* @param entt A valid identifier for the element to pop.
|
||||
*/
|
||||
void swap_only(const basic_iterator it) {
|
||||
void swap_only(const Entity entt) {
|
||||
ENTT_ASSERT(mode == deletion_policy::swap_only, "Deletion policy mismatch");
|
||||
const auto pos = index(*it);
|
||||
bump(traits_type::next(*it));
|
||||
const auto pos = index(entt);
|
||||
bump(traits_type::next(entt));
|
||||
swap_at(pos, head -= (pos < head));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases an entity from a sparse set.
|
||||
* @param it An iterator to the element to pop.
|
||||
* @param entt A valid identifier for the element to pop.
|
||||
*/
|
||||
void swap_and_pop(const basic_iterator it) {
|
||||
void swap_and_pop(const Entity entt) {
|
||||
ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatch");
|
||||
auto &self = sparse_ref(*it);
|
||||
const auto entt = traits_type::to_entity(self);
|
||||
sparse_ref(packed.back()) = traits_type::combine(entt, traits_type::to_integral(packed.back()));
|
||||
packed[static_cast<size_type>(entt)] = packed.back();
|
||||
auto &self = sparse_ref(entt);
|
||||
const auto pos = traits_type::to_entity(self);
|
||||
sparse_ref(packed.back()) = traits_type::combine(pos, traits_type::to_integral(packed.back()));
|
||||
packed[static_cast<size_type>(pos)] = packed.back();
|
||||
// unnecessary but it helps to detect nasty bugs
|
||||
// NOLINTNEXTLINE(bugprone-assert-side-effect)
|
||||
ENTT_ASSERT((packed.back() = null, true), "");
|
||||
@@ -277,12 +256,12 @@ protected:
|
||||
|
||||
/**
|
||||
* @brief Erases an entity from a sparse set.
|
||||
* @param it An iterator to the element to pop.
|
||||
* @param entt A valid identifier for the element to pop.
|
||||
*/
|
||||
void in_place_pop(const basic_iterator it) {
|
||||
void in_place_pop(const Entity entt) {
|
||||
ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatch");
|
||||
const auto pos = entity_to_pos(std::exchange(sparse_ref(*it), null));
|
||||
packed[pos] = traits_type::combine(static_cast<typename traits_type::entity_type>(std::exchange(head, pos)), tombstone);
|
||||
const auto pos = entity_to_pos(stl::exchange(sparse_ref(entt), null));
|
||||
packed[pos] = traits_type::combine(static_cast<traits_type::entity_type>(stl::exchange(head, pos)), tombstone);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,17 +273,17 @@ protected:
|
||||
switch(mode) {
|
||||
case deletion_policy::swap_and_pop:
|
||||
for(; first != last; ++first) {
|
||||
swap_and_pop(first);
|
||||
swap_and_pop(*first);
|
||||
}
|
||||
break;
|
||||
case deletion_policy::in_place:
|
||||
for(; first != last; ++first) {
|
||||
in_place_pop(first);
|
||||
in_place_pop(*first);
|
||||
}
|
||||
break;
|
||||
case deletion_policy::swap_only:
|
||||
for(; first != last; ++first) {
|
||||
swap_only(first);
|
||||
swap_only(*first);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -312,23 +291,15 @@ protected:
|
||||
|
||||
/*! @brief Erases all entities of a sparse set. */
|
||||
virtual void pop_all() {
|
||||
switch(mode) {
|
||||
case deletion_policy::in_place:
|
||||
if(head != max_size) {
|
||||
for(auto &&elem: packed) {
|
||||
if(elem != tombstone) {
|
||||
sparse_ref(elem) = null;
|
||||
if(!packed.empty()) {
|
||||
// suboptimal with few entities, but exploits cache way more with many
|
||||
for(auto &&elem: sparse) {
|
||||
if(elem) {
|
||||
for(size_type pos{}; pos < traits_type::page_size; ++pos) {
|
||||
elem[pos] = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case deletion_policy::swap_only:
|
||||
case deletion_policy::swap_and_pop:
|
||||
for(auto &&elem: packed) {
|
||||
sparse_ref(elem) = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
head = policy_to_head();
|
||||
@@ -351,20 +322,20 @@ protected:
|
||||
if(head != max_size && !force_back) {
|
||||
pos = head;
|
||||
ENTT_ASSERT(elem == null, "Slot not available");
|
||||
elem = traits_type::combine(static_cast<typename traits_type::entity_type>(head), traits_type::to_integral(entt));
|
||||
head = entity_to_pos(std::exchange(packed[pos], entt));
|
||||
elem = traits_type::combine(static_cast<traits_type::entity_type>(head), traits_type::to_integral(entt));
|
||||
head = entity_to_pos(stl::exchange(packed[pos], entt));
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case deletion_policy::swap_and_pop:
|
||||
packed.push_back(entt);
|
||||
ENTT_ASSERT(elem == null, "Slot not available");
|
||||
elem = traits_type::combine(static_cast<typename traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
|
||||
elem = traits_type::combine(static_cast<traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
|
||||
break;
|
||||
case deletion_policy::swap_only:
|
||||
if(elem == null) {
|
||||
packed.push_back(entt);
|
||||
elem = traits_type::combine(static_cast<typename traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
|
||||
elem = traits_type::combine(static_cast<traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
|
||||
} else {
|
||||
ENTT_ASSERT(!(entity_to_pos(elem) < head), "Slot not available");
|
||||
bump(entt);
|
||||
@@ -375,7 +346,7 @@ protected:
|
||||
break;
|
||||
}
|
||||
|
||||
return --(end() - static_cast<difference_type>(pos));
|
||||
return iterator{packed, static_cast<difference_type>(++pos)};
|
||||
}
|
||||
|
||||
/*! @brief Forwards variables to derived classes, if any. */
|
||||
@@ -386,23 +357,23 @@ public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename traits_type::value_type;
|
||||
using entity_type = traits_type::value_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename traits_type::version_type;
|
||||
using version_type = traits_type::version_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Pointer type to contained entities. */
|
||||
using pointer = typename packed_container_type::const_pointer;
|
||||
using pointer = packed_container_type::const_pointer;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = basic_iterator;
|
||||
/*! @brief Constant random access iterator type. */
|
||||
using const_iterator = iterator;
|
||||
/*! @brief Reverse iterator type. */
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using reverse_iterator = stl::reverse_iterator<iterator>;
|
||||
/*! @brief Constant reverse iterator type. */
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using const_reverse_iterator = stl::reverse_iterator<const_iterator>;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_sparse_set()
|
||||
@@ -433,7 +404,7 @@ public:
|
||||
explicit basic_sparse_set(const type_info &elem, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {})
|
||||
: sparse{allocator},
|
||||
packed{allocator},
|
||||
info{&elem},
|
||||
descriptor{&elem},
|
||||
mode{pol},
|
||||
head{policy_to_head()} {
|
||||
ENTT_ASSERT(traits_type::version_mask || mode != deletion_policy::in_place, "Policy does not support zero-sized versions");
|
||||
@@ -447,11 +418,11 @@ public:
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_sparse_set(basic_sparse_set &&other) noexcept
|
||||
: sparse{std::move(other.sparse)},
|
||||
packed{std::move(other.packed)},
|
||||
info{other.info},
|
||||
: sparse{stl::move(other.sparse)},
|
||||
packed{stl::move(other.packed)},
|
||||
descriptor{other.descriptor},
|
||||
mode{other.mode},
|
||||
head{std::exchange(other.head, policy_to_head())} {}
|
||||
head{stl::exchange(other.head, policy_to_head())} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
@@ -459,11 +430,11 @@ public:
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator)
|
||||
: sparse{std::move(other.sparse), allocator},
|
||||
packed{std::move(other.packed), allocator},
|
||||
info{other.info},
|
||||
: sparse{stl::move(other.sparse), allocator},
|
||||
packed{stl::move(other.packed), allocator},
|
||||
descriptor{other.descriptor},
|
||||
mode{other.mode},
|
||||
head{std::exchange(other.head, policy_to_head())} {
|
||||
head{stl::exchange(other.head, policy_to_head())} {
|
||||
ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed");
|
||||
}
|
||||
|
||||
@@ -494,10 +465,10 @@ public:
|
||||
* @param other Sparse set to exchange the content with.
|
||||
*/
|
||||
void swap(basic_sparse_set &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(sparse, other.sparse);
|
||||
swap(packed, other.packed);
|
||||
swap(info, other.info);
|
||||
swap(descriptor, other.descriptor);
|
||||
swap(mode, other.mode);
|
||||
swap(head, other.head);
|
||||
}
|
||||
@@ -560,18 +531,16 @@ public:
|
||||
virtual void shrink_to_fit() {
|
||||
sparse_container_type other{sparse.get_allocator()};
|
||||
const auto len = sparse.size();
|
||||
size_type cnt{};
|
||||
|
||||
other.reserve(len);
|
||||
|
||||
for(auto &&elem: std::as_const(packed)) {
|
||||
for(size_type cnt{}; auto &&elem: stl::as_const(packed)) {
|
||||
if(elem != tombstone) {
|
||||
if(const auto page = pos_to_page(entity_to_pos(elem)); sparse[page] != nullptr) {
|
||||
if(const auto sz = page + 1u; sz > other.size()) {
|
||||
other.resize(sz, nullptr);
|
||||
}
|
||||
|
||||
other[page] = std::exchange(sparse[page], nullptr);
|
||||
other[page] = stl::exchange(sparse[page], nullptr);
|
||||
|
||||
if(++cnt == len) {
|
||||
// early exit due to lack of pages
|
||||
@@ -681,7 +650,7 @@ public:
|
||||
* array.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rbegin() const noexcept {
|
||||
return std::make_reverse_iterator(end());
|
||||
return stl::make_reverse_iterator(end());
|
||||
}
|
||||
|
||||
/*! @copydoc rbegin */
|
||||
@@ -695,7 +664,7 @@ public:
|
||||
* reversed sparse set.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rend() const noexcept {
|
||||
return std::make_reverse_iterator(begin());
|
||||
return stl::make_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
/*! @copydoc rend */
|
||||
@@ -779,7 +748,7 @@ public:
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] void *value(const entity_type entt) noexcept {
|
||||
return const_cast<void *>(std::as_const(*this).value(entt));
|
||||
return const_cast<void *>(stl::as_const(*this).value(entt));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -805,14 +774,12 @@ public:
|
||||
* Attempting to assign an entity that already belongs to the sparse set
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @tparam It Type of input iterator.
|
||||
* @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.
|
||||
* @return Iterator pointing to the first element inserted in case of
|
||||
* success, the `end()` iterator otherwise.
|
||||
*/
|
||||
template<typename It>
|
||||
iterator push(It first, It last) {
|
||||
iterator push(stl::input_iterator auto first, stl::input_iterator auto last) {
|
||||
auto curr = end();
|
||||
|
||||
for(; first != last; ++first) {
|
||||
@@ -863,9 +830,9 @@ public:
|
||||
* @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.
|
||||
*/
|
||||
template<typename It>
|
||||
template<stl::input_iterator It>
|
||||
void erase(It first, It last) {
|
||||
if constexpr(std::is_same_v<It, basic_iterator>) {
|
||||
if constexpr(stl::is_same_v<It, basic_iterator>) {
|
||||
pop(first, last);
|
||||
} else {
|
||||
for(; first != last; ++first) {
|
||||
@@ -890,11 +857,11 @@ public:
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @return The number of entities actually removed.
|
||||
*/
|
||||
template<typename It>
|
||||
template<stl::input_iterator It>
|
||||
size_type remove(It first, It last) {
|
||||
size_type count{};
|
||||
|
||||
if constexpr(std::is_same_v<It, basic_iterator>) {
|
||||
if constexpr(stl::is_same_v<It, basic_iterator>) {
|
||||
while(first != last) {
|
||||
while(first != last && !contains(*first)) {
|
||||
++first;
|
||||
@@ -906,7 +873,7 @@ public:
|
||||
++first;
|
||||
}
|
||||
|
||||
count += static_cast<size_type>(std::distance(it, first));
|
||||
count += static_cast<size_type>(stl::distance(it, first));
|
||||
erase(it, first);
|
||||
}
|
||||
} else {
|
||||
@@ -922,17 +889,17 @@ public:
|
||||
void compact() {
|
||||
if(mode == deletion_policy::in_place) {
|
||||
size_type from = packed.size();
|
||||
size_type pos = std::exchange(head, max_size);
|
||||
size_type pos = stl::exchange(head, max_size);
|
||||
|
||||
for(; from && packed[from - 1u] == tombstone; --from) {}
|
||||
|
||||
while(pos != max_size) {
|
||||
if(const auto to = std::exchange(pos, entity_to_pos(packed[pos])); to < from) {
|
||||
if(const auto to = stl::exchange(pos, entity_to_pos(packed[pos])); to < from) {
|
||||
--from;
|
||||
swap_or_move(from, to);
|
||||
|
||||
packed[to] = packed[from];
|
||||
const auto elem = static_cast<typename traits_type::entity_type>(to);
|
||||
const auto elem = static_cast<traits_type::entity_type>(to);
|
||||
sparse_ref(packed[to]) = traits_type::combine(elem, traits_type::to_integral(packed[to]));
|
||||
|
||||
for(; from && packed[from - 1u] == tombstone; --from) {}
|
||||
@@ -1000,7 +967,7 @@ public:
|
||||
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed");
|
||||
ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements");
|
||||
|
||||
algo(packed.rend() - static_cast<difference_type>(length), packed.rend(), std::move(compare), std::forward<Args>(args)...);
|
||||
algo(packed.rend() - static_cast<difference_type>(length), packed.rend(), stl::move(compare), stl::forward<Args>(args)...);
|
||||
|
||||
for(size_type pos{}; pos < length; ++pos) {
|
||||
auto curr = pos;
|
||||
@@ -1011,9 +978,9 @@ public:
|
||||
const auto entt = packed[curr];
|
||||
|
||||
swap_or_move(next, idx);
|
||||
const auto elem = static_cast<typename traits_type::entity_type>(curr);
|
||||
const auto elem = static_cast<traits_type::entity_type>(curr);
|
||||
sparse_ref(entt) = traits_type::combine(elem, traits_type::to_integral(packed[curr]));
|
||||
curr = std::exchange(next, idx);
|
||||
curr = stl::exchange(next, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1033,7 +1000,7 @@ public:
|
||||
template<typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
|
||||
const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size();
|
||||
sort_n(len, std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
sort_n(len, stl::move(compare), stl::move(algo), stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1049,7 +1016,7 @@ public:
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
* @return An iterator past the last of the elements actually shared.
|
||||
*/
|
||||
template<typename It>
|
||||
template<stl::input_iterator It>
|
||||
iterator sort_as(It first, It last) {
|
||||
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed");
|
||||
const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size();
|
||||
@@ -1079,11 +1046,11 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returned value type, if any.
|
||||
* @return Returned value type, if any.
|
||||
* @brief Returns a type info object for the value type, if any.
|
||||
* @return A type info object for the value type, if any.
|
||||
*/
|
||||
[[nodiscard]] const type_info &type() const noexcept {
|
||||
return *info;
|
||||
[[nodiscard]] const type_info &info() const noexcept {
|
||||
return *descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1093,13 +1060,13 @@ public:
|
||||
*/
|
||||
template<typename Type>
|
||||
void bind(Type &&value) noexcept {
|
||||
bind_any(forward_as_any(std::forward<Type>(value)));
|
||||
bind_any(forward_as_any(stl::forward<Type>(value)));
|
||||
}
|
||||
|
||||
private:
|
||||
sparse_container_type sparse;
|
||||
packed_container_type packed;
|
||||
const type_info *info;
|
||||
const type_info *descriptor;
|
||||
deletion_policy mode;
|
||||
size_type head;
|
||||
};
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
#ifndef ENTT_ENTITY_STORAGE_HPP
|
||||
#define ENTT_ENTITY_STORAGE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <compare>
|
||||
#include "../config/config.h"
|
||||
#include "../core/bit.hpp"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/memory.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "component.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
@@ -20,27 +22,28 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename Container, auto Page>
|
||||
class storage_iterator final {
|
||||
friend storage_iterator<const Container, Page>;
|
||||
template<typename, auto>
|
||||
friend class storage_iterator;
|
||||
|
||||
using container_type = std::remove_const_t<Container>;
|
||||
using alloc_traits = std::allocator_traits<typename container_type::allocator_type>;
|
||||
using container_type = stl::remove_const_t<Container>;
|
||||
using alloc_traits = stl::allocator_traits<typename container_type::allocator_type>;
|
||||
|
||||
using iterator_traits = std::iterator_traits<std::conditional_t<
|
||||
std::is_const_v<Container>,
|
||||
typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
|
||||
typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
|
||||
using iterator_traits = stl::iterator_traits<stl::conditional_t<
|
||||
stl::is_const_v<Container>,
|
||||
typename alloc_traits::template rebind_traits<typename stl::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
|
||||
typename alloc_traits::template rebind_traits<typename stl::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
|
||||
|
||||
public:
|
||||
using value_type = typename iterator_traits::value_type;
|
||||
using pointer = typename iterator_traits::pointer;
|
||||
using reference = typename iterator_traits::reference;
|
||||
using difference_type = typename iterator_traits::difference_type;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using value_type = iterator_traits::value_type;
|
||||
using pointer = iterator_traits::pointer;
|
||||
using reference = iterator_traits::reference;
|
||||
using difference_type = iterator_traits::difference_type;
|
||||
using iterator_category = stl::random_access_iterator_tag;
|
||||
|
||||
constexpr storage_iterator() noexcept = default;
|
||||
|
||||
@@ -48,8 +51,9 @@ public:
|
||||
: payload{ref},
|
||||
offset{idx} {}
|
||||
|
||||
template<bool Const = std::is_const_v<Container>, typename = std::enable_if_t<Const>>
|
||||
constexpr storage_iterator(const storage_iterator<std::remove_const_t<Container>, Page> &other) noexcept
|
||||
template<stl::same_as<stl::remove_const_t<Container>> Other>
|
||||
requires stl::is_const_v<Container>
|
||||
constexpr storage_iterator(const storage_iterator<Other, Page> &other) noexcept
|
||||
: storage_iterator{other.payload, other.offset} {}
|
||||
|
||||
constexpr storage_iterator &operator++() noexcept {
|
||||
@@ -89,18 +93,35 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
|
||||
const auto pos = static_cast<typename Container::size_type>(index() - value);
|
||||
return (*payload)[pos / Page][fast_mod(static_cast<std::size_t>(pos), Page)];
|
||||
const auto pos = static_cast<Container::size_type>(index() - value);
|
||||
return (*payload)[pos / Page][fast_mod(static_cast<stl::size_t>(pos), Page)];
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::addressof(operator[](0));
|
||||
return stl::addressof(operator[](0));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return operator[](0);
|
||||
}
|
||||
|
||||
template<typename Other, auto Arg>
|
||||
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const storage_iterator<Other, Arg> &other) const noexcept {
|
||||
// intentionally reversed due to backward iteration
|
||||
return other.offset - offset;
|
||||
}
|
||||
|
||||
template<typename Other, auto Arg>
|
||||
[[nodiscard]] constexpr bool operator==(const storage_iterator<Other, Arg> &other) const noexcept {
|
||||
return offset == other.offset;
|
||||
}
|
||||
|
||||
template<typename Other, auto Arg>
|
||||
[[nodiscard]] constexpr auto operator<=>(const storage_iterator<Other, Arg> &other) const noexcept {
|
||||
// intentionally reversed due to backward iteration
|
||||
return other.offset <=> offset;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr difference_type index() const noexcept {
|
||||
return offset - 1;
|
||||
}
|
||||
@@ -110,54 +131,19 @@ private:
|
||||
difference_type offset;
|
||||
};
|
||||
|
||||
template<typename Lhs, typename Rhs, auto Page>
|
||||
[[nodiscard]] constexpr std::ptrdiff_t operator-(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
|
||||
return rhs.index() - lhs.index();
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs, auto Page>
|
||||
[[nodiscard]] constexpr bool operator==(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
|
||||
return lhs.index() == rhs.index();
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs, auto Page>
|
||||
[[nodiscard]] constexpr bool operator!=(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs, auto Page>
|
||||
[[nodiscard]] constexpr bool operator<(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
|
||||
return lhs.index() > rhs.index();
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs, auto Page>
|
||||
[[nodiscard]] constexpr bool operator>(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs, auto Page>
|
||||
[[nodiscard]] constexpr bool operator<=(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs, auto Page>
|
||||
[[nodiscard]] constexpr bool operator>=(const storage_iterator<Lhs, Page> &lhs, const storage_iterator<Rhs, Page> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename It, typename... Other>
|
||||
class extended_storage_iterator final {
|
||||
template<typename Iter, typename... Args>
|
||||
template<typename, typename...>
|
||||
friend class extended_storage_iterator;
|
||||
|
||||
public:
|
||||
using iterator_type = It;
|
||||
using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::forward_as_tuple(*std::declval<Other>()...)));
|
||||
using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval<It>()), stl::forward_as_tuple(*stl::declval<Other>()...)));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::forward_iterator_tag;
|
||||
|
||||
constexpr extended_storage_iterator()
|
||||
: it{} {}
|
||||
@@ -165,12 +151,13 @@ public:
|
||||
constexpr extended_storage_iterator(iterator_type base, Other... other)
|
||||
: it{base, other...} {}
|
||||
|
||||
template<typename... Args, typename = std::enable_if_t<(!std::is_same_v<Other, Args> && ...) && (std::is_constructible_v<Other, Args> && ...)>>
|
||||
template<typename... Args>
|
||||
requires (!stl::same_as<Other, Args> && ...) && (stl::constructible_from<Other, Args> && ...)
|
||||
constexpr extended_storage_iterator(const extended_storage_iterator<It, Args...> &other)
|
||||
: it{other.it} {}
|
||||
|
||||
constexpr extended_storage_iterator &operator++() noexcept {
|
||||
return ++std::get<It>(it), (++std::get<Other>(it), ...), *this;
|
||||
return ++stl::get<It>(it), (++stl::get<Other>(it), ...), *this;
|
||||
}
|
||||
|
||||
constexpr extended_storage_iterator operator++(int) noexcept {
|
||||
@@ -183,30 +170,22 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return {*std::get<It>(it), *std::get<Other>(it)...};
|
||||
return {*stl::get<It>(it), *stl::get<Other>(it)...};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr iterator_type base() const noexcept {
|
||||
return std::get<It>(it);
|
||||
return stl::get<It>(it);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
friend constexpr bool operator==(const extended_storage_iterator<Lhs...> &, const extended_storage_iterator<Rhs...> &) noexcept;
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator==(const extended_storage_iterator<Args...> &other) const noexcept {
|
||||
return stl::get<0>(it) == stl::get<0>(other.it);
|
||||
}
|
||||
|
||||
private:
|
||||
std::tuple<It, Other...> it;
|
||||
stl::tuple<It, Other...> it;
|
||||
};
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const extended_storage_iterator<Lhs...> &lhs, const extended_storage_iterator<Rhs...> &rhs) noexcept {
|
||||
return std::get<0>(lhs.it) == std::get<0>(rhs.it);
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const extended_storage_iterator<Lhs...> &lhs, const extended_storage_iterator<Rhs...> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
@@ -225,20 +204,20 @@ template<typename... Lhs, typename... Rhs>
|
||||
* @tparam Entity A valid entity type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Entity, typename Allocator, typename>
|
||||
class basic_storage: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
|
||||
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<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
|
||||
template<typename Type, typename Entity, typename Allocator>
|
||||
class basic_storage: public basic_sparse_set<Entity, typename stl::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
|
||||
using container_type = stl::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
|
||||
using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
|
||||
using underlying_iterator = typename underlying_type::basic_iterator;
|
||||
using underlying_iterator = underlying_type::basic_iterator;
|
||||
using traits_type = component_traits<Type, Entity>;
|
||||
|
||||
[[nodiscard]] auto &element_at(const std::size_t pos) const {
|
||||
[[nodiscard]] auto &element_at(const stl::size_t pos) const {
|
||||
return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
|
||||
}
|
||||
|
||||
auto assure_at_least(const std::size_t pos) {
|
||||
auto assure_at_least(const stl::size_t pos) {
|
||||
const auto idx = pos / traits_type::page_size;
|
||||
|
||||
if(!(idx < payload.size())) {
|
||||
@@ -265,8 +244,8 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
|
||||
const auto it = base_type::try_emplace(entt, force_back);
|
||||
|
||||
ENTT_TRY {
|
||||
auto *elem = to_address(assure_at_least(static_cast<size_type>(it.index())));
|
||||
entt::uninitialized_construct_using_allocator(elem, get_allocator(), std::forward<Args>(args)...);
|
||||
auto *elem = stl::to_address(assure_at_least(static_cast<size_type>(it.index())));
|
||||
entt::uninitialized_construct_using_allocator(elem, get_allocator(), stl::forward<Args>(args)...);
|
||||
}
|
||||
ENTT_CATCH {
|
||||
base_type::pop(it, it + 1u);
|
||||
@@ -276,17 +255,19 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
|
||||
return it;
|
||||
}
|
||||
|
||||
void shrink_to_size(const std::size_t sz) {
|
||||
void shrink_to_size(const stl::size_t sz) {
|
||||
const auto from = (sz + traits_type::page_size - 1u) / traits_type::page_size;
|
||||
allocator_type allocator{get_allocator()};
|
||||
|
||||
for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
|
||||
if constexpr(traits_type::in_place_delete) {
|
||||
if(base_type::data()[pos] != tombstone) {
|
||||
alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
|
||||
if constexpr(!stl::is_trivially_destructible_v<element_type>) {
|
||||
for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
|
||||
if constexpr(traits_type::in_place_delete) {
|
||||
if(base_type::data()[pos] != tombstone) {
|
||||
alloc_traits::destroy(allocator, stl::addressof(element_at(pos)));
|
||||
}
|
||||
} else {
|
||||
alloc_traits::destroy(allocator, stl::addressof(element_at(pos)));
|
||||
}
|
||||
} else {
|
||||
alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,25 +279,25 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
|
||||
payload.shrink_to_fit();
|
||||
}
|
||||
|
||||
void swap_at(const std::size_t lhs, const std::size_t rhs) {
|
||||
using std::swap;
|
||||
void swap_at(const stl::size_t lhs, const stl::size_t rhs) {
|
||||
using stl::swap;
|
||||
swap(element_at(lhs), element_at(rhs));
|
||||
}
|
||||
|
||||
void move_to(const std::size_t lhs, const std::size_t rhs) {
|
||||
void move_to(const stl::size_t lhs, const stl::size_t rhs) {
|
||||
auto &elem = element_at(lhs);
|
||||
allocator_type allocator{get_allocator()};
|
||||
entt::uninitialized_construct_using_allocator(to_address(assure_at_least(rhs)), allocator, std::move(elem));
|
||||
alloc_traits::destroy(allocator, std::addressof(elem));
|
||||
entt::uninitialized_construct_using_allocator(stl::to_address(assure_at_least(rhs)), allocator, stl::move(elem));
|
||||
alloc_traits::destroy(allocator, stl::addressof(elem));
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] const void *get_at(const std::size_t pos) const final {
|
||||
return std::addressof(element_at(pos));
|
||||
[[nodiscard]] const void *get_at(const stl::size_t pos) const final {
|
||||
return stl::addressof(element_at(pos));
|
||||
}
|
||||
|
||||
void swap_or_move([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) override {
|
||||
static constexpr bool is_pinned_type = !(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>);
|
||||
void swap_or_move([[maybe_unused]] const stl::size_t from, [[maybe_unused]] const stl::size_t to) override {
|
||||
static constexpr bool is_pinned_type = !(stl::is_move_constructible_v<Type> && stl::is_move_assignable_v<Type>);
|
||||
// use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy
|
||||
ENTT_ASSERT((from + 1u) && !is_pinned_type, "Pinned type");
|
||||
|
||||
@@ -341,31 +322,38 @@ protected:
|
||||
auto &elem = element_at(base_type::index(*first));
|
||||
|
||||
if constexpr(traits_type::in_place_delete) {
|
||||
base_type::in_place_pop(first);
|
||||
alloc_traits::destroy(allocator, std::addressof(elem));
|
||||
base_type::in_place_pop(*first);
|
||||
alloc_traits::destroy(allocator, stl::addressof(elem));
|
||||
} else if constexpr(stl::is_trivially_destructible_v<element_type>) {
|
||||
elem = stl::move(element_at(base_type::size() - 1u));
|
||||
base_type::swap_and_pop(*first);
|
||||
} else {
|
||||
auto &other = element_at(base_type::size() - 1u);
|
||||
// destroying on exit allows reentrant destructors
|
||||
[[maybe_unused]] auto unused = std::exchange(elem, std::move(other));
|
||||
alloc_traits::destroy(allocator, std::addressof(other));
|
||||
base_type::swap_and_pop(first);
|
||||
[[maybe_unused]] auto unused = stl::exchange(elem, stl::move(other));
|
||||
alloc_traits::destroy(allocator, stl::addressof(other));
|
||||
base_type::swap_and_pop(*first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Erases all entities of a storage. */
|
||||
void pop_all() override {
|
||||
allocator_type allocator{get_allocator()};
|
||||
if constexpr(stl::is_trivially_destructible_v<element_type>) {
|
||||
base_type::pop_all();
|
||||
} else {
|
||||
allocator_type allocator{get_allocator()};
|
||||
|
||||
for(auto first = base_type::begin(); !(first.index() < 0); ++first) {
|
||||
if constexpr(traits_type::in_place_delete) {
|
||||
if(*first != tombstone) {
|
||||
base_type::in_place_pop(first);
|
||||
alloc_traits::destroy(allocator, std::addressof(element_at(static_cast<size_type>(first.index()))));
|
||||
for(auto first = base_type::begin(); !(first.index() < 0); ++first) {
|
||||
if constexpr(traits_type::in_place_delete) {
|
||||
if(*first != tombstone) {
|
||||
base_type::in_place_pop(*first);
|
||||
alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast<size_type>(first.index()))));
|
||||
}
|
||||
} else {
|
||||
base_type::swap_and_pop(*first);
|
||||
alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast<size_type>(first.index()))));
|
||||
}
|
||||
} else {
|
||||
base_type::swap_and_pop(first);
|
||||
alloc_traits::destroy(allocator, std::addressof(element_at(static_cast<size_type>(first.index()))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,13 +367,13 @@ protected:
|
||||
*/
|
||||
underlying_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override {
|
||||
if(value != nullptr) {
|
||||
if constexpr(std::is_copy_constructible_v<element_type>) {
|
||||
if constexpr(stl::is_copy_constructible_v<element_type>) {
|
||||
return emplace_element(entt, force_back, *static_cast<const element_type *>(value));
|
||||
} else {
|
||||
return base_type::end();
|
||||
}
|
||||
} else {
|
||||
if constexpr(std::is_default_constructible_v<element_type>) {
|
||||
if constexpr(stl::is_default_constructible_v<element_type>) {
|
||||
return emplace_element(entt, force_back);
|
||||
} else {
|
||||
return base_type::end();
|
||||
@@ -405,21 +393,21 @@ public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Pointer type to contained elements. */
|
||||
using pointer = typename container_type::pointer;
|
||||
using pointer = container_type::pointer;
|
||||
/*! @brief Constant pointer type to contained elements. */
|
||||
using const_pointer = typename alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
|
||||
using const_pointer = alloc_traits::template rebind_traits<typename alloc_traits::const_pointer>::const_pointer;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = internal::storage_iterator<container_type, traits_type::page_size>;
|
||||
/*! @brief Constant random access iterator type. */
|
||||
using const_iterator = internal::storage_iterator<const container_type, traits_type::page_size>;
|
||||
/*! @brief Reverse iterator type. */
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using reverse_iterator = stl::reverse_iterator<iterator>;
|
||||
/*! @brief Constant reverse iterator type. */
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
using const_reverse_iterator = stl::reverse_iterator<const_iterator>;
|
||||
/*! @brief Extended iterable storage proxy. */
|
||||
using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator, iterator>>;
|
||||
/*! @brief Constant extended iterable storage proxy. */
|
||||
@@ -450,24 +438,20 @@ public:
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
// NOLINTBEGIN(bugprone-use-after-move)
|
||||
basic_storage(basic_storage &&other) noexcept
|
||||
: base_type{std::move(other)},
|
||||
payload{std::move(other.payload)} {}
|
||||
// NOLINTEND(bugprone-use-after-move)
|
||||
: base_type{static_cast<base_type &&>(other)},
|
||||
payload{stl::move(other.payload)} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
// NOLINTBEGIN(bugprone-use-after-move)
|
||||
basic_storage(basic_storage &&other, const allocator_type &allocator)
|
||||
: base_type{std::move(other), allocator},
|
||||
payload{std::move(other.payload), allocator} {
|
||||
: base_type{static_cast<base_type &&>(other), allocator},
|
||||
payload{stl::move(other.payload), allocator} {
|
||||
ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed");
|
||||
}
|
||||
// NOLINTEND(bugprone-use-after-move)
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
// NOLINTNEXTLINE(bugprone-exception-escape)
|
||||
@@ -497,7 +481,7 @@ public:
|
||||
* @param other Storage to exchange the content with.
|
||||
*/
|
||||
void swap(basic_storage &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(payload, other.payload);
|
||||
base_type::swap(other);
|
||||
}
|
||||
@@ -603,7 +587,7 @@ public:
|
||||
* @return An iterator to the first instance of the reversed internal array.
|
||||
*/
|
||||
[[nodiscard]] const_reverse_iterator crbegin() const noexcept {
|
||||
return std::make_reverse_iterator(cend());
|
||||
return stl::make_reverse_iterator(cend());
|
||||
}
|
||||
|
||||
/*! @copydoc crbegin */
|
||||
@@ -613,7 +597,7 @@ public:
|
||||
|
||||
/*! @copydoc rbegin */
|
||||
[[nodiscard]] reverse_iterator rbegin() noexcept {
|
||||
return std::make_reverse_iterator(end());
|
||||
return stl::make_reverse_iterator(end());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -622,7 +606,7 @@ public:
|
||||
* reversed internal array.
|
||||
*/
|
||||
[[nodiscard]] const_reverse_iterator crend() const noexcept {
|
||||
return std::make_reverse_iterator(cbegin());
|
||||
return stl::make_reverse_iterator(cbegin());
|
||||
}
|
||||
|
||||
/*! @copydoc crend */
|
||||
@@ -632,7 +616,7 @@ public:
|
||||
|
||||
/*! @copydoc rend */
|
||||
[[nodiscard]] reverse_iterator rend() noexcept {
|
||||
return std::make_reverse_iterator(begin());
|
||||
return stl::make_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -651,7 +635,7 @@ public:
|
||||
|
||||
/*! @copydoc get */
|
||||
[[nodiscard]] value_type &get(const entity_type entt) noexcept {
|
||||
return const_cast<value_type &>(std::as_const(*this).get(entt));
|
||||
return const_cast<value_type &>(stl::as_const(*this).get(entt));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -659,13 +643,13 @@ public:
|
||||
* @param entt A valid identifier.
|
||||
* @return The object assigned to the entity as a tuple.
|
||||
*/
|
||||
[[nodiscard]] std::tuple<const value_type &> get_as_tuple(const entity_type entt) const noexcept {
|
||||
return std::forward_as_tuple(get(entt));
|
||||
[[nodiscard]] stl::tuple<const value_type &> get_as_tuple(const entity_type entt) const noexcept {
|
||||
return stl::forward_as_tuple(get(entt));
|
||||
}
|
||||
|
||||
/*! @copydoc get_as_tuple */
|
||||
[[nodiscard]] std::tuple<value_type &> get_as_tuple(const entity_type entt) noexcept {
|
||||
return std::forward_as_tuple(get(entt));
|
||||
[[nodiscard]] stl::tuple<value_type &> get_as_tuple(const entity_type entt) noexcept {
|
||||
return stl::forward_as_tuple(get(entt));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -682,11 +666,11 @@ public:
|
||||
*/
|
||||
template<typename... Args>
|
||||
value_type &emplace(const entity_type entt, Args &&...args) {
|
||||
if constexpr(std::is_aggregate_v<value_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<value_type>)) {
|
||||
const auto it = emplace_element(entt, false, Type{std::forward<Args>(args)...});
|
||||
if constexpr(stl::is_aggregate_v<value_type> && (sizeof...(Args) != 0u || !stl::is_default_constructible_v<value_type>)) {
|
||||
const auto it = emplace_element(entt, false, Type{stl::forward<Args>(args)...});
|
||||
return element_at(static_cast<size_type>(it.index()));
|
||||
} else {
|
||||
const auto it = emplace_element(entt, false, std::forward<Args>(args)...);
|
||||
const auto it = emplace_element(entt, false, stl::forward<Args>(args)...);
|
||||
return element_at(static_cast<size_type>(it.index()));
|
||||
}
|
||||
}
|
||||
@@ -702,7 +686,7 @@ public:
|
||||
value_type &patch(const entity_type entt, Func &&...func) {
|
||||
const auto idx = base_type::index(entt);
|
||||
auto &elem = element_at(idx);
|
||||
(std::forward<Func>(func)(elem), ...);
|
||||
(stl::forward<Func>(func)(elem), ...);
|
||||
return elem;
|
||||
}
|
||||
|
||||
@@ -714,14 +698,12 @@ public:
|
||||
* Attempting to assign an entity that already belongs to the storage
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @tparam It Type of input iterator.
|
||||
* @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 value An instance of the object to construct.
|
||||
* @return Iterator pointing to the first element inserted, if any.
|
||||
*/
|
||||
template<typename It>
|
||||
iterator insert(It first, It last, const value_type &value = {}) {
|
||||
iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, const value_type &value = {}) {
|
||||
for(; first != last; ++first) {
|
||||
emplace_element(*first, true, value);
|
||||
}
|
||||
@@ -735,15 +717,15 @@ public:
|
||||
*
|
||||
* @sa construct
|
||||
*
|
||||
* @tparam EIt Type of input iterator.
|
||||
* @tparam CIt Type of input iterator.
|
||||
* @tparam It Type of input iterator.
|
||||
* @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 from An iterator to the first element of the range of objects.
|
||||
* @return Iterator pointing to the first element inserted, if any.
|
||||
*/
|
||||
template<typename EIt, typename CIt, typename = std::enable_if_t<std::is_same_v<typename std::iterator_traits<CIt>::value_type, value_type>>>
|
||||
iterator insert(EIt first, EIt last, CIt from) {
|
||||
template<stl::input_iterator It>
|
||||
requires stl::same_as<typename stl::iterator_traits<It>::value_type, value_type>
|
||||
iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, It from) {
|
||||
for(; first != last; ++first, ++from) {
|
||||
emplace_element(*first, true, *from);
|
||||
}
|
||||
@@ -790,10 +772,11 @@ private:
|
||||
|
||||
/*! @copydoc basic_storage */
|
||||
template<typename Type, typename Entity, typename Allocator>
|
||||
class basic_storage<Type, Entity, Allocator, std::enable_if_t<component_traits<Type, Entity>::page_size == 0u>>
|
||||
: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
|
||||
requires (component_traits<Type, Entity>::page_size == 0u)
|
||||
class basic_storage<Type, Entity, Allocator>
|
||||
: public basic_sparse_set<Entity, typename stl::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
|
||||
using traits_type = component_traits<Type, Entity>;
|
||||
|
||||
public:
|
||||
@@ -808,9 +791,9 @@ public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Extended iterable storage proxy. */
|
||||
using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>;
|
||||
/*! @brief Constant extended iterable storage proxy. */
|
||||
@@ -848,7 +831,7 @@ public:
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_storage(basic_storage &&other, const allocator_type &allocator)
|
||||
: base_type{std::move(other), allocator} {}
|
||||
: base_type{stl::move(other), allocator} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~basic_storage() override = default;
|
||||
@@ -871,12 +854,7 @@ public:
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
// std::allocator<void> has no cross constructors (waiting for C++20)
|
||||
if constexpr(std::is_void_v<element_type> && !std::is_constructible_v<allocator_type, typename base_type::allocator_type>) {
|
||||
return allocator_type{};
|
||||
} else {
|
||||
return allocator_type{base_type::get_allocator()};
|
||||
}
|
||||
return allocator_type{base_type::get_allocator()};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -897,9 +875,9 @@ public:
|
||||
* @param entt A valid identifier.
|
||||
* @return Returns an empty tuple.
|
||||
*/
|
||||
[[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
|
||||
[[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
|
||||
ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
|
||||
return std::tuple{};
|
||||
return stl::tuple{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -909,12 +887,9 @@ public:
|
||||
* Attempting to use an entity that already belongs to the storage results
|
||||
* in undefined behavior.
|
||||
*
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param entt A valid identifier.
|
||||
*/
|
||||
template<typename... Args>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
|
||||
void emplace(const entity_type entt, Args &&...) {
|
||||
void emplace(const entity_type entt, const auto &...) {
|
||||
base_type::try_emplace(entt, false);
|
||||
}
|
||||
|
||||
@@ -927,19 +902,15 @@ public:
|
||||
template<typename... Func>
|
||||
void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
|
||||
ENTT_ASSERT(base_type::contains(entt), "Invalid entity");
|
||||
(std::forward<Func>(func)(), ...);
|
||||
(stl::forward<Func>(func)(), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns entities to a storage.
|
||||
* @tparam It Type of input iterator.
|
||||
* @tparam Args Types of optional arguments.
|
||||
* @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.
|
||||
*/
|
||||
template<typename It, typename... Args>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
|
||||
void insert(It first, It last, Args &&...) {
|
||||
void insert(stl::input_iterator auto first, stl::input_iterator auto last, const auto &...) {
|
||||
for(; first != last; ++first) {
|
||||
base_type::try_emplace(*first, true);
|
||||
}
|
||||
@@ -986,13 +957,13 @@ public:
|
||||
template<typename Entity, typename Allocator>
|
||||
class basic_storage<Entity, Entity, Allocator>
|
||||
: public basic_sparse_set<Entity, Allocator> {
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
|
||||
using underlying_iterator = typename basic_sparse_set<Entity, Allocator>::basic_iterator;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
|
||||
using underlying_iterator = basic_sparse_set<Entity, Allocator>::basic_iterator;
|
||||
using traits_type = entt_traits<Entity>;
|
||||
|
||||
auto from_placeholder() noexcept {
|
||||
const auto entt = traits_type::combine(static_cast<typename traits_type::entity_type>(placeholder), {});
|
||||
const auto entt = traits_type::combine(static_cast<traits_type::entity_type>(placeholder), {});
|
||||
ENTT_ASSERT(entt != null, "No more entities available");
|
||||
placeholder += static_cast<size_type>(entt != null);
|
||||
return entt;
|
||||
@@ -1036,9 +1007,9 @@ public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Extended iterable storage proxy. */
|
||||
using iterable = iterable_adaptor<internal::extended_storage_iterator<typename base_type::iterator>>;
|
||||
/*! @brief Constant extended iterable storage proxy. */
|
||||
@@ -1069,22 +1040,20 @@ public:
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
// NOLINTBEGIN(bugprone-use-after-move)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
basic_storage(basic_storage &&other) noexcept
|
||||
: base_type{std::move(other)},
|
||||
: base_type{static_cast<base_type &&>(other)},
|
||||
placeholder{other.placeholder} {}
|
||||
// NOLINTEND(bugprone-use-after-move)
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
// NOLINTBEGIN(bugprone-use-after-move)
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
basic_storage(basic_storage &&other, const allocator_type &allocator)
|
||||
: base_type{std::move(other), allocator},
|
||||
: base_type{static_cast<base_type &&>(other), allocator},
|
||||
placeholder{other.placeholder} {}
|
||||
// NOLINTEND(bugprone-use-after-move)
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~basic_storage() override = default;
|
||||
@@ -1102,10 +1071,20 @@ public:
|
||||
*/
|
||||
basic_storage &operator=(basic_storage &&other) noexcept {
|
||||
placeholder = other.placeholder;
|
||||
base_type::operator=(std::move(other));
|
||||
base_type::operator=(stl::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given storage.
|
||||
* @param other Storage to exchange the content with.
|
||||
*/
|
||||
void swap(basic_storage &other) noexcept {
|
||||
using stl::swap;
|
||||
swap(placeholder, other.placeholder);
|
||||
base_type::swap(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the object assigned to an entity, that is `void`.
|
||||
*
|
||||
@@ -1124,9 +1103,9 @@ public:
|
||||
* @param entt A valid identifier.
|
||||
* @return Returns an empty tuple.
|
||||
*/
|
||||
[[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
|
||||
[[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
|
||||
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
|
||||
return std::tuple{};
|
||||
return stl::tuple{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1160,11 +1139,11 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Assigns each element in a range an identifier.
|
||||
* @tparam It Type of mutable forward iterator.
|
||||
* @tparam It Type of output iterator.
|
||||
* @param first An iterator to the first element of the range to generate.
|
||||
* @param last An iterator past the last element of the range to generate.
|
||||
*/
|
||||
template<typename It>
|
||||
template<stl::output_iterator<entity_type> It>
|
||||
void generate(It first, It last) {
|
||||
for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) {
|
||||
*first = *base_type::try_emplace(base_type::data()[base_type::free_list()], true);
|
||||
@@ -1175,27 +1154,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new identifier or recycles a destroyed one.
|
||||
* @return A valid identifier.
|
||||
*/
|
||||
[[deprecated("use ::generate() instead")]] entity_type emplace() {
|
||||
return generate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new identifier or recycles a destroyed one.
|
||||
*
|
||||
* If the requested identifier isn't in use, the suggested one is used.
|
||||
* Otherwise, a new identifier is returned.
|
||||
*
|
||||
* @param hint Required identifier.
|
||||
* @return A valid identifier.
|
||||
*/
|
||||
[[deprecated("use ::generate(hint) instead")]] entity_type emplace(const entity_type hint) {
|
||||
return generate(hint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates a given identifier.
|
||||
* @tparam Func Types of the function objects to invoke.
|
||||
@@ -1205,18 +1163,7 @@ public:
|
||||
template<typename... Func>
|
||||
void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
|
||||
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
|
||||
(std::forward<Func>(func)(), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns each element in a range an identifier.
|
||||
* @tparam It Type of mutable forward iterator.
|
||||
* @param first An iterator to the first element of the range to generate.
|
||||
* @param last An iterator past the last element of the range to generate.
|
||||
*/
|
||||
template<typename It>
|
||||
[[deprecated("use ::generate(first, last) instead")]] void insert(It first, It last) {
|
||||
generate(std::move(first), std::move(last));
|
||||
(stl::forward<Func>(func)(), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1227,7 +1174,7 @@ public:
|
||||
* @return An iterable object to use to _visit_ the storage.
|
||||
*/
|
||||
[[nodiscard]] iterable each() noexcept {
|
||||
return std::as_const(*this).each();
|
||||
return stl::as_const(*this).each();
|
||||
}
|
||||
|
||||
/*! @copydoc each */
|
||||
@@ -1245,7 +1192,7 @@ public:
|
||||
* @return A reverse iterable object to use to _visit_ the storage.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterable reach() noexcept {
|
||||
return std::as_const(*this).reach();
|
||||
return stl::as_const(*this).reach();
|
||||
}
|
||||
|
||||
/*! @copydoc reach */
|
||||
|
||||
@@ -1,72 +1,71 @@
|
||||
#ifndef ENTT_ENTITY_VIEW_HPP
|
||||
#define ENTT_ENTITY_VIEW_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/concepts.hpp"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/array.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename... Type>
|
||||
// NOLINTNEXTLINE(misc-redundant-expression)
|
||||
static constexpr bool tombstone_check_v = ((sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place));
|
||||
|
||||
template<typename Type>
|
||||
template<cvref_unqualified Type>
|
||||
const Type *view_placeholder() {
|
||||
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Unexpected type");
|
||||
static const Type placeholder{};
|
||||
return &placeholder;
|
||||
}
|
||||
|
||||
template<typename It, typename Entity>
|
||||
[[nodiscard]] bool all_of(It first, const It last, const Entity entt) noexcept {
|
||||
[[nodiscard]] bool all_of(auto first, const auto last, const auto entt) noexcept {
|
||||
for(; (first != last) && (*first)->contains(entt); ++first) {}
|
||||
return first == last;
|
||||
}
|
||||
|
||||
template<typename It, typename Entity>
|
||||
[[nodiscard]] bool none_of(It first, const It last, const Entity entt) noexcept {
|
||||
[[nodiscard]] bool none_of(auto first, const auto last, const auto entt) noexcept {
|
||||
for(; (first != last) && !(*first)->contains(entt); ++first) {}
|
||||
return first == last;
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
[[nodiscard]] bool fully_initialized(It first, const It last, const std::remove_pointer_t<typename std::iterator_traits<It>::value_type> *placeholder) noexcept {
|
||||
[[nodiscard]] bool fully_initialized(It first, const It last, const stl::remove_pointer_t<typename stl::iterator_traits<It>::value_type> *placeholder) noexcept {
|
||||
for(; (first != last) && *first != placeholder; ++first) {}
|
||||
return first == last;
|
||||
}
|
||||
|
||||
template<typename Result, typename View, typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
|
||||
[[nodiscard]] Result view_pack(const View &view, const Other &other, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>) {
|
||||
template<typename Result, typename View, typename Other, stl::size_t... GLhs, stl::size_t... ELhs, stl::size_t... GRhs, stl::size_t... ERhs>
|
||||
[[nodiscard]] Result view_pack(const View &view, const Other &other, stl::index_sequence<GLhs...>, stl::index_sequence<ELhs...>, stl::index_sequence<GRhs...>, stl::index_sequence<ERhs...>) {
|
||||
Result elem{};
|
||||
// friend-initialization, avoid multiple calls to refresh
|
||||
elem.pools = {view.template storage<GLhs>()..., other.template storage<GRhs>()...};
|
||||
auto filter_or_placeholder = [placeholder = elem.placeholder](auto *value) { return (value == nullptr) ? placeholder : value; };
|
||||
[[maybe_unused]] const auto filter_or_placeholder = [placeholder = elem.placeholder](auto *value) { return (value == nullptr) ? placeholder : value; };
|
||||
elem.filter = {filter_or_placeholder(view.template storage<sizeof...(GLhs) + ELhs>())..., filter_or_placeholder(other.template storage<sizeof...(GRhs) + ERhs>())...};
|
||||
elem.refresh();
|
||||
return elem;
|
||||
}
|
||||
|
||||
template<typename Type, bool Checked, std::size_t Get, std::size_t Exclude>
|
||||
template<typename Type, bool Checked, stl::size_t Get, stl::size_t Exclude>
|
||||
class view_iterator final {
|
||||
template<typename, typename...>
|
||||
friend class extended_view_iterator;
|
||||
friend struct extended_view_iterator;
|
||||
|
||||
using iterator_type = typename Type::const_iterator;
|
||||
using iterator_traits = std::iterator_traits<iterator_type>;
|
||||
using iterator_type = Type::const_iterator;
|
||||
using iterator_traits = stl::iterator_traits<iterator_type>;
|
||||
|
||||
[[nodiscard]] bool valid(const typename iterator_traits::value_type entt) const noexcept {
|
||||
[[nodiscard]] bool valid(const iterator_traits::value_type entt) const noexcept {
|
||||
return (!Checked || (entt != tombstone))
|
||||
&& ((Get == 1u) || (internal::all_of(pools.begin(), pools.begin() + index, entt) && internal::all_of(pools.begin() + index + 1, pools.end(), entt)))
|
||||
&& ((Exclude == 0u) || internal::none_of(filter.begin(), filter.end(), entt));
|
||||
@@ -77,11 +76,11 @@ class view_iterator final {
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = typename iterator_traits::value_type;
|
||||
using pointer = typename iterator_traits::pointer;
|
||||
using reference = typename iterator_traits::reference;
|
||||
using difference_type = typename iterator_traits::difference_type;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = iterator_traits::value_type;
|
||||
using pointer = iterator_traits::pointer;
|
||||
using reference = iterator_traits::reference;
|
||||
using difference_type = iterator_traits::difference_type;
|
||||
using iterator_category = stl::forward_iterator_tag;
|
||||
|
||||
constexpr view_iterator() noexcept
|
||||
: it{},
|
||||
@@ -89,7 +88,7 @@ public:
|
||||
filter{},
|
||||
index{} {}
|
||||
|
||||
view_iterator(iterator_type first, std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl, const std::size_t idx) noexcept
|
||||
view_iterator(iterator_type first, stl::array<const Type *, Get> value, stl::array<const Type *, Exclude> excl, const stl::size_t idx) noexcept
|
||||
: it{first},
|
||||
pools{value},
|
||||
filter{excl},
|
||||
@@ -117,41 +116,27 @@ public:
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
|
||||
friend constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &, const view_iterator<RhsType, RhsArgs...> &) noexcept;
|
||||
template<typename Other, auto... Args>
|
||||
[[nodiscard]] constexpr bool operator==(const view_iterator<Other, Args...> &other) const noexcept {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
private:
|
||||
iterator_type it;
|
||||
std::array<const Type *, Get> pools;
|
||||
std::array<const Type *, Exclude> filter;
|
||||
stl::array<const Type *, Get> pools;
|
||||
stl::array<const Type *, Exclude> filter;
|
||||
difference_type index;
|
||||
};
|
||||
|
||||
template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
|
||||
[[nodiscard]] constexpr bool operator==(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename LhsType, auto... LhsArgs, typename RhsType, auto... RhsArgs>
|
||||
[[nodiscard]] constexpr bool operator!=(const view_iterator<LhsType, LhsArgs...> &lhs, const view_iterator<RhsType, RhsArgs...> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename It, typename... Get>
|
||||
class extended_view_iterator final {
|
||||
template<std::size_t... Index>
|
||||
[[nodiscard]] auto dereference(std::index_sequence<Index...>) const noexcept {
|
||||
return std::tuple_cat(std::make_tuple(*it), static_cast<Get *>(const_cast<constness_as_t<typename Get::base_type, Get> *>(std::get<Index>(it.pools)))->get_as_tuple(*it)...);
|
||||
}
|
||||
|
||||
public:
|
||||
struct extended_view_iterator final {
|
||||
using iterator_type = It;
|
||||
using value_type = decltype(std::tuple_cat(std::make_tuple(*std::declval<It>()), std::declval<Get>().get_as_tuple({})...));
|
||||
using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval<It>()), stl::declval<Get>().get_as_tuple({})...));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::forward_iterator_tag;
|
||||
|
||||
constexpr extended_view_iterator()
|
||||
: it{} {}
|
||||
@@ -169,7 +154,9 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const noexcept {
|
||||
return dereference(std::index_sequence_for<Get...>{});
|
||||
return [this]<auto... Index>(stl::index_sequence<Index...>) {
|
||||
return stl::tuple_cat(stl::make_tuple(*it), static_cast<Get *>(const_cast<constness_as_t<typename Get::base_type, Get> *>(stl::get<Index>(it.pools)))->get_as_tuple(*it)...);
|
||||
}(stl::index_sequence_for<Get...>{});
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const noexcept {
|
||||
@@ -180,23 +167,15 @@ public:
|
||||
return it;
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
friend bool constexpr operator==(const extended_view_iterator<Lhs...> &, const extended_view_iterator<Rhs...> &) noexcept;
|
||||
template<typename... Other>
|
||||
[[nodiscard]] constexpr bool operator==(const extended_view_iterator<Other...> &other) const noexcept {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
};
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename... Lhs, typename... Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const extended_view_iterator<Lhs...> &lhs, const extended_view_iterator<Rhs...> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
@@ -218,7 +197,7 @@ template<typename... Lhs, typename... Rhs>
|
||||
* In all other cases, modifying the storage iterated by a view in any way can
|
||||
* invalidate all iterators.
|
||||
*/
|
||||
template<typename, typename, typename>
|
||||
template<typename, typename>
|
||||
class basic_view;
|
||||
|
||||
/**
|
||||
@@ -229,12 +208,10 @@ class basic_view;
|
||||
* @tparam Get Number of storage iterated by the view.
|
||||
* @tparam Exclude Number of storage used to filter the view.
|
||||
*/
|
||||
template<typename Type, bool Checked, std::size_t Get, std::size_t Exclude>
|
||||
template<cvref_unqualified Type, bool Checked, stl::size_t Get, stl::size_t Exclude>
|
||||
class basic_common_view {
|
||||
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Unexpected type");
|
||||
|
||||
template<typename Return, typename View, typename Other, std::size_t... GLhs, std::size_t... ELhs, std::size_t... GRhs, std::size_t... ERhs>
|
||||
friend Return internal::view_pack(const View &, const Other &, std::index_sequence<GLhs...>, std::index_sequence<ELhs...>, std::index_sequence<GRhs...>, std::index_sequence<ERhs...>);
|
||||
template<typename Return, typename View, typename Other, stl::size_t... GLhs, stl::size_t... ELhs, stl::size_t... GRhs, stl::size_t... ERhs>
|
||||
friend Return internal::view_pack(const View &, const Other &, stl::index_sequence<GLhs...>, stl::index_sequence<ELhs...>, stl::index_sequence<GRhs...>, stl::index_sequence<ERhs...>);
|
||||
|
||||
[[nodiscard]] auto offset() const noexcept {
|
||||
ENTT_ASSERT(index != Get, "Invalid view");
|
||||
@@ -254,44 +231,44 @@ class basic_common_view {
|
||||
}
|
||||
|
||||
protected:
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
basic_common_view() noexcept {
|
||||
for(size_type pos{}, last = filter.size(); pos < last; ++pos) {
|
||||
filter[pos] = placeholder;
|
||||
}
|
||||
}
|
||||
|
||||
basic_common_view(std::array<const Type *, Get> value, std::array<const Type *, Exclude> excl) noexcept
|
||||
basic_common_view(stl::array<const Type *, Get> value, stl::array<const Type *, Exclude> excl) noexcept
|
||||
: pools{value},
|
||||
filter{excl},
|
||||
index{Get} {
|
||||
unchecked_refresh();
|
||||
}
|
||||
|
||||
[[nodiscard]] const Type *pool_at(const std::size_t pos) const noexcept {
|
||||
[[nodiscard]] const Type *pool_at(const stl::size_t pos) const noexcept {
|
||||
return pools[pos];
|
||||
}
|
||||
|
||||
void pool_at(const std::size_t pos, const Type *elem) noexcept {
|
||||
void pool_at(const stl::size_t pos, const Type *elem) noexcept {
|
||||
ENTT_ASSERT(elem != nullptr, "Unexpected element");
|
||||
pools[pos] = elem;
|
||||
refresh();
|
||||
}
|
||||
|
||||
[[nodiscard]] const Type *filter_at(const std::size_t pos) const noexcept {
|
||||
[[nodiscard]] const Type *filter_at(const stl::size_t pos) const noexcept {
|
||||
return (filter[pos] == placeholder) ? nullptr : filter[pos];
|
||||
}
|
||||
|
||||
void filter_at(const std::size_t pos, const Type *elem) noexcept {
|
||||
void filter_at(const stl::size_t pos, const Type *elem) noexcept {
|
||||
ENTT_ASSERT(elem != nullptr, "Unexpected element");
|
||||
filter[pos] = elem;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool none_of(const typename Type::entity_type entt) const noexcept {
|
||||
[[nodiscard]] bool none_of(const Type::entity_type entt) const noexcept {
|
||||
return internal::none_of(filter.begin(), filter.end(), entt);
|
||||
}
|
||||
|
||||
void use(const std::size_t pos) noexcept {
|
||||
void use(const stl::size_t pos) noexcept {
|
||||
index = (index != Get) ? pos : Get;
|
||||
}
|
||||
/*! @endcond */
|
||||
@@ -300,11 +277,11 @@ public:
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = Type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename Type::entity_type;
|
||||
using entity_type = Type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Forward iterator type. */
|
||||
using iterator = internal::view_iterator<common_type, Checked, Get, Exclude>;
|
||||
|
||||
@@ -410,8 +387,8 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<const common_type *, Get> pools{};
|
||||
std::array<const common_type *, Exclude> filter{};
|
||||
stl::array<const common_type *, Get> pools{};
|
||||
stl::array<const common_type *, Exclude> filter{};
|
||||
const common_type *placeholder{internal::view_placeholder<common_type>()};
|
||||
size_type index{Get};
|
||||
};
|
||||
@@ -429,61 +406,57 @@ private:
|
||||
* @tparam Exclude Types of storage used to filter the view.
|
||||
*/
|
||||
template<typename... Get, typename... Exclude>
|
||||
class basic_view<get_t<Get...>, exclude_t<Exclude...>, std::enable_if_t<(sizeof...(Get) != 0u)>>
|
||||
: public basic_common_view<std::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)> {
|
||||
using base_type = basic_common_view<std::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)>;
|
||||
requires (sizeof...(Get) != 0u)
|
||||
class basic_view<get_t<Get...>, exclude_t<Exclude...>>
|
||||
: public basic_common_view<stl::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)> {
|
||||
using base_type = basic_common_view<stl::common_type_t<typename Get::base_type...>, internal::tombstone_check_v<Get...>, sizeof...(Get), sizeof...(Exclude)>;
|
||||
|
||||
template<std::size_t Index>
|
||||
template<stl::size_t Index>
|
||||
using element_at = type_list_element_t<Index, type_list<Get..., Exclude...>>;
|
||||
|
||||
template<typename Type>
|
||||
static constexpr std::size_t index_of = type_list_index_v<std::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
|
||||
static constexpr stl::size_t index_of = type_list_index_v<stl::remove_const_t<Type>, type_list<typename Get::element_type..., typename Exclude::element_type...>>;
|
||||
|
||||
template<std::size_t... Index>
|
||||
[[nodiscard]] auto get(const typename base_type::entity_type entt, std::index_sequence<Index...>) const noexcept {
|
||||
return std::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
|
||||
}
|
||||
|
||||
template<std::size_t Curr, std::size_t Other, typename... Args>
|
||||
[[nodiscard]] auto dispatch_get(const std::tuple<typename base_type::entity_type, Args...> &curr) const {
|
||||
template<stl::size_t Curr, stl::size_t Other, typename... Args>
|
||||
[[nodiscard]] auto dispatch_get(const stl::tuple<typename base_type::entity_type, Args...> &curr) const {
|
||||
if constexpr(Curr == Other) {
|
||||
return std::forward_as_tuple(std::get<Args>(curr)...);
|
||||
return stl::forward_as_tuple(stl::get<Args>(curr)...);
|
||||
} else {
|
||||
return storage<Other>()->get_as_tuple(std::get<0>(curr));
|
||||
return storage<Other>()->get_as_tuple(stl::get<0>(curr));
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Curr, typename Func, std::size_t... Index>
|
||||
void each(Func &func, std::index_sequence<Index...>) const {
|
||||
template<stl::size_t Curr, typename Func, stl::size_t... Index>
|
||||
void each(Func func, stl::index_sequence<Index...>) const {
|
||||
for(const auto curr: storage<Curr>()->each()) {
|
||||
if(const auto entt = std::get<0>(curr); (!internal::tombstone_check_v<Get...> || (entt != tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(entt)) && ...) && base_type::none_of(entt)) {
|
||||
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
|
||||
std::apply(func, std::tuple_cat(std::make_tuple(entt), dispatch_get<Curr, Index>(curr)...));
|
||||
if(const auto entt = stl::get<0>(curr); (!internal::tombstone_check_v<Get...> || (entt != tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(entt)) && ...) && base_type::none_of(entt)) {
|
||||
if constexpr(is_applicable_v<Func, decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_view>().get({})))>) {
|
||||
stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), dispatch_get<Curr, Index>(curr)...));
|
||||
} else {
|
||||
std::apply(func, std::tuple_cat(dispatch_get<Curr, Index>(curr)...));
|
||||
stl::apply(func, stl::tuple_cat(dispatch_get<Curr, Index>(curr)...));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Func, std::size_t... Index>
|
||||
void pick_and_each(Func &func, std::index_sequence<Index...> seq) const {
|
||||
if(const auto *view = base_type::handle(); view != nullptr) {
|
||||
((view == base_type::pool_at(Index) ? each<Index>(func, seq) : void()), ...);
|
||||
template<typename Type>
|
||||
void storage_if(Type *elem) noexcept {
|
||||
if(elem != nullptr) {
|
||||
storage<index_of<typename Type::element_type>>(*elem);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = typename base_type::common_type;
|
||||
using common_type = base_type::common_type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename base_type::entity_type;
|
||||
using entity_type = base_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename base_type::size_type;
|
||||
using size_type = base_type::size_type;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Forward iterator type. */
|
||||
using iterator = typename base_type::iterator;
|
||||
using iterator = base_type::iterator;
|
||||
/*! @brief Iterable view type. */
|
||||
using iterable = iterable_adaptor<internal::extended_view_iterator<iterator, Get...>>;
|
||||
|
||||
@@ -505,8 +478,21 @@ public:
|
||||
* @param value The storage for the types to iterate.
|
||||
* @param excl The storage for the types used to filter the view.
|
||||
*/
|
||||
basic_view(std::tuple<Get &...> value, std::tuple<Exclude &...> excl = {}) noexcept
|
||||
: basic_view{std::make_from_tuple<basic_view>(std::tuple_cat(value, excl))} {}
|
||||
basic_view(stl::tuple<Get &...> value, stl::tuple<Exclude &...> excl = {}) noexcept
|
||||
: basic_view{stl::make_from_tuple<basic_view>(stl::tuple_cat(value, excl))} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a view from a convertible counterpart.
|
||||
* @tparam Args Storage types managed by the other view.
|
||||
* @param other A view to convert from.
|
||||
*/
|
||||
template<typename... Args>
|
||||
requires (!stl::same_as<basic_view, basic_view<Args...>>)
|
||||
basic_view(const basic_view<Args...> &other) noexcept
|
||||
: basic_view{} {
|
||||
(storage_if(other.template storage<typename Get::element_type>()), ...);
|
||||
(storage_if(other.template storage<typename Exclude::element_type>()), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forces a view to use a given element to drive iterations
|
||||
@@ -521,7 +507,7 @@ public:
|
||||
* @brief Forces a view to use a given element to drive iterations
|
||||
* @tparam Index Index of the element to use to drive iterations.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
template<stl::size_t Index>
|
||||
void use() noexcept {
|
||||
base_type::use(Index);
|
||||
}
|
||||
@@ -541,7 +527,7 @@ public:
|
||||
* @tparam Index Index of the storage to return.
|
||||
* @return The storage for the given index.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
template<stl::size_t Index>
|
||||
[[nodiscard]] auto *storage() const noexcept {
|
||||
if constexpr(Index < sizeof...(Get)) {
|
||||
return static_cast<element_at<Index> *>(const_cast<constness_as_t<common_type, element_at<Index>> *>(base_type::pool_at(Index)));
|
||||
@@ -566,9 +552,9 @@ public:
|
||||
* @tparam Type Type of storage to assign to the view.
|
||||
* @param elem A storage to assign to the view.
|
||||
*/
|
||||
template<std::size_t Index, typename Type>
|
||||
template<stl::size_t Index, typename Type>
|
||||
void storage(Type &elem) noexcept {
|
||||
static_assert(std::is_convertible_v<Type &, element_at<Index> &>, "Unexpected type");
|
||||
static_assert(stl::is_convertible_v<Type &, element_at<Index> &>, "Unexpected type");
|
||||
|
||||
if constexpr(Index < sizeof...(Get)) {
|
||||
base_type::pool_at(Index, &elem);
|
||||
@@ -604,14 +590,16 @@ public:
|
||||
* @param entt A valid identifier.
|
||||
* @return The elements assigned to the entity.
|
||||
*/
|
||||
template<std::size_t... Index>
|
||||
template<stl::size_t... Index>
|
||||
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
|
||||
if constexpr(sizeof...(Index) == 0) {
|
||||
return get(entt, std::index_sequence_for<Get...>{});
|
||||
return [this, entt]<auto... Idx>(stl::index_sequence<Idx...>) {
|
||||
return stl::tuple_cat(this->storage<Idx>()->get_as_tuple(entt)...);
|
||||
}(stl::index_sequence_for<Get...>{});
|
||||
} else if constexpr(sizeof...(Index) == 1) {
|
||||
return (storage<Index>()->get(entt), ...);
|
||||
} else {
|
||||
return std::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
|
||||
return stl::tuple_cat(storage<Index>()->get_as_tuple(entt)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,7 +620,11 @@ public:
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
pick_and_each(func, std::index_sequence_for<Get...>{});
|
||||
[this, &func]<auto... Index>(stl::index_sequence<Index...> seq) {
|
||||
if(const auto *view = base_type::handle(); view != nullptr) {
|
||||
((view == base_type::pool_at(Index) ? each<Index>(stl::move(func), seq) : void()), ...);
|
||||
}
|
||||
}(stl::index_sequence_for<Get...>{});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -654,8 +646,8 @@ public:
|
||||
* @param other The storage for the type to combine the view with.
|
||||
* @return A more specific view.
|
||||
*/
|
||||
template<typename OGet>
|
||||
[[nodiscard]] std::enable_if_t<std::is_base_of_v<common_type, OGet>, basic_view<get_t<Get..., OGet>, exclude_t<Exclude...>>> operator|(OGet &other) const noexcept {
|
||||
template<stl::derived_from<common_type> OGet>
|
||||
[[nodiscard]] basic_view<get_t<Get..., OGet>, exclude_t<Exclude...>> operator|(OGet &other) const noexcept {
|
||||
return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
|
||||
}
|
||||
|
||||
@@ -666,10 +658,10 @@ public:
|
||||
* @param other The view to combine with.
|
||||
* @return A more specific view.
|
||||
*/
|
||||
template<typename... OGet, typename... OExclude>
|
||||
template<stl::derived_from<common_type>... OGet, stl::derived_from<common_type>... OExclude>
|
||||
[[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
|
||||
return internal::view_pack<basic_view<get_t<Get..., OGet...>, exclude_t<Exclude..., OExclude...>>>(
|
||||
*this, other, std::index_sequence_for<Get...>{}, std::index_sequence_for<Exclude...>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
|
||||
*this, other, stl::index_sequence_for<Get...>{}, stl::index_sequence_for<Exclude...>{}, stl::index_sequence_for<OGet...>{}, stl::index_sequence_for<OExclude...>{});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -679,12 +671,10 @@ public:
|
||||
* @tparam Type Common type among all storage types.
|
||||
* @tparam Policy Storage policy.
|
||||
*/
|
||||
template<typename Type, deletion_policy Policy>
|
||||
template<cvref_unqualified Type, deletion_policy Policy>
|
||||
class basic_storage_view {
|
||||
static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>, "Unexpected type");
|
||||
|
||||
protected:
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
basic_storage_view() noexcept = default;
|
||||
|
||||
basic_storage_view(const Type *value) noexcept
|
||||
@@ -697,15 +687,15 @@ public:
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = Type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename common_type::entity_type;
|
||||
using entity_type = common_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = std::conditional_t<Policy == deletion_policy::in_place, internal::view_iterator<common_type, true, 1u, 0u>, typename common_type::iterator>;
|
||||
using iterator = stl::conditional_t<Policy == deletion_policy::in_place, internal::view_iterator<common_type, true, 1u, 0u>, typename common_type::iterator>;
|
||||
/*! @brief Reverse iterator type. */
|
||||
using reverse_iterator = std::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
|
||||
using reverse_iterator = stl::conditional_t<Policy == deletion_policy::in_place, void, typename common_type::reverse_iterator>;
|
||||
|
||||
/**
|
||||
* @brief Returns the leading storage of a view, if any.
|
||||
@@ -717,11 +707,10 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Returns the number of entities that have the given element.
|
||||
* @tparam Pol Dummy template parameter used for sfinae purposes only.
|
||||
* @return Number of entities that have the given element.
|
||||
*/
|
||||
template<typename..., deletion_policy Pol = Policy>
|
||||
[[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, size_type> size() const noexcept {
|
||||
[[nodiscard]] size_type size() const noexcept
|
||||
requires (Policy != deletion_policy::in_place) {
|
||||
if constexpr(Policy == deletion_policy::swap_and_pop) {
|
||||
return leading ? leading->size() : size_type{};
|
||||
} else {
|
||||
@@ -732,21 +721,19 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Estimates the number of entities iterated by the view.
|
||||
* @tparam Pol Dummy template parameter used for sfinae purposes only.
|
||||
* @return Estimated number of entities iterated by the view.
|
||||
*/
|
||||
template<typename..., deletion_policy Pol = Policy>
|
||||
[[nodiscard]] std::enable_if_t<Pol == deletion_policy::in_place, size_type> size_hint() const noexcept {
|
||||
[[nodiscard]] size_type size_hint() const noexcept
|
||||
requires (Policy == deletion_policy::in_place) {
|
||||
return leading ? leading->size() : size_type{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a view is empty.
|
||||
* @tparam Pol Dummy template parameter used for sfinae purposes only.
|
||||
* @return True if the view is empty, false otherwise.
|
||||
*/
|
||||
template<typename..., deletion_policy Pol = Policy>
|
||||
[[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, bool> empty() const noexcept {
|
||||
[[nodiscard]] bool empty() const noexcept
|
||||
requires (Policy != deletion_policy::in_place) {
|
||||
if constexpr(Policy == deletion_policy::swap_and_pop) {
|
||||
return !leading || leading->empty();
|
||||
} else {
|
||||
@@ -791,23 +778,21 @@ public:
|
||||
*
|
||||
* If the view is empty, the returned iterator will be equal to `rend()`.
|
||||
*
|
||||
* @tparam Pol Dummy template parameter used for sfinae purposes only.
|
||||
* @return An iterator to the first entity of the reversed view.
|
||||
*/
|
||||
template<typename..., deletion_policy Pol = Policy>
|
||||
[[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator> rbegin() const noexcept {
|
||||
[[nodiscard]] reverse_iterator rbegin() const noexcept
|
||||
requires (Policy != deletion_policy::in_place) {
|
||||
return leading ? leading->rbegin() : reverse_iterator{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator that is past the last entity of the reversed
|
||||
* view.
|
||||
* @tparam Pol Dummy template parameter used for sfinae purposes only.
|
||||
* @return An iterator to the entity following the last entity of the
|
||||
* reversed view.
|
||||
*/
|
||||
template<typename..., deletion_policy Pol = Policy>
|
||||
[[nodiscard]] std::enable_if_t<Pol != deletion_policy::in_place, reverse_iterator> rend() const noexcept {
|
||||
[[nodiscard]] reverse_iterator rend() const noexcept
|
||||
requires (Policy != deletion_policy::in_place) {
|
||||
if constexpr(Policy == deletion_policy::swap_and_pop) {
|
||||
return leading ? leading->rend() : reverse_iterator{};
|
||||
} else {
|
||||
@@ -913,21 +898,27 @@ class basic_view<get_t<Get>, exclude_t<>>
|
||||
: public basic_storage_view<typename Get::base_type, Get::storage_policy> {
|
||||
using base_type = basic_storage_view<typename Get::base_type, Get::storage_policy>;
|
||||
|
||||
void storage_if(Get *value) noexcept {
|
||||
if(value != nullptr) {
|
||||
storage(*value);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Common type among all storage types. */
|
||||
using common_type = typename base_type::common_type;
|
||||
using common_type = base_type::common_type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename base_type::entity_type;
|
||||
using entity_type = base_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename base_type::size_type;
|
||||
using size_type = base_type::size_type;
|
||||
/*! @brief Signed integer type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename base_type::iterator;
|
||||
using iterator = base_type::iterator;
|
||||
/*! @brief Reverse iterator type. */
|
||||
using reverse_iterator = typename base_type::reverse_iterator;
|
||||
using reverse_iterator = base_type::reverse_iterator;
|
||||
/*! @brief Iterable view type. */
|
||||
using iterable = std::conditional_t<Get::storage_policy == deletion_policy::in_place, iterable_adaptor<internal::extended_view_iterator<iterator, Get>>, decltype(std::declval<Get>().each())>;
|
||||
using iterable = stl::conditional_t<Get::storage_policy == deletion_policy::in_place, iterable_adaptor<internal::extended_view_iterator<iterator, Get>>, decltype(stl::declval<Get>().each())>;
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid views. */
|
||||
basic_view() noexcept
|
||||
@@ -945,17 +936,29 @@ public:
|
||||
* @brief Constructs a view from a storage class.
|
||||
* @param value The storage for the type to iterate.
|
||||
*/
|
||||
basic_view(std::tuple<Get &> value, std::tuple<> = {}) noexcept
|
||||
: basic_view{std::get<0>(value)} {}
|
||||
basic_view(stl::tuple<Get &> value, stl::tuple<> = {}) noexcept
|
||||
: basic_view{stl::get<0>(value)} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a view from a convertible counterpart.
|
||||
* @tparam Args Storage types managed by the other view.
|
||||
* @param other A view to convert from.
|
||||
*/
|
||||
template<typename... Args>
|
||||
requires (!stl::same_as<basic_view, basic_view<Args...>>)
|
||||
basic_view(const basic_view<Args...> &other) noexcept
|
||||
: base_type{} {
|
||||
storage_if(other.template storage<typename Get::element_type>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the storage for a given element type, if any.
|
||||
* @tparam Type Type of element of which to return the storage.
|
||||
* @return The storage for the given element type.
|
||||
*/
|
||||
template<typename Type = typename Get::element_type>
|
||||
template<typename Type = Get::element_type>
|
||||
[[nodiscard]] auto *storage() const noexcept {
|
||||
static_assert(std::is_same_v<std::remove_const_t<Type>, typename Get::element_type>, "Invalid element type");
|
||||
static_assert(stl::is_same_v<stl::remove_const_t<Type>, typename Get::element_type>, "Invalid element type");
|
||||
return storage<0>();
|
||||
}
|
||||
|
||||
@@ -964,7 +967,7 @@ public:
|
||||
* @tparam Index Index of the storage to return.
|
||||
* @return The storage for the given index.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
template<stl::size_t Index>
|
||||
[[nodiscard]] auto *storage() const noexcept {
|
||||
static_assert(Index == 0u, "Index out of bounds");
|
||||
return static_cast<Get *>(const_cast<constness_as_t<common_type, Get> *>(base_type::handle()));
|
||||
@@ -983,7 +986,7 @@ public:
|
||||
* @tparam Index Index of the storage to assign to the view.
|
||||
* @param elem A storage to assign to the view.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
template<stl::size_t Index>
|
||||
void storage(Get &elem) noexcept {
|
||||
static_assert(Index == 0u, "Index out of bounds");
|
||||
*this = basic_view{elem};
|
||||
@@ -1014,7 +1017,7 @@ public:
|
||||
*/
|
||||
template<typename Elem>
|
||||
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
|
||||
static_assert(std::is_same_v<std::remove_const_t<Elem>, typename Get::element_type>, "Invalid element type");
|
||||
static_assert(stl::is_same_v<stl::remove_const_t<Elem>, typename Get::element_type>, "Invalid element type");
|
||||
return get<0>(entt);
|
||||
}
|
||||
|
||||
@@ -1024,7 +1027,7 @@ public:
|
||||
* @param entt A valid identifier.
|
||||
* @return The element assigned to the entity.
|
||||
*/
|
||||
template<std::size_t... Index>
|
||||
template<stl::size_t... Index>
|
||||
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
|
||||
if constexpr(sizeof...(Index) == 0) {
|
||||
return storage()->get_as_tuple(entt);
|
||||
@@ -1042,7 +1045,7 @@ public:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(const entity_type, Type &);
|
||||
* void(typename Type &);
|
||||
* void(Type &);
|
||||
* @endcode
|
||||
*
|
||||
* @tparam Func Type of the function object to invoke.
|
||||
@@ -1050,12 +1053,12 @@ public:
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_view>().get({})))>) {
|
||||
if constexpr(is_applicable_v<Func, decltype(stl::tuple_cat(stl::tuple<entity_type>{}, stl::declval<basic_view>().get({})))>) {
|
||||
for(const auto pack: each()) {
|
||||
std::apply(func, pack);
|
||||
stl::apply(func, pack);
|
||||
}
|
||||
} else if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) {
|
||||
if constexpr(std::is_void_v<typename Get::value_type>) {
|
||||
if constexpr(stl::is_void_v<typename Get::value_type>) {
|
||||
for(size_type pos = base_type::size(); pos; --pos) {
|
||||
func();
|
||||
}
|
||||
@@ -1070,7 +1073,7 @@ public:
|
||||
static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy");
|
||||
|
||||
for(const auto pack: each()) {
|
||||
std::apply([&func](const auto, auto &&...elem) { func(std::forward<decltype(elem)>(elem)...); }, pack);
|
||||
stl::apply([&func](const auto, auto &&...elem) { func(stl::forward<decltype(elem)>(elem)...); }, pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1099,8 +1102,8 @@ public:
|
||||
* @param other The storage for the type to combine the view with.
|
||||
* @return A more specific view.
|
||||
*/
|
||||
template<typename OGet>
|
||||
[[nodiscard]] std::enable_if_t<std::is_base_of_v<common_type, OGet>, basic_view<get_t<Get, OGet>, exclude_t<>>> operator|(OGet &other) const noexcept {
|
||||
template<stl::derived_from<common_type> OGet>
|
||||
[[nodiscard]] basic_view<get_t<Get, OGet>, exclude_t<>> operator|(OGet &other) const noexcept {
|
||||
return *this | basic_view<get_t<OGet>, exclude_t<>>{other};
|
||||
}
|
||||
|
||||
@@ -1111,10 +1114,10 @@ public:
|
||||
* @param other The view to combine with.
|
||||
* @return A more specific view.
|
||||
*/
|
||||
template<typename... OGet, typename... OExclude>
|
||||
template<stl::derived_from<common_type>... OGet, stl::derived_from<common_type>... OExclude>
|
||||
[[nodiscard]] auto operator|(const basic_view<get_t<OGet...>, exclude_t<OExclude...>> &other) const noexcept {
|
||||
return internal::view_pack<basic_view<get_t<Get, OGet...>, exclude_t<OExclude...>>>(
|
||||
*this, other, std::index_sequence_for<Get>{}, std::index_sequence_for<>{}, std::index_sequence_for<OGet...>{}, std::index_sequence_for<OExclude...>{});
|
||||
*this, other, stl::index_sequence_for<Get>{}, stl::index_sequence_for<>{}, stl::index_sequence_for<OGet...>{}, stl::index_sequence_for<OExclude...>{});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1132,7 +1135,7 @@ basic_view(Type &...storage) -> basic_view<get_t<Type...>, exclude_t<>>;
|
||||
* @tparam Exclude Types of elements used to filter the view.
|
||||
*/
|
||||
template<typename... Get, typename... Exclude>
|
||||
basic_view(std::tuple<Get &...>, std::tuple<Exclude &...> = {}) -> basic_view<get_t<Get...>, exclude_t<Exclude...>>;
|
||||
basic_view(stl::tuple<Get &...>, stl::tuple<Exclude &...> = {}) -> basic_view<get_t<Get...>, exclude_t<Exclude...>>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/*! @brief `EnTT` default namespace. */
|
||||
namespace entt {}
|
||||
|
||||
/*! @brief Custom `EnTT` namespace for the standard template library. */
|
||||
namespace entt::stl {}
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include "config/config.h"
|
||||
#include "config/macro.h"
|
||||
@@ -10,9 +13,9 @@ namespace entt {}
|
||||
#include "container/table.hpp"
|
||||
#include "core/algorithm.hpp"
|
||||
#include "core/any.hpp"
|
||||
#include "core/attribute.h"
|
||||
#include "core/bit.hpp"
|
||||
#include "core/compressed_pair.hpp"
|
||||
#include "core/concepts.hpp"
|
||||
#include "core/enum.hpp"
|
||||
#include "core/family.hpp"
|
||||
#include "core/hashed_string.hpp"
|
||||
@@ -66,4 +69,25 @@ namespace entt {}
|
||||
#include "signal/dispatcher.hpp"
|
||||
#include "signal/emitter.hpp"
|
||||
#include "signal/sigh.hpp"
|
||||
#include "stl/algorithm.hpp"
|
||||
#include "stl/array.hpp"
|
||||
#include "stl/atomic.hpp"
|
||||
#include "stl/bit.hpp"
|
||||
#include "stl/cmath.hpp"
|
||||
#include "stl/concepts.hpp"
|
||||
#include "stl/cstddef.hpp"
|
||||
#include "stl/cstdint.hpp"
|
||||
#include "stl/functional.hpp"
|
||||
#include "stl/ios.hpp"
|
||||
#include "stl/iterator.hpp"
|
||||
#include "stl/limits.hpp"
|
||||
#include "stl/memory.hpp"
|
||||
#include "stl/ostream.hpp"
|
||||
#include "stl/sstream.hpp"
|
||||
#include "stl/string.hpp"
|
||||
#include "stl/string_view.hpp"
|
||||
#include "stl/tuple.hpp"
|
||||
#include "stl/type_traits.hpp"
|
||||
#include "stl/utility.hpp"
|
||||
#include "stl/vector.hpp"
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
@@ -1,42 +1,43 @@
|
||||
#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 "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
class edge_iterator {
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
|
||||
void find_next() noexcept {
|
||||
for(; pos != last && !it[static_cast<typename It::difference_type>(pos)]; pos += offset) {}
|
||||
for(; pos != last && !it[static_cast<It::difference_type>(pos)]; pos += offset) {}
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = std::pair<size_type, size_type>;
|
||||
using value_type = stl::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;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::forward_iterator_tag;
|
||||
|
||||
constexpr edge_iterator() noexcept = default;
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||
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)},
|
||||
: it{stl::move(base)},
|
||||
vert{vertices},
|
||||
pos{from},
|
||||
last{to},
|
||||
@@ -60,11 +61,12 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::make_pair<size_type>(pos / vert, pos % vert);
|
||||
return stl::make_pair<size_type>(pos / vert, pos % vert);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
friend constexpr bool operator==(const edge_iterator<Type> &, const edge_iterator<Type> &) noexcept;
|
||||
[[nodiscard]] constexpr bool operator==(const edge_iterator &other) const noexcept {
|
||||
return pos == other.pos;
|
||||
}
|
||||
|
||||
private:
|
||||
It it{};
|
||||
@@ -74,16 +76,6 @@ private:
|
||||
size_type offset{};
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] constexpr bool operator==(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
|
||||
return lhs.pos == rhs.pos;
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
[[nodiscard]] constexpr bool operator!=(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
@@ -92,22 +84,21 @@ template<typename Container>
|
||||
* @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>
|
||||
template<stl::derived_from<directed_tag> 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>>;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, stl::size_t>, "Invalid value type");
|
||||
using container_type = stl::vector<stl::size_t, typename alloc_traits::template rebind_alloc<stl::size_t>>;
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Vertex type. */
|
||||
using vertex_type = size_type;
|
||||
/*! @brief Edge type. */
|
||||
using edge_type = std::pair<vertex_type, vertex_type>;
|
||||
using edge_type = stl::pair<vertex_type, vertex_type>;
|
||||
/*! @brief Vertex iterator type. */
|
||||
using vertex_iterator = iota_iterator<vertex_type>;
|
||||
/*! @brief Edge iterator type. */
|
||||
@@ -162,7 +153,7 @@ public:
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator)
|
||||
: matrix{std::move(other.matrix), allocator},
|
||||
: matrix{stl::move(other.matrix), allocator},
|
||||
vert{other.vert} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
@@ -185,7 +176,7 @@ public:
|
||||
* @param other Adjacency matrix to exchange the content with.
|
||||
*/
|
||||
void swap(adjacency_matrix &other) noexcept {
|
||||
using std::swap;
|
||||
using stl::swap;
|
||||
swap(matrix, other.matrix);
|
||||
swap(vert, other.vert);
|
||||
}
|
||||
@@ -289,16 +280,16 @@ public:
|
||||
* 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) {
|
||||
stl::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>) {
|
||||
if constexpr(stl::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);
|
||||
const auto inserted = !stl::exchange(matrix[pos], 1u);
|
||||
return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted};
|
||||
}
|
||||
|
||||
@@ -311,13 +302,13 @@ public:
|
||||
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>) {
|
||||
if constexpr(stl::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);
|
||||
return stl::exchange(matrix[pos], 0u);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef ENTT_GRAPH_DOT_HPP
|
||||
#define ENTT_GRAPH_DOT_HPP
|
||||
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/ostream.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
@@ -10,16 +10,14 @@ 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>) {
|
||||
template<typename Graph>
|
||||
requires stl::derived_from<typename Graph::graph_category, directed_tag>
|
||||
void dot(stl::ostream &out, const Graph &graph, stl::invocable<stl::ostream &, typename Graph::vertex_type> auto writer) {
|
||||
if constexpr(stl::same_as<typename Graph::graph_category, undirected_tag>) {
|
||||
out << "graph{";
|
||||
} else {
|
||||
out << "digraph{";
|
||||
@@ -32,7 +30,7 @@ void dot(std::ostream &out, const Graph &graph, Writer writer) {
|
||||
}
|
||||
|
||||
for(auto [lhs, rhs]: graph.edges()) {
|
||||
if constexpr(std::is_same_v<typename Graph::graph_category, undirected_tag>) {
|
||||
if constexpr(stl::same_as<typename Graph::graph_category, undirected_tag>) {
|
||||
out << lhs << "--" << rhs << ";";
|
||||
} else {
|
||||
out << lhs << "->" << rhs << ";";
|
||||
@@ -49,7 +47,7 @@ void dot(std::ostream &out, const Graph &graph, Writer writer) {
|
||||
* @param graph The graph to output.
|
||||
*/
|
||||
template<typename Graph>
|
||||
void dot(std::ostream &out, const Graph &graph) {
|
||||
void dot(stl::ostream &out, const Graph &graph) {
|
||||
return dot(out, graph, [](auto &&...) {});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
#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 "../stl/algorithm.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "adjacency_matrix.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
@@ -27,12 +27,12 @@ namespace entt {
|
||||
*/
|
||||
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<>, 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<>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, ro_rw_container_type>>>;
|
||||
using adjacency_matrix_type = adjacency_matrix<directed_tag, typename alloc_traits::template rebind_alloc<std::size_t>>;
|
||||
using alloc_traits = stl::allocator_traits<Allocator>;
|
||||
static_assert(stl::is_same_v<typename alloc_traits::value_type, id_type>, "Invalid value type");
|
||||
using task_container_type = dense_set<id_type, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<id_type>>;
|
||||
using ro_rw_container_type = stl::vector<stl::pair<stl::size_t, bool>, typename alloc_traits::template rebind_alloc<stl::pair<stl::size_t, bool>>>;
|
||||
using deps_container_type = dense_map<id_type, ro_rw_container_type, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc<stl::pair<const id_type, ro_rw_container_type>>>;
|
||||
using adjacency_matrix_type = adjacency_matrix<directed_tag, typename alloc_traits::template rebind_alloc<stl::size_t>>;
|
||||
|
||||
void emplace(const id_type res, const bool is_rw) {
|
||||
ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
|
||||
@@ -55,7 +55,7 @@ class basic_flow {
|
||||
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) {
|
||||
} else if(const auto next = stl::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);
|
||||
@@ -68,7 +68,7 @@ class basic_flow {
|
||||
}
|
||||
} else {
|
||||
// ro item (first iteration only)
|
||||
if(const auto next = std::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
|
||||
if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
|
||||
for(; it != next; ++it) {
|
||||
matrix.insert(it->first, next->first);
|
||||
}
|
||||
@@ -83,9 +83,9 @@ class basic_flow {
|
||||
void transitive_closure(adjacency_matrix_type &matrix) const {
|
||||
const auto length = matrix.size();
|
||||
|
||||
for(std::size_t vk{}; vk < length; ++vk) {
|
||||
for(std::size_t vi{}; vi < length; ++vi) {
|
||||
for(std::size_t vj{}; vj < length; ++vj) {
|
||||
for(stl::size_t vk{}; vk < length; ++vk) {
|
||||
for(stl::size_t vi{}; vi < length; ++vi) {
|
||||
for(stl::size_t vj{}; vj < length; ++vj) {
|
||||
if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) {
|
||||
matrix.insert(vi, vj);
|
||||
}
|
||||
@@ -97,14 +97,14 @@ class basic_flow {
|
||||
void transitive_reduction(adjacency_matrix_type &matrix) const {
|
||||
const auto length = matrix.size();
|
||||
|
||||
for(std::size_t vert{}; vert < length; ++vert) {
|
||||
for(stl::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) {
|
||||
for(stl::size_t vj{}; vj < length; ++vj) {
|
||||
for(stl::size_t vi{}; vi < length; ++vi) {
|
||||
if(matrix.contains(vi, vj)) {
|
||||
for(std::size_t vk{}; vk < length; ++vk) {
|
||||
for(stl::size_t vk{}; vk < length; ++vk) {
|
||||
if(matrix.contains(vj, vk)) {
|
||||
matrix.erase(vi, vk);
|
||||
}
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
/*! @brief Iterable task list. */
|
||||
using iterable = iterable_adaptor<typename task_container_type::const_iterator>;
|
||||
/*! @brief Adjacency matrix type. */
|
||||
@@ -161,8 +161,8 @@ public:
|
||||
*/
|
||||
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},
|
||||
vertices{stl::move(other.vertices), allocator},
|
||||
deps{stl::move(other.deps), allocator},
|
||||
sync_on{other.sync_on} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
@@ -185,11 +185,11 @@ public:
|
||||
* @param other Flow builder to exchange the content with.
|
||||
*/
|
||||
void swap(basic_flow &other) noexcept {
|
||||
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);
|
||||
using stl::swap;
|
||||
swap(index, other.index);
|
||||
swap(vertices, other.vertices);
|
||||
swap(deps, other.deps);
|
||||
swap(sync_on, other.sync_on);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +206,7 @@ public:
|
||||
* @return The requested identifier.
|
||||
*/
|
||||
[[nodiscard]] id_type operator[](const size_type pos) const {
|
||||
return vertices.cbegin()[static_cast<typename task_container_type::difference_type>(pos)];
|
||||
return vertices.cbegin()[static_cast<task_container_type::difference_type>(pos)];
|
||||
}
|
||||
|
||||
/*! @brief Clears the flow builder. */
|
||||
@@ -283,14 +283,11 @@ public:
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
basic_flow &ro(stl::input_iterator auto first, stl::input_iterator auto last) {
|
||||
for(; first != last; ++first) {
|
||||
emplace(*first, false);
|
||||
}
|
||||
@@ -310,14 +307,11 @@ public:
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
basic_flow &rw(stl::input_iterator auto first, stl::input_iterator auto last) {
|
||||
for(; first != last; ++first) {
|
||||
emplace(*first, true);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef ENTT_GRAPH_FWD_HPP
|
||||
#define ENTT_GRAPH_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
@@ -13,10 +14,10 @@ struct directed_tag {};
|
||||
/*! @brief Directed graph category tag. */
|
||||
struct undirected_tag: directed_tag {};
|
||||
|
||||
template<typename, typename = std::allocator<std::size_t>>
|
||||
template<stl::derived_from<directed_tag>, typename = stl::allocator<stl::size_t>>
|
||||
class adjacency_matrix;
|
||||
|
||||
template<typename = std::allocator<id_type>>
|
||||
template<typename = stl::allocator<id_type>>
|
||||
class basic_flow;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef ENTT_LOCATOR_LOCATOR_HPP
|
||||
#define ENTT_LOCATOR_LOCATOR_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
@@ -27,7 +28,7 @@ template<typename Service>
|
||||
class locator final {
|
||||
class service_handle {
|
||||
friend class locator<Service>;
|
||||
std::shared_ptr<Service> value{};
|
||||
stl::shared_ptr<Service> value{};
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -84,9 +85,10 @@ public:
|
||||
* @param args Parameters to use to construct the fallback service.
|
||||
* @return A reference to a valid service.
|
||||
*/
|
||||
template<typename Type = Service, typename... Args>
|
||||
template<stl::derived_from<Service> Type = Service, typename... Args>
|
||||
requires stl::constructible_from<Type, Args...>
|
||||
[[nodiscard]] static Service &value_or(Args &&...args) {
|
||||
return service ? *service : emplace<Type>(std::forward<Args>(args)...);
|
||||
return service ? *service : emplace<Type>(stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,24 +98,25 @@ public:
|
||||
* @param args Parameters to use to construct the service.
|
||||
* @return A reference to a valid service.
|
||||
*/
|
||||
template<typename Type = Service, typename... Args>
|
||||
template<stl::derived_from<Service> Type = Service, typename... Args>
|
||||
requires stl::constructible_from<Type, Args...>
|
||||
static Service &emplace(Args &&...args) {
|
||||
service = std::make_shared<Type>(std::forward<Args>(args)...);
|
||||
service = stl::make_shared<Type>(stl::forward<Args>(args)...);
|
||||
return *service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets or replaces a service using a given allocator.
|
||||
* @tparam Type 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.
|
||||
*/
|
||||
template<typename Type = Service, typename Allocator, typename... Args>
|
||||
static Service &emplace(std::allocator_arg_t, Allocator alloc, Args &&...args) {
|
||||
service = std::allocate_shared<Type>(alloc, std::forward<Args>(args)...);
|
||||
template<stl::derived_from<Service> Type = Service, typename... Args>
|
||||
requires stl::constructible_from<Type, Args...>
|
||||
static Service &emplace(stl::allocator_arg_t, auto alloc, Args &&...args) {
|
||||
service = stl::allocate_shared<Type>(alloc, stl::forward<Args>(args)...);
|
||||
return *service;
|
||||
}
|
||||
|
||||
@@ -142,15 +145,15 @@ public:
|
||||
* @param elem A pointer to a service to manage.
|
||||
* @param deleter A deleter to use to destroy the service.
|
||||
*/
|
||||
template<typename Type, typename Deleter = std::default_delete<Type>>
|
||||
template<stl::derived_from<Service> Type, typename Deleter = stl::default_delete<Type>>
|
||||
static void reset(Type *elem, Deleter deleter = {}) {
|
||||
service = std::shared_ptr<Service>{elem, std::move(deleter)};
|
||||
service = stl::shared_ptr<Service>{elem, stl::move(deleter)};
|
||||
}
|
||||
|
||||
private:
|
||||
// std::shared_ptr because of its type erased allocator which is useful here
|
||||
// stl::shared_ptr because of its type erased allocator which is useful here
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
inline static std::shared_ptr<Service> service{};
|
||||
inline static stl::shared_ptr<Service> service{};
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -3,53 +3,54 @@
|
||||
#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 "../core/concepts.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "context.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "meta.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct fixed_size_sequence_container: std::true_type {};
|
||||
template<typename Type>
|
||||
struct sequence_container_extent: integral_constant<meta_dynamic_extent> {};
|
||||
|
||||
template<typename Type>
|
||||
struct fixed_size_sequence_container<Type, std::void_t<decltype(&Type::clear)>>: std::false_type {};
|
||||
requires is_complete_v<stl::tuple_size<Type>>
|
||||
struct sequence_container_extent<Type>: integral_constant<stl::tuple_size_v<Type>> {};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool fixed_size_sequence_container_v = fixed_size_sequence_container<Type>::value;
|
||||
|
||||
template<typename, typename = void>
|
||||
struct key_only_associative_container: std::true_type {};
|
||||
inline constexpr stl::size_t sequence_container_extent_v = sequence_container_extent<Type>::value;
|
||||
|
||||
template<typename Type>
|
||||
struct key_only_associative_container<Type, std::void_t<typename Type::mapped_type>>: std::false_type {};
|
||||
concept meta_sequence_container_like = requires(Type elem) {
|
||||
typename Type::value_type;
|
||||
typename Type::iterator;
|
||||
requires entt::stl::forward_iterator<typename Type::iterator>;
|
||||
{ elem.begin() } -> stl::same_as<typename Type::iterator>;
|
||||
{ elem.end() } -> stl::same_as<typename Type::iterator>;
|
||||
requires !requires { typename Type::key_type; };
|
||||
requires !requires { elem.substr(); };
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool key_only_associative_container_v = key_only_associative_container<Type>::value;
|
||||
|
||||
template<typename, typename = void>
|
||||
struct reserve_aware_container: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct reserve_aware_container<Type, std::void_t<decltype(&Type::reserve)>>: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool reserve_aware_container_v = reserve_aware_container<Type>::value;
|
||||
concept meta_associative_container_like = requires(Type value) {
|
||||
typename Type::key_type;
|
||||
typename Type::value_type;
|
||||
typename Type::iterator;
|
||||
requires entt::stl::forward_iterator<typename Type::iterator>;
|
||||
{ value.begin() } -> stl::same_as<typename Type::iterator>;
|
||||
{ value.end() } -> stl::same_as<typename Type::iterator>;
|
||||
value.find(stl::declval<typename Type::key_type>());
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
@@ -58,17 +59,15 @@ inline constexpr bool reserve_aware_container_v = reserve_aware_container<Type>:
|
||||
* @brief General purpose implementation of meta sequence container traits.
|
||||
* @tparam Type Type of underlying sequence container.
|
||||
*/
|
||||
template<typename Type>
|
||||
template<cvref_unqualified Type>
|
||||
struct basic_meta_sequence_container_traits {
|
||||
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
|
||||
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename meta_sequence_container::size_type;
|
||||
using size_type = meta_sequence_container::size_type;
|
||||
/*! @brief Meta iterator type. */
|
||||
using iterator = typename meta_sequence_container::iterator;
|
||||
using iterator = meta_sequence_container::iterator;
|
||||
|
||||
/*! @brief True in case of key-only containers, false otherwise. */
|
||||
static constexpr bool fixed_size = internal::fixed_size_sequence_container_v<Type>;
|
||||
/*! @brief Number of elements, or `meta_dynamic_extent` if dynamic. */
|
||||
static constexpr stl::size_t extent = internal::sequence_container_extent_v<Type>;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a container.
|
||||
@@ -85,11 +84,11 @@ struct basic_meta_sequence_container_traits {
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] static bool clear([[maybe_unused]] void *container) {
|
||||
if constexpr(fixed_size) {
|
||||
return false;
|
||||
} else {
|
||||
if constexpr(requires(Type elem) { elem.clear(); }) {
|
||||
static_cast<Type *>(container)->clear();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +99,7 @@ struct basic_meta_sequence_container_traits {
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
|
||||
if constexpr(internal::reserve_aware_container_v<Type>) {
|
||||
if constexpr(requires(Type elem) { elem.reserve(sz); }) {
|
||||
static_cast<Type *>(container)->reserve(sz);
|
||||
return true;
|
||||
} else {
|
||||
@@ -115,36 +114,27 @@ struct basic_meta_sequence_container_traits {
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
|
||||
if constexpr(fixed_size || !std::is_default_constructible_v<typename Type::value_type>) {
|
||||
return false;
|
||||
} else {
|
||||
if constexpr(stl::is_default_constructible_v<typename Type::value_type> && requires(Type elem) { elem.resize(sz); }) {
|
||||
static_cast<Type *>(container)->resize(sz);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a possibly const iterator to the beginning.
|
||||
* @brief Returns a possibly const iterator to the beginning or the end.
|
||||
* @param area The context to pass to the newly created iterator.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param as_const Const opaque pointer fallback.
|
||||
* @return An iterator to the first element of the container.
|
||||
* @param end False to get a pointer that is past the last element.
|
||||
* @return An iterator to the first or past the last element of the
|
||||
* container.
|
||||
*/
|
||||
static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
|
||||
return (container != nullptr) ? iterator{area, static_cast<Type *>(container)->begin()}
|
||||
: iterator{area, static_cast<const Type *>(as_const)->begin()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a possibly const iterator to the end.
|
||||
* @param area The context to pass to the newly created iterator.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param as_const Const opaque pointer fallback.
|
||||
* @return An iterator that is past the last element of the container.
|
||||
*/
|
||||
static iterator end(const meta_ctx &area, void *container, const void *as_const) {
|
||||
return (container != nullptr) ? iterator{area, static_cast<Type *>(container)->end()}
|
||||
: iterator{area, static_cast<const Type *>(as_const)->end()};
|
||||
static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) {
|
||||
return (container == nullptr)
|
||||
? iterator{area, end ? static_cast<const Type *>(as_const)->cend() : static_cast<const Type *>(as_const)->cbegin()}
|
||||
: iterator{area, end ? static_cast<Type *>(container)->end() : static_cast<Type *>(container)->begin()};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,13 +150,13 @@ struct basic_meta_sequence_container_traits {
|
||||
* @return A possibly invalid iterator to the inserted element.
|
||||
*/
|
||||
[[nodiscard]] static iterator insert([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const void *value, [[maybe_unused]] const void *cref, [[maybe_unused]] const iterator &it) {
|
||||
if constexpr(fixed_size) {
|
||||
return iterator{};
|
||||
} else {
|
||||
if constexpr(requires(Type elem, typename Type::const_iterator iter, Type::value_type instance) { elem.insert(iter, instance); }) {
|
||||
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
|
||||
return {area, static_cast<Type *>(container)->insert(
|
||||
non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()),
|
||||
(value != nullptr) ? *static_cast<const typename Type::value_type *>(value) : *static_cast<const std::remove_reference_t<typename Type::const_reference> *>(cref))};
|
||||
(value != nullptr) ? *static_cast<const Type::value_type *>(value) : *static_cast<const stl::remove_reference_t<typename Type::const_reference> *>(cref))};
|
||||
} else {
|
||||
return iterator{};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,11 +168,11 @@ struct basic_meta_sequence_container_traits {
|
||||
* @return A possibly invalid iterator following the last removed element.
|
||||
*/
|
||||
[[nodiscard]] static iterator erase([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) {
|
||||
if constexpr(fixed_size) {
|
||||
return iterator{};
|
||||
} else {
|
||||
if constexpr(requires(Type elem, typename Type::const_iterator iter) { elem.erase(iter); }) {
|
||||
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
|
||||
return {area, static_cast<Type *>(container)->erase(non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()))};
|
||||
} else {
|
||||
return iterator{};
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -191,17 +181,15 @@ struct basic_meta_sequence_container_traits {
|
||||
* @brief General purpose implementation of meta associative container traits.
|
||||
* @tparam Type Type of underlying associative container.
|
||||
*/
|
||||
template<typename Type>
|
||||
template<cvref_unqualified Type>
|
||||
struct basic_meta_associative_container_traits {
|
||||
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
|
||||
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename meta_associative_container::size_type;
|
||||
using size_type = meta_associative_container::size_type;
|
||||
/*! @brief Meta iterator type. */
|
||||
using iterator = typename meta_associative_container::iterator;
|
||||
using iterator = meta_associative_container::iterator;
|
||||
|
||||
/*! @brief True in case of key-only containers, false otherwise. */
|
||||
static constexpr bool key_only = internal::key_only_associative_container_v<Type>;
|
||||
static constexpr bool key_only = !requires { typename Type::mapped_type; };
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a container.
|
||||
@@ -229,7 +217,7 @@ struct basic_meta_associative_container_traits {
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
|
||||
if constexpr(internal::reserve_aware_container_v<Type>) {
|
||||
if constexpr(requires(Type elem) { elem.reserve(sz); }) {
|
||||
static_cast<Type *>(container)->reserve(sz);
|
||||
return true;
|
||||
} else {
|
||||
@@ -238,27 +226,18 @@ struct basic_meta_associative_container_traits {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a possibly const iterator to the beginning.
|
||||
* @brief Returns a possibly const iterator to the beginning or the end.
|
||||
* @param area The context to pass to the newly created iterator.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param as_const Const opaque pointer fallback.
|
||||
* @return An iterator to the first element of the container.
|
||||
* @param end False to get a pointer that is past the last element.
|
||||
* @return An iterator to the first or past the last element of the
|
||||
* container.
|
||||
*/
|
||||
static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
|
||||
return (container != nullptr) ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->begin()}
|
||||
: iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->begin()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a possibly const iterator to the end.
|
||||
* @param area The context to pass to the newly created iterator.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param as_const Const opaque pointer fallback.
|
||||
* @return An iterator that is past the last element of the container.
|
||||
*/
|
||||
static iterator end(const meta_ctx &area, void *container, const void *as_const) {
|
||||
return (container != nullptr) ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->end()}
|
||||
: iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->end()};
|
||||
static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) {
|
||||
return (container == nullptr)
|
||||
? iterator{area, stl::bool_constant<key_only>{}, end ? static_cast<const Type *>(as_const)->cend() : static_cast<const Type *>(as_const)->cbegin()}
|
||||
: iterator{area, stl::bool_constant<key_only>{}, end ? static_cast<Type *>(container)->end() : static_cast<Type *>(container)->begin()};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,9 +249,9 @@ struct basic_meta_associative_container_traits {
|
||||
*/
|
||||
[[nodiscard]] static bool insert(void *container, const void *key, [[maybe_unused]] const void *value) {
|
||||
if constexpr(key_only) {
|
||||
return static_cast<Type *>(container)->insert(*static_cast<const typename Type::key_type *>(key)).second;
|
||||
return static_cast<Type *>(container)->insert(*static_cast<const Type::key_type *>(key)).second;
|
||||
} else {
|
||||
return static_cast<Type *>(container)->emplace(*static_cast<const typename Type::key_type *>(key), *static_cast<const typename Type::mapped_type *>(value)).second;
|
||||
return static_cast<Type *>(container)->emplace(*static_cast<const Type::key_type *>(key), *static_cast<const Type::mapped_type *>(value)).second;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,7 +262,7 @@ struct basic_meta_associative_container_traits {
|
||||
* @return Number of elements removed (either 0 or 1).
|
||||
*/
|
||||
[[nodiscard]] static size_type erase(void *container, const void *key) {
|
||||
return static_cast<Type *>(container)->erase(*static_cast<const typename Type::key_type *>(key));
|
||||
return static_cast<Type *>(container)->erase(*static_cast<const Type::key_type *>(key));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,93 +274,24 @@ struct basic_meta_associative_container_traits {
|
||||
* @return An iterator to the element with the given key, if any.
|
||||
*/
|
||||
static iterator find(const meta_ctx &area, void *container, const void *as_const, const void *key) {
|
||||
return (container != nullptr) ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->find(*static_cast<const typename Type::key_type *>(key))}
|
||||
: iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->find(*static_cast<const typename Type::key_type *>(key))};
|
||||
return (container != nullptr) ? iterator{area, stl::bool_constant<key_only>{}, static_cast<Type *>(container)->find(*static_cast<const Type::key_type *>(key))}
|
||||
: iterator{area, stl::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->find(*static_cast<const Type::key_type *>(key))};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::vector`s of any type.
|
||||
* @tparam Args Template arguments for the container.
|
||||
* @brief Traits meta sequence container like types.
|
||||
* @tparam Type Container type to inspect.
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_sequence_container_traits<std::vector<Args...>>
|
||||
: basic_meta_sequence_container_traits<std::vector<Args...>> {};
|
||||
template<internal::meta_sequence_container_like Type>
|
||||
struct meta_sequence_container_traits<Type>: basic_meta_sequence_container_traits<Type> {};
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @brief Traits for meta associative container like types.
|
||||
* @tparam Type Container type to inspect.
|
||||
*/
|
||||
template<typename Type, auto N>
|
||||
struct meta_sequence_container_traits<std::array<Type, N>>
|
||||
: 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...>>
|
||||
: 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...>>
|
||||
: 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...>>
|
||||
: 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...>>
|
||||
: 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...>>
|
||||
: 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...>>
|
||||
: 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...>>
|
||||
: 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...>>
|
||||
: basic_meta_associative_container_traits<dense_set<Args...>> {};
|
||||
template<internal::meta_associative_container_like Type>
|
||||
struct meta_associative_container_traits<Type>: basic_meta_associative_container_traits<Type> {};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
|
||||
@@ -3,22 +3,24 @@
|
||||
|
||||
#include "../container/dense_map.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
class meta_ctx;
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
struct meta_type_node;
|
||||
|
||||
struct meta_context {
|
||||
dense_map<id_type, meta_type_node, identity> value;
|
||||
using container_type = dense_map<id_type, stl::unique_ptr<meta_type_node>, stl::identity>;
|
||||
|
||||
[[nodiscard]] inline static meta_context &from(meta_ctx &ctx);
|
||||
[[nodiscard]] inline static const meta_context &from(const meta_ctx &ctx);
|
||||
container_type bucket;
|
||||
|
||||
[[nodiscard]] inline static meta_context &from(meta_ctx &);
|
||||
[[nodiscard]] inline static const meta_context &from(const meta_ctx &);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
@@ -36,7 +38,7 @@ class meta_ctx: private internal::meta_context {
|
||||
friend struct internal::meta_context;
|
||||
};
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
[[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
#ifndef ENTT_META_FACTORY_HPP
|
||||
#define ENTT_META_FACTORY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/bit.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/hashed_string.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../locator/locator.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/cstdint.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "context.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "meta.hpp"
|
||||
#include "node.hpp"
|
||||
#include "policy.hpp"
|
||||
@@ -24,119 +26,131 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
class basic_meta_factory {
|
||||
using invoke_type = std::remove_pointer_t<decltype(meta_func_node::invoke)>;
|
||||
using invoke_type = stl::remove_pointer_t<decltype(meta_func_node::invoke)>;
|
||||
|
||||
auto *find_member_or_assert() {
|
||||
auto *member = find_member<&meta_data_node::id>(details->data, bucket);
|
||||
enum class mode {
|
||||
type,
|
||||
data,
|
||||
func
|
||||
};
|
||||
|
||||
[[nodiscard]] auto *find_member_or_assert() {
|
||||
auto *member = find_member(parent->details->data, bucket);
|
||||
ENTT_ASSERT(member != nullptr, "Cannot find member");
|
||||
return member;
|
||||
}
|
||||
|
||||
auto *find_overload_or_assert() {
|
||||
auto *overload = find_overload(find_member<&meta_func_node::id>(details->func, bucket), invoke);
|
||||
[[nodiscard]] auto *find_overload_or_assert() {
|
||||
ENTT_ASSERT(invoke != nullptr, "Invoke function not available");
|
||||
auto *overload = find_overload(find_member(parent->details->func, bucket), invoke);
|
||||
ENTT_ASSERT(overload != nullptr, "Cannot find overload");
|
||||
return overload;
|
||||
}
|
||||
|
||||
void reset_bucket(const id_type id, invoke_type *const ref = nullptr) {
|
||||
invoke = ref;
|
||||
bucket = id;
|
||||
}
|
||||
|
||||
protected:
|
||||
void type(const id_type id) noexcept {
|
||||
reset_bucket(parent);
|
||||
auto &&elem = meta_context::from(*ctx).value[parent];
|
||||
ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier");
|
||||
elem.id = id;
|
||||
void type(const id_type id, const char *name) noexcept {
|
||||
state = mode::type;
|
||||
ENTT_ASSERT(parent->id == id || !resolve(*ctx, id), "Duplicate identifier");
|
||||
parent->name = name;
|
||||
parent->id = id;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void insert_or_assign(Type node) {
|
||||
reset_bucket(parent);
|
||||
state = mode::type;
|
||||
|
||||
if constexpr(std::is_same_v<Type, meta_base_node>) {
|
||||
auto *member = find_member<&meta_base_node::type>(details->base, node.type);
|
||||
member ? (*member = node) : details->base.emplace_back(node);
|
||||
} else if constexpr(std::is_same_v<Type, meta_conv_node>) {
|
||||
auto *member = find_member<&meta_conv_node::type>(details->conv, node.type);
|
||||
member ? (*member = node) : details->conv.emplace_back(node);
|
||||
if constexpr(stl::is_same_v<Type, meta_base_node>) {
|
||||
auto *member = find_member(parent->details->base, node.id);
|
||||
member ? (*member = node) : parent->details->base.emplace_back(node);
|
||||
} else if constexpr(stl::is_same_v<Type, meta_conv_node>) {
|
||||
auto *member = find_member(parent->details->conv, node.id);
|
||||
member ? (*member = node) : parent->details->conv.emplace_back(node);
|
||||
} else {
|
||||
static_assert(std::is_same_v<Type, meta_ctor_node>, "Unexpected type");
|
||||
auto *member = find_member<&meta_ctor_node::id>(details->ctor, node.id);
|
||||
member ? (*member = node) : details->ctor.emplace_back(node);
|
||||
static_assert(stl::is_same_v<Type, meta_ctor_node>, "Unexpected type");
|
||||
auto *member = find_member(parent->details->ctor, node.id);
|
||||
member ? (*member = node) : parent->details->ctor.emplace_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
void dtor(meta_dtor_node node) {
|
||||
reset_bucket(parent);
|
||||
meta_context::from(*ctx).value[parent].dtor = node;
|
||||
}
|
||||
|
||||
void data(meta_data_node node) {
|
||||
reset_bucket(node.id);
|
||||
state = mode::data;
|
||||
bucket = node.id;
|
||||
|
||||
if(auto *member = find_member<&meta_data_node::id>(details->data, node.id); member == nullptr) {
|
||||
details->data.emplace_back(std::move(node));
|
||||
if(auto *member = find_member(parent->details->data, node.id); member == nullptr) {
|
||||
parent->details->data.emplace_back(stl::move(node));
|
||||
} else if(member->set != node.set || member->get != node.get) {
|
||||
*member = std::move(node);
|
||||
*member = stl::move(node);
|
||||
}
|
||||
}
|
||||
|
||||
void func(meta_func_node node) {
|
||||
reset_bucket(node.id, node.invoke);
|
||||
state = mode::func;
|
||||
bucket = node.id;
|
||||
invoke = node.invoke;
|
||||
|
||||
if(auto *member = find_member<&meta_func_node::id>(details->func, node.id); member == nullptr) {
|
||||
details->func.emplace_back(std::move(node));
|
||||
if(auto *member = find_member(parent->details->func, node.id); member == nullptr) {
|
||||
parent->details->func.emplace_back(stl::move(node));
|
||||
} else if(auto *overload = find_overload(member, node.invoke); overload == nullptr) {
|
||||
while(member->next != nullptr) { member = member->next.get(); }
|
||||
member->next = std::make_shared<meta_func_node>(std::move(node));
|
||||
member->next = stl::make_unique<meta_func_node>(stl::move(node));
|
||||
}
|
||||
}
|
||||
|
||||
void traits(const meta_traits value) {
|
||||
if(bucket == parent) {
|
||||
meta_context::from(*ctx).value[bucket].traits |= value;
|
||||
} else if(invoke == nullptr) {
|
||||
find_member_or_assert()->traits |= value;
|
||||
} else {
|
||||
find_overload_or_assert()->traits |= value;
|
||||
void traits(const meta_traits value, const bool unset) {
|
||||
const auto set_or_unset_on = [=](auto &node) {
|
||||
node.traits = (unset ? (node.traits & ~value) : (node.traits | value));
|
||||
};
|
||||
|
||||
switch(state) {
|
||||
case mode::type:
|
||||
set_or_unset_on(*parent);
|
||||
break;
|
||||
case mode::data:
|
||||
set_or_unset_on(*find_member_or_assert());
|
||||
break;
|
||||
case mode::func:
|
||||
set_or_unset_on(*find_overload_or_assert());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void custom(meta_custom_node node) {
|
||||
if(bucket == parent) {
|
||||
meta_context::from(*ctx).value[bucket].custom = std::move(node);
|
||||
} else if(invoke == nullptr) {
|
||||
find_member_or_assert()->custom = std::move(node);
|
||||
} else {
|
||||
find_overload_or_assert()->custom = std::move(node);
|
||||
switch(state) {
|
||||
case mode::type:
|
||||
parent->custom = stl::move(node);
|
||||
break;
|
||||
case mode::data:
|
||||
find_member_or_assert()->custom = stl::move(node);
|
||||
break;
|
||||
case mode::func:
|
||||
find_overload_or_assert()->custom = stl::move(node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
basic_meta_factory(meta_ctx &area, meta_type_node node)
|
||||
: ctx{&area},
|
||||
parent{node.info->hash()},
|
||||
bucket{parent},
|
||||
details{node.details.get()} {
|
||||
if(details == nullptr) {
|
||||
node.details = std::make_shared<meta_type_descriptor>();
|
||||
meta_context::from(*ctx).value[parent] = node;
|
||||
details = node.details.get();
|
||||
bucket{node.info->hash()},
|
||||
state{mode::type} {
|
||||
if(const auto it = meta_context::from(*ctx).bucket.find(bucket); it == meta_context::from(*ctx).bucket.cend()) {
|
||||
parent = meta_context::from(*ctx).bucket.emplace(node.info->hash(), stl::make_unique<meta_type_node>(stl::move(node))).first->second.get();
|
||||
parent->details = stl::make_unique<meta_type_descriptor>();
|
||||
} else {
|
||||
parent = it->second.get();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
meta_ctx *ctx{};
|
||||
id_type parent{};
|
||||
id_type bucket{};
|
||||
invoke_type *invoke{};
|
||||
meta_type_descriptor *details{};
|
||||
meta_type_node *parent{};
|
||||
mode state{};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
@@ -144,32 +158,16 @@ private:
|
||||
|
||||
/**
|
||||
* @brief Meta factory to be used for reflection purposes.
|
||||
* @tparam Type Reflected type for which the factory was created.
|
||||
* @tparam Type Type for which the factory was created.
|
||||
*/
|
||||
template<typename Type>
|
||||
class meta_factory: private internal::basic_meta_factory {
|
||||
using base_type = internal::basic_meta_factory;
|
||||
|
||||
template<typename Setter, auto Getter, typename Policy, std::size_t... Index>
|
||||
[[deprecated("use variant types or conversion support")]]
|
||||
void data(const id_type id, std::index_sequence<Index...>) noexcept {
|
||||
using data_type = std::invoke_result_t<decltype(Getter), Type &>;
|
||||
using args_type = type_list<typename meta_function_helper_t<Type, decltype(value_list_element_v<Index, Setter>)>::args_type...>;
|
||||
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
|
||||
|
||||
base_type::data(
|
||||
internal::meta_data_node{
|
||||
id,
|
||||
/* this is never static */
|
||||
(std::is_member_object_pointer_v<decltype(value_list_element_v<Index, Setter>)> && ... && std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
|
||||
Setter::size,
|
||||
&internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
|
||||
&meta_arg<type_list<type_list_element_t<static_cast<std::size_t>(type_list_element_t<Index, args_type>::size != 1u), type_list_element_t<Index, args_type>>...>>,
|
||||
+[](meta_handle instance, meta_any value) { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
|
||||
&meta_getter<Type, Getter, Policy>});
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Type of object for which this factory builds a meta type. */
|
||||
using element_type = Type;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
meta_factory() noexcept
|
||||
: meta_factory{locator<meta_ctx>::value_or()} {}
|
||||
@@ -179,15 +177,25 @@ public:
|
||||
* @param area The context into which to construct meta types.
|
||||
*/
|
||||
meta_factory(meta_ctx &area) noexcept
|
||||
: internal::basic_meta_factory{area, internal::resolve<Type>(internal::meta_context::from(area))} {}
|
||||
: internal::basic_meta_factory{area, internal::setup_node_for<Type>()} {}
|
||||
|
||||
/**
|
||||
* @brief Assigns a custom unique identifier to a meta type.
|
||||
* @param name A custom unique identifier as a **string literal**.
|
||||
* @return A meta factory for the given type.
|
||||
*/
|
||||
meta_factory type(const char *name) noexcept {
|
||||
return type(hashed_string::value(name), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a custom unique identifier to a meta type.
|
||||
* @param id A custom unique identifier.
|
||||
* @param name An optional name for the type as a **string literal**.
|
||||
* @return A meta factory for the given type.
|
||||
*/
|
||||
meta_factory type(const id_type id) noexcept {
|
||||
base_type::type(id);
|
||||
meta_factory type(const id_type id, const char *name = nullptr) noexcept {
|
||||
base_type::type(id, name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -200,10 +208,18 @@ public:
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename Base>
|
||||
requires stl::derived_from<Type, Base>
|
||||
meta_factory base() noexcept {
|
||||
static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>, "Invalid base type");
|
||||
auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
|
||||
base_type::insert_or_assign(internal::meta_base_node{type_id<Base>().hash(), &internal::resolve<Base>, op});
|
||||
if constexpr(!stl::same_as<Type, Base>) {
|
||||
auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
|
||||
|
||||
base_type::insert_or_assign(
|
||||
internal::meta_base_node{
|
||||
type_id<Base>().hash(),
|
||||
&internal::resolve<Base>,
|
||||
op});
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -221,9 +237,14 @@ public:
|
||||
*/
|
||||
template<auto Candidate>
|
||||
auto conv() noexcept {
|
||||
using conv_type = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
|
||||
auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, std::invoke(Candidate, *static_cast<const Type *>(instance))); };
|
||||
base_type::insert_or_assign(internal::meta_conv_node{type_id<conv_type>().hash(), op});
|
||||
using conv_type = stl::remove_cvref_t<stl::invoke_result_t<decltype(Candidate), Type &>>;
|
||||
auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, stl::invoke(Candidate, *static_cast<const Type *>(instance))); };
|
||||
|
||||
base_type::insert_or_assign(
|
||||
internal::meta_conv_node{
|
||||
type_id<conv_type>().hash(),
|
||||
op});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -238,9 +259,14 @@ public:
|
||||
*/
|
||||
template<typename To>
|
||||
meta_factory conv() noexcept {
|
||||
using conv_type = std::remove_cv_t<std::remove_reference_t<To>>;
|
||||
using conv_type = stl::remove_cvref_t<To>;
|
||||
auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast<To>(*static_cast<const Type *>(instance))); };
|
||||
base_type::insert_or_assign(internal::meta_conv_node{type_id<conv_type>().hash(), op});
|
||||
|
||||
base_type::insert_or_assign(
|
||||
internal::meta_conv_node{
|
||||
type_id<conv_type>().hash(),
|
||||
op});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -257,12 +283,19 @@ public:
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<auto Candidate, typename Policy = as_is_t>
|
||||
template<auto Candidate, typename Policy = as_value_t>
|
||||
meta_factory ctor() noexcept {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
|
||||
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
|
||||
static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>, Type>, "The function doesn't return an object of the required type");
|
||||
base_type::insert_or_assign(internal::meta_ctor_node{type_id<typename descriptor::args_type>().hash(), descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Candidate, Policy>});
|
||||
static_assert(stl::is_same_v<stl::remove_cvref_t<typename descriptor::return_type>, Type>, "The function doesn't return an object of the required type");
|
||||
|
||||
base_type::insert_or_assign(
|
||||
internal::meta_ctor_node{
|
||||
type_id<typename descriptor::args_type>().hash(),
|
||||
descriptor::args_type::size,
|
||||
&meta_arg<typename descriptor::args_type>,
|
||||
&meta_construct<Type, Candidate, Policy>});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -281,36 +314,28 @@ public:
|
||||
// default constructor is already implicitly generated, no need for redundancy
|
||||
if constexpr(sizeof...(Args) != 0u) {
|
||||
using descriptor = meta_function_helper_t<Type, Type (*)(Args...)>;
|
||||
base_type::insert_or_assign(internal::meta_ctor_node{type_id<typename descriptor::args_type>().hash(), descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Args...>});
|
||||
|
||||
base_type::insert_or_assign(
|
||||
internal::meta_ctor_node{
|
||||
type_id<typename descriptor::args_type>().hash(),
|
||||
descriptor::args_type::size,
|
||||
&meta_arg<typename descriptor::args_type>,
|
||||
&meta_construct<Type, Args...>});
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a meta destructor to a meta type.
|
||||
*
|
||||
* Both free functions and member functions can be assigned to meta types in
|
||||
* the role of destructors.<br/>
|
||||
* The signature of a free function should be identical to the following:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(Type &);
|
||||
* @endcode
|
||||
*
|
||||
* Member functions should not take arguments instead.<br/>
|
||||
* The purpose is to give users the ability to free up resources that
|
||||
* require special treatment before an object is actually destroyed.
|
||||
*
|
||||
* @tparam Func The actual function to use as a destructor.
|
||||
* @return A meta factory for the parent type.
|
||||
* @brief Assigns a meta data to a meta type.
|
||||
* @tparam Data The actual variable to attach to the meta type.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param name A custom unique identifier as a **string literal**.
|
||||
* @return A meta factory for the given type.
|
||||
*/
|
||||
template<auto Func>
|
||||
meta_factory dtor() noexcept {
|
||||
static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
|
||||
auto *const op = +[](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
|
||||
base_type::dtor(internal::meta_dtor_node{op});
|
||||
return *this;
|
||||
template<auto Data, typename Policy = as_value_t>
|
||||
meta_factory data(const char *name) noexcept {
|
||||
return data<Data, Policy>(hashed_string::value(name), name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,28 +349,30 @@ public:
|
||||
* @tparam Data The actual variable to attach to the meta type.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param id Unique identifier.
|
||||
* @param name An optional name for the meta data as a **string literal**.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<auto Data, typename Policy = as_is_t>
|
||||
meta_factory data(const id_type id) noexcept {
|
||||
if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::invoke_result_t<decltype(Data), Type &>;
|
||||
template<auto Data, typename Policy = as_value_t>
|
||||
meta_factory data(const id_type id, const char *name = nullptr) noexcept {
|
||||
if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = stl::invoke_result_t<decltype(Data), Type &>;
|
||||
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
|
||||
|
||||
base_type::data(
|
||||
internal::meta_data_node{
|
||||
id,
|
||||
name,
|
||||
/* this is never static */
|
||||
std::is_const_v<std::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
|
||||
stl::is_const_v<stl::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
|
||||
1u,
|
||||
&internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
|
||||
&meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
|
||||
&internal::resolve<stl::remove_cvref_t<data_type>>,
|
||||
&meta_arg<type_list<stl::remove_cvref_t<data_type>>>,
|
||||
&meta_setter<Type, Data>,
|
||||
&meta_getter<Type, Data, Policy>});
|
||||
} else {
|
||||
using data_type = std::remove_pointer_t<decltype(Data)>;
|
||||
using data_type = stl::remove_pointer_t<decltype(Data)>;
|
||||
|
||||
if constexpr(std::is_pointer_v<decltype(Data)>) {
|
||||
if constexpr(stl::is_pointer_v<decltype(Data)>) {
|
||||
static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
|
||||
} else {
|
||||
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
|
||||
@@ -354,10 +381,11 @@ public:
|
||||
base_type::data(
|
||||
internal::meta_data_node{
|
||||
id,
|
||||
((!std::is_pointer_v<decltype(Data)> || std::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
|
||||
name,
|
||||
((!stl::is_pointer_v<decltype(Data)> || stl::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
|
||||
1u,
|
||||
&internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
|
||||
&meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
|
||||
&internal::resolve<stl::remove_cvref_t<data_type>>,
|
||||
&meta_arg<type_list<stl::remove_cvref_t<data_type>>>,
|
||||
&meta_setter<Type, Data>,
|
||||
&meta_getter<Type, Data, Policy>});
|
||||
}
|
||||
@@ -365,6 +393,20 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a meta data to a meta type by means of its setter and
|
||||
* getter.
|
||||
* @tparam Setter The actual function to use as a setter.
|
||||
* @tparam Getter The actual function to use as a getter.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param name A custom unique identifier as a **string literal**.
|
||||
* @return A meta factory for the given type.
|
||||
*/
|
||||
template<auto Setter, auto Getter, typename Policy = as_value_t>
|
||||
meta_factory data(const char *name) noexcept {
|
||||
return data<Setter, Getter, Policy>(hashed_string::value(name), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a meta data to a meta type by means of its setter and
|
||||
* getter.
|
||||
@@ -383,35 +425,38 @@ public:
|
||||
* @tparam Getter The actual function to use as a getter.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param id Unique identifier.
|
||||
* @param name An optional name for the meta data as a **string literal**.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<auto Setter, auto Getter, typename Policy = as_is_t>
|
||||
meta_factory data(const id_type id) noexcept {
|
||||
template<auto Setter, auto Getter, typename Policy = as_value_t>
|
||||
meta_factory data(const id_type id, const char *name = nullptr) noexcept {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Getter)>;
|
||||
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
|
||||
|
||||
if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
|
||||
if constexpr(stl::is_same_v<decltype(Setter), stl::nullptr_t>) {
|
||||
base_type::data(
|
||||
internal::meta_data_node{
|
||||
id,
|
||||
name,
|
||||
/* this is never static */
|
||||
internal::meta_traits::is_const,
|
||||
0u,
|
||||
&internal::resolve<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>,
|
||||
&internal::resolve<stl::remove_cvref_t<typename descriptor::return_type>>,
|
||||
&meta_arg<type_list<>>,
|
||||
&meta_setter<Type, Setter>,
|
||||
&meta_getter<Type, Getter, Policy>});
|
||||
} else {
|
||||
using args_type = typename meta_function_helper_t<Type, decltype(Setter)>::args_type;
|
||||
using args_type = meta_function_helper_t<Type, decltype(Setter)>::args_type;
|
||||
|
||||
base_type::data(
|
||||
internal::meta_data_node{
|
||||
id,
|
||||
name,
|
||||
/* this is never static nor const */
|
||||
internal::meta_traits::is_none,
|
||||
1u,
|
||||
&internal::resolve<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>,
|
||||
&meta_arg<type_list<type_list_element_t<static_cast<std::size_t>(args_type::size != 1u), args_type>>>,
|
||||
&internal::resolve<stl::remove_cvref_t<typename descriptor::return_type>>,
|
||||
&meta_arg<type_list<type_list_element_t<static_cast<stl::size_t>(args_type::size != 1u), args_type>>>,
|
||||
&meta_setter<Type, Setter>,
|
||||
&meta_getter<Type, Getter, Policy>});
|
||||
}
|
||||
@@ -420,27 +465,15 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a meta data to a meta type by means of its setters and
|
||||
* getter.
|
||||
*
|
||||
* Multi-setter support for meta data members. All setters are tried in the
|
||||
* order of definition before returning to the caller.<br/>
|
||||
* Setters can be either free functions, member functions or a mix of them
|
||||
* and are provided via a `value_list` type.
|
||||
*
|
||||
* @sa data
|
||||
*
|
||||
* @tparam Setter The actual functions to use as setters.
|
||||
* @tparam Getter The actual getter function.
|
||||
* @brief Assigns a meta function to a meta type.
|
||||
* @tparam Candidate The actual function to attach to the meta function.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param id Unique identifier.
|
||||
* @return A meta factory for the parent type.
|
||||
* @param name A custom unique identifier as a **string literal**.
|
||||
* @return A meta factory for the given type.
|
||||
*/
|
||||
template<typename Setter, auto Getter, typename Policy = as_is_t>
|
||||
[[deprecated("use variant types or conversion support")]]
|
||||
meta_factory data(const id_type id) noexcept {
|
||||
data<Setter, Getter, Policy>(id, std::make_index_sequence<Setter::size>{});
|
||||
return *this;
|
||||
template<auto Candidate, typename Policy = as_value_t>
|
||||
meta_factory func(const char *name) noexcept {
|
||||
return func<Candidate, Policy>(hashed_string::value(name), name);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -454,19 +487,21 @@ public:
|
||||
* @tparam Candidate The actual function to attach to the meta type.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param id Unique identifier.
|
||||
* @param name An optional name for the function as a **string literal**.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<auto Candidate, typename Policy = as_is_t>
|
||||
meta_factory func(const id_type id) noexcept {
|
||||
template<auto Candidate, typename Policy = as_value_t>
|
||||
meta_factory func(const id_type id, const char *name = nullptr) noexcept {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
|
||||
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
|
||||
|
||||
base_type::func(
|
||||
internal::meta_func_node{
|
||||
id,
|
||||
name,
|
||||
(descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
|
||||
descriptor::args_type::size,
|
||||
&internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>,
|
||||
&internal::resolve<stl::conditional_t<stl::is_same_v<Policy, as_void_t>, void, stl::remove_cvref_t<typename descriptor::return_type>>>,
|
||||
&meta_arg<typename descriptor::args_type>,
|
||||
&meta_invoke<Type, Candidate, Policy>});
|
||||
|
||||
@@ -480,12 +515,13 @@ public:
|
||||
*
|
||||
* @tparam Value Type of the traits value.
|
||||
* @param value Traits value.
|
||||
* @param unset True to unset the given traits, false otherwise.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename Value>
|
||||
meta_factory traits(const Value value) {
|
||||
static_assert(std::is_enum_v<Value>, "Invalid enum type");
|
||||
base_type::traits(internal::user_to_meta_traits(value));
|
||||
meta_factory traits(const Value value, const bool unset = false) {
|
||||
static_assert(stl::is_enum_v<Value>, "Invalid enum type");
|
||||
base_type::traits(internal::user_to_meta_traits(value), unset);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -498,44 +534,11 @@ public:
|
||||
*/
|
||||
template<typename Value, typename... Args>
|
||||
meta_factory custom(Args &&...args) {
|
||||
base_type::custom(internal::meta_custom_node{type_id<Value>().hash(), std::make_shared<Value>(std::forward<Args>(args)...)});
|
||||
base_type::custom(internal::meta_custom_node{type_id<Value>().hash(), stl::make_shared<Value>(stl::forward<Args>(args)...)});
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Utility function to use for reflection.
|
||||
*
|
||||
* This is the point from which everything starts.<br/>
|
||||
* By invoking this function with a type that is not yet reflected, a meta type
|
||||
* is created to which it will be possible to attach meta objects through a
|
||||
* dedicated factory.
|
||||
*
|
||||
* @tparam Type Type to reflect.
|
||||
* @param ctx The context into which to construct meta types.
|
||||
* @return A meta factory for the given type.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] [[deprecated("use meta_factory directly instead")]] auto meta(meta_ctx &ctx) noexcept {
|
||||
return meta_factory<Type>{ctx};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to use for reflection.
|
||||
*
|
||||
* This is the point from which everything starts.<br/>
|
||||
* By invoking this function with a type that is not yet reflected, a meta type
|
||||
* is created to which it will be possible to attach meta objects through a
|
||||
* dedicated factory.
|
||||
*
|
||||
* @tparam Type Type to reflect.
|
||||
* @return A meta factory for the given type.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] [[deprecated("use meta_factory directly instead")]] auto meta() noexcept {
|
||||
return meta<Type>(locator<meta_ctx>::value_or());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets a type and all its parts.
|
||||
*
|
||||
@@ -549,11 +552,11 @@ template<typename Type>
|
||||
* @param ctx The context from which to reset meta types.
|
||||
*/
|
||||
inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept {
|
||||
auto &&context = internal::meta_context::from(ctx);
|
||||
auto &context = internal::meta_context::from(ctx);
|
||||
|
||||
for(auto it = context.value.begin(); it != context.value.end();) {
|
||||
if(it->second.id == id) {
|
||||
it = context.value.erase(it);
|
||||
for(auto it = context.bucket.begin(); it != context.bucket.end();) {
|
||||
if(it->second->id == id) {
|
||||
it = context.bucket.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
@@ -585,7 +588,7 @@ inline void meta_reset(const id_type id) noexcept {
|
||||
*/
|
||||
template<typename Type>
|
||||
void meta_reset(meta_ctx &ctx) noexcept {
|
||||
internal::meta_context::from(ctx).value.erase(type_id<Type>().hash());
|
||||
internal::meta_context::from(ctx).bucket.erase(type_id<Type>().hash());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -608,7 +611,7 @@ void meta_reset() noexcept {
|
||||
* @param ctx The context from which to reset meta types.
|
||||
*/
|
||||
inline void meta_reset(meta_ctx &ctx) noexcept {
|
||||
internal::meta_context::from(ctx).value.clear();
|
||||
internal::meta_context::from(ctx).bucket.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
#ifndef ENTT_META_FWD_HPP
|
||||
#define ENTT_META_FWD_HPP
|
||||
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/limits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
class meta_ctx;
|
||||
|
||||
class meta_sequence_container;
|
||||
|
||||
class meta_associative_container;
|
||||
|
||||
class meta_any;
|
||||
|
||||
struct meta_handle;
|
||||
class meta_handle;
|
||||
|
||||
struct meta_custom;
|
||||
|
||||
@@ -17,8 +22,16 @@ struct meta_data;
|
||||
|
||||
struct meta_func;
|
||||
|
||||
struct meta_base;
|
||||
|
||||
class meta_type;
|
||||
|
||||
template<typename>
|
||||
class meta_factory;
|
||||
|
||||
/*! @brief Used to identicate that a sequence container has not a fixed size. */
|
||||
inline constexpr stl::size_t meta_dynamic_extent = (stl::numeric_limits<stl::size_t>::max)();
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,32 +1,32 @@
|
||||
#ifndef ENTT_META_NODE_HPP
|
||||
#define ENTT_META_NODE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../core/attribute.h"
|
||||
#include "../core/bit.hpp"
|
||||
#include "../core/concepts.hpp"
|
||||
#include "../core/enum.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "../stl/array.hpp"
|
||||
#include "../stl/bit.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/cstdint.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "../stl/vector.hpp"
|
||||
#include "context.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
class meta_any;
|
||||
class meta_type;
|
||||
struct meta_handle;
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
enum class meta_traits : std::uint32_t {
|
||||
enum class meta_traits : stl::uint32_t {
|
||||
is_none = 0x0000,
|
||||
is_const = 0x0001,
|
||||
is_static = 0x0002,
|
||||
@@ -45,41 +45,41 @@ enum class meta_traits : std::uint32_t {
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
requires stl::is_enum_v<Type>
|
||||
[[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept {
|
||||
static_assert(std::is_enum_v<Type>, "Invalid enum type");
|
||||
constexpr auto shift = popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
|
||||
return Type{static_cast<std::underlying_type_t<Type>>(static_cast<std::underlying_type_t<meta_traits>>(traits) >> shift)};
|
||||
constexpr auto shift = stl::popcount(static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
|
||||
return Type{static_cast<stl::underlying_type_t<Type>>(static_cast<stl::underlying_type_t<meta_traits>>(traits) >> shift)};
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
requires stl::is_enum_v<Type>
|
||||
[[nodiscard]] auto user_to_meta_traits(const Type value) noexcept {
|
||||
static_assert(std::is_enum_v<Type>, "Invalid enum type");
|
||||
constexpr auto shift = popcount(static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
|
||||
const auto traits = static_cast<std::underlying_type_t<internal::meta_traits>>(static_cast<std::underlying_type_t<Type>>(value));
|
||||
ENTT_ASSERT(traits < ((~static_cast<std::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits");
|
||||
constexpr auto shift = stl::popcount(static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
|
||||
const auto traits = static_cast<stl::underlying_type_t<internal::meta_traits>>(static_cast<stl::underlying_type_t<Type>>(value));
|
||||
ENTT_ASSERT(traits < ((~static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits");
|
||||
return meta_traits{traits << shift};
|
||||
}
|
||||
|
||||
struct meta_type_node;
|
||||
|
||||
struct meta_custom_node {
|
||||
id_type type{};
|
||||
std::shared_ptr<void> value;
|
||||
id_type id{};
|
||||
stl::shared_ptr<void> value{};
|
||||
};
|
||||
|
||||
struct meta_base_node {
|
||||
id_type type{};
|
||||
meta_type_node (*resolve)(const meta_context &) noexcept {};
|
||||
id_type id{};
|
||||
const meta_type_node &(*type)(const meta_context &) noexcept {};
|
||||
const void *(*cast)(const void *) noexcept {};
|
||||
};
|
||||
|
||||
struct meta_conv_node {
|
||||
id_type type{};
|
||||
id_type id{};
|
||||
meta_any (*conv)(const meta_ctx &, const void *){};
|
||||
};
|
||||
|
||||
struct meta_ctor_node {
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
|
||||
id_type id{};
|
||||
size_type arity{0u};
|
||||
@@ -87,17 +87,14 @@ struct meta_ctor_node {
|
||||
meta_any (*invoke)(const meta_ctx &, meta_any *const){};
|
||||
};
|
||||
|
||||
struct meta_dtor_node {
|
||||
void (*dtor)(void *){};
|
||||
};
|
||||
|
||||
struct meta_data_node {
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
|
||||
id_type id{};
|
||||
const char *name{};
|
||||
meta_traits traits{meta_traits::is_none};
|
||||
size_type arity{0u};
|
||||
meta_type_node (*type)(const meta_context &) noexcept {};
|
||||
const meta_type_node &(*type)(const meta_context &) noexcept {};
|
||||
meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
|
||||
bool (*set)(meta_handle, meta_any){};
|
||||
meta_any (*get)(meta_handle){};
|
||||
@@ -105,80 +102,82 @@ struct meta_data_node {
|
||||
};
|
||||
|
||||
struct meta_func_node {
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
|
||||
id_type id{};
|
||||
const char *name{};
|
||||
meta_traits traits{meta_traits::is_none};
|
||||
size_type arity{0u};
|
||||
meta_type_node (*ret)(const meta_context &) noexcept {};
|
||||
const meta_type_node &(*ret)(const meta_context &) noexcept {};
|
||||
meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
|
||||
meta_any (*invoke)(meta_handle, meta_any *const){};
|
||||
std::shared_ptr<meta_func_node> next;
|
||||
stl::unique_ptr<meta_func_node> next;
|
||||
meta_custom_node custom{};
|
||||
};
|
||||
|
||||
struct meta_template_node {
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
|
||||
size_type arity{0u};
|
||||
meta_type_node (*resolve)(const meta_context &) noexcept {};
|
||||
meta_type_node (*arg)(const meta_context &, const size_type) noexcept {};
|
||||
const meta_type_node &(*resolve)(const meta_context &) noexcept {};
|
||||
const meta_type_node &(*arg)(const meta_context &, const size_type) noexcept {};
|
||||
};
|
||||
|
||||
struct meta_type_descriptor {
|
||||
std::vector<meta_ctor_node> ctor;
|
||||
std::vector<meta_base_node> base;
|
||||
std::vector<meta_conv_node> conv;
|
||||
std::vector<meta_data_node> data;
|
||||
std::vector<meta_func_node> func;
|
||||
stl::vector<meta_ctor_node> ctor{};
|
||||
stl::vector<meta_base_node> base{};
|
||||
stl::vector<meta_conv_node> conv{};
|
||||
stl::vector<meta_data_node> data{};
|
||||
stl::vector<meta_func_node> func{};
|
||||
};
|
||||
|
||||
struct meta_type_node {
|
||||
using size_type = std::size_t;
|
||||
using size_type = stl::size_t;
|
||||
|
||||
const type_info *info{};
|
||||
id_type id{};
|
||||
const char *name{};
|
||||
meta_traits traits{meta_traits::is_none};
|
||||
size_type size_of{0u};
|
||||
meta_type_node (*resolve)(const meta_context &) noexcept {};
|
||||
meta_type_node (*remove_pointer)(const meta_context &) noexcept {};
|
||||
const meta_type_node &(*remove_pointer)(const meta_context &) noexcept {};
|
||||
meta_any (*default_constructor)(const meta_ctx &){};
|
||||
double (*conversion_helper)(void *, const void *){};
|
||||
meta_any (*from_void)(const meta_ctx &, void *, const void *){};
|
||||
meta_template_node templ{};
|
||||
meta_dtor_node dtor{};
|
||||
meta_custom_node custom{};
|
||||
std::shared_ptr<meta_type_descriptor> details;
|
||||
stl::unique_ptr<meta_type_descriptor> details{};
|
||||
};
|
||||
|
||||
template<auto Member, typename Type, typename Value>
|
||||
template<typename Type, typename Value>
|
||||
[[nodiscard]] auto *find_member(Type &from, const Value value) {
|
||||
for(auto &&elem: from) {
|
||||
if((elem.*Member) == value) {
|
||||
if(elem.id == value) {
|
||||
return &elem;
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<typename Type::value_type *>(nullptr);
|
||||
return static_cast<Type::value_type *>(nullptr);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline auto *find_overload(meta_func_node *curr, std::remove_pointer_t<decltype(meta_func_node::invoke)> *const ref) {
|
||||
[[nodiscard]] inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t<decltype(meta_func_node::invoke)> *const ref) {
|
||||
while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
|
||||
return curr;
|
||||
}
|
||||
|
||||
template<auto Member>
|
||||
[[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id) {
|
||||
using value_type = typename std::remove_reference_t<decltype((node.details.get()->*Member))>::value_type;
|
||||
[[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) {
|
||||
using value_type = stl::remove_reference_t<decltype((node.details.get()->*Member))>::value_type;
|
||||
|
||||
if(node.details) {
|
||||
if(auto *member = find_member<&value_type::id>((node.details.get()->*Member), id); member != nullptr) {
|
||||
if(auto *member = find_member((node.details.get()->*Member), id); member != nullptr) {
|
||||
return member;
|
||||
}
|
||||
|
||||
for(auto &&curr: node.details->base) {
|
||||
if(auto *elem = look_for<Member>(context, curr.resolve(context), id); elem) {
|
||||
return elem;
|
||||
if(recursive) {
|
||||
for(auto &&curr: node.details->base) {
|
||||
if(auto *elem = look_for<Member>(context, curr.type(context), id, recursive); elem) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -186,30 +185,23 @@ template<auto Member>
|
||||
return static_cast<value_type *>(nullptr);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
meta_type_node resolve(const meta_context &) noexcept;
|
||||
template<cvref_unqualified Type>
|
||||
const meta_type_node &resolve(const meta_context &) noexcept;
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] auto meta_arg_node(const meta_context &context, type_list<Args...>, [[maybe_unused]] const std::size_t index) noexcept {
|
||||
meta_type_node (*value)(const meta_context &) noexcept = nullptr;
|
||||
|
||||
if constexpr(sizeof...(Args) != 0u) {
|
||||
std::size_t pos{};
|
||||
((value = (pos++ == index ? &resolve<std::remove_cv_t<std::remove_reference_t<Args>>> : value)), ...);
|
||||
}
|
||||
|
||||
ENTT_ASSERT(value != nullptr, "Out of bounds");
|
||||
return value(context);
|
||||
[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list<Args...>, const stl::size_t index) noexcept {
|
||||
using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept;
|
||||
constexpr stl::array<resolve_type, sizeof...(Args)> list{&resolve<stl::remove_cvref_t<Args>>...};
|
||||
ENTT_ASSERT(index < sizeof...(Args), "Out of bounds");
|
||||
return list[index](context);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const type_info &to, const void *instance) noexcept {
|
||||
if((from.info != nullptr) && *from.info == to) {
|
||||
return instance;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const id_type to, const void *instance) noexcept {
|
||||
if(from.details) {
|
||||
for(auto &&curr: from.details->base) {
|
||||
if(const void *elem = try_cast(context, curr.resolve(context), to, curr.cast(instance)); elem) {
|
||||
if(const void *other = curr.cast(instance); curr.id == to) {
|
||||
return other;
|
||||
} else if(const void *elem = try_cast(context, curr.type(context), to, other); elem) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
@@ -218,91 +210,53 @@ template<typename... Args>
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
[[nodiscard]] inline auto try_convert(const meta_context &context, const meta_type_node &from, const type_info &to, const bool arithmetic_or_enum, const void *instance, Func func) {
|
||||
if(from.info && *from.info == to) {
|
||||
return func(instance, from);
|
||||
}
|
||||
|
||||
if(from.details) {
|
||||
for(auto &&elem: from.details->conv) {
|
||||
if(elem.type == to.hash()) {
|
||||
return func(instance, elem);
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &&curr: from.details->base) {
|
||||
if(auto other = try_convert(context, curr.resolve(context), to, arithmetic_or_enum, curr.cast(instance), func); other) {
|
||||
return other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(from.conversion_helper && arithmetic_or_enum) {
|
||||
return func(instance, from.conversion_helper);
|
||||
}
|
||||
|
||||
return func(instance);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
|
||||
const auto it = context.value.find(info.hash());
|
||||
return it != context.value.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] meta_type_node resolve(const meta_context &context) noexcept {
|
||||
static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
|
||||
|
||||
if(auto *elem = try_resolve(context, type_id<Type>()); elem) {
|
||||
return *elem;
|
||||
}
|
||||
|
||||
auto setup_node_for() noexcept {
|
||||
meta_type_node node{
|
||||
&type_id<Type>(),
|
||||
type_id<Type>().hash(),
|
||||
(std::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
|
||||
| (std::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
|
||||
| (std::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
|
||||
| (std::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
|
||||
| (std::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
|
||||
| (std::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
|
||||
| (std::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
|
||||
nullptr,
|
||||
(stl::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
|
||||
| (stl::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
|
||||
| (stl::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
|
||||
| (stl::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
|
||||
| (stl::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
|
||||
| (stl::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
|
||||
| (stl::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
|
||||
| (is_meta_pointer_like_v<Type> ? meta_traits::is_pointer_like : meta_traits::is_none)
|
||||
| (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_sequence_container : meta_traits::is_none)
|
||||
| (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_associative_container : meta_traits::is_none),
|
||||
size_of_v<Type>,
|
||||
&resolve<Type>,
|
||||
&resolve<std::remove_cv_t<std::remove_pointer_t<Type>>>};
|
||||
&resolve<stl::remove_const_t<stl::remove_pointer_t<Type>>>};
|
||||
|
||||
if constexpr(std::is_default_constructible_v<Type>) {
|
||||
if constexpr(stl::is_default_constructible_v<Type>) {
|
||||
node.default_constructor = +[](const meta_ctx &ctx) {
|
||||
return meta_any{ctx, std::in_place_type<Type>};
|
||||
return meta_any{ctx, stl::in_place_type<Type>};
|
||||
};
|
||||
}
|
||||
|
||||
if constexpr(std::is_arithmetic_v<Type>) {
|
||||
if constexpr(stl::is_arithmetic_v<Type>) {
|
||||
node.conversion_helper = +[](void *lhs, const void *rhs) {
|
||||
return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(*static_cast<const double *>(rhs))) : static_cast<double>(*static_cast<const Type *>(rhs));
|
||||
};
|
||||
} else if constexpr(std::is_enum_v<Type>) {
|
||||
} else if constexpr(stl::is_enum_v<Type>) {
|
||||
node.conversion_helper = +[](void *lhs, const void *rhs) {
|
||||
return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(static_cast<std::underlying_type_t<Type>>(*static_cast<const double *>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
|
||||
return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(static_cast<stl::underlying_type_t<Type>>(*static_cast<const double *>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
|
||||
};
|
||||
}
|
||||
|
||||
if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
|
||||
if constexpr(!stl::is_void_v<Type> && !stl::is_function_v<Type>) {
|
||||
node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) {
|
||||
if(elem && celem) { // ownership construction request
|
||||
return meta_any{ctx, std::in_place, static_cast<std::decay_t<Type> *>(elem)};
|
||||
return meta_any{ctx, stl::in_place, static_cast<stl::decay_t<Type> *>(elem)};
|
||||
}
|
||||
|
||||
if(elem) { // non-const reference construction request
|
||||
return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *static_cast<std::decay_t<Type> *>(elem)};
|
||||
return meta_any{ctx, stl::in_place_type<stl::decay_t<Type> &>, *static_cast<stl::decay_t<Type> *>(elem)};
|
||||
}
|
||||
|
||||
// const reference construction request
|
||||
return meta_any{ctx, std::in_place_type<const std::decay_t<Type> &>, *static_cast<const std::decay_t<Type> *>(celem)};
|
||||
return meta_any{ctx, stl::in_place_type<const stl::decay_t<Type> &>, *static_cast<const stl::decay_t<Type> *>(celem)};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -310,12 +264,24 @@ template<typename Type>
|
||||
node.templ = meta_template_node{
|
||||
meta_template_traits<Type>::args_type::size,
|
||||
&resolve<typename meta_template_traits<Type>::class_type>,
|
||||
+[](const meta_context &area, const std::size_t index) noexcept { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
|
||||
+[](const meta_context &area, const stl::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
|
||||
const auto it = context.bucket.find(info.hash());
|
||||
return (it != context.bucket.end()) ? it->second.get() : nullptr;
|
||||
}
|
||||
|
||||
template<cvref_unqualified Type>
|
||||
[[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept {
|
||||
static const meta_type_node node = setup_node_for<Type>();
|
||||
const auto *elem = try_resolve(context, *node.info);
|
||||
return (elem == nullptr) ? node : *elem;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
|
||||
@@ -3,56 +3,39 @@
|
||||
#ifndef ENTT_META_POINTER_HPP
|
||||
#define ENTT_META_POINTER_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Makes plain pointers pointer-like types for the meta system.
|
||||
* @tparam Type Element type.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_meta_pointer_like<Type *>
|
||||
: std::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Partial specialization used to reject pointers to arrays.
|
||||
* @tparam Type Type of elements of the array.
|
||||
* @tparam N Number of elements of the array.
|
||||
*/
|
||||
template<typename Type, std::size_t N>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
struct is_meta_pointer_like<Type (*)[N]>
|
||||
: std::false_type {};
|
||||
|
||||
/**
|
||||
* @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta
|
||||
* @brief Makes `stl::shared_ptr`s of any type pointer-like types for the meta
|
||||
* system.
|
||||
* @tparam Type Element type.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_meta_pointer_like<std::shared_ptr<Type>>
|
||||
: std::true_type {};
|
||||
struct is_meta_pointer_like<stl::shared_ptr<Type>>
|
||||
: stl::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Makes `std::unique_ptr`s of any type pointer-like types for the meta
|
||||
* @brief Makes `stl::unique_ptr`s of any type pointer-like types for the meta
|
||||
* system.
|
||||
* @tparam Type Element type.
|
||||
* @tparam Args Other arguments.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
struct is_meta_pointer_like<std::unique_ptr<Type, Args...>>
|
||||
: std::true_type {};
|
||||
struct is_meta_pointer_like<stl::unique_ptr<Type, Args...>>
|
||||
: stl::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Specialization for self-proclaimed meta pointer like types.
|
||||
* @tparam Type Element type.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_meta_pointer_like<Type, std::void_t<typename Type::is_meta_pointer_like>>
|
||||
: std::true_type {};
|
||||
requires requires { typename Type::is_meta_pointer_like; }
|
||||
struct is_meta_pointer_like<Type>
|
||||
: stl::true_type {};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
|
||||
@@ -1,37 +1,53 @@
|
||||
#ifndef ENTT_META_POLICY_HPP
|
||||
#define ENTT_META_POLICY_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include "../stl/type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @brief Empty class type used to request the _as ref_ policy. */
|
||||
struct as_ref_t final {
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
template<typename Type>
|
||||
static constexpr bool value = std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>;
|
||||
/*! @endcond */
|
||||
};
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
/*! @brief Empty class type used to request the _as cref_ policy. */
|
||||
struct as_cref_t final {
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
template<typename Type>
|
||||
static constexpr bool value = std::is_reference_v<Type>;
|
||||
/*! @endcond */
|
||||
};
|
||||
struct meta_policy {};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/*! @brief Empty class type used to request the _as-is_ policy. */
|
||||
struct as_is_t final {
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
struct as_value_t final: private internal::meta_policy {
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
template<typename>
|
||||
static constexpr bool value = true;
|
||||
/*! @endcond */
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as void_ policy. */
|
||||
struct as_void_t final {
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
struct as_void_t final: private internal::meta_policy {
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
template<typename>
|
||||
static constexpr bool value = true;
|
||||
/*! @endcond */
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as ref_ policy. */
|
||||
struct as_ref_t final: private internal::meta_policy {
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
template<typename Type>
|
||||
static constexpr bool value = stl::is_reference_v<Type> && !stl::is_const_v<stl::remove_reference_t<Type>>;
|
||||
/*! @endcond */
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as cref_ policy. */
|
||||
struct as_cref_t final: private internal::meta_policy {
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
template<typename Type>
|
||||
static constexpr bool value = stl::is_reference_v<Type>;
|
||||
/*! @endcond */
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as auto_ policy. */
|
||||
struct as_is_t final: private internal::meta_policy {
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
template<typename>
|
||||
static constexpr bool value = true;
|
||||
/*! @endcond */
|
||||
@@ -44,7 +60,7 @@ struct as_void_t final {
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_meta_policy
|
||||
: std::bool_constant<std::is_same_v<Type, as_ref_t> || std::is_same_v<Type, as_cref_t> || std::is_same_v<Type, as_is_t> || std::is_same_v<Type, as_void_t>> {};
|
||||
: stl::bool_constant<stl::is_base_of_v<internal::meta_policy, Type>> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -53,6 +69,13 @@ struct is_meta_policy
|
||||
template<typename Type>
|
||||
inline constexpr bool is_meta_policy_v = is_meta_policy<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Specifies whether a type is a meta policy.
|
||||
* @tparam Type Type to check.
|
||||
*/
|
||||
template<typename Type>
|
||||
concept meta_policy = is_meta_policy_v<Type>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
#ifndef ENTT_META_RANGE_HPP
|
||||
#define ENTT_META_RANGE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <compare>
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/iterator.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
struct meta_base_node;
|
||||
|
||||
template<typename Type, typename It>
|
||||
struct meta_range_iterator final {
|
||||
using value_type = std::pair<id_type, Type>;
|
||||
using value_type = stl::pair<id_type, 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;
|
||||
using iterator_concept = std::random_access_iterator_tag;
|
||||
using difference_type = stl::ptrdiff_t;
|
||||
using iterator_category = stl::input_iterator_tag;
|
||||
using iterator_concept = stl::random_access_iterator_tag;
|
||||
|
||||
constexpr meta_range_iterator() noexcept
|
||||
: it{},
|
||||
@@ -69,10 +71,8 @@ struct meta_range_iterator final {
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
|
||||
if constexpr(std::is_same_v<It, typename decltype(meta_context::value)::const_iterator>) {
|
||||
return {it[value].first, Type{*ctx, it[value].second}};
|
||||
} else if constexpr(std::is_same_v<typename std::iterator_traits<It>::value_type, meta_base_node>) {
|
||||
return {it[value].type, Type{*ctx, it[value]}};
|
||||
if constexpr(stl::is_same_v<It, typename meta_context::container_type::const_iterator>) {
|
||||
return {it[value].first, Type{*ctx, *it[value].second}};
|
||||
} else {
|
||||
return {it[value].id, Type{*ctx, it[value]}};
|
||||
}
|
||||
@@ -86,55 +86,23 @@ struct meta_range_iterator final {
|
||||
return operator[](0);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
friend constexpr std::ptrdiff_t operator-(const meta_range_iterator<Args...> &, const meta_range_iterator<Args...> &) noexcept;
|
||||
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const meta_range_iterator &other) const noexcept {
|
||||
return it - other.it;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
friend constexpr bool operator==(const meta_range_iterator<Args...> &, const meta_range_iterator<Args...> &) noexcept;
|
||||
[[nodiscard]] constexpr bool operator==(const meta_range_iterator &other) const noexcept {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
friend constexpr bool operator<(const meta_range_iterator<Args...> &, const meta_range_iterator<Args...> &) noexcept;
|
||||
[[nodiscard]] constexpr auto operator<=>(const meta_range_iterator &other) const noexcept {
|
||||
return it <=> other.it;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
const meta_ctx *ctx;
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr std::ptrdiff_t operator-(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
|
||||
return lhs.it - rhs.it;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator==(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator!=(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator<(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
|
||||
return lhs.it < rhs.it;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator>(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator<=(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] constexpr bool operator>=(const meta_range_iterator<Args...> &lhs, const meta_range_iterator<Args...> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
@@ -143,7 +111,7 @@ template<typename... Args>
|
||||
* @tparam Type Type of meta objects returned.
|
||||
* @tparam It Type of forward iterator.
|
||||
*/
|
||||
template<typename Type, typename It>
|
||||
template<typename Type, stl::forward_iterator It>
|
||||
using meta_range = iterable_adaptor<internal::meta_range_iterator<Type, It>>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#ifndef ENTT_META_RESOLVE_HPP
|
||||
#define ENTT_META_RESOLVE_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../locator/locator.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "context.hpp"
|
||||
#include "meta.hpp"
|
||||
#include "node.hpp"
|
||||
@@ -19,8 +19,8 @@ namespace entt {
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] meta_type resolve(const meta_ctx &ctx) noexcept {
|
||||
auto &&context = internal::meta_context::from(ctx);
|
||||
return {ctx, internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(context)};
|
||||
const auto &context = internal::meta_context::from(ctx);
|
||||
return {ctx, internal::resolve<stl::remove_cvref_t<Type>>(context)};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -38,16 +38,16 @@ template<typename Type>
|
||||
* @param ctx The context from which to search for meta types.
|
||||
* @return An iterable range to use to visit all meta types.
|
||||
*/
|
||||
[[nodiscard]] inline meta_range<meta_type, typename decltype(internal::meta_context::value)::const_iterator> resolve(const meta_ctx &ctx) noexcept {
|
||||
auto &&context = internal::meta_context::from(ctx);
|
||||
return {{ctx, context.value.cbegin()}, {ctx, context.value.cend()}};
|
||||
[[nodiscard]] inline meta_range<meta_type, typename internal::meta_context::container_type::const_iterator> resolve(const meta_ctx &ctx) noexcept {
|
||||
const auto &context = internal::meta_context::from(ctx);
|
||||
return {{ctx, context.bucket.cbegin()}, {ctx, context.bucket.cend()}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a range to use to visit all meta types.
|
||||
* @return An iterable range to use to visit all meta types.
|
||||
*/
|
||||
[[nodiscard]] inline meta_range<meta_type, typename decltype(internal::meta_context::value)::const_iterator> resolve() noexcept {
|
||||
[[nodiscard]] inline meta_range<meta_type, typename internal::meta_context::container_type::const_iterator> resolve() noexcept {
|
||||
return resolve(locator<meta_ctx>::value_or());
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ template<typename Type>
|
||||
* @return The meta type associated with the given type info object, if any.
|
||||
*/
|
||||
[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const type_info &info) noexcept {
|
||||
auto &&context = internal::meta_context::from(ctx);
|
||||
const auto &context = internal::meta_context::from(ctx);
|
||||
const auto *elem = internal::try_resolve(context, info);
|
||||
return (elem != nullptr) ? meta_type{ctx, *elem} : meta_type{};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef ENTT_META_TYPE_TRAITS_HPP
|
||||
#define ENTT_META_TYPE_TRAITS_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
@@ -31,8 +31,8 @@ struct meta_associative_container_traits;
|
||||
* @brief Provides the member constant `value` to true if a given type is a
|
||||
* pointer-like type from the point of view of the meta system, false otherwise.
|
||||
*/
|
||||
template<typename, typename = void>
|
||||
struct is_meta_pointer_like: std::false_type {};
|
||||
template<typename>
|
||||
struct is_meta_pointer_like: stl::false_type {};
|
||||
|
||||
/**
|
||||
* @brief Partial specialization to ensure that const pointer-like types are
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef ENTT_META_UTILITY_HPP
|
||||
#define ENTT_META_UTILITY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../locator/locator.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "meta.hpp"
|
||||
#include "node.hpp"
|
||||
#include "policy.hpp"
|
||||
@@ -48,8 +48,8 @@ template<typename Type, typename Ret, typename Class, typename... Args>
|
||||
struct meta_function_descriptor<Type, Ret (Class::*)(Args...) const>
|
||||
: meta_function_descriptor_traits<
|
||||
Ret,
|
||||
std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<const Class &, Args...>>,
|
||||
!std::is_base_of_v<Class, Type>,
|
||||
stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<Args...>, type_list<const Class &, Args...>>,
|
||||
!stl::is_base_of_v<Class, Type>,
|
||||
true> {};
|
||||
|
||||
/**
|
||||
@@ -63,8 +63,8 @@ template<typename Type, typename Ret, typename Class, typename... Args>
|
||||
struct meta_function_descriptor<Type, Ret (Class::*)(Args...)>
|
||||
: meta_function_descriptor_traits<
|
||||
Ret,
|
||||
std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<Class &, Args...>>,
|
||||
!std::is_base_of_v<Class, Type>,
|
||||
stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<Args...>, type_list<Class &, Args...>>,
|
||||
!stl::is_base_of_v<Class, Type>,
|
||||
false> {};
|
||||
|
||||
/**
|
||||
@@ -77,8 +77,8 @@ template<typename Type, typename Ret, typename Class>
|
||||
struct meta_function_descriptor<Type, Ret Class::*>
|
||||
: meta_function_descriptor_traits<
|
||||
Ret &,
|
||||
std::conditional_t<std::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>,
|
||||
!std::is_base_of_v<Class, Type>,
|
||||
stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>,
|
||||
!stl::is_base_of_v<Class, Type>,
|
||||
false> {};
|
||||
|
||||
/**
|
||||
@@ -92,12 +92,12 @@ template<typename Type, typename Ret, typename MaybeType, typename... Args>
|
||||
struct meta_function_descriptor<Type, Ret (*)(MaybeType, Args...)>
|
||||
: meta_function_descriptor_traits<
|
||||
Ret,
|
||||
std::conditional_t<
|
||||
std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>,
|
||||
stl::conditional_t<
|
||||
stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>,
|
||||
type_list<Args...>,
|
||||
type_list<MaybeType, Args...>>,
|
||||
!(std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>),
|
||||
std::is_const_v<std::remove_reference_t<MaybeType>> && (std::is_same_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type> || std::is_base_of_v<std::remove_cv_t<std::remove_reference_t<MaybeType>>, Type>)> {};
|
||||
!(stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>),
|
||||
stl::is_const_v<stl::remove_reference_t<MaybeType>> && (stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>)> {};
|
||||
|
||||
/**
|
||||
* @brief Meta function descriptor.
|
||||
@@ -124,23 +124,24 @@ struct meta_function_descriptor<Type, Ret (*)()>
|
||||
template<typename Type, typename Candidate>
|
||||
class meta_function_helper {
|
||||
template<typename Ret, typename... Args, typename Class>
|
||||
static constexpr meta_function_descriptor<Type, Ret (Class::*)(Args...) const> get_rid_of_noexcept(Ret (Class::*)(Args...) const);
|
||||
static meta_function_descriptor<Type, Ret (Class::*)(Args...) const> get_rid_of_noexcept(Ret (Class::*)(Args...) const);
|
||||
|
||||
template<typename Ret, typename... Args, typename Class>
|
||||
static constexpr meta_function_descriptor<Type, Ret (Class::*)(Args...)> get_rid_of_noexcept(Ret (Class::*)(Args...));
|
||||
static meta_function_descriptor<Type, Ret (Class::*)(Args...)> get_rid_of_noexcept(Ret (Class::*)(Args...));
|
||||
|
||||
template<typename Ret, typename Class, typename = std::enable_if_t<std::is_member_object_pointer_v<Ret Class::*>>>
|
||||
static constexpr meta_function_descriptor<Type, Ret Class::*> get_rid_of_noexcept(Ret Class::*);
|
||||
template<typename Ret, typename Class>
|
||||
requires stl::is_member_object_pointer_v<Ret Class::*>
|
||||
static meta_function_descriptor<Type, Ret Class::*> get_rid_of_noexcept(Ret Class::*);
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
static constexpr meta_function_descriptor<Type, Ret (*)(Args...)> get_rid_of_noexcept(Ret (*)(Args...));
|
||||
static meta_function_descriptor<Type, Ret (*)(Args...)> get_rid_of_noexcept(Ret (*)(Args...));
|
||||
|
||||
template<typename Class>
|
||||
static constexpr meta_function_descriptor<Class, decltype(&Class::operator())> get_rid_of_noexcept(Class);
|
||||
static meta_function_descriptor<Class, decltype(&Class::operator())> get_rid_of_noexcept(Class);
|
||||
|
||||
public:
|
||||
/*! @brief The meta function descriptor of the given function. */
|
||||
using type = decltype(get_rid_of_noexcept(std::declval<Candidate>()));
|
||||
using type = decltype(get_rid_of_noexcept(stl::declval<Candidate>()));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -149,7 +150,7 @@ public:
|
||||
* @tparam Candidate The actual function to associate with the reflected type.
|
||||
*/
|
||||
template<typename Type, typename Candidate>
|
||||
using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::type;
|
||||
using meta_function_helper_t = meta_function_helper<Type, Candidate>::type;
|
||||
|
||||
/**
|
||||
* @brief Wraps a value depending on the given policy.
|
||||
@@ -164,17 +165,17 @@ using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::t
|
||||
* @param value Value to wrap.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Policy = as_is_t, typename Type>
|
||||
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
|
||||
if constexpr(std::is_same_v<Policy, as_void_t>) {
|
||||
return meta_any{ctx, std::in_place_type<void>};
|
||||
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
|
||||
return meta_any{ctx, std::in_place_type<Type>, value};
|
||||
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
|
||||
static_assert(std::is_lvalue_reference_v<Type>, "Invalid type");
|
||||
return meta_any{ctx, std::in_place_type<const std::remove_reference_t<Type> &>, std::as_const(value)};
|
||||
template<meta_policy Policy = as_value_t, typename Type>
|
||||
[[nodiscard]] meta_any meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
|
||||
if constexpr(stl::is_same_v<Policy, as_cref_t>) {
|
||||
static_assert(stl::is_lvalue_reference_v<Type>, "Invalid type");
|
||||
return meta_any{ctx, stl::in_place_type<const stl::remove_reference_t<Type> &>, stl::as_const(value)};
|
||||
} else if constexpr(stl::is_same_v<Policy, as_ref_t> || (stl::is_same_v<Policy, as_is_t> && stl::is_lvalue_reference_v<Type>)) {
|
||||
return meta_any{ctx, stl::in_place_type<Type>, value};
|
||||
} else if constexpr(stl::is_same_v<Policy, as_void_t>) {
|
||||
return meta_any{ctx, stl::in_place_type<void>};
|
||||
} else {
|
||||
return meta_any{ctx, std::forward<Type>(value)};
|
||||
return meta_any{ctx, stl::forward<Type>(value)};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,52 +186,52 @@ template<typename Policy = as_is_t, typename Type>
|
||||
* @param value Value to wrap.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Policy = as_is_t, typename Type>
|
||||
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_dispatch(Type &&value) {
|
||||
return meta_dispatch<Policy, Type>(locator<meta_ctx>::value_or(), std::forward<Type>(value));
|
||||
template<meta_policy Policy = as_value_t, typename Type>
|
||||
[[nodiscard]] meta_any meta_dispatch(Type &&value) {
|
||||
return meta_dispatch<Policy, Type>(locator<meta_ctx>::value_or(), stl::forward<Type>(value));
|
||||
}
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename Policy, typename Candidate, typename... Args>
|
||||
[[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) {
|
||||
if constexpr(std::is_void_v<decltype(std::invoke(std::forward<Candidate>(candidate), args...))>) {
|
||||
std::invoke(std::forward<Candidate>(candidate), args...);
|
||||
return meta_any{ctx, std::in_place_type<void>};
|
||||
if constexpr(stl::is_void_v<decltype(stl::invoke(stl::forward<Candidate>(candidate), args...))>) {
|
||||
stl::invoke(stl::forward<Candidate>(candidate), args...);
|
||||
return meta_any{ctx, stl::in_place_type<void>};
|
||||
} else {
|
||||
return meta_dispatch<Policy>(ctx, std::invoke(std::forward<Candidate>(candidate), args...));
|
||||
return meta_dispatch<Policy>(ctx, stl::invoke(stl::forward<Candidate>(candidate), args...));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type, typename Policy, typename Candidate, std::size_t... Index>
|
||||
[[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, std::index_sequence<Index...>) {
|
||||
using descriptor = meta_function_helper_t<Type, std::remove_reference_t<Candidate>>;
|
||||
template<typename Type, typename Policy, typename Candidate, stl::size_t... Index>
|
||||
[[nodiscard]] meta_any meta_invoke(meta_any &instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, stl::index_sequence<Index...>) {
|
||||
using descriptor = meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>;
|
||||
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
|
||||
if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
|
||||
if(const auto *const clazz = instance->try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
|
||||
if constexpr(stl::is_invocable_v<stl::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
|
||||
if(const auto *const clazz = instance.try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Policy>(instance.context(), stl::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
} else if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
} else if constexpr(stl::is_invocable_v<stl::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
|
||||
if(auto *const clazz = instance.try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Policy>(instance.context(), stl::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
} else {
|
||||
if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Policy>(instance->context(), std::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
return meta_invoke_with_args<Policy>(instance.context(), stl::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
}
|
||||
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
|
||||
return meta_any{meta_ctx_arg, instance->context()};
|
||||
return meta_any{meta_ctx_arg, instance.context()};
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args, std::size_t... Index>
|
||||
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, std::index_sequence<Index...>) {
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
|
||||
template<typename Type, typename... Args, stl::size_t... Index>
|
||||
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, stl::index_sequence<Index...>) {
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
|
||||
if(((args + Index)->allow_cast<Args>() && ...)) {
|
||||
return meta_any{ctx, std::in_place_type<Type>, (args + Index)->cast<Args>()...};
|
||||
return meta_any{ctx, stl::in_place_type<Type>, (args + Index)->cast<Args>()...};
|
||||
}
|
||||
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
|
||||
@@ -248,8 +249,8 @@ template<typename Type, typename... Args, std::size_t... Index>
|
||||
* @return The meta type of the i-th element of the list of arguments.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] static meta_type meta_arg(const meta_ctx &ctx, const std::size_t index) noexcept {
|
||||
auto &&context = internal::meta_context::from(ctx);
|
||||
[[nodiscard]] meta_type meta_arg(const meta_ctx &ctx, const stl::size_t index) noexcept {
|
||||
const auto &context = internal::meta_context::from(ctx);
|
||||
return {ctx, internal::meta_arg_node(context, Type{}, index)};
|
||||
}
|
||||
|
||||
@@ -260,7 +261,7 @@ template<typename Type>
|
||||
* @return The meta type of the i-th element of the list of arguments.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] static meta_type meta_arg(const std::size_t index) noexcept {
|
||||
[[nodiscard]] meta_type meta_arg(const stl::size_t index) noexcept {
|
||||
return meta_arg<Type>(locator<meta_ctx>::value_or(), index);
|
||||
}
|
||||
|
||||
@@ -274,27 +275,27 @@ template<typename Type>
|
||||
*/
|
||||
template<typename Type, auto Data>
|
||||
[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
|
||||
if constexpr(std::is_member_function_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
|
||||
if constexpr(stl::is_member_function_pointer_v<decltype(Data)> || stl::is_function_v<stl::remove_reference_t<stl::remove_pointer_t<decltype(Data)>>>) {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Data)>;
|
||||
using data_type = type_list_element_t<descriptor::is_static, typename descriptor::args_type>;
|
||||
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
|
||||
std::invoke(Data, *clazz, value.cast<data_type>());
|
||||
stl::invoke(Data, *clazz, value.cast<data_type>());
|
||||
return true;
|
||||
}
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
|
||||
} else if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = stl::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
|
||||
|
||||
if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
|
||||
if constexpr(!stl::is_array_v<data_type> && !stl::is_const_v<data_type>) {
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
|
||||
std::invoke(Data, *clazz) = value.cast<data_type>();
|
||||
stl::invoke(Data, *clazz) = value.cast<data_type>();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if constexpr(std::is_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_reference_t<decltype(*Data)>;
|
||||
} else if constexpr(stl::is_pointer_v<decltype(Data)>) {
|
||||
using data_type = stl::remove_reference_t<decltype(*Data)>;
|
||||
|
||||
if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
|
||||
if constexpr(!stl::is_array_v<data_type> && !stl::is_const_v<data_type>) {
|
||||
if(value.allow_cast<data_type>()) {
|
||||
*Data = value.cast<data_type>();
|
||||
return true;
|
||||
@@ -313,26 +314,26 @@ template<typename Type, auto Data>
|
||||
* @param instance An opaque instance of the underlying type, if required.
|
||||
* @return A meta any containing the value of the underlying variable.
|
||||
*/
|
||||
template<typename Type, auto Data, typename Policy = as_is_t>
|
||||
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_getter(meta_handle instance) {
|
||||
if constexpr(std::is_member_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
|
||||
if constexpr(!std::is_array_v<std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>>>) {
|
||||
if constexpr(std::is_invocable_v<decltype(Data), Type &>) {
|
||||
template<typename Type, auto Data, meta_policy Policy = as_value_t>
|
||||
[[nodiscard]] meta_any meta_getter(meta_handle instance) {
|
||||
if constexpr(stl::is_member_pointer_v<decltype(Data)> || stl::is_function_v<stl::remove_reference_t<stl::remove_pointer_t<decltype(Data)>>>) {
|
||||
if constexpr(!stl::is_array_v<stl::remove_cvref_t<stl::invoke_result_t<decltype(Data), Type &>>>) {
|
||||
if constexpr(stl::is_invocable_v<decltype(Data), Type &>) {
|
||||
if(auto *clazz = instance->try_cast<Type>(); clazz) {
|
||||
return meta_dispatch<Policy>(instance->context(), std::invoke(Data, *clazz));
|
||||
return meta_dispatch<Policy>(instance->context(), stl::invoke(Data, *clazz));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr(std::is_invocable_v<decltype(Data), const Type &>) {
|
||||
if constexpr(stl::is_invocable_v<decltype(Data), const Type &>) {
|
||||
if(auto *fallback = instance->try_cast<const Type>(); fallback) {
|
||||
return meta_dispatch<Policy>(instance->context(), std::invoke(Data, *fallback));
|
||||
return meta_dispatch<Policy>(instance->context(), stl::invoke(Data, *fallback));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return meta_any{meta_ctx_arg, instance->context()};
|
||||
} else if constexpr(std::is_pointer_v<decltype(Data)>) {
|
||||
if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
|
||||
} else if constexpr(stl::is_pointer_v<decltype(Data)>) {
|
||||
if constexpr(stl::is_array_v<stl::remove_pointer_t<decltype(Data)>>) {
|
||||
return meta_any{meta_ctx_arg, instance->context()};
|
||||
} else {
|
||||
return meta_dispatch<Policy>(instance->context(), *Data);
|
||||
@@ -342,20 +343,6 @@ template<typename Type, auto Data, typename Policy = as_is_t>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the value of a given variable.
|
||||
* @tparam Type Reflected type to which the variable is associated.
|
||||
* @tparam Data The actual variable to get.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param ctx The context from which to search for meta types.
|
||||
* @param instance An opaque instance of the underlying type, if required.
|
||||
* @return A meta any containing the value of the underlying variable.
|
||||
*/
|
||||
template<typename Type, auto Data, typename Policy = as_is_t>
|
||||
[[deprecated("a context is no longer required, it is inferred from the meta_handle")]] [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_getter(const meta_ctx &ctx, meta_handle instance) {
|
||||
return meta_getter<Type, Data, Policy>(meta_handle{ctx, std::move(instance)});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to _invoke_ an object given a list of erased parameters.
|
||||
* @tparam Type Reflected type to which the object to _invoke_ is associated.
|
||||
@@ -366,25 +353,9 @@ template<typename Type, auto Data, typename Policy = as_is_t>
|
||||
* @param args Parameters to use to _invoke_ the object.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
|
||||
return internal::meta_invoke<Type, Policy>(std::move(instance), std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to _invoke_ an object given a list of erased parameters.
|
||||
* @tparam Type Reflected type to which the object to _invoke_ is associated.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param ctx The context from which to search for meta types.
|
||||
* @tparam Candidate The type of the actual object to _invoke_.
|
||||
* @param instance An opaque instance of the underlying type, if required.
|
||||
* @param candidate The actual object to _invoke_.
|
||||
* @param args Parameters to use to _invoke_ the object.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
[[deprecated("a context is no longer required, it is inferred from the meta_handle")]] [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(const meta_ctx &ctx, meta_handle instance, Candidate &&candidate, meta_any *const args) {
|
||||
return meta_invoke<Type, Policy>(meta_handle{ctx, std::move(instance)}, std::forward<Candidate>(candidate), args);
|
||||
template<typename Type, meta_policy Policy = as_value_t, typename Candidate>
|
||||
[[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
|
||||
return internal::meta_invoke<Type, Policy>(*instance.operator->(), stl::forward<Candidate>(candidate), args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,24 +367,9 @@ template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
* @param args Parameters to use to invoke the function.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, auto Candidate, typename Policy = as_is_t>
|
||||
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(meta_handle instance, meta_any *const args) {
|
||||
return internal::meta_invoke<Type, Policy>(std::move(instance), Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to invoke a function given a list of erased parameters.
|
||||
* @tparam Type Reflected type to which the function is associated.
|
||||
* @tparam Candidate The actual function to invoke.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param ctx The context from which to search for meta types.
|
||||
* @param instance An opaque instance of the underlying type, if required.
|
||||
* @param args Parameters to use to invoke the function.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, auto Candidate, typename Policy = as_is_t>
|
||||
[[deprecated("a context is no longer required, it is inferred from the meta_handle")]] [[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_invoke(const meta_ctx &ctx, meta_handle instance, meta_any *const args) {
|
||||
return meta_invoke<Type, Candidate, Policy>(meta_handle{ctx, std::move(instance)}, args);
|
||||
template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
|
||||
[[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) {
|
||||
return internal::meta_invoke<Type, Policy>(*instance.operator->(), Candidate, args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -431,7 +387,7 @@ template<typename Type, auto Candidate, typename Policy = as_is_t>
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
|
||||
return internal::meta_construct<Type, Args...>(ctx, args, std::index_sequence_for<Args...>{});
|
||||
return internal::meta_construct<Type, Args...>(ctx, args, stl::index_sequence_for<Args...>{});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -461,14 +417,14 @@ template<typename Type, typename... Args>
|
||||
* @param args Parameters to use to _invoke_ the object.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
template<typename Type, typename Policy = as_value_t, typename Candidate>
|
||||
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) {
|
||||
if constexpr(meta_function_helper_t<Type, Candidate>::is_static || std::is_class_v<std::remove_cv_t<std::remove_reference_t<Candidate>>>) {
|
||||
return internal::meta_invoke<Type, Policy>(meta_handle{meta_ctx_arg, ctx}, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
|
||||
if constexpr(meta_function_helper_t<Type, Candidate>::is_static || stl::is_class_v<stl::remove_cvref_t<Candidate>>) {
|
||||
meta_any placeholder{meta_ctx_arg, ctx};
|
||||
return internal::meta_invoke<Type, Policy>(placeholder, stl::forward<Candidate>(candidate), args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
|
||||
} else {
|
||||
meta_any handle{ctx, args->as_ref()};
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span)
|
||||
return internal::meta_invoke<Type, Policy>(handle, std::forward<Candidate>(candidate), args + 1u, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
|
||||
return internal::meta_invoke<Type, Policy>(*args, stl::forward<Candidate>(candidate), args + 1u, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,9 +437,9 @@ template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
* @param args Parameters to use to _invoke_ the object.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(Candidate &&candidate, meta_any *const args) {
|
||||
return meta_construct<Type, Policy>(locator<meta_ctx>::value_or(), std::forward<Candidate>(candidate), args);
|
||||
template<typename Type, meta_policy Policy = as_value_t, typename Candidate>
|
||||
[[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) {
|
||||
return meta_construct<Type, Policy>(locator<meta_ctx>::value_or(), stl::forward<Candidate>(candidate), args);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,8 +456,8 @@ template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
* @param args Parameters to use to invoke the function.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, auto Candidate, typename Policy = as_is_t>
|
||||
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(const meta_ctx &ctx, meta_any *const args) {
|
||||
template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
|
||||
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
|
||||
return meta_construct<Type, Policy>(ctx, Candidate, args);
|
||||
}
|
||||
|
||||
@@ -513,8 +469,8 @@ template<typename Type, auto Candidate, typename Policy = as_is_t>
|
||||
* @param args Parameters to use to invoke the function.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, auto Candidate, typename Policy = as_is_t>
|
||||
[[nodiscard]] std::enable_if_t<is_meta_policy_v<Policy>, meta_any> meta_construct(meta_any *const args) {
|
||||
template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
|
||||
[[nodiscard]] meta_any meta_construct(meta_any *const args) {
|
||||
return meta_construct<Type, Candidate, Policy>(locator<meta_ctx>::value_or(), args);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?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>
|
||||
<DisplayString>{{ policy={ mode,en } }}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::compressed_pair<*>">
|
||||
<Intrinsic Name="first" Optional="true" Expression="((first_base*)this)->value"/>
|
||||
@@ -47,7 +47,7 @@
|
||||
<Intrinsic Name="is_valid_entity" Expression="!traits_type::version_mask || (*((traits_type::entity_type *)&entity) < (traits_type::version_mask << traits_type::length))">
|
||||
<Parameter Name="entity" Type="const traits_type::value_type &"/>
|
||||
</Intrinsic>
|
||||
<DisplayString>{{ size={ packed.size() }, type={ info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{ size={ packed.size() }, type={ descriptor->alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" ExcludeView="simple">packed.capacity()</Item>
|
||||
<Item Name="[policy]" ExcludeView="simple">mode,en</Item>
|
||||
@@ -94,7 +94,7 @@
|
||||
<Intrinsic Name="is_valid_entity" Expression="!base_type::traits_type::version_mask || (*((base_type::traits_type::entity_type *)&entity) < (base_type::traits_type::version_mask << base_type::traits_type::length))">
|
||||
<Parameter Name="entity" Type="const base_type::traits_type::value_type &"/>
|
||||
</Intrinsic>
|
||||
<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::descriptor->alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" Optional="true" ExcludeView="simple">payload.capacity() * traits_type::page_size</Item>
|
||||
<Item Name="[page size]" Optional="true" ExcludeView="simple">traits_type::page_size</Item>
|
||||
@@ -163,7 +163,7 @@
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="pool_at(pos)->sparse.size() > page && pool_at(pos)->sparse[page] != nullptr && ((*((traits_type::entity_type *)&pool_at(pos)->sparse[page][offset])) & entity_mask) != entity_mask">
|
||||
<Item Name="[{ pool_at(pos)->info->alias,na }:{ ((*((traits_type::entity_type *)&pool_at(pos)->sparse[page][offset])) & entity_mask) != entity_mask }]">pool_at(pos),view(simple)nanr</Item>
|
||||
<Item Name="[{ pool_at(pos)->descriptor->alias,na }:{ ((*((traits_type::entity_type *)&pool_at(pos)->sparse[page][offset])) & entity_mask) != entity_mask }]">pool_at(pos),view(simple)nanr</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
</Loop>
|
||||
@@ -1,17 +1,17 @@
|
||||
<?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 Condition="resolve != nullptr">{{ type={ type } }}</DisplayString>
|
||||
<DisplayString Condition="type != nullptr">{{ id={ id } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[type]">type</Item>
|
||||
<Item Name="[id]">id</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_conv_node">
|
||||
<DisplayString Condition="conv != nullptr">{{ type={ type } }}</DisplayString>
|
||||
<DisplayString Condition="conv != nullptr">{{ id={ id } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[type]">type</Item>
|
||||
<Item Name="[type]">id</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_ctor_node">
|
||||
@@ -23,10 +23,10 @@
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_custom_node">
|
||||
<DisplayString Condition="value != nullptr">{{ type={ type } }}</DisplayString>
|
||||
<DisplayString Condition="value != nullptr">{{ id={ id } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[type]">type</Item>
|
||||
<Item Name="[id]">id</Item>
|
||||
<Item Name="[value]">value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
@@ -34,33 +34,33 @@
|
||||
<Intrinsic Name="has_trait" Expression="!!(traits & property)">
|
||||
<Parameter Name="property" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString Condition="name != nullptr">{{ id={ name,na } }}</DisplayString>
|
||||
<DisplayString Condition="get != nullptr">{{ id={ id } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[id]">id</Item>
|
||||
<Item Name="[name]" Condition="name != nullptr">name,na</Item>
|
||||
<Item Name="[arity]">arity</Item>
|
||||
<Item Name="[is_const]">has_trait(entt::internal::meta_traits::is_const)</Item>
|
||||
<Item Name="[is_static]">has_trait(entt::internal::meta_traits::is_static)</Item>
|
||||
<Item Name="[custom]">custom</Item>
|
||||
<Item Name="[custom]" Condition="custom.value != nullptr">custom</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_dtor_node">
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand/>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_func_node" >
|
||||
<Intrinsic Name="has_trait" Expression="!!(traits & property)">
|
||||
<Parameter Name="property" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString Condition="name != nullptr">{{ id={ name,na } }}</DisplayString>
|
||||
<DisplayString Condition="invoke != nullptr">{{ id={ id } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[id]">id</Item>
|
||||
<Item Name="[name]" Condition="name != nullptr">name,na</Item>
|
||||
<Item Name="[arity]">arity</Item>
|
||||
<Item Name="[is_const]">has_trait(entt::internal::meta_traits::is_const)</Item>
|
||||
<Item Name="[is_static]">has_trait(entt::internal::meta_traits::is_static)</Item>
|
||||
<Item Name="[next]" Condition="next != nullptr">*next</Item>
|
||||
<Item Name="[custom]">custom</Item>
|
||||
<Item Name="[custom]" Condition="custom.value != nullptr">custom</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_template_node">
|
||||
@@ -84,10 +84,12 @@
|
||||
<Intrinsic Name="has_trait" Expression="!!(traits & property)">
|
||||
<Parameter Name="property" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString Condition="name != nullptr">{{ type={ name,na } }}</DisplayString>
|
||||
<DisplayString Condition="info != nullptr">{{ type={ info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[id]">id</Item>
|
||||
<Item Name="[name]" Condition="name != nullptr">name,na</Item>
|
||||
<Item Name="[sizeof]">size_of</Item>
|
||||
<Item Name="[is_arithmetic]">has_trait(entt::internal::meta_traits::is_arithmetic)</Item>
|
||||
<Item Name="[is_integral]">has_trait(entt::internal::meta_traits::is_integral)</Item>
|
||||
@@ -102,17 +104,17 @@
|
||||
<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="[custom]">custom</Item>
|
||||
<Item Name="[details]" Condition="!(details == nullptr)">*details</Item>
|
||||
<Item Name="[template_info]" Condition="templ.arity != 0u">templ</Item>
|
||||
<Item Name="[custom]" Condition="custom.value != nullptr">custom</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>{ storage }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
<ExpandedItem Condition="node != nullptr">node,na</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_handle">
|
||||
@@ -125,7 +127,7 @@
|
||||
<DisplayString Condition="data != nullptr">{{ const={ const_only } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
|
||||
<Item Name="[const]">const_only</Item>
|
||||
<Item Name="[data]">data</Item>
|
||||
</Expand>
|
||||
@@ -134,49 +136,59 @@
|
||||
<DisplayString Condition="data != nullptr">{{ const={ const_only } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
|
||||
<Item Name="[const]">const_only</Item>
|
||||
<Item Name="[data]">data</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_custom">
|
||||
<DisplayString>{ node }</DisplayString>
|
||||
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>node</ExpandedItem>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_data">
|
||||
<DisplayString Condition="node.get != nullptr">{ node }</DisplayString>
|
||||
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node.get != nullptr">node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_func">
|
||||
<DisplayString Condition="node.invoke != nullptr">{ node }</DisplayString>
|
||||
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node.invoke != nullptr">node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_base">
|
||||
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_type">
|
||||
<DisplayString>{ node }</DisplayString>
|
||||
<DisplayString Condition="node != nullptr">{ node,na }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_ctx">
|
||||
<Intrinsic Name="element_at" Expression="value.packed.first_base::value[pos].element">
|
||||
<Intrinsic Name="element_at" Expression="bucket.packed.first_base::value[pos].element">
|
||||
<Parameter Name="pos" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString>{ value }</DisplayString>
|
||||
<DisplayString>{ bucket }</DisplayString>
|
||||
<Expand>
|
||||
<CustomListItems>
|
||||
<Variable Name="pos" InitialValue="0"/>
|
||||
<Variable Name="last" InitialValue="value.size()"/>
|
||||
<Variable Name="last" InitialValue="bucket.size()"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<Item Name="[{ element_at(pos).first }]">element_at(pos).second</Item>
|
||||
21
src/entt/natvis/process.natvis
Normal file
21
src/entt/natvis/process.natvis
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::basic_process<*>">
|
||||
<DisplayString>{{ state={ current,en } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[state]">current,en</Item>
|
||||
<Item Name="[child]" Condition="next.first_base::value != nullptr">*next.first_base::value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_scheduler<*>">
|
||||
<Intrinsic Name="size" Expression="handlers.first_base::value.size()"/>
|
||||
<DisplayString>{{ size={ size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" ExcludeView="simple">handlers.first_base::value.capacity()</Item>
|
||||
<IndexListItems>
|
||||
<Size>size()</Size>
|
||||
<ValueNode>*handlers.first_base::value[$i]</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
@@ -21,6 +21,7 @@
|
||||
<DisplayString>{{ size={ events.size() }, event={ "$T1" } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[signal]">signal</Item>
|
||||
<Item Name="[events]">events,view(simple)</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::emitter<*>">
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef ENTT_POLY_FWD_HPP
|
||||
#define ENTT_POLY_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include "../stl/cstddef.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
|
||||
template<typename, std::size_t Len = sizeof(double[2]), std::size_t = alignof(double[2])>
|
||||
template<typename, stl::size_t Len = sizeof(double[2]), stl::size_t = alignof(double[2])>
|
||||
class basic_poly;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
#ifndef ENTT_POLY_POLY_HPP
|
||||
#define ENTT_POLY_POLY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../core/any.hpp"
|
||||
#include "../core/concepts.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/concepts.hpp"
|
||||
#include "../stl/cstddef.hpp"
|
||||
#include "../stl/functional.hpp"
|
||||
#include "../stl/tuple.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
@@ -29,11 +31,11 @@ struct poly_inspector {
|
||||
* @param args The arguments to pass to the function.
|
||||
* @return A poly inspector convertible to any type.
|
||||
*/
|
||||
template<std::size_t Member, typename... Args>
|
||||
template<stl::size_t Member, typename... Args>
|
||||
[[nodiscard]] poly_inspector invoke(Args &&...args) const;
|
||||
|
||||
/*! @copydoc invoke */
|
||||
template<std::size_t Member, typename... Args>
|
||||
template<stl::size_t Member, typename... Args>
|
||||
[[nodiscard]] poly_inspector invoke(Args &&...args);
|
||||
};
|
||||
|
||||
@@ -43,78 +45,80 @@ struct poly_inspector {
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Alignment requirement.
|
||||
*/
|
||||
template<typename Concept, std::size_t Len, std::size_t Align>
|
||||
template<typename Concept, stl::size_t Len, stl::size_t Align>
|
||||
class poly_vtable {
|
||||
using inspector = typename Concept::template type<poly_inspector>;
|
||||
using inspector = Concept::template type<poly_inspector>;
|
||||
|
||||
template<typename Ret, typename Clazz, typename... Args>
|
||||
requires stl::derived_from<inspector, stl::remove_const_t<Clazz>>
|
||||
static auto vtable_entry(Ret (*)(Clazz &, Args...))
|
||||
-> std::enable_if_t<std::is_base_of_v<std::remove_const_t<Clazz>, inspector>, Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...)>;
|
||||
-> Ret (*)(constness_as_t<basic_any<Len, Align>, Clazz> &, Args...);
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
static auto vtable_entry(Ret (*)(Args...))
|
||||
-> Ret (*)(const basic_any<Len, Align> &, Args...);
|
||||
|
||||
template<typename Ret, typename Clazz, typename... Args>
|
||||
requires stl::derived_from<inspector, Clazz>
|
||||
static auto vtable_entry(Ret (Clazz::*)(Args...))
|
||||
-> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(basic_any<Len, Align> &, Args...)>;
|
||||
-> Ret (*)(basic_any<Len, Align> &, Args...);
|
||||
|
||||
template<typename Ret, typename Clazz, typename... Args>
|
||||
requires stl::derived_from<inspector, Clazz>
|
||||
static auto vtable_entry(Ret (Clazz::*)(Args...) const)
|
||||
-> std::enable_if_t<std::is_base_of_v<Clazz, inspector>, Ret (*)(const basic_any<Len, Align> &, Args...)>;
|
||||
-> Ret (*)(const basic_any<Len, Align> &, Args...);
|
||||
|
||||
template<auto... Candidate>
|
||||
static auto make_vtable(value_list<Candidate...>) noexcept
|
||||
-> decltype(std::make_tuple(vtable_entry(Candidate)...));
|
||||
-> decltype(stl::make_tuple(vtable_entry(Candidate)...));
|
||||
|
||||
template<typename... Func>
|
||||
[[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) noexcept {
|
||||
[[nodiscard]] static ENTT_CONSTEVAL auto make_vtable(type_list<Func...>) noexcept {
|
||||
if constexpr(sizeof...(Func) == 0u) {
|
||||
return decltype(make_vtable(typename Concept::template impl<inspector>{})){};
|
||||
} else if constexpr((std::is_function_v<Func> && ...)) {
|
||||
return decltype(std::make_tuple(vtable_entry(std::declval<Func inspector::*>())...)){};
|
||||
} else if constexpr((stl::is_function_v<Func> && ...)) {
|
||||
return decltype(stl::make_tuple(vtable_entry(stl::declval<Func inspector::*>())...)){};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type, auto Candidate, typename Ret, typename Any, typename... Args>
|
||||
static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) noexcept {
|
||||
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
|
||||
if constexpr(stl::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
|
||||
entry = +[](Any &, Args... args) -> Ret {
|
||||
return std::invoke(Candidate, std::forward<Args>(args)...);
|
||||
return stl::invoke(Candidate, stl::forward<Args>(args)...);
|
||||
};
|
||||
} else {
|
||||
entry = +[](Any &instance, Args... args) -> Ret {
|
||||
return static_cast<Ret>(std::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(instance), std::forward<Args>(args)...));
|
||||
return static_cast<Ret>(stl::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(instance), stl::forward<Args>(args)...));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type, auto... Index>
|
||||
[[nodiscard]] static auto fill_vtable(std::index_sequence<Index...>) noexcept {
|
||||
[[nodiscard]] static auto fill_vtable(stl::index_sequence<Index...>) noexcept {
|
||||
vtable_type impl{};
|
||||
(fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(std::get<Index>(impl)), ...);
|
||||
(fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(stl::get<Index>(impl)), ...);
|
||||
return impl;
|
||||
}
|
||||
|
||||
using vtable_type = decltype(make_vtable(Concept{}));
|
||||
static constexpr bool is_mono = std::tuple_size_v<vtable_type> == 1u;
|
||||
static constexpr bool is_mono = stl::tuple_size_v<vtable_type> == 1u;
|
||||
|
||||
public:
|
||||
/*! @brief Virtual table type. */
|
||||
using type = std::conditional_t<is_mono, std::tuple_element_t<0u, vtable_type>, const vtable_type *>;
|
||||
using type = stl::conditional_t<is_mono, stl::tuple_element_t<0u, vtable_type>, const vtable_type *>;
|
||||
|
||||
/**
|
||||
* @brief Returns a static virtual table for a specific concept and type.
|
||||
* @tparam Type The type for which to generate the virtual table.
|
||||
* @return A static virtual table for the given concept and type.
|
||||
*/
|
||||
template<typename Type>
|
||||
template<cvref_unqualified Type>
|
||||
[[nodiscard]] static type instance() noexcept {
|
||||
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Type differs from its decayed form");
|
||||
static const vtable_type vtable = fill_vtable<Type>(std::make_index_sequence<Concept::template impl<Type>::size>{});
|
||||
static const vtable_type vtable = fill_vtable<Type>(stl::make_index_sequence<Concept::template impl<Type>::size>{});
|
||||
|
||||
if constexpr(is_mono) {
|
||||
return std::get<0>(vtable);
|
||||
return stl::get<0>(vtable);
|
||||
} else {
|
||||
return &vtable;
|
||||
}
|
||||
@@ -135,27 +139,27 @@ struct poly_base {
|
||||
* @param args The arguments to pass to the function.
|
||||
* @return The return value of the invoked function, if any.
|
||||
*/
|
||||
template<std::size_t Member, typename... Args>
|
||||
template<stl::size_t Member, typename... Args>
|
||||
[[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&...args) const {
|
||||
const auto &poly = static_cast<const Poly &>(self);
|
||||
|
||||
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
|
||||
return poly.vtable(poly.storage, std::forward<Args>(args)...);
|
||||
if constexpr(stl::is_function_v<stl::remove_pointer_t<decltype(poly.vtable)>>) {
|
||||
return poly.vtable(poly.storage, stl::forward<Args>(args)...);
|
||||
} else {
|
||||
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
|
||||
return stl::get<Member>(*poly.vtable)(poly.storage, stl::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc invoke */
|
||||
template<std::size_t Member, typename... Args>
|
||||
template<stl::size_t Member, typename... Args>
|
||||
[[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) {
|
||||
auto &poly = static_cast<Poly &>(self);
|
||||
|
||||
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
|
||||
if constexpr(stl::is_function_v<stl::remove_pointer_t<decltype(poly.vtable)>>) {
|
||||
static_assert(Member == 0u, "Unknown member");
|
||||
return poly.vtable(poly.storage, std::forward<Args>(args)...);
|
||||
return poly.vtable(poly.storage, stl::forward<Args>(args)...);
|
||||
} else {
|
||||
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
|
||||
return stl::get<Member>(*poly.vtable)(poly.storage, stl::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -169,9 +173,9 @@ struct poly_base {
|
||||
* @param args The arguments to pass to the function.
|
||||
* @return The return value of the invoked function, if any.
|
||||
*/
|
||||
template<std::size_t Member, typename Poly, typename... Args>
|
||||
template<stl::size_t Member, typename Poly, typename... Args>
|
||||
decltype(auto) poly_call(Poly &&self, Args &&...args) {
|
||||
return std::forward<Poly>(self).template invoke<Member>(self, std::forward<Args>(args)...);
|
||||
return stl::forward<Poly>(self).template invoke<Member>(self, stl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,15 +193,15 @@ decltype(auto) poly_call(Poly &&self, Args &&...args) {
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Optional alignment requirement.
|
||||
*/
|
||||
template<typename Concept, std::size_t Len, std::size_t Align>
|
||||
template<typename Concept, stl::size_t Len, stl::size_t Align>
|
||||
class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, Len, Align>>> {
|
||||
friend struct poly_base<basic_poly>;
|
||||
|
||||
public:
|
||||
/*! @brief Concept type. */
|
||||
using concept_type = typename Concept::template type<poly_base<basic_poly>>;
|
||||
using concept_type = Concept::template type<poly_base<basic_poly>>;
|
||||
/*! @brief Virtual table type. */
|
||||
using vtable_type = typename poly_vtable<Concept, Len, Align>::type;
|
||||
using vtable_type = poly_vtable<Concept, Len, Align>::type;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_poly() noexcept = default;
|
||||
@@ -209,25 +213,26 @@ public:
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
explicit basic_poly(std::in_place_type_t<Type>, Args &&...args)
|
||||
: storage{std::in_place_type<Type>, std::forward<Args>(args)...},
|
||||
vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>()} {}
|
||||
explicit basic_poly(stl::in_place_type_t<Type>, Args &&...args)
|
||||
: storage{stl::in_place_type<Type>, stl::forward<Args>(args)...},
|
||||
vtable{poly_vtable<Concept, Len, Align>::template instance<stl::remove_cvref_t<Type>>()} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a poly from a given value.
|
||||
* @tparam Type Type of object to use to initialize the poly.
|
||||
* @param value An instance of an object to use to initialize the poly.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, basic_poly>>>
|
||||
template<typename Type>
|
||||
requires (!stl::same_as<stl::remove_cvref_t<Type>, basic_poly>)
|
||||
basic_poly(Type &&value) noexcept
|
||||
: basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
|
||||
: basic_poly{stl::in_place_type<stl::remove_cvref_t<Type>>, stl::forward<Type>(value)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns the object type if any, `type_id<void>()` otherwise.
|
||||
* @return The object type if any, `type_id<void>()` otherwise.
|
||||
* @brief Returns the object type info if any, `type_id<void>()` otherwise.
|
||||
* @return The object type info if any, `type_id<void>()` otherwise.
|
||||
*/
|
||||
[[nodiscard]] const type_info &type() const noexcept {
|
||||
return storage.type();
|
||||
[[nodiscard]] const type_info &info() const noexcept {
|
||||
return storage.info();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,8 +256,8 @@ public:
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
void emplace(Args &&...args) {
|
||||
storage.template emplace<Type>(std::forward<Args>(args)...);
|
||||
vtable = poly_vtable<Concept, Len, Align>::template instance<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
storage.template emplace<Type>(stl::forward<Args>(args)...);
|
||||
vtable = poly_vtable<Concept, Len, Align>::template instance<stl::remove_cvref_t<Type>>();
|
||||
}
|
||||
|
||||
/*! @brief Destroys contained object */
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
#ifndef ENTT_PROCESS_FWD_HPP
|
||||
#define ENTT_PROCESS_FWD_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include "../stl/cstdint.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<typename, typename>
|
||||
class process;
|
||||
template<typename, typename = stl::allocator<void>>
|
||||
class basic_process;
|
||||
|
||||
template<typename = std::uint32_t, typename = std::allocator<void>>
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using process = basic_process<stl::uint32_t>;
|
||||
|
||||
template<typename, typename = stl::allocator<void>>
|
||||
class basic_scheduler;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using scheduler = basic_scheduler<>;
|
||||
using scheduler = basic_scheduler<stl::uint32_t>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user