Compare commits
658 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7821307565 | ||
|
|
27efd6fdf4 | ||
|
|
4dc3f650e8 | ||
|
|
d5a2e353cd | ||
|
|
3fd8b84d04 | ||
|
|
2909e7ab1f | ||
|
|
60703f6845 | ||
|
|
062c95fc11 | ||
|
|
15ce55bc60 | ||
|
|
2d3fa3e51a | ||
|
|
7f49768739 | ||
|
|
fedcb920ce | ||
|
|
6e0c2baf9d | ||
|
|
20aa62c584 | ||
|
|
9fbd167bd0 | ||
|
|
2562bf76f6 | ||
|
|
b5ac3c5f41 | ||
|
|
7af8d015bc | ||
|
|
f01fe06b7a | ||
|
|
5618fd9549 | ||
|
|
76397ad2e6 | ||
|
|
6ca1bca26c | ||
|
|
b0b5b2ec4d | ||
|
|
1c460130a5 | ||
|
|
31b2a2129c | ||
|
|
f3a6fdbc02 | ||
|
|
f6232603c4 | ||
|
|
15d63ec358 | ||
|
|
9800bfa680 | ||
|
|
6b91bbab28 | ||
|
|
b7e929b0cc | ||
|
|
f38ab24b7a | ||
|
|
b698e53131 | ||
|
|
346165e4f9 | ||
|
|
9708727269 | ||
|
|
0f6e1d8aef | ||
|
|
51932b4459 | ||
|
|
2b092c2fce | ||
|
|
b152c63dd6 | ||
|
|
f920a84ac0 | ||
|
|
4e9cc9773d | ||
|
|
4d32c1ba58 | ||
|
|
2776f9bad9 | ||
|
|
fc381b72d3 | ||
|
|
a77a223223 | ||
|
|
b249fa252d | ||
|
|
b32b8002d3 | ||
|
|
8177f8934c | ||
|
|
ac4c38a10a | ||
|
|
854dedfda0 | ||
|
|
52f8e6db30 | ||
|
|
140d0dab6a | ||
|
|
1ff2db8aa2 | ||
|
|
34f700fcca | ||
|
|
8c53e0514e | ||
|
|
b6cea84910 | ||
|
|
f4d9a7729f | ||
|
|
47ab69f394 | ||
|
|
aab9277d8d | ||
|
|
6d21fdcc78 | ||
|
|
1d9f771af3 | ||
|
|
18330eb330 | ||
|
|
6f38fdaea6 | ||
|
|
bd75e33694 | ||
|
|
010f0b9402 | ||
|
|
776c541d1c | ||
|
|
f20abd5767 | ||
|
|
8cb0c8802d | ||
|
|
a4a0abdbd6 | ||
|
|
4bd0f26a26 | ||
|
|
5ea8f0382b | ||
|
|
8beaea89f2 | ||
|
|
433fca98a3 | ||
|
|
24aac47ce5 | ||
|
|
d5518c63e9 | ||
|
|
4a06c41a33 | ||
|
|
4d63ac5c88 | ||
|
|
6e31855717 | ||
|
|
76e668034c | ||
|
|
28424709d5 | ||
|
|
fc3df2b0ac | ||
|
|
27698a2a0a | ||
|
|
9b7aa49adc | ||
|
|
8022cf4200 | ||
|
|
bd06d384e0 | ||
|
|
17913a7a14 | ||
|
|
ef914bad8c | ||
|
|
867656f549 | ||
|
|
6e665b27bf | ||
|
|
f34dbcd7d8 | ||
|
|
6b608f51fb | ||
|
|
cbf853fa75 | ||
|
|
14450df1ee | ||
|
|
27a46a97a6 | ||
|
|
d2344e8e62 | ||
|
|
4b5a6cd2c6 | ||
|
|
f3ce121be3 | ||
|
|
eef8b42c77 | ||
|
|
03551c242c | ||
|
|
f5a8feb47f | ||
|
|
3208281d94 | ||
|
|
2271fb8c0f | ||
|
|
feb0bb02ae | ||
|
|
6c99ca50e7 | ||
|
|
cadcd9ce43 | ||
|
|
0bf1817b9a | ||
|
|
cd887237b8 | ||
|
|
218cb02492 | ||
|
|
5a2be7d6eb | ||
|
|
c6f3a5408e | ||
|
|
b6d0921177 | ||
|
|
6ac7a02172 | ||
|
|
a35612a4f8 | ||
|
|
4d9ff926b6 | ||
|
|
636749eff3 | ||
|
|
685467acba | ||
|
|
9605af3f54 | ||
|
|
a3db63342d | ||
|
|
57ec8d9ca3 | ||
|
|
f11d93ab25 | ||
|
|
b3489857ad | ||
|
|
205e21e313 | ||
|
|
cd59efab8f | ||
|
|
72304e6781 | ||
|
|
bdd213009c | ||
|
|
5f576667d3 | ||
|
|
1ec2f3eeb8 | ||
|
|
b1a5b4b982 | ||
|
|
9e4f40fee6 | ||
|
|
fa0add3c02 | ||
|
|
937ed81fa2 | ||
|
|
daa83a1885 | ||
|
|
eb290d8bd4 | ||
|
|
dad6061cbb | ||
|
|
07777c78aa | ||
|
|
7a12dc6533 | ||
|
|
80c8c76fdb | ||
|
|
1931ade325 | ||
|
|
2e264dffb3 | ||
|
|
09197a91a0 | ||
|
|
70053f9301 | ||
|
|
91a193141f | ||
|
|
5d8a1e3ee1 | ||
|
|
9c85cd8d55 | ||
|
|
1fb1027036 | ||
|
|
bdea65d500 | ||
|
|
88f65c8d5d | ||
|
|
8355f12398 | ||
|
|
f3120f7e7d | ||
|
|
a74b1b8220 | ||
|
|
b81e40e07e | ||
|
|
e4df106417 | ||
|
|
d0a16cd852 | ||
|
|
b274d49b3f | ||
|
|
3d9651b783 | ||
|
|
dfd7cb90d0 | ||
|
|
c33bee892d | ||
|
|
a986f68e45 | ||
|
|
c0f1a691f9 | ||
|
|
711e82b688 | ||
|
|
5190db0222 | ||
|
|
b00830d382 | ||
|
|
cd24c0aac5 | ||
|
|
a927d6db07 | ||
|
|
294a606cf9 | ||
|
|
735db1e6af | ||
|
|
3ec5e81d81 | ||
|
|
4664d0601f | ||
|
|
43fcc94682 | ||
|
|
4cdff43781 | ||
|
|
9d23522086 | ||
|
|
feed10c9f6 | ||
|
|
9732092c0f | ||
|
|
aa46b2504c | ||
|
|
c3e36e7148 | ||
|
|
c912b85f6e | ||
|
|
4f700f90ec | ||
|
|
f2c417435c | ||
|
|
48c374be2a | ||
|
|
4cb4553796 | ||
|
|
3db20d0aa5 | ||
|
|
9e62e1dab6 | ||
|
|
42529d0ab2 | ||
|
|
637d6bbabc | ||
|
|
f8eba58e19 | ||
|
|
d58c5766bc | ||
|
|
5b2c136a7c | ||
|
|
8c532fb377 | ||
|
|
c5552d85c3 | ||
|
|
d5c162e6a0 | ||
|
|
95b73d94f7 | ||
|
|
9f80b14f88 | ||
|
|
1a6565d5f9 | ||
|
|
9c60708203 | ||
|
|
e0cac58500 | ||
|
|
60e2557c45 | ||
|
|
228066c1f6 | ||
|
|
0744937811 | ||
|
|
a383c0c0a5 | ||
|
|
b6da31d933 | ||
|
|
5985531d9e | ||
|
|
847099932d | ||
|
|
d43416102b | ||
|
|
9e73c3c44a | ||
|
|
d152153547 | ||
|
|
5016dd8bb0 | ||
|
|
a3fdc96b0d | ||
|
|
b5fbe50fa1 | ||
|
|
e9039ece28 | ||
|
|
60e8763fe8 | ||
|
|
e3475c026c | ||
|
|
24c95e493f | ||
|
|
8ce80145de | ||
|
|
838d0e5f76 | ||
|
|
7fecbf7e03 | ||
|
|
e04f2bdb24 | ||
|
|
c26a24e713 | ||
|
|
c785260783 | ||
|
|
8372292841 | ||
|
|
2ce6317c9a | ||
|
|
16d43d2975 | ||
|
|
d7d8752a84 | ||
|
|
339df18c06 | ||
|
|
757eb5f10c | ||
|
|
580f1edb91 | ||
|
|
6e03ca088e | ||
|
|
c75a4804da | ||
|
|
3487196d0d | ||
|
|
adbcc8dca9 | ||
|
|
8b79ee586a | ||
|
|
abfd8e035c | ||
|
|
9bad12064c | ||
|
|
a5608bf7bb | ||
|
|
b84a4bed29 | ||
|
|
94582777e8 | ||
|
|
c2b5be0836 | ||
|
|
8e13ede4d5 | ||
|
|
857d70528d | ||
|
|
b16e4c1ec7 | ||
|
|
b8b41b3ac7 | ||
|
|
f13dcae6d3 | ||
|
|
1724e8cfeb | ||
|
|
e53601e860 | ||
|
|
5e8544cfc6 | ||
|
|
dc184c10e2 | ||
|
|
f89e8560a3 | ||
|
|
f4a54cc0da | ||
|
|
6aa4c770e6 | ||
|
|
afe942ef2e | ||
|
|
9b4c920d1f | ||
|
|
00d0ff2e45 | ||
|
|
3f5b6a1693 | ||
|
|
d98821e976 | ||
|
|
223c8ab9b9 | ||
|
|
76a6a22527 | ||
|
|
ee7e025680 | ||
|
|
68125c4187 | ||
|
|
fd1abc952f | ||
|
|
5c04c872c5 | ||
|
|
8405a78bd8 | ||
|
|
0e4f5a6870 | ||
|
|
a4f2ba1ab8 | ||
|
|
3c8ddbb0a5 | ||
|
|
1dbe025d36 | ||
|
|
16d55c9f59 | ||
|
|
f3bd033bf6 | ||
|
|
ba87e22af0 | ||
|
|
9d2bbac695 | ||
|
|
5e0f4e6ef0 | ||
|
|
9a362b39bf | ||
|
|
fb624bab50 | ||
|
|
e0661a55f6 | ||
|
|
1773cc9eb5 | ||
|
|
dd7c8f2ad6 | ||
|
|
592ff17c5f | ||
|
|
6d6d83afdb | ||
|
|
134640411a | ||
|
|
6e1a5c0353 | ||
|
|
b1a884f898 | ||
|
|
1717b3683c | ||
|
|
a00f9e5f77 | ||
|
|
e210c31bf2 | ||
|
|
93094740b2 | ||
|
|
8ee3c333fb | ||
|
|
302b246475 | ||
|
|
90b9186fd6 | ||
|
|
29e2f13e1e | ||
|
|
3d9da1dbce | ||
|
|
62a13526c9 | ||
|
|
4dcc0e8666 | ||
|
|
7e98afe6fe | ||
|
|
e835bfbec7 | ||
|
|
577ff97980 | ||
|
|
76516e0320 | ||
|
|
385155f043 | ||
|
|
29b2552cf2 | ||
|
|
ee1e1a4cd5 | ||
|
|
a0c85add5b | ||
|
|
94472a6782 | ||
|
|
cdc47832ef | ||
|
|
acae98324b | ||
|
|
4786178705 | ||
|
|
2e375a4482 | ||
|
|
e58735a6fd | ||
|
|
0f1fff7ac8 | ||
|
|
0ef43f5d57 | ||
|
|
7a2c5753c5 | ||
|
|
2a3ae06d85 | ||
|
|
f009d99e5e | ||
|
|
206d2f623d | ||
|
|
273035ff49 | ||
|
|
3540fbab74 | ||
|
|
4983d40358 | ||
|
|
fd970971af | ||
|
|
c8a0701597 | ||
|
|
ad99c4eb14 | ||
|
|
67d7b0080e | ||
|
|
2bf66e5b42 | ||
|
|
88d0b5a17d | ||
|
|
c042e3d985 | ||
|
|
2defe1c2c4 | ||
|
|
0bc946b333 | ||
|
|
98dd0fbad7 | ||
|
|
4bb37f7e25 | ||
|
|
23703f5c01 | ||
|
|
215a22f425 | ||
|
|
e742fe7bf9 | ||
|
|
57d1754bc8 | ||
|
|
b95bb9bedb | ||
|
|
39f6349878 | ||
|
|
678131429b | ||
|
|
bb70e8b14e | ||
|
|
b9c86b3f99 | ||
|
|
0ec50842a7 | ||
|
|
a678133e47 | ||
|
|
b0a5f4f3e8 | ||
|
|
642f4e70b5 | ||
|
|
efd03711cc | ||
|
|
4c067ee13d | ||
|
|
5cb7fc2610 | ||
|
|
05ba05393c | ||
|
|
2206d3f921 | ||
|
|
1f7f613800 | ||
|
|
8d92440451 | ||
|
|
5fca9d4c94 | ||
|
|
663353cbdb | ||
|
|
8550a9f159 | ||
|
|
f01dbd68f3 | ||
|
|
5913829e21 | ||
|
|
c201a44f1a | ||
|
|
382be6c4e1 | ||
|
|
aad20ed035 | ||
|
|
c24adea40f | ||
|
|
223e2376b6 | ||
|
|
0ce65cec6b | ||
|
|
7ddef2586c | ||
|
|
4d9f137980 | ||
|
|
03aabbfa07 | ||
|
|
fe0d412b98 | ||
|
|
826eb7ed65 | ||
|
|
2dc121e3df | ||
|
|
75bff4d67f | ||
|
|
9d33ae86be | ||
|
|
173c4e1c78 | ||
|
|
2d0b451ed0 | ||
|
|
35f2dbad09 | ||
|
|
872fc4751b | ||
|
|
504959850c | ||
|
|
2466c7123e | ||
|
|
0f9b4f1b6c | ||
|
|
38f63135a8 | ||
|
|
b0ad2ddbe7 | ||
|
|
94b3944003 | ||
|
|
aa1bfebc46 | ||
|
|
62dd41f0a1 | ||
|
|
bb54e2542c | ||
|
|
639191af23 | ||
|
|
4670a939bf | ||
|
|
391dcf9639 | ||
|
|
7378abdedb | ||
|
|
43c5c2dd0d | ||
|
|
ffa0a7f276 | ||
|
|
592147a499 | ||
|
|
02e2532e17 | ||
|
|
4891c8fcd2 | ||
|
|
ae20db416f | ||
|
|
283ad71283 | ||
|
|
25bbc4e053 | ||
|
|
913d313098 | ||
|
|
7efbafb8b4 | ||
|
|
3500757c97 | ||
|
|
c4c6ba7620 | ||
|
|
c53eaf939d | ||
|
|
d5613e8c65 | ||
|
|
7fada722e7 | ||
|
|
66ee7bab32 | ||
|
|
8848040203 | ||
|
|
33ef814a76 | ||
|
|
06e032bc6d | ||
|
|
25e844fadd | ||
|
|
08474c671b | ||
|
|
8f94041ea2 | ||
|
|
08fc2b3a4a | ||
|
|
37aec0ab84 | ||
|
|
61ad570ecc | ||
|
|
90e158e519 | ||
|
|
97d49b4bf3 | ||
|
|
4c3a35bc95 | ||
|
|
244b5d56ff | ||
|
|
755cb0f4e0 | ||
|
|
7b2b402d37 | ||
|
|
41481548b8 | ||
|
|
f2411a1db7 | ||
|
|
073cbae9d5 | ||
|
|
db8e22196d | ||
|
|
8a68fea16e | ||
|
|
6501ca9b3c | ||
|
|
0c7c6c58c0 | ||
|
|
f3f0ba6955 | ||
|
|
52da5cf894 | ||
|
|
2878e096e6 | ||
|
|
4f3ef4818a | ||
|
|
ffc0c5f2d3 | ||
|
|
9d97c83909 | ||
|
|
6a21e29397 | ||
|
|
8fdc24097e | ||
|
|
4e7368f79a | ||
|
|
1e1dee88b7 | ||
|
|
91e4ff6a08 | ||
|
|
4be9aac7a6 | ||
|
|
af059b5e21 | ||
|
|
fdb1978f89 | ||
|
|
8332e59c62 | ||
|
|
20cc263502 | ||
|
|
361d4ec4dd | ||
|
|
11f8ba5a8f | ||
|
|
c3bf842f9f | ||
|
|
33b598289b | ||
|
|
cfc7f99405 | ||
|
|
1d79550f3c | ||
|
|
db5ecd2c96 | ||
|
|
1280367a35 | ||
|
|
14706c8f9a | ||
|
|
b821df4279 | ||
|
|
07ff28d9dc | ||
|
|
d15fd2a8b7 | ||
|
|
6e4381934a | ||
|
|
46ccded145 | ||
|
|
01453b67fc | ||
|
|
7ec739b5c7 | ||
|
|
fd8279ee90 | ||
|
|
a6fea6727b | ||
|
|
e561e8cbdd | ||
|
|
8d39f89aff | ||
|
|
05644a742f | ||
|
|
f0f7fcf5b7 | ||
|
|
16bb54c524 | ||
|
|
70c3eaab80 | ||
|
|
104fb0f06c | ||
|
|
d93f96f48f | ||
|
|
8731eb91f4 | ||
|
|
a987609b2a | ||
|
|
40793e9485 | ||
|
|
874587a591 | ||
|
|
59a401fbe2 | ||
|
|
9c797ead28 | ||
|
|
b6bb7c1a84 | ||
|
|
995f7e8e19 | ||
|
|
9732f0547d | ||
|
|
9c9a71af74 | ||
|
|
be09b3a40a | ||
|
|
d79d08ef11 | ||
|
|
c7377cbbbf | ||
|
|
bbcc88217a | ||
|
|
c2838b4861 | ||
|
|
19c256d9a4 | ||
|
|
7b08533a76 | ||
|
|
baf0057628 | ||
|
|
99bf93dce6 | ||
|
|
776ec96565 | ||
|
|
d03c444eae | ||
|
|
de6678c47a | ||
|
|
b780198526 | ||
|
|
27f1e9e476 | ||
|
|
a9de9da75b | ||
|
|
4f0a119279 | ||
|
|
9d3b4b8d78 | ||
|
|
9a59de939e | ||
|
|
c5a2d00395 | ||
|
|
36c2087269 | ||
|
|
7178970524 | ||
|
|
d76fa92be3 | ||
|
|
e942348211 | ||
|
|
3e12f4f55f | ||
|
|
4ed51d3fd8 | ||
|
|
c9a5fda400 | ||
|
|
45d4bd0cf5 | ||
|
|
aafa8a9b0b | ||
|
|
b1e47fc7d4 | ||
|
|
b87b8cf272 | ||
|
|
e797fadaff | ||
|
|
316b5b9992 | ||
|
|
5aeae3a452 | ||
|
|
3f4f976396 | ||
|
|
7cd83ced17 | ||
|
|
f832a8f97c | ||
|
|
256eb727a5 | ||
|
|
3ae6613445 | ||
|
|
5979dd2e15 | ||
|
|
b203a31039 | ||
|
|
1f99b49617 | ||
|
|
efbf5e3111 | ||
|
|
b52fe64628 | ||
|
|
0d3511c05f | ||
|
|
ace3da4173 | ||
|
|
f65a21f88c | ||
|
|
47aeeabc51 | ||
|
|
049860b884 | ||
|
|
b7d23e1aec | ||
|
|
f1f33a3ac7 | ||
|
|
607e6d96a4 | ||
|
|
d8551ead86 | ||
|
|
29510716bb | ||
|
|
735e0af91a | ||
|
|
2666982645 | ||
|
|
768c8de48c | ||
|
|
ce6a04ae5a | ||
|
|
f8012d5055 | ||
|
|
966efd2397 | ||
|
|
9344798fa1 | ||
|
|
95643b6a56 | ||
|
|
6b2c88e542 | ||
|
|
0df38df1c6 | ||
|
|
73dd3dcc26 | ||
|
|
1e65fede6c | ||
|
|
b3c0d91eb3 | ||
|
|
eaa93d287e | ||
|
|
4517ae22e5 | ||
|
|
f4537ad272 | ||
|
|
c425199239 | ||
|
|
e15894872d | ||
|
|
54a15d7b51 | ||
|
|
b1b6470cc2 | ||
|
|
3a89263e73 | ||
|
|
533b755b11 | ||
|
|
c5d94545b5 | ||
|
|
2ae3e52f76 | ||
|
|
f20b9e3875 | ||
|
|
a1ca352818 | ||
|
|
6b96e2f2a9 | ||
|
|
b1b4c67b75 | ||
|
|
f775d3be67 | ||
|
|
09f7814503 | ||
|
|
745c5384bb | ||
|
|
5ff2b97f67 | ||
|
|
44f30dc01c | ||
|
|
4b307cb2b2 | ||
|
|
378d98096d | ||
|
|
2b12d29a2f | ||
|
|
7382a68505 | ||
|
|
e10d2cb37e | ||
|
|
c4e7a62ac3 | ||
|
|
f354378fec | ||
|
|
c638cb38b9 | ||
|
|
d255ecf0f9 | ||
|
|
4ea691118c | ||
|
|
bfd962cda2 | ||
|
|
719c233e77 | ||
|
|
bd78235b28 | ||
|
|
aa292ed113 | ||
|
|
b99d789543 | ||
|
|
5ef58cce5d | ||
|
|
31c3868bc8 | ||
|
|
071a97becb | ||
|
|
1df40ada5c | ||
|
|
a12b99ad49 | ||
|
|
e1d84d0b92 | ||
|
|
fb47ef66da | ||
|
|
9621348ad0 | ||
|
|
560e1429f1 | ||
|
|
18a945e7d6 | ||
|
|
16548fc3a1 | ||
|
|
4272d954ea | ||
|
|
77b5907a9f | ||
|
|
acae0533bc | ||
|
|
a5e259c19b | ||
|
|
12865f318e | ||
|
|
51704ee7ce | ||
|
|
ad6f4a3dd8 | ||
|
|
70ffa25c4c | ||
|
|
4aef168a50 | ||
|
|
40fe70f15f | ||
|
|
812351cfdb | ||
|
|
518e1abb26 | ||
|
|
9db64d3389 | ||
|
|
2ad1a44432 | ||
|
|
3047c73952 | ||
|
|
c8f5b1afa6 | ||
|
|
54be0c2d9c | ||
|
|
b5b4991ae6 | ||
|
|
3273c75057 | ||
|
|
f60f0cf279 | ||
|
|
9e7881ee08 | ||
|
|
9d45825947 | ||
|
|
c993388e5c | ||
|
|
b45cf33eef | ||
|
|
de376a0b25 | ||
|
|
c659fad434 | ||
|
|
5e7e4a4b11 | ||
|
|
7efbc3f72d | ||
|
|
8c93171303 | ||
|
|
d8f314df25 | ||
|
|
be0872e71e | ||
|
|
3b95cbd697 | ||
|
|
5ef07da451 | ||
|
|
5d98fc06c2 | ||
|
|
7f531e5e2d | ||
|
|
542a700f2c | ||
|
|
f3eaa1f74a | ||
|
|
06680c64eb | ||
|
|
4b1a19677a | ||
|
|
5792f43185 | ||
|
|
e89298eb52 | ||
|
|
22fada19ec | ||
|
|
ef7fa8ae0f | ||
|
|
72fa115160 | ||
|
|
3665cf11f3 | ||
|
|
9b5910547f | ||
|
|
04bcb51c73 | ||
|
|
774049c75e | ||
|
|
b8e52934ea | ||
|
|
5047aeacb5 | ||
|
|
6594da85f1 | ||
|
|
f532807d62 | ||
|
|
ffdc7893fe | ||
|
|
25a401042a | ||
|
|
22914d4687 | ||
|
|
7970a24359 | ||
|
|
8bbc113258 | ||
|
|
10c13e8fbe | ||
|
|
0fec57e76d | ||
|
|
e72bf9acb1 | ||
|
|
fc4287e9e1 | ||
|
|
5f184ed655 | ||
|
|
abad59f0ce | ||
|
|
cd3474e5b5 | ||
|
|
57d8072901 | ||
|
|
d7d0ba498c | ||
|
|
169fcdc323 | ||
|
|
a8a19b0c4d | ||
|
|
a669b84e6a | ||
|
|
c5e764750b | ||
|
|
7d2b7974fb | ||
|
|
ee955f7bef | ||
|
|
ad370d35c2 | ||
|
|
6a76afc061 | ||
|
|
c67f659041 | ||
|
|
dc5eea48ae |
1
.bazelignore
Normal file
1
.bazelignore
Normal file
@@ -0,0 +1 @@
|
||||
test
|
||||
1
.bazeliskrc
Normal file
1
.bazeliskrc
Normal file
@@ -0,0 +1 @@
|
||||
USE_BAZEL_VERSION=6.x
|
||||
17
.bazelrc
Normal file
17
.bazelrc
Normal file
@@ -0,0 +1,17 @@
|
||||
common --enable_bzlmod
|
||||
build --enable_platform_specific_config
|
||||
build --incompatible_use_platforms_repo_for_constraints
|
||||
build --incompatible_enable_cc_toolchain_resolution
|
||||
build --enable_runfiles
|
||||
build --incompatible_strict_action_env
|
||||
|
||||
# required for googletest
|
||||
build:linux --cxxopt=-std=c++17
|
||||
build:macos --cxxopt=-std=c++17
|
||||
|
||||
common:ci --announce_rc
|
||||
common:ci --verbose_failures
|
||||
common:ci --keep_going
|
||||
test:ci --test_output=errors
|
||||
|
||||
try-import %workspace%/user.bazelrc
|
||||
26
.clang-tidy
Normal file
26
.clang-tidy
Normal file
@@ -0,0 +1,26 @@
|
||||
Checks: >
|
||||
bugprone-*,
|
||||
concurrency-*,
|
||||
cppcoreguidelines-*,
|
||||
misc-*,
|
||||
-misc-no-recursion,
|
||||
modernize-*,
|
||||
-modernize-use-trailing-return-type,
|
||||
performance-*,
|
||||
portability-*,
|
||||
readibility-*
|
||||
CheckOptions:
|
||||
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
|
||||
value: true
|
||||
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
|
||||
value: true
|
||||
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctionsWhenCopyIsDeleted
|
||||
value: true
|
||||
- key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
|
||||
value: true
|
||||
- key: misc-non-private-member-variables-in-classes.IgnorePublicMemberVariables
|
||||
value: true
|
||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnorePowersOf2IntegerValues
|
||||
value: true
|
||||
- key: cppcoreguidelines-avoid-magic-numbers.IgnoreAllFloatingPointValues
|
||||
value: true
|
||||
6
.github/workflows/analyzer.yml
vendored
6
.github/workflows/analyzer.yml
vendored
@@ -12,14 +12,14 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
|
||||
env:
|
||||
IWYU: 0.19
|
||||
LLVM: 15
|
||||
IWYU: "0.20"
|
||||
LLVM: "16"
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install llvm/clang
|
||||
# see: https://apt.llvm.org/
|
||||
run: |
|
||||
|
||||
20
.github/workflows/bazel-release-archive.yml
vendored
Normal file
20
.github/workflows/bazel-release-archive.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Bazel Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
# A release archive is required for bzlmod
|
||||
# See: https://blog.bazel.build/2023/02/15/github-archive-checksum.html
|
||||
bazel-release-archive:
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: git archive $GITHUB_REF -o "entt-${GITHUB_REF:10}.tar.gz"
|
||||
- run: gh release upload ${GITHUB_REF:10} "entt-${GITHUB_REF:10}.tar.gz"
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
20
.github/workflows/bazel.yml
vendored
Normal file
20
.github/workflows/bazel.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: bazel
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
- macos-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: bazelisk test --config=ci ...
|
||||
working-directory: test
|
||||
env:
|
||||
USE_BAZEL_VERSION: 6.x
|
||||
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
@@ -55,7 +55,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install compiler
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
run: ctest -C Debug -j4
|
||||
|
||||
windows:
|
||||
timeout-minutes: 15
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
@@ -100,14 +100,14 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
run: ctest -C Debug -j4
|
||||
|
||||
macos:
|
||||
timeout-minutes: 15
|
||||
runs-on: macOS-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
run: ctest -C Debug -j4
|
||||
|
||||
extra:
|
||||
timeout-minutes: 15
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
@@ -141,4 +141,4 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
run: ctest -C Debug -j4
|
||||
|
||||
4
.github/workflows/coverage.yml
vendored
4
.github/workflows/coverage.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
run: ctest -C Debug -j4
|
||||
- name: Collect data
|
||||
working-directory: build
|
||||
run: |
|
||||
|
||||
6
.github/workflows/sanitizer.yml
vendored
6
.github/workflows/sanitizer.yml
vendored
@@ -16,7 +16,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
# temporary workaround for https://github.com/actions/runner-images/issues/8659
|
||||
- uses: mjp41/workaround8649@c8550b715ccdc17f89c8d5c28d7a48eeff9c94a8
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
@@ -28,4 +30,4 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
run: ctest -C Debug -j4
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,3 +11,5 @@ cpp.hint
|
||||
|
||||
# Bazel
|
||||
/bazel-*
|
||||
/test/bazel-*
|
||||
/user.bazelrc
|
||||
|
||||
14
BUILD.bazel
14
BUILD.bazel
@@ -1,14 +1,6 @@
|
||||
_msvc_copts = ["/std:c++17"]
|
||||
_gcc_copts = ["-std=c++17"]
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cc_library(
|
||||
alias(
|
||||
name = "entt",
|
||||
visibility = ["//visibility:public"],
|
||||
strip_include_prefix = "src",
|
||||
hdrs = glob(["src/**/*.h", "src/**/*.hpp"]),
|
||||
copts = select({
|
||||
"@bazel_tools//src/conditions:windows": _msvc_copts,
|
||||
"@bazel_tools//src/conditions:windows_msvc": _msvc_copts,
|
||||
"//conditions:default": _gcc_copts,
|
||||
}),
|
||||
actual = "//src:entt",
|
||||
)
|
||||
|
||||
@@ -1,21 +1,15 @@
|
||||
#
|
||||
# EnTT
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.15.7)
|
||||
|
||||
#
|
||||
# Read project version
|
||||
#
|
||||
|
||||
set(ENTT_VERSION_REGEX "#define ENTT_VERSION_.*[ \t]+(.+)")
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/src/entt/config/version.h" ENTT_VERSION REGEX ${ENTT_VERSION_REGEX})
|
||||
list(TRANSFORM ENTT_VERSION REPLACE ${ENTT_VERSION_REGEX} "\\1")
|
||||
string(JOIN "." ENTT_VERSION ${ENTT_VERSION})
|
||||
|
||||
#
|
||||
# Project configuration
|
||||
#
|
||||
|
||||
project(
|
||||
EnTT
|
||||
@@ -34,18 +28,15 @@ message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||
message(VERBOSE "* Copyright (c) 2017-2023 Michele Caini <michele.caini@gmail.com>")
|
||||
message(VERBOSE "*")
|
||||
|
||||
#
|
||||
# CMake stuff
|
||||
#
|
||||
|
||||
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||
|
||||
#
|
||||
# Compiler stuff
|
||||
#
|
||||
|
||||
option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." OFF)
|
||||
option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags if available." OFF)
|
||||
option(ENTT_USE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF)
|
||||
|
||||
if(ENTT_USE_LIBCPP)
|
||||
if(NOT WIN32)
|
||||
@@ -65,7 +56,7 @@ if(ENTT_USE_LIBCPP)
|
||||
endif()
|
||||
|
||||
if(NOT ENTT_HAS_LIBCPP)
|
||||
message(VERBOSE "The option ENTT_USE_LIBCPP is set but libc++ is not available. The flag will not be added to the target.")
|
||||
message(VERBOSE "The option ENTT_USE_LIBCPP is set but libc++ is not available.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -76,13 +67,19 @@ if(ENTT_USE_SANITIZER)
|
||||
endif()
|
||||
|
||||
if(NOT ENTT_HAS_SANITIZER)
|
||||
message(VERBOSE "The option ENTT_USE_SANITIZER is set but sanitizer support is not available. The flags will not be added to the target.")
|
||||
message(VERBOSE "The option ENTT_USE_SANITIZER is set but sanitizer support is not available.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENTT_USE_CLANG_TIDY)
|
||||
find_program(ENTT_CLANG_TIDY_EXECUTABLE "clang-tidy")
|
||||
|
||||
if(NOT ENTT_CLANG_TIDY_EXECUTABLE)
|
||||
message(VERBOSE "The option ENTT_USE_CLANG_TIDY is set but clang-tidy executable is not available.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# Add EnTT target
|
||||
#
|
||||
|
||||
option(ENTT_INCLUDE_HEADERS "Add all EnTT headers to the EnTT target." OFF)
|
||||
option(ENTT_INCLUDE_NATVIS "Add EnTT natvis files to the EnTT target." OFF)
|
||||
@@ -216,13 +213,15 @@ if(ENTT_HAS_SANITIZER)
|
||||
target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
|
||||
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/.*;--extra-arg=/EHsc")
|
||||
endif()
|
||||
|
||||
if(ENTT_HAS_LIBCPP)
|
||||
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Install pkg-config file
|
||||
#
|
||||
|
||||
include(JoinPaths)
|
||||
|
||||
@@ -241,9 +240,7 @@ install(
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
)
|
||||
|
||||
#
|
||||
# Install EnTT
|
||||
#
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
@@ -285,13 +282,17 @@ install(
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
|
||||
)
|
||||
|
||||
install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
install(
|
||||
DIRECTORY src/
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
PATTERN "*.hpp"
|
||||
)
|
||||
|
||||
export(PACKAGE EnTT)
|
||||
|
||||
#
|
||||
# Tests
|
||||
#
|
||||
|
||||
option(ENTT_BUILD_TESTING "Enable building tests." OFF)
|
||||
|
||||
@@ -310,9 +311,15 @@ if(ENTT_BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Tools
|
||||
|
||||
option(ENTT_BUILD_TOOLS "Enable building tools." OFF)
|
||||
|
||||
if(ENTT_BUILD_TOOLS)
|
||||
add_subdirectory(tools)
|
||||
endif()
|
||||
|
||||
# Documentation
|
||||
#
|
||||
|
||||
option(ENTT_BUILD_DOCS "Enable building with documentation." OFF)
|
||||
|
||||
|
||||
8
MODULE.bazel
Normal file
8
MODULE.bazel
Normal file
@@ -0,0 +1,8 @@
|
||||
module(
|
||||
name = "entt",
|
||||
version = "3.12.2",
|
||||
compatibility_level = 3012,
|
||||
)
|
||||
|
||||
bazel_dep(name = "rules_cc", version = "0.0.8")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.4.2")
|
||||
52
README.md
52
README.md
@@ -6,11 +6,11 @@
|
||||
[](https://github.com/skypjack/entt/actions)
|
||||
[](https://codecov.io/gh/skypjack/entt)
|
||||
[](https://godbolt.org/z/zxW73f)
|
||||
[](https://vcpkg.link/ports/entt)
|
||||
[](https://skypjack.github.io/entt/)
|
||||
[](https://vcpkg.link/ports/entt)
|
||||
[](https://conan.io/center/recipes/entt)
|
||||
[](https://gitter.im/skypjack/entt)
|
||||
[](https://discord.gg/5BjPWBd)
|
||||
[](https://www.paypal.me/skypjack)
|
||||
|
||||
> `EnTT` has been a dream so far, we haven't found a single bug to date and it's
|
||||
> super easy to work with
|
||||
@@ -39,7 +39,8 @@ Don't forget to check the
|
||||
there.
|
||||
|
||||
Do you want to support `EnTT`? Consider becoming a
|
||||
[**sponsor**](https://github.com/users/skypjack/sponsorship).
|
||||
[**sponsor**](https://github.com/users/skypjack/sponsorship) or making a
|
||||
donation via [**PayPal**](https://www.paypal.me/skypjack).<br/>
|
||||
Many thanks to [these people](https://skypjack.github.io/sponsorship/) and
|
||||
**special** thanks to:
|
||||
|
||||
@@ -51,7 +52,7 @@ Many thanks to [these people](https://skypjack.github.io/sponsorship/) and
|
||||
* [Introduction](#introduction)
|
||||
* [Code Example](#code-example)
|
||||
* [Motivation](#motivation)
|
||||
* [Performance](#performance)
|
||||
* [Benchmark](#benchmark)
|
||||
* [Integration](#integration)
|
||||
* [Requirements](#requirements)
|
||||
* [CMake](#cmake)
|
||||
@@ -175,37 +176,28 @@ Nowadays, `EnTT` is finally what I was looking for: still faster than its
|
||||
_competitors_, lower memory usage in the average case, a really good API and an
|
||||
amazing set of features. And even more, of course.
|
||||
|
||||
## Performance
|
||||
## Benchmark
|
||||
|
||||
The proposed entity-component system is incredibly fast to iterate entities and
|
||||
components, this is a fact. Some compilers make a lot of optimizations because
|
||||
of how `EnTT` works, some others aren't that good. In general, if we consider
|
||||
real world cases, `EnTT` is somewhere between a bit and much faster than many of
|
||||
the other solutions around, although I couldn't check them all for obvious
|
||||
reasons.
|
||||
For what it's worth, you'll **never** see me trying to make other projects look
|
||||
bad or offer dubious comparisons just to make this library seem cooler.<br/>
|
||||
I leave this activity to others, if they enjoy it (and it seems that some people
|
||||
actually like it). I prefer to make better use of my time.
|
||||
|
||||
If you are interested, you can compile the `benchmark` test in release mode (to
|
||||
enable compiler optimizations, otherwise it would make little sense) by setting
|
||||
the `ENTT_BUILD_BENCHMARK` option of `CMake` to `ON`, then evaluate yourself
|
||||
whether you're satisfied with the results or not.
|
||||
|
||||
Honestly I got tired of updating the README file whenever there is an
|
||||
improvement.<br/>
|
||||
There are already a lot of projects out there that use `EnTT` as a basis for
|
||||
There are also a lot of projects out there that use `EnTT` as a basis for
|
||||
comparison (this should already tell you a lot). Many of these benchmarks are
|
||||
completely wrong, many others are simply incomplete, good at omitting some
|
||||
information and using the wrong function to compare a given feature. Certainly
|
||||
there are also good ones but they age quickly if nobody updates them, especially
|
||||
when the library they are dealing with is actively developed.
|
||||
|
||||
The choice to use `EnTT` should be based on its carefully designed API, its
|
||||
set of features and the general performance, **not** because some single
|
||||
benchmark shows it to be the fastest tool available.
|
||||
|
||||
In the future I'll likely try to get even better performance while still adding
|
||||
new features, mainly for fun.<br/>
|
||||
If you want to contribute and/or have suggestions, feel free to make a PR or
|
||||
open an issue to discuss your idea.
|
||||
when the library they are dealing with is actively developed.<br/>
|
||||
Out of all of them, [this](https://github.com/abeimler/ecs_benchmark) seems like
|
||||
the most up-to-date project and also covers a certain number of libraries. I
|
||||
can't say exactly whether `EnTT` is used correctly or not. However, even if used
|
||||
poorly, it should still give the reader an idea of where it's going to operate.
|
||||
|
||||
# Integration
|
||||
|
||||
@@ -327,6 +319,18 @@ If you spot errors or have suggestions, any contribution is welcome!
|
||||
[documentation](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-repositories)
|
||||
for more details.
|
||||
|
||||
* [`bzlmod`](https://bazel.build/external/overview#bzlmod), Bazel's external
|
||||
dependency management system.<br/>
|
||||
To use the [`entt`](https://registry.bazel.build/modules/entt) module in a
|
||||
`bazel` project, add the following to your `MODULE.bazel` file:
|
||||
|
||||
```starlark
|
||||
bazel_dep(name = "entt", version = "3.12.2")
|
||||
```
|
||||
|
||||
EnTT will now be available as `@entt` (short for `@entt//:entt`) to be used
|
||||
in your `cc_*` rule `deps`.
|
||||
|
||||
Consider this list a work in progress and help me to make it longer if you like.
|
||||
|
||||
## pkg-config
|
||||
|
||||
27
TODO
27
TODO
@@ -4,23 +4,28 @@ EXAMPLES
|
||||
|
||||
DOC:
|
||||
* custom storage/view
|
||||
* examples (and credits) from @alanjfs :)
|
||||
* update entity doc when the storage based model is in place
|
||||
* in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
|
||||
* view: single vs multi type views are no longer a thing actually
|
||||
* bump entities, reserved bits on identifiers
|
||||
|
||||
TODO (high prio):
|
||||
* check natvis files (periodically :)
|
||||
TODO:
|
||||
* resource cache: avoid using shared ptr with loader and the others
|
||||
* further optimize exclusion lists in multi type views (no existence check)
|
||||
* further improve the snapshot stuff, ie component functions
|
||||
* use fixture for storage tests to reduce loc number and duplication as much as possible
|
||||
* basic_view<...>::reach(...)
|
||||
* doc: bump entities
|
||||
|
||||
WIP:
|
||||
* further improve meta resolve function by id (bimap)
|
||||
* get rid of observers, storage based views made them pointless - document alternatives
|
||||
* exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details)
|
||||
* process scheduler: reviews, use free lists internally
|
||||
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
|
||||
* bring nested groups back in place (see bd34e7f)
|
||||
* work stealing job system (see #100) + mt scheduler based on const awareness for types
|
||||
* 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
|
||||
* basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) uses moved-from packed in assert (same for storage)
|
||||
* maybe drop begin(v)/end(v) from sparse set and only use scoped begin/end at call sites
|
||||
* view unchecked_refresh loop is never executed if Get is 1u
|
||||
* review all // NOLINT + linter workflow + review clang-tidy file
|
||||
* self contained entity traits to avoid explicit specializations (ie enum constants)
|
||||
* review assure conflicts check, hash doesn't fit the purpose maybe
|
||||
* allow to zero-sized versions (with non-regression tests)
|
||||
* auto type info data from types if present
|
||||
|
||||
1
WORKSPACE.bazel
Normal file
1
WORKSPACE.bazel
Normal file
@@ -0,0 +1 @@
|
||||
# SEE MODULE.bazel
|
||||
0
bazel/BUILD.bazel
Normal file
0
bazel/BUILD.bazel
Normal file
13
bazel/copts.bzl
Normal file
13
bazel/copts.bzl
Normal file
@@ -0,0 +1,13 @@
|
||||
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",
|
||||
"-w",
|
||||
],
|
||||
("@rules_cc//cc/compiler:msvc-cl", "@rules_cc//cc/compiler:clang-cl"): [
|
||||
"/std:c++17",
|
||||
"/permissive-",
|
||||
"/w",
|
||||
],
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Doxygen configuration (documentation)
|
||||
#
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
doxygen-awesome-css
|
||||
|
||||
129
docs/doxy.in
129
docs/doxy.in
@@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.9.6
|
||||
# Doxyfile 1.9.7
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project.
|
||||
@@ -353,6 +353,17 @@ MARKDOWN_SUPPORT = YES
|
||||
|
||||
TOC_INCLUDE_HEADINGS = 5
|
||||
|
||||
# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
|
||||
# generate identifiers for the Markdown headings. Note: Every identifier is
|
||||
# unique.
|
||||
# Possible values are: DOXYGEN Use a fixed 'autotoc_md' string followed by a
|
||||
# sequence number starting at 0. and GITHUB Use the lower case version of title
|
||||
# with any whitespace replaced by '-' and punctations characters removed..
|
||||
# The default value is: DOXYGEN.
|
||||
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
|
||||
|
||||
MARKDOWN_ID_STYLE = DOXYGEN
|
||||
|
||||
# When enabled doxygen tries to link words that correspond to documented
|
||||
# classes, or namespaces to their corresponding documentation. Such a link can
|
||||
# be prevented in individual cases by putting a % sign in front of the word or
|
||||
@@ -477,6 +488,14 @@ LOOKUP_CACHE_SIZE = 0
|
||||
|
||||
NUM_PROC_THREADS = 1
|
||||
|
||||
# If the TIMESTAMP tag is set different from NO then each generated page will
|
||||
# contain the date or date and time when the page was generated. Setting this to
|
||||
# NO can help when comparing the output of multiple runs.
|
||||
# Possible values are: YES, NO, DATETIME and DATE.
|
||||
# The default value is: NO.
|
||||
|
||||
TIMESTAMP = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
@@ -862,7 +881,14 @@ WARN_IF_UNDOC_ENUM_VAL = NO
|
||||
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
||||
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
||||
# at the end of the doxygen process doxygen will return with a non-zero status.
|
||||
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
|
||||
# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
|
||||
# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
|
||||
# write the warning messages in between other messages but write them at the end
|
||||
# of a run, in case a WARN_LOGFILE is defined the warning messages will be
|
||||
# besides being in the defined file also be shown at the end of a run, unless
|
||||
# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
|
||||
# the behavior will remain as with the setting FAIL_ON_WARNINGS.
|
||||
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_AS_ERROR = NO
|
||||
@@ -990,9 +1016,6 @@ EXCLUDE_PATTERNS =
|
||||
# output. The symbol name can be a fully qualified name, a word, or if the
|
||||
# wildcard * is used, a substring. Examples: ANamespace, AClass,
|
||||
# ANamespace::AClass, ANamespace::*Test
|
||||
#
|
||||
# Note that the wildcards are matched against the file with absolute path, so to
|
||||
# exclude all test directories use the pattern */test/*
|
||||
|
||||
EXCLUDE_SYMBOLS =
|
||||
|
||||
@@ -1375,15 +1398,6 @@ HTML_COLORSTYLE_SAT = 100
|
||||
|
||||
HTML_COLORSTYLE_GAMMA = 80
|
||||
|
||||
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
|
||||
# page will contain the date and time when the page was generated. Setting this
|
||||
# to YES can help to show when doxygen was last run and thus if the
|
||||
# documentation is up to date.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
HTML_TIMESTAMP = NO
|
||||
|
||||
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
|
||||
# documentation will contain a main index with vertical navigation menus that
|
||||
# are dynamically created via JavaScript. If disabled, the navigation index will
|
||||
@@ -1533,6 +1547,16 @@ BINARY_TOC = NO
|
||||
|
||||
TOC_EXPAND = NO
|
||||
|
||||
# The SITEMAP_URL tag is used to specify the full URL of the place where the
|
||||
# generated documentation will be placed on the server by the user during the
|
||||
# deployment of the documentation. The generated sitemap is called sitemap.xml
|
||||
# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
|
||||
# is specified no sitemap is generated. For information about the sitemap
|
||||
# protocol see https://www.sitemaps.org
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
SITEMAP_URL =
|
||||
|
||||
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
|
||||
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
|
||||
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
|
||||
@@ -2021,9 +2045,16 @@ PDF_HYPERLINKS = YES
|
||||
|
||||
USE_PDFLATEX = YES
|
||||
|
||||
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
|
||||
# command to the generated LaTeX files. This will instruct LaTeX to keep running
|
||||
# if errors occur, instead of asking the user for help.
|
||||
# The LATEX_BATCHMODE tag ignals the behavior of LaTeX in case of an error.
|
||||
# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
|
||||
# mode nothing is printed on the terminal, errors are scrolled as if <return> is
|
||||
# hit at every error; missing files that TeX tries to input or request from
|
||||
# keyboard input (\read on a not open input stream) cause the job to abort,
|
||||
# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
|
||||
# but there is no possibility of user interaction just like in batch mode,
|
||||
# SCROLL In scroll mode, TeX will stop only for missing files to input or if
|
||||
# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
|
||||
# each error, asking for user intervention.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
@@ -2044,14 +2075,6 @@ LATEX_HIDE_INDICES = NO
|
||||
|
||||
LATEX_BIB_STYLE = plain
|
||||
|
||||
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
|
||||
# page will contain the date and time when the page was generated. Setting this
|
||||
# to NO can help when comparing the output of multiple runs.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag GENERATE_LATEX is set to YES.
|
||||
|
||||
LATEX_TIMESTAMP = NO
|
||||
|
||||
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
|
||||
# path from which the emoji images will be read. If a relative path is entered,
|
||||
# it will be relative to the LATEX_OUTPUT directory. If left blank the
|
||||
@@ -2217,7 +2240,7 @@ DOCBOOK_OUTPUT = docbook
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
|
||||
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
|
||||
# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
|
||||
# the structure of the code including all documentation. Note that this feature
|
||||
# is still experimental and incomplete at the moment.
|
||||
# The default value is: NO.
|
||||
@@ -2388,16 +2411,9 @@ EXTERNAL_GROUPS = YES
|
||||
EXTERNAL_PAGES = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
# Configuration options related to diagram generator tools
|
||||
#---------------------------------------------------------------------------
|
||||
|
||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||
# then run dia to produce the diagram and insert it in the documentation. The
|
||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||
# If left empty dia is assumed to be found in the default search path.
|
||||
|
||||
DIA_PATH =
|
||||
|
||||
# If set to YES the inheritance and collaboration graphs will hide inheritance
|
||||
# and usage relations if the target is undocumented or is not a class.
|
||||
# The default value is: YES.
|
||||
@@ -2406,7 +2422,7 @@ HIDE_UNDOC_RELATIONS = YES
|
||||
|
||||
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
|
||||
# available from the path. This tool is part of Graphviz (see:
|
||||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# Bell Labs. The other options in this section have no effect if this option is
|
||||
# set to NO
|
||||
# The default value is: NO.
|
||||
@@ -2459,13 +2475,15 @@ DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
|
||||
|
||||
DOT_FONTPATH =
|
||||
|
||||
# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
|
||||
# graph for each documented class showing the direct and indirect inheritance
|
||||
# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
|
||||
# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
|
||||
# to TEXT the direct and indirect inheritance relations will be shown as texts /
|
||||
# links.
|
||||
# Possible values are: NO, YES, TEXT and GRAPH.
|
||||
# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
|
||||
# generate a graph for each documented class showing the direct and indirect
|
||||
# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
|
||||
# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
|
||||
# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
|
||||
# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
|
||||
# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
|
||||
# relations will be shown as texts / links.
|
||||
# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
|
||||
# The default value is: YES.
|
||||
|
||||
CLASS_GRAPH = YES
|
||||
@@ -2606,7 +2624,7 @@ DIR_GRAPH_MAX_DEPTH = 1
|
||||
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
|
||||
# generated by dot. For an explanation of the image formats see the section
|
||||
# output formats in the documentation of the dot tool (Graphviz (see:
|
||||
# http://www.graphviz.org/)).
|
||||
# https://www.graphviz.org/)).
|
||||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
||||
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
||||
# requirement).
|
||||
@@ -2643,11 +2661,12 @@ DOT_PATH =
|
||||
|
||||
DOTFILE_DIRS =
|
||||
|
||||
# The MSCFILE_DIRS tag can be used to specify one or more directories that
|
||||
# contain msc files that are included in the documentation (see the \mscfile
|
||||
# command).
|
||||
# You can include diagrams made with dia in doxygen documentation. Doxygen will
|
||||
# then run dia to produce the diagram and insert it in the documentation. The
|
||||
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
|
||||
# If left empty dia is assumed to be found in the default search path.
|
||||
|
||||
MSCFILE_DIRS =
|
||||
DIA_PATH =
|
||||
|
||||
# The DIAFILE_DIRS tag can be used to specify one or more directories that
|
||||
# contain dia files that are included in the documentation (see the \diafile
|
||||
@@ -2724,3 +2743,19 @@ GENERATE_LEGEND = YES
|
||||
# The default value is: YES.
|
||||
|
||||
DOT_CLEANUP = YES
|
||||
|
||||
# You can define message sequence charts within doxygen comments using the \msc
|
||||
# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
|
||||
# use a built-in version of mscgen tool to produce the charts. Alternatively,
|
||||
# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
|
||||
# specifying prog as the value, doxygen will call the tool as prog -T
|
||||
# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
|
||||
# output file formats "png", "eps", "svg", and "ismap".
|
||||
|
||||
MSCGEN_TOOL =
|
||||
|
||||
# The MSCFILE_DIRS tag can be used to specify one or more directories that
|
||||
# contain msc files that are included in the documentation (see the \mscfile
|
||||
# command).
|
||||
|
||||
MSCFILE_DIRS =
|
||||
|
||||
@@ -63,4 +63,5 @@ implicit list within the packed array itself.
|
||||
|
||||
The interface is in all respects similar to its counterpart in the standard
|
||||
library, that is, the `std::unordered_set` class.<br/>
|
||||
Therefore, there is no need to go into the API description.
|
||||
However, this type of set also supports reverse iteration and therefore offers
|
||||
all the functions necessary for the purpose (such as `rbegin` and `rend`).
|
||||
|
||||
@@ -773,7 +773,7 @@ A utility to quickly find the n-th argument of a function, member function or
|
||||
data member (for blind operations on opaque types):
|
||||
|
||||
```cpp
|
||||
using type = entt::nth_argument_t<1u, &clazz::member>;
|
||||
using type = entt::nth_argument_t<1u, decltype(&clazz::member)>;
|
||||
```
|
||||
|
||||
Disambiguation of overloaded functions is the responsibility of the user, should
|
||||
|
||||
@@ -583,7 +583,7 @@ There are two functions that respond to slightly different needs:
|
||||
* Components are sorted either directly:
|
||||
|
||||
```cpp
|
||||
registry.sort<renderable>([](const auto &lhs, const auto &rhs) {
|
||||
registry.sort<renderable>([](const renderable &lhs, const renderable &rhs) {
|
||||
return lhs.z < rhs.z;
|
||||
});
|
||||
```
|
||||
@@ -1372,7 +1372,7 @@ Finally, when the user asks the registry for an iterable object to visit all the
|
||||
storage elements inside it as follows:
|
||||
|
||||
```cpp
|
||||
for(auto [id, storage]: registry.each()) {
|
||||
for(auto [id, storage]: registry.storage()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -1549,7 +1549,7 @@ own API for them. However, there is still no limit to the possibilities of use:
|
||||
auto &&other = registry.storage<velocity>("other"_hs);
|
||||
|
||||
registry.emplace<velocity>(entity);
|
||||
storage.push(entity);
|
||||
other.push(entity);
|
||||
```
|
||||
|
||||
Anything that can be done via the registry interface can also be done directly
|
||||
@@ -1817,7 +1817,10 @@ However, it's possible to _enforce_ iteration of a view by given component order
|
||||
by means of the `use` function:
|
||||
|
||||
```cpp
|
||||
for(auto entity : registry.view<position, velocity>().use<position>()) {
|
||||
auto view = registry.view<position, velocity>();
|
||||
view.use<position>();
|
||||
|
||||
for(auto entity: view) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -2105,28 +2108,27 @@ The same concepts apply to groups as well.
|
||||
Views and groups are narrow windows on the entire list of entities. They work by
|
||||
filtering entities according to their components.<br/>
|
||||
In some cases there may be the need to iterate all the entities still in use
|
||||
regardless of their components. The registry offers a specific member function
|
||||
to do that:
|
||||
regardless of their components. This is done by accessing entity storage:
|
||||
|
||||
```cpp
|
||||
registry.each([](auto entity) {
|
||||
for(auto entity: registry.view<entt::entity>()) {
|
||||
// ...
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
As a rule of thumb, consider using a view or a group if the goal is to iterate
|
||||
entities that have a determinate set of components. These tools are usually much
|
||||
faster than combining the `each` function with a bunch of custom tests.<br/>
|
||||
faster than filtering entities with a bunch of custom tests.<br/>
|
||||
In all the other cases, this is the way to go. For example, it's possible to
|
||||
combine `each` with the `orphan` member function to clean up orphan entities
|
||||
combine this view with the `orphan` member function to clean up orphan entities
|
||||
(that is, entities that are still in use and have no assigned components):
|
||||
|
||||
```cpp
|
||||
registry.each([®istry](auto entity) {
|
||||
for(auto entity: registry.view<entt::entity>()) {
|
||||
if(registry.orphan(entity)) {
|
||||
registry.release(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
In general, iterating all entities can result in poor performance. It should not
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* [Warning C4003: the min, the max and the macro](#warning-C4003-the-min-the-max-and-the-macro)
|
||||
* [The standard and the non-copyable types](#the-standard-and-the-non-copyable-types)
|
||||
* [Which functions trigger which signals](#which-functions-trigger-which-signals)
|
||||
* [Duplicate storage for the same component](#duplicate-storage-for-the-same-component)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
@@ -213,3 +214,28 @@ otherwise the latter is replaced and therefore `on_update` is triggered. As for
|
||||
the second case, components are removed from their entities and thus freed when
|
||||
they are recycled. It means that `on_destroyed` is triggered for every component
|
||||
owned by the entity that is destroyed.
|
||||
|
||||
## Duplicate storage for the same component
|
||||
|
||||
It's rare but you can see double sometimes, especially when it comes to storage.
|
||||
This can be caused by a conflict in the hash assigned to the various component
|
||||
types (one of a kind) or by bugs in your compiler
|
||||
([more common](https://github.com/skypjack/entt/issues/1063) apparently).<br/>
|
||||
Regardless of the cause, `EnTT` offers a customization point that also serves as
|
||||
a solution in this case:
|
||||
|
||||
```cpp
|
||||
template<>
|
||||
struct entt::type_hash<Type> final {
|
||||
[[nodiscard]] static constexpr id_type value() noexcept {
|
||||
return hashed_string::value("Type");
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr operator id_type() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Specializing `type_hash` directly bypasses the default implementation offered by
|
||||
`EnTT`, thus avoiding any possible conflicts or compiler bugs.
|
||||
|
||||
@@ -39,6 +39,9 @@ I hope the following lists can grow much more in the future.
|
||||
* [Minecraft](https://minecraft.net/en-us/attribution/) by
|
||||
[Mojang](https://mojang.com/): of course, **that** Minecraft, see the
|
||||
open source attributions page for more details.
|
||||
* [Minecraft Legends](https://www.minecraft.net/it-it/about-legends) by
|
||||
[Mojang](https://mojang.com/): an action strategy game where users have to
|
||||
fight to defend the Overworld.
|
||||
* [Minecraft Earth](https://www.minecraft.net/en-us/about-earth) by
|
||||
[Mojang](https://mojang.com/): an augmented reality game for mobile, that
|
||||
lets users bring Minecraft into the real world.
|
||||
@@ -124,6 +127,16 @@ I hope the following lists can grow much more in the future.
|
||||
multi-player arcade shooter game prototype.
|
||||
* [Confetti Party](https://github.com/hexerei/entt-confetti): C++ sample
|
||||
application as a starting point using `EnTT` and `SDL2`.
|
||||
* [Hellbound](https://buas.itch.io/hellbound): a top-down action rogue-like
|
||||
where to fight colossal demons in procedurally generated levels of hell.
|
||||
* [Saurian Sorcery](https://github.com/cajallen/spellbook): a tower defense
|
||||
game where to assemble a tribe of lizards to defend against robot invaders.
|
||||
* [robotfindskitten](https://github.com/autogalkin/robotfindskitten): a clone
|
||||
of `robotfindskitten` inside `Notepad.exe`, powered by `EnTT`.
|
||||
* [Orion](https://github.com/alekskoloch/Orion): Outer-space Research and
|
||||
Interstellar Observation Network (a space shooter game).
|
||||
* [EnTT Boids](https://github.com/DanielEliasib/entt_boids): a simple boids
|
||||
implementation using `EnTT` and `Raylib`.
|
||||
|
||||
## Engines and the like:
|
||||
|
||||
@@ -200,7 +213,14 @@ I hope the following lists can grow much more in the future.
|
||||
open-source engine for building 2D & 3D real-time rendering and interactive
|
||||
contents.
|
||||
* [Kengine](https://github.com/phisko/kengine): the _Koala engine_ is a game
|
||||
engine entirely implemented as an entity-component-ystem.
|
||||
engine entirely implemented as an entity-component-system.
|
||||
* [Scion2D](https://github.com/dwjclark11/Scion2D): 2D game engine with
|
||||
[YouTube series](https://www.youtube.com/playlist?list=PL3HUvSWOJR7XRDwVVQqqWO-zyyscb8L-v)
|
||||
included.
|
||||
* [EnTT Editor](https://github.com/TheDimin/EnttEditor): an editor for `EnTT`
|
||||
libary that combines its built-in reflection system with `ImGui`.
|
||||
* [Era Game Engine](https://github.com/EldarMuradov/EraGameEngine): a modern
|
||||
ECS-based game engine.
|
||||
|
||||
## Articles, videos and blog posts:
|
||||
|
||||
@@ -227,6 +247,17 @@ I hope the following lists can grow much more in the future.
|
||||
- ... And so on.
|
||||
[Check out](https://www.youtube.com/channel/UCQ-W1KE9EYfdxhL6S4twUNw) the
|
||||
_Game Engine Series_ by The Cherno for more videos.
|
||||
* [Game Engine series](https://www.youtube.com/@JADE-iteGames/videos) by
|
||||
[dwjclark11](https://github.com/dwjclark11) (not just `EnTT` but a lot of
|
||||
it):
|
||||
- [Getting into ECS](https://youtu.be/k9CbonLopJU?si=za3Tisyc96_92DWM)
|
||||
- [Creating ECS Wrapper Classes](https://youtu.be/yetyuMJRdbo?si=PJTkmap4Ysqbzb_M)
|
||||
- [Runtime Reflection using EnTT meta](https://youtu.be/GrXV5A07GTY?si=fKdWTj9AOhnhtiXq)
|
||||
- [Adding entt::meta and Sol2 bindings](https://youtu.be/IM55JgxOqFA?si=rsbb4AG_NVh4IUmD)
|
||||
(with [part two](https://youtu.be/-PTt-b1tzRw?si=zPJ4vEluyheMcNgO) too)
|
||||
- ... And so on.
|
||||
[Check it out](https://www.youtube.com/playlist?list=PL3HUvSWOJR7XRDwVVQqqWO-zyyscb8L-v)
|
||||
for more videos.
|
||||
* [Warmonger Dynasty devlog series](https://david-delassus.medium.com/list/warmonger-dynasty-devlogs-f64b71f556de)
|
||||
by [linkdd](https://github.com/linkdd): an interesting walkthrough of
|
||||
developing a game (also) with EnTT.
|
||||
|
||||
@@ -385,6 +385,10 @@ to case. In particular:
|
||||
true in case of success.<br/>
|
||||
For example, it's not possible to clear fixed size containers.
|
||||
|
||||
* The `reserve` member function allows to increase the capacity of the wrapped
|
||||
container and returns true in case of success.<br/>
|
||||
For example, it's not possible to increase capacity of fixed size containers.
|
||||
|
||||
* The `begin` and `end` member functions return opaque iterators that is used to
|
||||
iterate the container directly:
|
||||
|
||||
@@ -472,6 +476,10 @@ differences in behavior in the case of key-only containers. In particular:
|
||||
* The `clear` member function allows to clear the wrapped container and returns
|
||||
true in case of success.
|
||||
|
||||
* The `reserve` member function allows to increase the capacity of the wrapped
|
||||
container and returns true in case of success.<br/>
|
||||
For example, it's not possible to increase capacity of standard maps.
|
||||
|
||||
* The `begin` and `end` member functions return opaque iterators that are used
|
||||
to iterate the container directly:
|
||||
|
||||
|
||||
@@ -177,8 +177,8 @@ To attach a process to a scheduler there are mainly two ways:
|
||||
scheduler.attach([](auto...){ /* ... */ });
|
||||
```
|
||||
|
||||
In both cases, the return value is an opaque object that offers a `then` member
|
||||
function used to create chains of processes to run sequentially.<br/>
|
||||
In both cases, the scheduler is returned and its `then` member function can be
|
||||
used to create chains of processes to run sequentially.<br/>
|
||||
As a minimal example of use:
|
||||
|
||||
```cpp
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
## 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
|
||||
|
||||
68
entt.imp
68
entt.imp
@@ -1,34 +1,42 @@
|
||||
[
|
||||
# gtest only
|
||||
{ "include": [ "@<gtest/internal/.*>", "private", "<gtest/gtest.h>", "public" ] },
|
||||
{ "include": [ "@<gtest/gtest-.*>", "private", "<gtest/gtest.h>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_map.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_set.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/any.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/family.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/hashed_string.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/ident.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/monostate.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_info.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_traits.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/entity.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/group.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/handle.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/helper.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/observer.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/organizer.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/registry.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/runtime_view.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/snapshot.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/sparse_set.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/storage.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/view.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/meta/fwd.hpp[\">]", "private", "<entt/meta/meta.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/poly/fwd.hpp[\">]", "private", "<entt/poly/poly.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/cache.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/loader.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/resource.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/delegate.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/dispatcher.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/emitter.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/sigh.hpp>", "public" ] }
|
||||
# forward files
|
||||
{ "include": [ "@[\"<].*/container/fwd\\.hpp[\">]", "private", "<entt/container/dense_map.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/container/fwd\\.hpp[\">]", "private", "<entt/container/dense_set.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/any.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/family.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/hashed_string.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/ident.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/monostate.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/type_info.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/type_traits.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/component.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/entity.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/group.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/handle.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/helper.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/observer.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/organizer.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/registry.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/runtime_view.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/snapshot.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/sparse_set.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/storage.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/view.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/graph/fwd\\.hpp[\">]", "private", "<entt/graph/adjacency_matrix.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/graph/fwd\\.hpp[\">]", "private", "<entt/graph/dot.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/graph/fwd\\.hpp[\">]", "private", "<entt/graph/flow.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/meta/fwd\\.hpp[\">]", "private", "<entt/meta/meta.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/poly/fwd\\.hpp[\">]", "private", "<entt/poly/poly.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/process/fwd\\.hpp[\">]", "private", "<entt/process/process.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/process/fwd\\.hpp[\">]", "private", "<entt/process/scheduler.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/resource/fwd\\.hpp[\">]", "private", "<entt/resource/cache.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/resource/fwd\\.hpp[\">]", "private", "<entt/resource/loader.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/resource/fwd\\.hpp[\">]", "private", "<entt/resource/resource.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd\\.hpp[\">]", "private", "<entt/signal/delegate.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd\\.hpp[\">]", "private", "<entt/signal/dispatcher.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd\\.hpp[\">]", "private", "<entt/signal/emitter.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd\\.hpp[\">]", "private", "<entt/signal/sigh.hpp>", "public" ] }
|
||||
]
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::basic_registry<*>">
|
||||
<Intrinsic Name="to_entity" Expression="*((traits_type::entity_type *)&entity) & traits_type::entity_mask">
|
||||
<Parameter Name="entity" Type="traits_type::value_type &"/>
|
||||
</Intrinsic>
|
||||
<DisplayString>{{ pools={ pools.size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[entities]">entities</Item>
|
||||
@@ -33,10 +30,12 @@
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_sparse_set<*>">
|
||||
<Intrinsic Name="cap" Expression="(traits_type::version_mask << traits_type::length)"/>
|
||||
<DisplayString>{{ size={ packed.size() }, type={ info->alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" ExcludeView="simple">packed.capacity()</Item>
|
||||
<Item Name="[policy]">mode,en</Item>
|
||||
<Item Name="[free_list]">head</Item>
|
||||
<Synthetic Name="[sparse]">
|
||||
<DisplayString>{ sparse.size() * traits_type::page_size }</DisplayString>
|
||||
<Expand>
|
||||
@@ -50,7 +49,7 @@
|
||||
<Break Condition="pos == last"/>
|
||||
<Exec>page = pos / traits_type::page_size</Exec>
|
||||
<Exec>offset = pos & (traits_type::page_size - 1)</Exec>
|
||||
<If Condition="sparse[page] && (*((traits_type::entity_type *)&sparse[page][offset]) < ~traits_type::entity_mask)">
|
||||
<If Condition="sparse[page] && (*((traits_type::entity_type *)&sparse[page][offset]) < cap())">
|
||||
<Item Name="[{ pos }]">*((traits_type::entity_type *)&sparse[page][offset]) & traits_type::entity_mask</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
@@ -67,7 +66,7 @@
|
||||
<Variable Name="last" InitialValue="packed.size()"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="*((traits_type::entity_type *)&packed[pos]) < ~traits_type::entity_mask">
|
||||
<If Condition="*((traits_type::entity_type *)&packed[pos]) < cap()">
|
||||
<Item Name="[{ pos }]">packed[pos]</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
@@ -78,11 +77,11 @@
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_storage<*>">
|
||||
<Intrinsic Name="cap" Expression="(base_type::traits_type::version_mask << base_type::traits_type::length)"/>
|
||||
<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::info->alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" Optional="true" ExcludeView="simple">payload.capacity() * traits_type::page_size</Item>
|
||||
<Item Name="[page size]" Optional="true" ExcludeView="simple">traits_type::page_size</Item>
|
||||
<Item Name="[length]" Optional="true" ExcludeView="simple">length</Item>
|
||||
<Item Name="[base]" ExcludeView="simple">(base_type*)this,nand</Item>
|
||||
<Item Name="[base]" IncludeView="simple">(base_type*)this,view(simple)nand</Item>
|
||||
<!-- having SFINAE-like techniques in natvis is priceless :) -->
|
||||
@@ -91,7 +90,7 @@
|
||||
<Variable Name="last" InitialValue="base_type::packed.size()"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="*((base_type::traits_type::entity_type *)&base_type::packed[pos]) < ~base_type::traits_type::entity_mask">
|
||||
<If Condition="*((base_type::traits_type::entity_type *)&base_type::packed[pos]) < cap()">
|
||||
<Item Name="[{ pos }:{ base_type::packed[pos] }]">payload[pos / traits_type::page_size][pos & (traits_type::page_size - 1)]</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
@@ -100,10 +99,12 @@
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_view<*>">
|
||||
<DisplayString>{{ size_hint={ view->packed.size() } }}</DisplayString>
|
||||
<DisplayString Condition="leading != nullptr">{{ size_hint={ leading->packed.size() } }}</DisplayString>
|
||||
<DisplayString>{{ size_hint=0 }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[pools]">pools,na</Item>
|
||||
<Item Name="[filter]">filter,na</Item>
|
||||
<Item Name="[pools]" Optional="true">pools,na</Item>
|
||||
<Item Name="[filter]" Optional="true">filter,na</Item>
|
||||
<Item Name="[handle]" Condition="leading != nullptr">leading,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_runtime_view<*>">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
11
src/BUILD.bazel
Normal file
11
src/BUILD.bazel
Normal file
@@ -0,0 +1,11 @@
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
load("//bazel:copts.bzl", "COPTS")
|
||||
|
||||
package(default_visibility = ["//:__subpackages__"])
|
||||
|
||||
cc_library(
|
||||
name = "entt",
|
||||
includes = ["."],
|
||||
hdrs = glob(["**/*.h", "**/*.hpp"]),
|
||||
copts = COPTS,
|
||||
)
|
||||
@@ -25,6 +25,8 @@
|
||||
#ifndef ENTT_ID_TYPE
|
||||
# include <cstdint>
|
||||
# define ENTT_ID_TYPE std::uint32_t
|
||||
#else
|
||||
# include <cstdint> // provides coverage for types in the std namespace
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_SPARSE_PAGE
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#include "macro.h"
|
||||
|
||||
#define ENTT_VERSION_MAJOR 3
|
||||
#define ENTT_VERSION_MINOR 12
|
||||
#define ENTT_VERSION_PATCH 1
|
||||
#define ENTT_VERSION_MINOR 13
|
||||
#define ENTT_VERSION_PATCH 2
|
||||
|
||||
#define ENTT_VERSION \
|
||||
ENTT_XSTR(ENTT_VERSION_MAJOR) \
|
||||
|
||||
@@ -20,11 +20,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Key, typename Type>
|
||||
@@ -69,6 +65,7 @@ public:
|
||||
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;
|
||||
|
||||
constexpr dense_map_iterator() noexcept
|
||||
: it{} {}
|
||||
@@ -190,6 +187,7 @@ public:
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
|
||||
constexpr dense_map_local_iterator() noexcept
|
||||
: it{},
|
||||
@@ -241,11 +239,7 @@ template<typename Lhs, typename Rhs>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Associative container for key-value pairs with unique keys.
|
||||
@@ -989,7 +983,7 @@ public:
|
||||
sparse.first().resize(sz);
|
||||
|
||||
for(auto &&elem: sparse.first()) {
|
||||
elem = std::numeric_limits<size_type>::max();
|
||||
elem = (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
|
||||
for(size_type pos{}, last = size(); pos < last; ++pos) {
|
||||
@@ -1033,11 +1027,7 @@ private:
|
||||
|
||||
} // namespace entt
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace std {
|
||||
|
||||
template<typename Key, typename Value, typename Allocator>
|
||||
@@ -1045,10 +1035,6 @@ struct uses_allocator<entt::internal::dense_map_node<Key, Value>, Allocator>
|
||||
: std::true_type {};
|
||||
|
||||
} // namespace std
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,11 +19,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
@@ -206,11 +202,7 @@ template<typename Lhs, typename Rhs>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Associative container for unique objects of a given type.
|
||||
@@ -311,6 +303,10 @@ public:
|
||||
using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>;
|
||||
/*! @brief Constant random access iterator type. */
|
||||
using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_iterator>;
|
||||
/*! @brief Reverse iterator type. */
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
/*! @brief Constant reverse iterator type. */
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
/*! @brief Forward iterator type. */
|
||||
using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>;
|
||||
/*! @brief Constant forward iterator type. */
|
||||
@@ -447,6 +443,46 @@ public:
|
||||
return packed.first().end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reverse iterator to the beginning.
|
||||
*
|
||||
* If the array is empty, the returned iterator will be equal to `rend()`.
|
||||
*
|
||||
* @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());
|
||||
}
|
||||
|
||||
/*! @copydoc crbegin */
|
||||
[[nodiscard]] const_reverse_iterator rbegin() const noexcept {
|
||||
return crbegin();
|
||||
}
|
||||
|
||||
/*! @copydoc rbegin */
|
||||
[[nodiscard]] reverse_iterator rbegin() noexcept {
|
||||
return std::make_reverse_iterator(end());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reverse iterator to the end.
|
||||
* @return An iterator to the element following the last instance of the
|
||||
* reversed internal array.
|
||||
*/
|
||||
[[nodiscard]] const_reverse_iterator crend() const noexcept {
|
||||
return std::make_reverse_iterator(cbegin());
|
||||
}
|
||||
|
||||
/*! @copydoc crend */
|
||||
[[nodiscard]] const_reverse_iterator rend() const noexcept {
|
||||
return crend();
|
||||
}
|
||||
|
||||
/*! @copydoc rend */
|
||||
[[nodiscard]] reverse_iterator rend() noexcept {
|
||||
return std::make_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a container is empty.
|
||||
* @return True if the container is empty, false otherwise.
|
||||
@@ -842,7 +878,7 @@ public:
|
||||
sparse.first().resize(sz);
|
||||
|
||||
for(auto &&elem: sparse.first()) {
|
||||
elem = std::numeric_limits<size_type>::max();
|
||||
elem = (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
|
||||
for(size_type pos{}, last = size(); pos < last; ++pos) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
@@ -13,11 +13,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
enum class any_operation : std::uint8_t {
|
||||
@@ -30,19 +26,19 @@ enum class any_operation : std::uint8_t {
|
||||
get
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/*! @brief Possible modes of an any object. */
|
||||
enum class any_policy : std::uint8_t {
|
||||
/*! @brief Default mode, the object owns the contained element. */
|
||||
owner,
|
||||
/*! @brief Aliasing mode, the object _points_ to a non-const element. */
|
||||
ref,
|
||||
/*! @brief Const aliasing mode, the object _points_ to a const element. */
|
||||
cref
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief A SBO friendly, type-safe container for single values of any type.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
@@ -51,7 +47,6 @@ enum class any_policy : std::uint8_t {
|
||||
template<std::size_t Len, std::size_t Align>
|
||||
class basic_any {
|
||||
using operation = internal::any_operation;
|
||||
using policy = internal::any_policy;
|
||||
using vtable_type = const void *(const operation, const basic_any &, const void *);
|
||||
|
||||
struct storage_type {
|
||||
@@ -63,11 +58,11 @@ class basic_any {
|
||||
|
||||
template<typename Type>
|
||||
static const void *basic_vtable(const operation op, const basic_any &value, const void *other) {
|
||||
static_assert(!std::is_same_v<Type, void> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
|
||||
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 *element = nullptr;
|
||||
|
||||
if constexpr(in_situ<Type>) {
|
||||
element = value.owner() ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance);
|
||||
element = (value.mode == any_policy::owner) ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance);
|
||||
} else {
|
||||
element = static_cast<const Type *>(value.instance);
|
||||
}
|
||||
@@ -80,7 +75,7 @@ class basic_any {
|
||||
break;
|
||||
case operation::move:
|
||||
if constexpr(in_situ<Type>) {
|
||||
if(value.owner()) {
|
||||
if(value.mode == any_policy::owner) {
|
||||
return new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(element))};
|
||||
}
|
||||
}
|
||||
@@ -129,7 +124,7 @@ class basic_any {
|
||||
|
||||
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>> ? policy::cref : policy::ref;
|
||||
mode = std::is_const_v<std::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
|
||||
instance = (std::addressof(args), ...);
|
||||
} else if constexpr(in_situ<std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
if constexpr(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>)) {
|
||||
@@ -147,7 +142,7 @@ class basic_any {
|
||||
}
|
||||
}
|
||||
|
||||
basic_any(const basic_any &other, const policy pol) noexcept
|
||||
basic_any(const basic_any &other, const any_policy pol) noexcept
|
||||
: instance{other.data()},
|
||||
info{other.info},
|
||||
vtable{other.vtable},
|
||||
@@ -174,7 +169,7 @@ public:
|
||||
: instance{},
|
||||
info{},
|
||||
vtable{},
|
||||
mode{policy::owner} {
|
||||
mode{any_policy::owner} {
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -214,7 +209,7 @@ public:
|
||||
|
||||
/*! @brief Frees the internal storage, whatever it means. */
|
||||
~basic_any() {
|
||||
if(vtable && owner()) {
|
||||
if(vtable && (mode == any_policy::owner)) {
|
||||
vtable(operation::destroy, *this, nullptr);
|
||||
}
|
||||
}
|
||||
@@ -295,7 +290,7 @@ public:
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data() noexcept {
|
||||
return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data());
|
||||
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,7 +299,7 @@ public:
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data(const type_info &req) noexcept {
|
||||
return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
|
||||
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -325,7 +320,7 @@ public:
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool assign(const basic_any &other) {
|
||||
if(vtable && mode != policy::cref && *info == *other.info) {
|
||||
if(vtable && mode != any_policy::cref && *info == *other.info) {
|
||||
return (vtable(operation::assign, *this, other.data()) != nullptr);
|
||||
}
|
||||
|
||||
@@ -334,7 +329,7 @@ public:
|
||||
|
||||
/*! @copydoc assign */
|
||||
bool assign(basic_any &&other) {
|
||||
if(vtable && mode != policy::cref && *info == *other.info) {
|
||||
if(vtable && mode != any_policy::cref && *info == *other.info) {
|
||||
if(auto *val = other.data(); val) {
|
||||
return (vtable(operation::transfer, *this, val) != nullptr);
|
||||
} else {
|
||||
@@ -347,7 +342,7 @@ public:
|
||||
|
||||
/*! @brief Destroys contained object */
|
||||
void reset() {
|
||||
if(vtable && owner()) {
|
||||
if(vtable && (mode == any_policy::owner)) {
|
||||
vtable(operation::destroy, *this, nullptr);
|
||||
}
|
||||
|
||||
@@ -355,7 +350,7 @@ public:
|
||||
ENTT_ASSERT((instance = nullptr) == nullptr, "");
|
||||
info = &type_id<void>();
|
||||
vtable = nullptr;
|
||||
mode = policy::owner;
|
||||
mode = any_policy::owner;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -393,20 +388,28 @@ public:
|
||||
* @return A wrapper that shares a reference to an unmanaged object.
|
||||
*/
|
||||
[[nodiscard]] basic_any as_ref() noexcept {
|
||||
return basic_any{*this, (mode == policy::cref ? policy::cref : policy::ref)};
|
||||
return basic_any{*this, (mode == any_policy::cref ? any_policy::cref : any_policy::ref)};
|
||||
}
|
||||
|
||||
/*! @copydoc as_ref */
|
||||
[[nodiscard]] basic_any as_ref() const noexcept {
|
||||
return basic_any{*this, policy::cref};
|
||||
return basic_any{*this, any_policy::cref};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a wrapper owns its object, false otherwise.
|
||||
* @return True if the wrapper owns its object, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool owner() const noexcept {
|
||||
return (mode == policy::owner);
|
||||
[[deprecated("use policy() and any_policy instead")]] [[nodiscard]] bool owner() const noexcept {
|
||||
return (mode == any_policy::owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current mode of an any object.
|
||||
* @return The current mode of the any object.
|
||||
*/
|
||||
[[nodiscard]] any_policy policy() const noexcept {
|
||||
return mode;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -416,7 +419,7 @@ private:
|
||||
};
|
||||
const type_info *info;
|
||||
vtable_type *vtable;
|
||||
policy mode;
|
||||
any_policy mode;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,11 +9,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, std::size_t, typename = void>
|
||||
@@ -73,11 +69,7 @@ struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Ty
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief A compressed pair.
|
||||
|
||||
@@ -7,11 +7,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename>
|
||||
@@ -43,11 +39,7 @@ struct basic_hashed_string {
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Zero overhead unique identifier.
|
||||
@@ -175,7 +167,7 @@ public:
|
||||
* @return The size of the hashed string.
|
||||
*/
|
||||
[[nodiscard]] constexpr size_type size() const noexcept {
|
||||
return base_type::length;
|
||||
return base_type::length; // NOLINT
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Checks whether a value is a power of two or not.
|
||||
* @brief Checks whether a value is a power of two or not (waiting for C++20 and
|
||||
* `std::has_single_bit`).
|
||||
* @param value A value that may or may not be a power of two.
|
||||
* @return True if the value is a power of two, false otherwise.
|
||||
*/
|
||||
@@ -21,7 +22,8 @@ namespace entt {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the smallest power of two greater than or equal to a value.
|
||||
* @brief Computes the smallest power of two greater than or equal to a value
|
||||
* (waiting for C++20 and `std::bit_ceil`).
|
||||
* @param value The value to use.
|
||||
* @return The smallest power of two greater than or equal to the given value.
|
||||
*/
|
||||
@@ -163,11 +165,7 @@ ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) {
|
||||
return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
|
||||
}
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Type>
|
||||
@@ -223,11 +221,7 @@ struct uses_allocator_construction<std::pair<Type, Other>> {
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Uses-allocator construction utility (waiting for C++20).
|
||||
|
||||
@@ -7,11 +7,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename>
|
||||
@@ -21,11 +17,7 @@ template<typename... Args>
|
||||
struct is_tuple_impl<std::tuple<Args...>>: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is a
|
||||
|
||||
@@ -11,11 +11,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
struct ENTT_API type_index final {
|
||||
@@ -38,26 +34,26 @@ template<typename Type>
|
||||
}
|
||||
|
||||
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
|
||||
[[nodiscard]] static constexpr std::string_view type_name(int) noexcept {
|
||||
[[nodiscard]] constexpr std::string_view type_name(int) noexcept {
|
||||
constexpr auto value = stripped_type_name<Type>();
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static std::string_view type_name(char) noexcept {
|
||||
[[nodiscard]] std::string_view type_name(char) noexcept {
|
||||
static const auto value = stripped_type_name<Type>();
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
|
||||
[[nodiscard]] static constexpr id_type type_hash(int) noexcept {
|
||||
[[nodiscard]] constexpr id_type type_hash(int) noexcept {
|
||||
constexpr auto stripped = stripped_type_name<Type>();
|
||||
constexpr auto value = hashed_string::value(stripped.data(), stripped.size());
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static id_type type_hash(char) noexcept {
|
||||
[[nodiscard]] id_type type_hash(char) noexcept {
|
||||
static const auto value = [](const auto stripped) {
|
||||
return hashed_string::value(stripped.data(), stripped.size());
|
||||
}(stripped_type_name<Type>());
|
||||
@@ -65,11 +61,7 @@ template<typename Type>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Type sequential identifier.
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace entt {
|
||||
*/
|
||||
template<std::size_t N>
|
||||
struct choice_t
|
||||
// Unfortunately, doxygen cannot parse such a construct.
|
||||
// unfortunately, doxygen cannot parse such a construct
|
||||
: /*! @cond TURN_OFF_DOXYGEN */ choice_t<N - 1> /*! @endcond */
|
||||
{};
|
||||
|
||||
@@ -250,37 +250,40 @@ struct type_list_cat<type_list<Type...>> {
|
||||
template<typename... List>
|
||||
using type_list_cat_t = typename type_list_cat<List...>::type;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename>
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename...>
|
||||
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>> {};
|
||||
|
||||
template<typename... Type>
|
||||
struct type_list_unique<type_list<>, Type...> {
|
||||
using type = type_list<Type...>;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Removes duplicates types from a type list.
|
||||
* @tparam Type One of the types provided by the given type list.
|
||||
* @tparam Other The other types provided by the given type list.
|
||||
* @tparam List Type list.
|
||||
*/
|
||||
template<typename Type, typename... Other>
|
||||
struct type_list_unique<type_list<Type, Other...>> {
|
||||
template<typename List>
|
||||
struct type_list_unique {
|
||||
/*! @brief A type list without duplicate types. */
|
||||
using type = std::conditional_t<
|
||||
(std::is_same_v<Type, Other> || ...),
|
||||
typename type_list_unique<type_list<Other...>>::type,
|
||||
type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>>;
|
||||
};
|
||||
|
||||
/*! @brief Removes duplicates types from a type list. */
|
||||
template<>
|
||||
struct type_list_unique<type_list<>> {
|
||||
/*! @brief A type list without duplicate types. */
|
||||
using type = type_list<>;
|
||||
using type = typename internal::type_list_unique<List>::type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type A type list.
|
||||
* @tparam List Type list.
|
||||
*/
|
||||
template<typename Type>
|
||||
using type_list_unique_t = typename type_list_unique<Type>::type;
|
||||
template<typename List>
|
||||
using type_list_unique_t = typename type_list_unique<List>::type;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a type list contains a
|
||||
@@ -675,11 +678,7 @@ inline constexpr bool is_complete_v = is_complete<Type>::value;
|
||||
template<typename Type, typename = void>
|
||||
struct is_iterator: std::false_type {};
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
@@ -689,15 +688,11 @@ template<typename Type>
|
||||
struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/*! @copydoc is_iterator */
|
||||
template<typename Type>
|
||||
struct is_iterator<Type, std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_pointer_t<Type>>, void>>>
|
||||
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> {};
|
||||
|
||||
/**
|
||||
@@ -742,19 +737,7 @@ 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;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is
|
||||
* equality comparable, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_equality_comparable: std::false_type {};
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
@@ -763,51 +746,69 @@ struct has_tuple_size_value: std::false_type {};
|
||||
template<typename Type>
|
||||
struct has_tuple_size_value<Type, std::void_t<decltype(std::tuple_size<const Type>::value)>>: std::true_type {};
|
||||
|
||||
template<typename, 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 {};
|
||||
|
||||
template<typename>
|
||||
[[nodiscard]] constexpr bool dispatch_is_equality_comparable();
|
||||
|
||||
template<typename Type, std::size_t... Index>
|
||||
[[nodiscard]] constexpr bool unpack_maybe_equality_comparable(std::index_sequence<Index...>) {
|
||||
return (is_equality_comparable<std::tuple_element_t<Index, Type>>::value && ...);
|
||||
return (dispatch_is_equality_comparable<std::tuple_element_t<Index, Type>>() && ...);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
[[nodiscard]] constexpr bool maybe_equality_comparable(choice_t<0>) {
|
||||
[[nodiscard]] constexpr bool maybe_equality_comparable(char) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto maybe_equality_comparable(int) -> decltype(std::declval<Type>() == std::declval<Type>()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto maybe_equality_comparable(choice_t<1>) -> decltype(std::declval<typename Type::value_type>(), bool{}) {
|
||||
if constexpr(is_iterator_v<Type>) {
|
||||
return true;
|
||||
} else if constexpr(std::is_same_v<typename Type::value_type, Type>) {
|
||||
return maybe_equality_comparable<Type>(choice<0>);
|
||||
[[nodiscard]] constexpr bool dispatch_is_equality_comparable() {
|
||||
if constexpr(std::is_array_v<Type>) {
|
||||
return false;
|
||||
} else if constexpr(is_iterator_v<Type>) {
|
||||
return maybe_equality_comparable<Type>(0);
|
||||
} else if constexpr(has_value_type<Type>::value) {
|
||||
if constexpr(std::is_same_v<typename Type::value_type, Type>) {
|
||||
return maybe_equality_comparable<Type>(0);
|
||||
} else if constexpr(dispatch_is_equality_comparable<typename Type::value_type>()) {
|
||||
return maybe_equality_comparable<Type>(0);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if constexpr(is_complete_v<std::tuple_size<std::remove_cv_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>{});
|
||||
} else {
|
||||
return maybe_equality_comparable<Type>(0);
|
||||
}
|
||||
} else {
|
||||
return is_equality_comparable<typename Type::value_type>::value;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<is_complete_v<std::tuple_size<std::remove_cv_t<Type>>>, bool> maybe_equality_comparable(choice_t<2>) {
|
||||
if constexpr(has_tuple_size_value<Type>::value) {
|
||||
return unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
|
||||
} else {
|
||||
return maybe_equality_comparable<Type>(choice<1>);
|
||||
return maybe_equality_comparable<Type>(0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
* @brief Provides the member constant `value` to true if a given type is
|
||||
* equality comparable, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_equality_comparable: std::bool_constant<internal::dispatch_is_equality_comparable<Type>()> {};
|
||||
|
||||
/*! @copydoc is_equality_comparable */
|
||||
template<typename Type>
|
||||
struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>>
|
||||
: std::bool_constant<internal::maybe_equality_comparable<Type>(choice<2>)> {};
|
||||
|
||||
/*! @copydoc is_equality_comparable */
|
||||
template<typename Type, auto N>
|
||||
struct is_equality_comparable<Type[N]>: std::false_type {};
|
||||
struct is_equality_comparable<const Type>: is_equality_comparable<Type> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
@@ -874,9 +875,9 @@ using member_class_t = typename member_class<Member>::type;
|
||||
/**
|
||||
* @brief Extracts the n-th argument of a given function or member function.
|
||||
* @tparam Index The index of the argument to extract.
|
||||
* @tparam Candidate A valid function, member function or data member.
|
||||
* @tparam Candidate A valid function, member function or data member type.
|
||||
*/
|
||||
template<std::size_t Index, auto Candidate>
|
||||
template<std::size_t Index, typename Candidate>
|
||||
class nth_argument {
|
||||
template<typename Ret, typename... Args>
|
||||
static constexpr type_list<Args...> pick_up(Ret (*)(Args...));
|
||||
@@ -892,15 +893,15 @@ class nth_argument {
|
||||
|
||||
public:
|
||||
/*! @brief N-th argument of the given function or member function. */
|
||||
using type = type_list_element_t<Index, decltype(pick_up(Candidate))>;
|
||||
using type = type_list_element_t<Index, decltype(pick_up(std::declval<Candidate>()))>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Index The index of the argument to extract.
|
||||
* @tparam Candidate A valid function, member function or data member.
|
||||
* @tparam Candidate A valid function, member function or data member type.
|
||||
*/
|
||||
template<std::size_t Index, auto Candidate>
|
||||
template<std::size_t Index, typename Candidate>
|
||||
using nth_argument_t = typename nth_argument<Index, Candidate>::type;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -8,11 +8,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, typename = void>
|
||||
@@ -32,15 +28,11 @@ template<>
|
||||
struct page_size<void>: std::integral_constant<std::size_t, 0u> {};
|
||||
|
||||
template<typename Type>
|
||||
struct page_size<Type, std::enable_if_t<std::is_convertible_v<decltype(Type::page_size), std::size_t>>>
|
||||
struct page_size<Type, std::void_t<decltype(Type::page_size)>>
|
||||
: std::integral_constant<std::size_t, Type::page_size> {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Common way to access various properties of components.
|
||||
|
||||
@@ -9,16 +9,12 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
// waiting for C++20 (and std::popcount)
|
||||
// waiting for C++20 and std::popcount
|
||||
template<typename Type>
|
||||
static constexpr int popcount(Type value) noexcept {
|
||||
constexpr int popcount(Type value) noexcept {
|
||||
return value ? (int(value & 1) + popcount(value >> 1)) : 0;
|
||||
}
|
||||
|
||||
@@ -60,11 +56,7 @@ struct entt_traits<std::uint64_t> {
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Common basic entity traits implementation.
|
||||
@@ -114,7 +106,7 @@ public:
|
||||
* @return The integral representation of the version part.
|
||||
*/
|
||||
[[nodiscard]] static constexpr version_type to_version(const value_type value) noexcept {
|
||||
return static_cast<version_type>(to_integral(value) >> length);
|
||||
return (static_cast<version_type>(to_integral(value) >> length) & version_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +116,7 @@ public:
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type next(const value_type value) noexcept {
|
||||
const auto vers = to_version(value) + 1;
|
||||
return construct(to_entity(value), static_cast<version_type>(vers + (vers == version_mask)));
|
||||
return construct(to_integral(value), static_cast<version_type>(vers + (vers == version_mask)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +130,7 @@ public:
|
||||
* @return A properly constructed identifier.
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) noexcept {
|
||||
return value_type{(entity & entity_mask) | (static_cast<entity_type>(version) << length)};
|
||||
return value_type{(entity & entity_mask) | (static_cast<entity_type>(version & version_mask) << length)};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,8 +144,7 @@ public:
|
||||
* @return A properly constructed identifier.
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept {
|
||||
constexpr auto mask = (version_mask << length);
|
||||
return value_type{(lhs & entity_mask) | (rhs & mask)};
|
||||
return value_type{(lhs & entity_mask) | (rhs & (version_mask << length))};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -170,8 +161,10 @@ struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> {
|
||||
};
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_integral
|
||||
* @brief Converts an entity to its underlying type.
|
||||
* @tparam Entity The value type.
|
||||
* @param value The value to convert.
|
||||
* @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 {
|
||||
@@ -179,8 +172,10 @@ template<typename Entity>
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_entity
|
||||
* @brief Returns the entity part once converted to the underlying type.
|
||||
* @tparam Entity The value type.
|
||||
* @param value The value to convert.
|
||||
* @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 {
|
||||
@@ -188,8 +183,10 @@ template<typename Entity>
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_version
|
||||
* @brief Returns the version part once converted to the underlying type.
|
||||
* @tparam Entity The value type.
|
||||
* @param value The value to convert.
|
||||
* @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 {
|
||||
|
||||
@@ -17,7 +17,9 @@ enum class deletion_policy : std::uint8_t {
|
||||
/*! @brief Swap-and-pop deletion policy. */
|
||||
swap_and_pop = 0u,
|
||||
/*! @brief In-place deletion policy. */
|
||||
in_place = 1u
|
||||
in_place = 1u,
|
||||
/*! @brief Swap-only deletion policy. */
|
||||
swap_only = 2u
|
||||
};
|
||||
|
||||
template<typename Entity = entity, typename = std::allocator<Entity>>
|
||||
@@ -26,46 +28,8 @@ class basic_sparse_set;
|
||||
template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
|
||||
class basic_storage;
|
||||
|
||||
template<typename Type>
|
||||
class sigh_mixin;
|
||||
|
||||
/**
|
||||
* @brief Provides a common way to define storage types.
|
||||
* @tparam Type Storage value 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<Type>, typename = void>
|
||||
struct storage_type {
|
||||
/*! @brief Type-to-storage conversion result. */
|
||||
using type = sigh_mixin<basic_storage<Type, Entity, Allocator>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using storage_type_t = typename storage_type<Args...>::type;
|
||||
|
||||
/**
|
||||
* Type-to-storage conversion utility that preserves constness.
|
||||
* @tparam Type Storage value type, eventually const.
|
||||
* @tparam Entity A valid entity type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
|
||||
struct storage_for {
|
||||
/*! @brief Type-to-storage conversion result. */
|
||||
using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using storage_for_t = typename storage_for<Args...>::type;
|
||||
template<typename, typename>
|
||||
class basic_sigh_mixin;
|
||||
|
||||
template<typename Entity = entity, typename = std::allocator<Entity>>
|
||||
class basic_registry;
|
||||
@@ -97,6 +61,67 @@ class basic_snapshot_loader;
|
||||
template<typename>
|
||||
class basic_continuous_loader;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using sparse_set = basic_sparse_set<>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Type Type of objects assigned to the entities.
|
||||
*/
|
||||
template<typename Type>
|
||||
using storage = basic_storage<Type>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Type Underlying storage type.
|
||||
*/
|
||||
template<typename Type>
|
||||
using sigh_mixin = basic_sigh_mixin<Type, basic_registry<typename Type::entity_type, typename Type::base_type::allocator_type>>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using registry = basic_registry<>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using observer = basic_observer<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using organizer = basic_organizer<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using handle = basic_handle<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using const_handle = basic_handle<const registry>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using handle_view = basic_handle<registry, Args...>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using const_handle_view = basic_handle<const registry, Args...>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot = basic_snapshot<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot_loader = basic_snapshot_loader<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using continuous_loader = basic_continuous_loader<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using runtime_view = basic_runtime_view<sparse_set>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using const_runtime_view = basic_runtime_view<const sparse_set>;
|
||||
|
||||
/**
|
||||
* @brief Alias for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
@@ -181,53 +206,43 @@ struct type_list_transform<owned_t<Type...>, Op> {
|
||||
using type = owned_t<typename Op<Type>::type...>;
|
||||
};
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using sparse_set = basic_sparse_set<>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Type Type of objects assigned to the entities.
|
||||
* @brief Provides a common way to define storage types.
|
||||
* @tparam Type Storage value type.
|
||||
* @tparam Entity A valid entity type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type>
|
||||
using storage = basic_storage<Type>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using registry = basic_registry<>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using observer = basic_observer<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using organizer = basic_organizer<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using handle = basic_handle<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using const_handle = basic_handle<const registry>;
|
||||
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
|
||||
struct storage_type {
|
||||
/*! @brief Type-to-storage conversion result. */
|
||||
using type = sigh_mixin<basic_storage<Type, Entity, Allocator>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
* @brief Helper type.
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using handle_view = basic_handle<registry, Args...>;
|
||||
using storage_type_t = typename storage_type<Args...>::type;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
* Type-to-storage conversion utility that preserves constness.
|
||||
* @tparam Type Storage value type, eventually const.
|
||||
* @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>>>
|
||||
struct storage_for {
|
||||
/*! @brief Type-to-storage conversion result. */
|
||||
using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using const_handle_view = basic_handle<const registry, Args...>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot = basic_snapshot<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot_loader = basic_snapshot_loader<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using continuous_loader = basic_continuous_loader<registry>;
|
||||
using storage_for_t = typename storage_for<Args...>::type;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
@@ -237,12 +252,6 @@ using continuous_loader = basic_continuous_loader<registry>;
|
||||
template<typename Get, typename Exclude = exclude_t<>>
|
||||
using view = basic_view<type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using runtime_view = basic_runtime_view<sparse_set>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using const_runtime_view = basic_runtime_view<const sparse_set>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Owned Types of storage _owned_ by the group.
|
||||
|
||||
@@ -16,11 +16,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename, typename>
|
||||
@@ -44,12 +40,13 @@ public:
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
|
||||
constexpr extended_group_iterator()
|
||||
: it{},
|
||||
pools{} {}
|
||||
|
||||
extended_group_iterator(It from, const std::tuple<Owned *..., Get *...> &cpools)
|
||||
extended_group_iterator(iterator_type from, const std::tuple<Owned *..., Get *...> &cpools)
|
||||
: it{from},
|
||||
pools{cpools} {}
|
||||
|
||||
@@ -112,27 +109,28 @@ class group_handler<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> fin
|
||||
using base_type = std::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
|
||||
using entity_type = typename base_type::entity_type;
|
||||
|
||||
void swap_elements(const std::size_t pos, const entity_type entt) {
|
||||
std::apply([pos, entt](auto *...cpool) { (cpool->swap_elements(cpool->data()[pos], entt), ...); }, pools);
|
||||
template<std::size_t... Index>
|
||||
void swap_elements(const std::size_t pos, const entity_type entt, std::index_sequence<Index...>) {
|
||||
(std::get<Index>(pools)->swap_elements(std::get<Index>(pools)->data()[pos], entt), ...);
|
||||
}
|
||||
|
||||
void push_on_construct(const entity_type entt) {
|
||||
if(std::apply([entt, len = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < len) && (other->contains(entt) && ...); }, pools)
|
||||
&& std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
|
||||
swap_elements(len++, entt);
|
||||
swap_elements(len++, entt, std::index_sequence_for<Owned...>{});
|
||||
}
|
||||
}
|
||||
|
||||
void push_on_destroy(const entity_type entt) {
|
||||
if(std::apply([entt, len = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < len) && (other->contains(entt) && ...); }, pools)
|
||||
&& std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
|
||||
swap_elements(len++, entt);
|
||||
swap_elements(len++, entt, std::index_sequence_for<Owned...>{});
|
||||
}
|
||||
}
|
||||
|
||||
void remove_if(const entity_type entt) {
|
||||
if(std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < len)) {
|
||||
swap_elements(--len, entt);
|
||||
swap_elements(--len, entt, std::index_sequence_for<Owned...>{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,13 +164,11 @@ public:
|
||||
return len;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
Type pools_as() const noexcept {
|
||||
auto pools_as_tuple() const noexcept {
|
||||
return pools;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
Type filter_as() const noexcept {
|
||||
auto filter_as_tuple() const noexcept {
|
||||
return filter;
|
||||
}
|
||||
|
||||
@@ -234,13 +230,11 @@ public:
|
||||
return elem;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
Type pools_as() const noexcept {
|
||||
auto pools_as_tuple() const noexcept {
|
||||
return pools;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
Type filter_as() const noexcept {
|
||||
auto filter_as_tuple() const noexcept {
|
||||
return filter;
|
||||
}
|
||||
|
||||
@@ -251,11 +245,7 @@ private:
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Group.
|
||||
@@ -298,12 +288,12 @@ class basic_group<owned_t<>, get_t<Get...>, exclude_t<Exclude...>> {
|
||||
|
||||
auto pools() const noexcept {
|
||||
using return_type = std::tuple<Get *...>;
|
||||
return descriptor ? descriptor->template pools_as<return_type>() : return_type{};
|
||||
return descriptor ? descriptor->pools_as_tuple() : return_type{};
|
||||
}
|
||||
|
||||
auto filter() const noexcept {
|
||||
using return_type = std::tuple<Exclude *...>;
|
||||
return descriptor ? descriptor->template filter_as<return_type>() : return_type{};
|
||||
return descriptor ? descriptor->filter_as_tuple() : return_type{};
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -498,11 +488,6 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Returns the components assigned to the given entity.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an entity that doesn't belong to the group results in
|
||||
* undefined behavior.
|
||||
*
|
||||
* @tparam Type Type of the component to get.
|
||||
* @tparam Other Other types of components to get.
|
||||
* @param entt A valid identifier.
|
||||
@@ -515,11 +500,6 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Returns the components assigned to the given entity.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an entity that doesn't belong to the groups results in
|
||||
* undefined behavior.
|
||||
*
|
||||
* @tparam Index Indexes of the components to get.
|
||||
* @param entt A valid identifier.
|
||||
* @return The components assigned to the entity.
|
||||
@@ -660,17 +640,28 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sort the shared pool of entities according to a given storage.
|
||||
* @brief Sort entities according to their order in a range.
|
||||
*
|
||||
* 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 {
|
||||
if(*this) {
|
||||
descriptor->handle().sort_as(first, last);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sort entities according to their order in a range.
|
||||
* @param other The storage to use to impose the order.
|
||||
*/
|
||||
void sort_as(const common_type &other) const {
|
||||
if(*this) {
|
||||
descriptor->handle().sort_as(other);
|
||||
}
|
||||
[[deprecated("use iterator based sort_as instead")]] void sort_as(const common_type &other) const {
|
||||
sort_as(other.begin(), other.end());
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -718,12 +709,12 @@ class basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> {
|
||||
|
||||
auto pools() const noexcept {
|
||||
using return_type = std::tuple<Owned *..., Get *...>;
|
||||
return descriptor ? descriptor->template pools_as<return_type>() : return_type{};
|
||||
return descriptor ? descriptor->pools_as_tuple() : return_type{};
|
||||
}
|
||||
|
||||
auto filter() const noexcept {
|
||||
using return_type = std::tuple<Exclude *...>;
|
||||
return descriptor ? descriptor->template filter_as<return_type>() : return_type{};
|
||||
return descriptor ? descriptor->filter_as_tuple() : return_type{};
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -903,11 +894,6 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Returns the components assigned to the given entity.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an entity that doesn't belong to the group results in
|
||||
* undefined behavior.
|
||||
*
|
||||
* @tparam Type Type of the component to get.
|
||||
* @tparam Other Other types of components to get.
|
||||
* @param entt A valid identifier.
|
||||
@@ -920,11 +906,6 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Returns the components assigned to the given entity.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to use an entity that doesn't belong to the groups results in
|
||||
* undefined behavior.
|
||||
*
|
||||
* @tparam Index Indexes of the components to get.
|
||||
* @param entt A valid identifier.
|
||||
* @return The components assigned to the entity.
|
||||
|
||||
@@ -12,11 +12,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
@@ -33,6 +29,7 @@ public:
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
|
||||
constexpr handle_storage_iterator() noexcept
|
||||
: entt{null},
|
||||
@@ -86,11 +83,7 @@ template<typename ILhs, typename IRhs>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Non-owning handle to an entity.
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "../signal/delegate.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "group.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "view.hpp"
|
||||
|
||||
namespace entt {
|
||||
@@ -103,7 +104,7 @@ private:
|
||||
* @param reg A registry that contains the given entity and its components.
|
||||
* @param entt Entity from which to get the component.
|
||||
*/
|
||||
template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, Member>>>
|
||||
template<auto Member, typename Registry = std::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");
|
||||
delegate<void(Registry &, const typename Registry::entity_type)> func;
|
||||
@@ -115,27 +116,41 @@ void invoke(Registry ®, const typename Registry::entity_type entt) {
|
||||
* @brief Returns the entity associated with a given component.
|
||||
*
|
||||
* @warning
|
||||
* Currently, this function only works correctly with the default pool as it
|
||||
* Currently, this function only works correctly with the default storage as it
|
||||
* makes assumptions about how the components are laid out.
|
||||
*
|
||||
* @tparam Registry Basic registry type.
|
||||
* @tparam Args Storage type template parameters.
|
||||
* @param storage A storage that contains the given component.
|
||||
* @param instance A valid component instance.
|
||||
* @return The entity associated with the given component.
|
||||
*/
|
||||
template<typename... Args>
|
||||
auto to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) -> typename basic_storage<Args...>::entity_type {
|
||||
constexpr auto page_size = basic_storage<Args...>::traits_type::page_size;
|
||||
const typename basic_storage<Args...>::base_type &base = storage;
|
||||
const auto *addr = std::addressof(instance);
|
||||
|
||||
for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) {
|
||||
if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(page_size)) {
|
||||
return *(it + dist);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @copybrief to_entity
|
||||
* @tparam Args Registry type template parameters.
|
||||
* @tparam Component Type of component.
|
||||
* @param reg A registry that contains the given entity and its components.
|
||||
* @param instance A valid component instance.
|
||||
* @return The entity associated with the given component.
|
||||
*/
|
||||
template<typename Registry, typename Component>
|
||||
typename Registry::entity_type to_entity(const Registry ®, const Component &instance) {
|
||||
template<typename... Args, typename Component>
|
||||
[[deprecated("use storage based to_entity instead")]] typename basic_registry<Args...>::entity_type to_entity(const basic_registry<Args...> ®, const Component &instance) {
|
||||
if(const auto *storage = reg.template storage<Component>(); storage) {
|
||||
constexpr auto page_size = std::remove_const_t<std::remove_pointer_t<decltype(storage)>>::traits_type::page_size;
|
||||
const typename Registry::common_type &base = *storage;
|
||||
const auto *addr = std::addressof(instance);
|
||||
|
||||
for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) {
|
||||
if(const auto dist = (addr - std::addressof(storage->get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(page_size)) {
|
||||
return *(it + dist);
|
||||
}
|
||||
}
|
||||
return to_entity(*storage, instance);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -22,18 +22,23 @@ namespace entt {
|
||||
*
|
||||
* This applies to all signals made available.
|
||||
*
|
||||
* @tparam Type The type of the underlying storage.
|
||||
* @tparam Type Underlying storage type.
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Type>
|
||||
class sigh_mixin final: public Type {
|
||||
template<typename Type, typename Registry>
|
||||
class basic_sigh_mixin final: public Type {
|
||||
using underlying_type = Type;
|
||||
using owner_type = Registry;
|
||||
|
||||
using basic_registry_type = basic_registry<typename underlying_type::entity_type, typename underlying_type::base_type::allocator_type>;
|
||||
using sigh_type = sigh<void(basic_registry_type &, const typename underlying_type::entity_type), typename underlying_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;
|
||||
|
||||
basic_registry_type &owner_or_assert() const noexcept {
|
||||
static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
|
||||
|
||||
owner_type &owner_or_assert() const noexcept {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
return *owner;
|
||||
return static_cast<owner_type &>(*owner);
|
||||
}
|
||||
|
||||
void pop(underlying_iterator first, underlying_iterator last) final {
|
||||
@@ -51,13 +56,17 @@ class sigh_mixin final: public Type {
|
||||
|
||||
void pop_all() final {
|
||||
if(auto ® = owner_or_assert(); !destruction.empty()) {
|
||||
for(auto pos = underlying_type::each().begin().base().index(); !(pos < 0); --pos) {
|
||||
if constexpr(underlying_type::traits_type::in_place_delete) {
|
||||
if(const auto entt = underlying_type::operator[](static_cast<typename underlying_type::size_type>(pos)); entt != tombstone) {
|
||||
destruction.publish(reg, entt);
|
||||
}
|
||||
for(auto it = underlying_type::base_type::begin(0), last = underlying_type::base_type::end(0); it != last; ++it) {
|
||||
if constexpr(std::is_same_v<typename underlying_type::value_type, typename underlying_type::entity_type>) {
|
||||
destruction.publish(reg, *it);
|
||||
} else {
|
||||
destruction.publish(reg, underlying_type::operator[](static_cast<typename underlying_type::size_type>(pos)));
|
||||
if constexpr(underlying_type::traits_type::in_place_delete) {
|
||||
if(const auto entt = *it; entt != tombstone) {
|
||||
destruction.publish(reg, entt);
|
||||
}
|
||||
} else {
|
||||
destruction.publish(reg, *it);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,17 +90,17 @@ public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename underlying_type::entity_type;
|
||||
/*! @brief Expected registry type. */
|
||||
using registry_type = basic_registry_type;
|
||||
using registry_type = owner_type;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
sigh_mixin()
|
||||
: sigh_mixin{allocator_type{}} {}
|
||||
basic_sigh_mixin()
|
||||
: basic_sigh_mixin{allocator_type{}} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty storage with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit sigh_mixin(const allocator_type &allocator)
|
||||
explicit basic_sigh_mixin(const allocator_type &allocator)
|
||||
: underlying_type{allocator},
|
||||
owner{},
|
||||
construction{allocator},
|
||||
@@ -102,7 +111,7 @@ public:
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
sigh_mixin(sigh_mixin &&other) noexcept
|
||||
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
|
||||
: underlying_type{std::move(other)},
|
||||
owner{other.owner},
|
||||
construction{std::move(other.construction)},
|
||||
@@ -114,7 +123,7 @@ public:
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
sigh_mixin(sigh_mixin &&other, const allocator_type &allocator) noexcept
|
||||
basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator) noexcept
|
||||
: underlying_type{std::move(other), allocator},
|
||||
owner{other.owner},
|
||||
construction{std::move(other.construction), allocator},
|
||||
@@ -126,7 +135,7 @@ public:
|
||||
* @param other The instance to move from.
|
||||
* @return This storage.
|
||||
*/
|
||||
sigh_mixin &operator=(sigh_mixin &&other) noexcept {
|
||||
basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept {
|
||||
underlying_type::operator=(std::move(other));
|
||||
owner = other.owner;
|
||||
construction = std::move(other.construction);
|
||||
@@ -139,7 +148,7 @@ public:
|
||||
* @brief Exchanges the contents with those of a given storage.
|
||||
* @param other Storage to exchange the content with.
|
||||
*/
|
||||
void swap(sigh_mixin &other) {
|
||||
void swap(basic_sigh_mixin &other) {
|
||||
using std::swap;
|
||||
underlying_type::swap(other);
|
||||
swap(owner, other.owner);
|
||||
@@ -262,11 +271,12 @@ public:
|
||||
*/
|
||||
template<typename It, typename... Args>
|
||||
void insert(It first, It last, Args &&...args) {
|
||||
auto from = underlying_type::size();
|
||||
underlying_type::insert(first, last, std::forward<Args>(args)...);
|
||||
|
||||
if(auto ® = owner_or_assert(); !construction.empty()) {
|
||||
for(; first != last; ++first) {
|
||||
construction.publish(reg, *first);
|
||||
for(const auto to = underlying_type::size(); from != to; ++from) {
|
||||
construction.publish(reg, underlying_type::operator[](from));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename>
|
||||
@@ -87,11 +83,7 @@ template<typename... Req, typename Ret, typename Class, typename... Args>
|
||||
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Utility class for creating a static task graph.
|
||||
|
||||
@@ -30,11 +30,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
@@ -50,6 +46,7 @@ public:
|
||||
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;
|
||||
|
||||
constexpr registry_storage_iterator() noexcept
|
||||
: it{} {}
|
||||
@@ -225,11 +222,7 @@ private:
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Fast and reliable entity-component system.
|
||||
@@ -249,17 +242,18 @@ class basic_registry {
|
||||
|
||||
template<typename 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>) {
|
||||
return entities;
|
||||
} else {
|
||||
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
|
||||
auto &cpool = pools[id];
|
||||
|
||||
if(!cpool) {
|
||||
using storage_type = storage_for_type<Type>;
|
||||
using alloc_type = typename storage_type::allocator_type;
|
||||
|
||||
if constexpr(std::is_same_v<Type, void> && !std::is_constructible_v<alloc_type, allocator_type>) {
|
||||
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 {
|
||||
@@ -276,11 +270,11 @@ class basic_registry {
|
||||
|
||||
template<typename 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>) {
|
||||
return &entities;
|
||||
} else {
|
||||
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
|
||||
|
||||
if(const auto it = pools.find(id); it != pools.cend()) {
|
||||
ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
|
||||
return static_cast<const storage_for_type<Type> *>(it->second.get());
|
||||
@@ -313,6 +307,10 @@ public:
|
||||
using common_type = base_type;
|
||||
/*! @brief Context type. */
|
||||
using context = internal::registry_context<allocator_type>;
|
||||
/*! @brief Iterable registry type. */
|
||||
using iterable = iterable_adaptor<internal::registry_storage_iterator<typename pool_container_type::iterator>>;
|
||||
/*! @brief Constant iterable registry type. */
|
||||
using const_iterable = iterable_adaptor<internal::registry_storage_iterator<typename pool_container_type::const_iterator>>;
|
||||
|
||||
/**
|
||||
* @copybrief storage_for
|
||||
@@ -395,7 +393,7 @@ public:
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return pools.get_allocator();
|
||||
return entities.get_allocator();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -406,12 +404,12 @@ public:
|
||||
*
|
||||
* @return An iterable object to use to _visit_ the registry.
|
||||
*/
|
||||
[[nodiscard]] auto storage() noexcept {
|
||||
[[nodiscard]] iterable storage() noexcept {
|
||||
return iterable_adaptor{internal::registry_storage_iterator{pools.begin()}, internal::registry_storage_iterator{pools.end()}};
|
||||
}
|
||||
|
||||
/*! @copydoc storage */
|
||||
[[nodiscard]] auto storage() const noexcept {
|
||||
[[nodiscard]] const_iterable storage() const noexcept {
|
||||
return iterable_adaptor{internal::registry_storage_iterator{pools.cbegin()}, internal::registry_storage_iterator{pools.cend()}};
|
||||
}
|
||||
|
||||
@@ -456,78 +454,13 @@ public:
|
||||
return assure<Type>(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of entities created so far.
|
||||
* @return Number of entities created so far.
|
||||
*/
|
||||
[[deprecated("use .storage<Entity>().size() instead")]] [[nodiscard]] size_type size() const noexcept {
|
||||
return entities.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of entities still in use.
|
||||
* @return Number of entities still in use.
|
||||
*/
|
||||
[[deprecated("use .storage<Entity>().in_use() instead")]] [[nodiscard]] size_type alive() const {
|
||||
return entities.in_use();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increases the capacity (number of entities) of the registry.
|
||||
* @param cap Desired capacity.
|
||||
*/
|
||||
[[deprecated("use .storage<Entity>().reserve(cap) instead")]] void reserve(const size_type cap) {
|
||||
entities.reserve(cap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of entities that a registry has currently
|
||||
* allocated space for.
|
||||
* @return Capacity of the registry.
|
||||
*/
|
||||
[[deprecated("use .storage<Entity>().capacity() instead")]] [[nodiscard]] size_type capacity() const noexcept {
|
||||
return entities.capacity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether the registry is empty (no entities still in use).
|
||||
* @return True if the registry is empty, false otherwise.
|
||||
*/
|
||||
[[deprecated("use .storage<Entity>().in_use() instead")]] [[nodiscard]] bool empty() const {
|
||||
return !alive();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Direct access to the list of entities of a registry.
|
||||
*
|
||||
* The returned pointer is such that range `[data(), data() + size())` is
|
||||
* always a valid range, even if the registry is empty.
|
||||
*
|
||||
* @warning
|
||||
* This list contains both valid and destroyed entities and isn't suitable
|
||||
* for direct use.
|
||||
*
|
||||
* @return A pointer to the array of entities.
|
||||
*/
|
||||
[[deprecated("use .storage<Entity>().data() instead")]] [[nodiscard]] const entity_type *data() const noexcept {
|
||||
return entities.data();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of released entities.
|
||||
* @return The number of released entities.
|
||||
*/
|
||||
[[deprecated("use .storage<Entity>().size() and .storage<Entity>().in_use() instead")]] [[nodiscard]] size_type released() const noexcept {
|
||||
return (entities.size() - entities.in_use());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if an identifier refers to a valid entity.
|
||||
* @param entt An identifier, either valid or not.
|
||||
* @return True if the identifier is valid, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool valid(const entity_type entt) const {
|
||||
return entities.contains(entt);
|
||||
return entities.contains(entt) && (entities.index(entt) < entities.free_list());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -575,74 +508,6 @@ public:
|
||||
entities.insert(std::move(first), std::move(last));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns identifiers to an empty registry.
|
||||
*
|
||||
* This function is intended for use in conjunction with `data`, `size` and
|
||||
* `released`.<br/>
|
||||
* Don't try to inject ranges of randomly generated entities nor the _wrong_
|
||||
* head for the list of destroyed entities. There is no guarantee that a
|
||||
* registry will continue to work properly in this case.
|
||||
*
|
||||
* @warning
|
||||
* There must be no entities still alive for this to work properly.
|
||||
*
|
||||
* @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 destroyed The number of released entities.
|
||||
*/
|
||||
template<typename It>
|
||||
[[deprecated("use .storage<Entity>().push(first, last) and .storage<Entity>().in_use(len) instead")]] void assign(It first, It last, const size_type destroyed) {
|
||||
ENTT_ASSERT(!entities.in_use(), "Non-empty registry");
|
||||
entities.push(first, last);
|
||||
entities.in_use(entities.size() - destroyed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases an identifier.
|
||||
*
|
||||
* The version is updated and the identifier can be recycled at any time.
|
||||
*
|
||||
* @param entt A valid identifier.
|
||||
* @return The version of the recycled entity.
|
||||
*/
|
||||
[[deprecated("use .orphan(entt) and .storage<Entity>().erase(entt) instead")]] version_type release(const entity_type entt) {
|
||||
ENTT_ASSERT(orphan(entt), "Non-orphan entity");
|
||||
entities.erase(entt);
|
||||
return entities.current(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases an identifier.
|
||||
*
|
||||
* The suggested version or the valid version closest to the suggested one
|
||||
* is used instead of the implicitly generated version.
|
||||
*
|
||||
* @param entt A valid identifier.
|
||||
* @param version A desired version upon destruction.
|
||||
* @return The version actually assigned to the entity.
|
||||
*/
|
||||
[[deprecated("use .orphan(entt), then .storage<Entity>().erase(entt)/.bump(next) instead")]] version_type release(const entity_type entt, const version_type version) {
|
||||
ENTT_ASSERT(orphan(entt), "Non-orphan entity");
|
||||
entities.erase(entt);
|
||||
const auto elem = traits_type::construct(traits_type::to_entity(entt), version);
|
||||
return entities.bump((elem == tombstone) ? traits_type::next(elem) : elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Releases all identifiers in a range.
|
||||
*
|
||||
* @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>
|
||||
[[deprecated("use .orphan(entt) and .storage<Entity>().erase(first, last) instead")]] void release(It first, It last) {
|
||||
ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return orphan(entt); }), "Non-orphan entity");
|
||||
entities.erase(std::move(first), std::move(last));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroys an entity and releases its identifier.
|
||||
*
|
||||
@@ -691,11 +556,13 @@ public:
|
||||
*/
|
||||
template<typename It>
|
||||
void destroy(It first, It last) {
|
||||
const auto from = entities.each().cbegin().base();
|
||||
const auto to = from + entities.pack(first, last);
|
||||
entities.sort_as(first, last);
|
||||
|
||||
for(size_type pos = pools.size(); pos; --pos) {
|
||||
pools.begin()[pos - 1u].second->remove(from, to);
|
||||
const auto from = entities.cbegin(0);
|
||||
const auto to = from + std::distance(first, last);
|
||||
|
||||
for(auto &&curr: pools) {
|
||||
curr.second->remove(from, to);
|
||||
}
|
||||
|
||||
entities.erase(from, to);
|
||||
@@ -963,7 +830,7 @@ public:
|
||||
* @return True if the entity is part of all the storage, false otherwise.
|
||||
*/
|
||||
template<typename... Type>
|
||||
[[nodiscard]] bool all_of(const entity_type entt) const {
|
||||
[[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
|
||||
if constexpr(sizeof...(Type) == 1u) {
|
||||
auto *cpool = assure<std::remove_const_t<Type>...>();
|
||||
return cpool && cpool->contains(entt);
|
||||
@@ -980,7 +847,7 @@ public:
|
||||
* otherwise.
|
||||
*/
|
||||
template<typename... Type>
|
||||
[[nodiscard]] bool any_of(const entity_type entt) const {
|
||||
[[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const {
|
||||
return (all_of<Type>(entt) || ...);
|
||||
}
|
||||
|
||||
@@ -1062,8 +929,7 @@ public:
|
||||
template<typename... Type>
|
||||
[[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
|
||||
if constexpr(sizeof...(Type) == 1u) {
|
||||
auto &cpool = assure<std::remove_const_t<Type>...>();
|
||||
return (static_cast<Type *>(cpool.contains(entt) ? std::addressof(cpool.get(entt)) : nullptr), ...);
|
||||
return (const_cast<Type *>(std::as_const(*this).template try_get<Type>(entt)), ...);
|
||||
} else {
|
||||
return std::make_tuple(try_get<Type>(entt)...);
|
||||
}
|
||||
@@ -1080,34 +946,13 @@ public:
|
||||
pools.begin()[pos - 1u].second->clear();
|
||||
}
|
||||
|
||||
const auto iterable = entities.each();
|
||||
entities.erase(iterable.begin().base(), iterable.end().base());
|
||||
const auto elem = entities.each();
|
||||
entities.erase(elem.begin().base(), elem.end().base());
|
||||
} else {
|
||||
(assure<Type>().clear(), ...);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates all the entities that are still in use.
|
||||
*
|
||||
* The signature of the function should be equivalent to the following:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(const Entity);
|
||||
* @endcode
|
||||
*
|
||||
* It's not defined whether entities created during iteration are returned.
|
||||
*
|
||||
* @tparam Func Type of the function object to invoke.
|
||||
* @param func A valid function object.
|
||||
*/
|
||||
template<typename Func>
|
||||
[[deprecated("use .storage<Entity>().each() instead")]] void each(Func func) const {
|
||||
for(auto [entt]: entities.each()) {
|
||||
func(entt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if an entity has components assigned.
|
||||
* @param entt A valid identifier.
|
||||
@@ -1330,7 +1175,8 @@ public:
|
||||
template<typename To, typename From>
|
||||
void sort() {
|
||||
ENTT_ASSERT(!owned<To>(), "Cannot sort owned storage");
|
||||
assure<To>().sort_as(assure<From>());
|
||||
const base_type &cpool = assure<From>();
|
||||
assure<To>().sort_as(cpool.begin(), cpool.end());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,11 +11,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Set>
|
||||
@@ -95,11 +91,7 @@ private:
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Generic runtime view.
|
||||
|
||||
@@ -16,30 +16,22 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Registry>
|
||||
void orphans(Registry ®istry) {
|
||||
auto view = registry.template view<typename Registry::entity_type>();
|
||||
auto &storage = registry.template storage<typename Registry::entity_type>();
|
||||
|
||||
for(auto entt: view) {
|
||||
for(auto entt: storage) {
|
||||
if(registry.orphan(entt)) {
|
||||
view.storage()->erase(entt);
|
||||
storage.erase(entt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Utility class to create snapshots from a registry.
|
||||
@@ -89,11 +81,22 @@ public:
|
||||
archive(static_cast<typename traits_type::entity_type>(storage->size()));
|
||||
|
||||
if constexpr(std::is_same_v<Type, entity_type>) {
|
||||
archive(static_cast<typename traits_type::entity_type>(storage->in_use()));
|
||||
archive(static_cast<typename traits_type::entity_type>(storage->free_list()));
|
||||
|
||||
for(auto first = storage->data(), last = first + storage->size(); first != last; ++first) {
|
||||
archive(*first);
|
||||
}
|
||||
} else if constexpr(component_traits<Type>::in_place_delete) {
|
||||
const typename registry_type::common_type &base = *storage;
|
||||
|
||||
for(auto it = base.rbegin(), last = base.rend(); it != last; ++it) {
|
||||
if(const auto entt = *it; entt == tombstone) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(auto elem: storage->reach()) {
|
||||
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, elem);
|
||||
@@ -140,45 +143,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serializes all identifiers, including those to be recycled.
|
||||
* @tparam Archive Type of output archive.
|
||||
* @param archive A valid reference to an output archive.
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename Archive>
|
||||
[[deprecated("use .get<Entity>(archive) instead")]] const basic_snapshot &entities(Archive &archive) const {
|
||||
return get<entity_type>(archive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serializes all elements of a type with associated identifiers.
|
||||
* @tparam Component Types of components to serialize.
|
||||
* @tparam Archive Type of output archive.
|
||||
* @param archive A valid reference to an output archive.
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename... Component, typename Archive>
|
||||
[[deprecated("use .get<Type>(archive) instead")]] const basic_snapshot &component(Archive &archive) const {
|
||||
return (get<Component>(archive), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serializes all elements of a type with associated identifiers for
|
||||
* the entities in a range.
|
||||
* @tparam Component Types of components 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.
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename... Component, typename Archive, typename It>
|
||||
[[deprecated("use .get<Type>(archive, first, last) instead")]] const basic_snapshot &component(Archive &archive, It first, It last) const {
|
||||
return (get<Component>(archive, first, last), ...);
|
||||
}
|
||||
|
||||
private:
|
||||
const registry_type *reg;
|
||||
};
|
||||
@@ -211,7 +175,7 @@ public:
|
||||
basic_snapshot_loader(registry_type &source) noexcept
|
||||
: reg{&source} {
|
||||
// restoring a snapshot as a whole requires a clean registry
|
||||
ENTT_ASSERT(reg->empty(), "Registry must be empty");
|
||||
ENTT_ASSERT(reg->template storage<entity_type>().free_list() == 0u, "Registry must be empty");
|
||||
}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
@@ -229,24 +193,24 @@ public:
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename Type, typename Archive>
|
||||
basic_snapshot_loader &get([[maybe_unused]] Archive &archive, const id_type id = type_hash<Type>::value()) {
|
||||
basic_snapshot_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
|
||||
auto &storage = reg->template storage<Type>(id);
|
||||
typename traits_type::entity_type length{};
|
||||
|
||||
archive(length);
|
||||
|
||||
if constexpr(std::is_same_v<Type, entity_type>) {
|
||||
typename traits_type::entity_type in_use{};
|
||||
typename traits_type::entity_type count{};
|
||||
|
||||
storage.reserve(length);
|
||||
archive(in_use);
|
||||
archive(count);
|
||||
|
||||
for(entity_type entity = null; length; --length) {
|
||||
archive(entity);
|
||||
storage.emplace(entity);
|
||||
}
|
||||
|
||||
storage.in_use(in_use);
|
||||
storage.free_list(count);
|
||||
} else {
|
||||
auto &other = reg->template storage<entity_type>();
|
||||
entity_type entt{null};
|
||||
@@ -256,7 +220,7 @@ public:
|
||||
const auto entity = other.contains(entt) ? entt : other.emplace(entt);
|
||||
ENTT_ASSERT(entity == entt, "Entity not available for use");
|
||||
|
||||
if constexpr(Registry::template storage_for_type<Type>::traits_type::page_size == 0u) {
|
||||
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
|
||||
storage.emplace(entity);
|
||||
} else {
|
||||
Type elem{};
|
||||
@@ -270,33 +234,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Restores all identifiers, including those to be recycled.
|
||||
* @tparam Archive Type of input archive.
|
||||
* @param archive A valid reference to an input archive.
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename Archive>
|
||||
[[deprecated("use .get<Entity>(archive) instead")]] basic_snapshot_loader &entities(Archive &archive) {
|
||||
return get<entity_type>(archive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Restores all elements of a type with associated identifiers.
|
||||
*
|
||||
* The template parameter list must be exactly the same used during
|
||||
* serialization.
|
||||
*
|
||||
* @tparam Component Type of component to restore.
|
||||
* @tparam Archive Type of input archive.
|
||||
* @param archive A valid reference to an input archive.
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename... Component, typename Archive>
|
||||
[[deprecated("use .get<Type>(archive) instead")]] basic_snapshot_loader &component(Archive &archive) {
|
||||
return (get<Component>(archive), ...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroys those entities that have no components.
|
||||
*
|
||||
@@ -427,7 +364,7 @@ public:
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename Type, typename Archive>
|
||||
basic_continuous_loader &get([[maybe_unused]] Archive &archive, const id_type id = type_hash<Type>::value()) {
|
||||
basic_continuous_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
|
||||
auto &storage = reg->template storage<Type>(id);
|
||||
typename traits_type::entity_type length{};
|
||||
entity_type entt{null};
|
||||
@@ -465,7 +402,7 @@ public:
|
||||
if(archive(entt); entt != null) {
|
||||
restore(entt);
|
||||
|
||||
if constexpr(Registry::template storage_for_type<Type>::traits_type::page_size == 0u) {
|
||||
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
|
||||
storage.emplace(map(entt));
|
||||
} else {
|
||||
Type elem{};
|
||||
@@ -479,79 +416,6 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Restores all identifiers, including those to be recycled.
|
||||
*
|
||||
* It creates local counterparts for remote elements as needed.
|
||||
*
|
||||
* @tparam Archive Type of input archive.
|
||||
* @param archive A valid reference to an input archive.
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
template<typename Archive>
|
||||
[[deprecated("use .get<Entity>(archive) instead")]] basic_continuous_loader &entities(Archive &archive) {
|
||||
return get<entity_type>(archive);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Serializes all elements of a type with associated identifiers.
|
||||
*
|
||||
* It creates local counterparts for remote elements as needed.<br/>
|
||||
* Members are either data members of type entity_type or containers of
|
||||
* entities. In both cases, a loader visits them and replaces entities with
|
||||
* their local counterpart.
|
||||
*
|
||||
* @tparam Component Type of component to restore.
|
||||
* @tparam Archive Type of input archive.
|
||||
* @tparam Member Types of members to update with their local counterparts.
|
||||
* @param archive A valid reference to an input archive.
|
||||
* @param member Members to update with their local counterparts.
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
template<typename... Component, typename Archive, typename... Member, typename... Clazz>
|
||||
[[deprecated("use .component<Type>(archive, members...) instead")]] basic_continuous_loader &component(Archive &archive, Member Clazz::*...member) {
|
||||
([&](auto &storage) {
|
||||
for(auto &&ref: remloc) {
|
||||
storage.remove(ref.second.second);
|
||||
}
|
||||
|
||||
typename traits_type::entity_type length{};
|
||||
entity_type entt{null};
|
||||
|
||||
archive(length);
|
||||
|
||||
while(length--) {
|
||||
if(archive(entt); entt != null) {
|
||||
restore(entt);
|
||||
|
||||
if constexpr(std::remove_reference_t<decltype(storage)>::traits_type::page_size == 0u) {
|
||||
storage.emplace(map(entt));
|
||||
} else {
|
||||
typename std::remove_reference_t<decltype(storage)>::value_type elem{};
|
||||
archive(elem);
|
||||
(update(elem, member), ...);
|
||||
storage.emplace(map(entt), std::move(elem));
|
||||
}
|
||||
}
|
||||
}
|
||||
}(reg->template storage<Component>()),
|
||||
...);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helps to purge entities that no longer have a counterpart.
|
||||
*
|
||||
* Users should invoke this member function after restoring each snapshot,
|
||||
* unless they know exactly what they are doing.
|
||||
*
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
[[deprecated("use .get<Entity>(archive) instead")]] basic_continuous_loader &shrink() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroys those entities that have no components.
|
||||
*
|
||||
|
||||
@@ -17,11 +17,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Container>
|
||||
@@ -137,11 +133,7 @@ template<typename Container>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Basic sparse set implementation.
|
||||
@@ -168,6 +160,7 @@ class basic_sparse_set {
|
||||
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 underlying_type = typename entt_traits<Entity>::entity_type;
|
||||
|
||||
[[nodiscard]] auto sparse_ptr(const Entity entt) const {
|
||||
const auto pos = static_cast<size_type>(traits_type::to_entity(entt));
|
||||
@@ -194,14 +187,13 @@ class basic_sparse_set {
|
||||
}
|
||||
|
||||
if(!sparse[page]) {
|
||||
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, null);
|
||||
std::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init);
|
||||
}
|
||||
|
||||
auto &elem = sparse[page][fast_mod(pos, traits_type::page_size)];
|
||||
ENTT_ASSERT(elem == null, "Slot not available");
|
||||
return elem;
|
||||
return sparse[page][fast_mod(pos, traits_type::page_size)];
|
||||
}
|
||||
|
||||
void release_sparse_pages() {
|
||||
@@ -216,31 +208,42 @@ class basic_sparse_set {
|
||||
}
|
||||
}
|
||||
|
||||
void swap_at(const std::size_t from, const std::size_t to) {
|
||||
auto &lhs = packed[from];
|
||||
auto &rhs = packed[to];
|
||||
|
||||
sparse_ref(lhs) = traits_type::combine(static_cast<typename traits_type::entity_type>(to), traits_type::to_integral(lhs));
|
||||
sparse_ref(rhs) = traits_type::combine(static_cast<typename traits_type::entity_type>(from), traits_type::to_integral(rhs));
|
||||
|
||||
std::swap(lhs, rhs);
|
||||
}
|
||||
|
||||
underlying_type policy_to_head() {
|
||||
return traits_type::entity_mask * (mode != deletion_policy::swap_only);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual const void *get_at(const std::size_t) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void swap_or_move(const std::size_t, const std::size_t) {}
|
||||
virtual void swap_or_move([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {
|
||||
ENTT_ASSERT((mode != deletion_policy::swap_only) || (((lhs < free_list()) + (rhs < free_list())) != 1u), "Cross swapping is not supported");
|
||||
}
|
||||
|
||||
protected:
|
||||
/*! @brief Random access iterator type. */
|
||||
using basic_iterator = internal::sparse_set_iterator<packed_container_type>;
|
||||
|
||||
/**
|
||||
* @brief Swaps two items at specific locations.
|
||||
* @param lhs A position to move from.
|
||||
* @param rhs The other position to move from.
|
||||
* @brief Erases an entity from a sparse set.
|
||||
* @param it An iterator to the element to pop.
|
||||
*/
|
||||
void swap_at(const std::size_t lhs, const std::size_t rhs) {
|
||||
const auto entity = static_cast<typename traits_type::entity_type>(lhs);
|
||||
const auto other = static_cast<typename traits_type::entity_type>(rhs);
|
||||
|
||||
sparse_ref(packed[lhs]) = traits_type::combine(other, traits_type::to_integral(packed[lhs]));
|
||||
sparse_ref(packed[rhs]) = traits_type::combine(entity, traits_type::to_integral(packed[rhs]));
|
||||
|
||||
using std::swap;
|
||||
swap(packed[lhs], packed[rhs]);
|
||||
void swap_only(const basic_iterator it) {
|
||||
ENTT_ASSERT(mode == deletion_policy::swap_only, "Deletion policy mismatch");
|
||||
const auto pos = static_cast<underlying_type>(index(*it));
|
||||
bump(traits_type::next(*it));
|
||||
swap_at(pos, static_cast<size_type>(head -= (pos < head)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,7 +251,7 @@ protected:
|
||||
* @param it An iterator to the element to pop.
|
||||
*/
|
||||
void swap_and_pop(const basic_iterator it) {
|
||||
ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatched");
|
||||
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()));
|
||||
@@ -265,9 +268,9 @@ protected:
|
||||
* @param it An iterator to the element to pop.
|
||||
*/
|
||||
void in_place_pop(const basic_iterator it) {
|
||||
ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatched");
|
||||
ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatch");
|
||||
const auto entt = traits_type::to_entity(std::exchange(sparse_ref(*it), null));
|
||||
packed[static_cast<size_type>(entt)] = std::exchange(free_list, traits_type::combine(entt, tombstone));
|
||||
packed[static_cast<size_type>(entt)] = traits_type::combine(std::exchange(head, entt), tombstone);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -277,31 +280,47 @@ protected:
|
||||
* @param last An iterator past the last element of the range of entities.
|
||||
*/
|
||||
virtual void pop(basic_iterator first, basic_iterator last) {
|
||||
if(mode == deletion_policy::swap_and_pop) {
|
||||
switch(mode) {
|
||||
case deletion_policy::swap_and_pop:
|
||||
for(; first != last; ++first) {
|
||||
swap_and_pop(first);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
case deletion_policy::in_place:
|
||||
for(; first != last; ++first) {
|
||||
in_place_pop(first);
|
||||
}
|
||||
break;
|
||||
case deletion_policy::swap_only:
|
||||
for(; first != last; ++first) {
|
||||
swap_only(first);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Erases all entities of a sparse set. */
|
||||
virtual void pop_all() {
|
||||
if(const auto prev = std::exchange(free_list, tombstone); prev == null) {
|
||||
switch(mode) {
|
||||
case deletion_policy::in_place:
|
||||
if(head != traits_type::to_entity(null)) {
|
||||
for(auto first = begin(); !(first.index() < 0); ++first) {
|
||||
if(*first != tombstone) {
|
||||
sparse_ref(*first) = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case deletion_policy::swap_only:
|
||||
case deletion_policy::swap_and_pop:
|
||||
for(auto first = begin(); !(first.index() < 0); ++first) {
|
||||
sparse_ref(*first) = null;
|
||||
}
|
||||
} else {
|
||||
for(auto first = begin(); !(first.index() < 0); ++first) {
|
||||
if(*first != tombstone) {
|
||||
sparse_ref(*first) = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
head = policy_to_head();
|
||||
packed.clear();
|
||||
}
|
||||
|
||||
@@ -312,18 +331,42 @@ protected:
|
||||
* @return Iterator pointing to the emplaced element.
|
||||
*/
|
||||
virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) {
|
||||
ENTT_ASSERT(!contains(entt), "Set already contains entity");
|
||||
auto &elem = assure_at_least(entt);
|
||||
auto pos = size();
|
||||
|
||||
if(auto &elem = assure_at_least(entt); free_list == null || force_back) {
|
||||
switch(mode) {
|
||||
case deletion_policy::in_place:
|
||||
if(head != traits_type::to_entity(null) && !force_back) {
|
||||
pos = static_cast<size_type>(head);
|
||||
ENTT_ASSERT(elem == null, "Slot not available");
|
||||
elem = traits_type::combine(head, traits_type::to_integral(entt));
|
||||
head = traits_type::to_entity(std::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));
|
||||
return begin();
|
||||
} else {
|
||||
const auto pos = static_cast<size_type>(traits_type::to_entity(free_list));
|
||||
elem = traits_type::combine(traits_type::to_integral(free_list), traits_type::to_integral(entt));
|
||||
free_list = std::exchange(packed[pos], entt);
|
||||
return --(end() - pos);
|
||||
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));
|
||||
} else {
|
||||
ENTT_ASSERT(!(traits_type::to_entity(elem) < head), "Slot not available");
|
||||
bump(entt);
|
||||
}
|
||||
|
||||
if(force_back) {
|
||||
pos = static_cast<size_type>(head++);
|
||||
swap_at(static_cast<size_type>(traits_type::to_entity(elem)), pos);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return --(end() - pos);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -378,8 +421,8 @@ public:
|
||||
: sparse{allocator},
|
||||
packed{allocator},
|
||||
info{&elem},
|
||||
free_list{tombstone},
|
||||
mode{pol} {}
|
||||
mode{pol},
|
||||
head{policy_to_head()} {}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
@@ -389,8 +432,8 @@ public:
|
||||
: sparse{std::move(other.sparse)},
|
||||
packed{std::move(other.packed)},
|
||||
info{other.info},
|
||||
free_list{std::exchange(other.free_list, tombstone)},
|
||||
mode{other.mode} {}
|
||||
mode{other.mode},
|
||||
head{std::exchange(other.head, policy_to_head())} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
@@ -401,8 +444,8 @@ public:
|
||||
: sparse{std::move(other.sparse), allocator},
|
||||
packed{std::move(other.packed), allocator},
|
||||
info{other.info},
|
||||
free_list{std::exchange(other.free_list, tombstone)},
|
||||
mode{other.mode} {
|
||||
mode{other.mode},
|
||||
head{std::exchange(other.head, policy_to_head())} {
|
||||
ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed");
|
||||
}
|
||||
|
||||
@@ -423,8 +466,8 @@ public:
|
||||
sparse = std::move(other.sparse);
|
||||
packed = std::move(other.packed);
|
||||
info = other.info;
|
||||
free_list = std::exchange(other.free_list, tombstone);
|
||||
mode = other.mode;
|
||||
head = std::exchange(other.head, policy_to_head());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -437,8 +480,8 @@ public:
|
||||
swap(sparse, other.sparse);
|
||||
swap(packed, other.packed);
|
||||
swap(info, other.info);
|
||||
swap(free_list, other.free_list);
|
||||
swap(mode, other.mode);
|
||||
swap(head, other.head);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -457,6 +500,23 @@ public:
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the head of the free list, if any.
|
||||
* @return The head of the free list.
|
||||
*/
|
||||
[[nodiscard]] size_type free_list() const noexcept {
|
||||
return static_cast<size_type>(head);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the head of the free list, if possible.
|
||||
* @param len The value to use as the new head of the free list.
|
||||
*/
|
||||
void free_list(const size_type len) noexcept {
|
||||
ENTT_ASSERT((mode == deletion_policy::swap_only) && !(len > packed.size()), "Invalid value");
|
||||
head = static_cast<underlying_type>(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increases the capacity of a sparse set.
|
||||
*
|
||||
@@ -524,7 +584,7 @@ public:
|
||||
* @return True if the sparse set is fully packed, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contiguous() const noexcept {
|
||||
return (free_list == null);
|
||||
return (mode != deletion_policy::in_place) || (head == traits_type::to_entity(null));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -543,7 +603,7 @@ public:
|
||||
*
|
||||
* @return An iterator to the first entity of the sparse set.
|
||||
*/
|
||||
[[nodiscard]] const_iterator begin() const noexcept {
|
||||
[[nodiscard]] iterator begin() const noexcept {
|
||||
const auto pos = static_cast<typename iterator::difference_type>(packed.size());
|
||||
return iterator{packed, pos};
|
||||
}
|
||||
@@ -576,7 +636,7 @@ public:
|
||||
* @return An iterator to the first entity of the reversed internal packed
|
||||
* array.
|
||||
*/
|
||||
[[nodiscard]] const_reverse_iterator rbegin() const noexcept {
|
||||
[[nodiscard]] reverse_iterator rbegin() const noexcept {
|
||||
return std::make_reverse_iterator(end());
|
||||
}
|
||||
|
||||
@@ -599,13 +659,53 @@ public:
|
||||
return rend();
|
||||
}
|
||||
|
||||
/*! @copydoc begin Useful only in case of swap-only policy. */
|
||||
[[nodiscard]] iterator begin(int) const noexcept {
|
||||
return (mode == deletion_policy::swap_only) ? (end() - static_cast<typename iterator::difference_type>(head)) : begin();
|
||||
}
|
||||
|
||||
/*! @copydoc cbegin Useful only in case of swap-only policy. */
|
||||
[[nodiscard]] const_iterator cbegin(int) const noexcept {
|
||||
return begin(0);
|
||||
}
|
||||
|
||||
/*! @copydoc end Useful only in case of swap-only policy. */
|
||||
[[nodiscard]] iterator end(int) const noexcept {
|
||||
return end();
|
||||
}
|
||||
|
||||
/*! @copydoc cend Useful only in case of swap-only policy. */
|
||||
[[nodiscard]] const_iterator cend(int) const noexcept {
|
||||
return end(0);
|
||||
}
|
||||
|
||||
/*! @copydoc rbegin Useful only in case of swap-only policy. */
|
||||
[[nodiscard]] reverse_iterator rbegin(int) const noexcept {
|
||||
return std::make_reverse_iterator(end(0));
|
||||
}
|
||||
|
||||
/*! @copydoc rbegin Useful only in case of swap-only policy. */
|
||||
[[nodiscard]] const_reverse_iterator crbegin(int) const noexcept {
|
||||
return rbegin(0);
|
||||
}
|
||||
|
||||
/*! @copydoc rbegin Useful only in case of swap-only policy. */
|
||||
[[nodiscard]] reverse_iterator rend(int) const noexcept {
|
||||
return std::make_reverse_iterator(begin(0));
|
||||
}
|
||||
|
||||
/*! @copydoc rbegin Useful only in case of swap-only policy. */
|
||||
[[nodiscard]] const_reverse_iterator crend(int) const noexcept {
|
||||
return rend(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an entity.
|
||||
* @param entt A valid identifier.
|
||||
* @return An iterator to the given entity if it's found, past the end
|
||||
* iterator otherwise.
|
||||
*/
|
||||
[[nodiscard]] iterator find(const entity_type entt) const noexcept {
|
||||
[[nodiscard]] const_iterator find(const entity_type entt) const noexcept {
|
||||
return contains(entt) ? to_iterator(entt) : end();
|
||||
}
|
||||
|
||||
@@ -616,9 +716,10 @@ public:
|
||||
*/
|
||||
[[nodiscard]] bool contains(const entity_type entt) const noexcept {
|
||||
const auto elem = sparse_ptr(entt);
|
||||
constexpr auto cap = traits_type::to_entity(null);
|
||||
constexpr auto cap = traits_type::entity_mask;
|
||||
constexpr auto mask = traits_type::to_integral(null) & ~cap;
|
||||
// testing versions permits to avoid accessing the packed array
|
||||
return elem && (((~cap & traits_type::to_integral(entt)) ^ traits_type::to_integral(*elem)) < cap);
|
||||
return elem && (((mask & traits_type::to_integral(entt)) ^ traits_type::to_integral(*elem)) < cap);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -653,7 +754,7 @@ public:
|
||||
* @param pos The position for which to return the entity.
|
||||
* @return The entity at specified location if any, a null entity otherwise.
|
||||
*/
|
||||
[[nodiscard]] entity_type at(const size_type pos) const noexcept {
|
||||
[[deprecated("use .begin()[pos] instead")]] [[nodiscard]] entity_type at(const size_type pos) const noexcept {
|
||||
return pos < packed.size() ? packed[pos] : null;
|
||||
}
|
||||
|
||||
@@ -699,7 +800,7 @@ public:
|
||||
* `end()` iterator otherwise.
|
||||
*/
|
||||
iterator push(const entity_type entt, const void *elem = nullptr) {
|
||||
return try_emplace(entt, false, elem);
|
||||
return try_emplace(entt, (mode == deletion_policy::swap_only), elem);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -822,25 +923,26 @@ public:
|
||||
|
||||
/*! @brief Removes all tombstones from a sparse set. */
|
||||
void compact() {
|
||||
size_type from = packed.size();
|
||||
for(; from && packed[from - 1u] == tombstone; --from) {}
|
||||
if(mode == deletion_policy::in_place) {
|
||||
size_type from = packed.size();
|
||||
for(; from && packed[from - 1u] == tombstone; --from) {}
|
||||
underlying_type pos = std::exchange(head, traits_type::entity_mask);
|
||||
|
||||
for(auto *it = &free_list; *it != null && from; it = std::addressof(packed[traits_type::to_entity(*it)])) {
|
||||
if(const size_type to = traits_type::to_entity(*it); to < from) {
|
||||
--from;
|
||||
swap_or_move(from, to);
|
||||
while(pos != traits_type::to_entity(null)) {
|
||||
if(const auto to = static_cast<size_type>(std::exchange(pos, traits_type::to_entity(packed[pos]))); to < from) {
|
||||
--from;
|
||||
swap_or_move(from, to);
|
||||
|
||||
packed[to] = std::exchange(packed[from], tombstone);
|
||||
const auto entity = static_cast<typename traits_type::entity_type>(to);
|
||||
sparse_ref(packed[to]) = traits_type::combine(entity, traits_type::to_integral(packed[to]));
|
||||
packed[to] = packed[from];
|
||||
const auto entity = static_cast<typename traits_type::entity_type>(to);
|
||||
sparse_ref(packed[to]) = traits_type::combine(entity, traits_type::to_integral(packed[to]));
|
||||
|
||||
*it = traits_type::combine(static_cast<typename traits_type::entity_type>(from), tombstone);
|
||||
for(; from && packed[from - 1u] == tombstone; --from) {}
|
||||
for(; from && packed[from - 1u] == tombstone; --from) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free_list = tombstone;
|
||||
packed.resize(from);
|
||||
packed.erase(packed.begin() + from, packed.end());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -897,8 +999,8 @@ public:
|
||||
*/
|
||||
template<typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) {
|
||||
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == traits_type::to_entity(null)), "Sorting with tombstones not allowed");
|
||||
ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements");
|
||||
ENTT_ASSERT(free_list == null, "Partial sorting with tombstones is not supported");
|
||||
|
||||
algo(packed.rend() - length, packed.rend(), std::move(compare), std::forward<Args>(args)...);
|
||||
|
||||
@@ -932,28 +1034,27 @@ public:
|
||||
*/
|
||||
template<typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
|
||||
compact();
|
||||
sort_n(packed.size(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
sort_n(static_cast<size_type>(end(0) - begin(0)), std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sort entities according to their order in another sparse set.
|
||||
* @brief Sort entities according to their order in a range.
|
||||
*
|
||||
* Entities that are part of both the sparse sets are ordered internally
|
||||
* according to the order they have in `other`.<br/>
|
||||
* All the other entities goes to the end of the list and there are no
|
||||
* Entities that are part of both the sparse set and the range are ordered
|
||||
* internally according to the order they have in the range.<br/>
|
||||
* All other entities goes to the end of the sparse set and there are no
|
||||
* guarantees on their order.
|
||||
*
|
||||
* @param other The sparse sets that imposes the order of the entities.
|
||||
* @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.
|
||||
*/
|
||||
void sort_as(const basic_sparse_set &other) {
|
||||
compact();
|
||||
template<typename It>
|
||||
void sort_as(It first, It last) {
|
||||
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == traits_type::to_entity(null)), "Sorting with tombstones not allowed");
|
||||
|
||||
const auto to = other.end();
|
||||
auto from = other.begin();
|
||||
|
||||
for(auto it = begin(); it.index() && from != to; ++from) {
|
||||
if(const auto curr = *from; contains(curr)) {
|
||||
for(auto it = begin(0); it.index() && first != last; ++first) {
|
||||
if(const auto curr = *first; contains(curr)) {
|
||||
if(const auto entt = *it; entt != curr) {
|
||||
// basic no-leak guarantee (with invalid state) if swapping throws
|
||||
swap_elements(entt, curr);
|
||||
@@ -964,12 +1065,20 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @copybrief sort_as
|
||||
* @param other The sparse sets that imposes the order of the entities.
|
||||
*/
|
||||
[[deprecated("use iterator based sort_as instead")]] void sort_as(const basic_sparse_set &other) {
|
||||
sort_as(other.begin(), other.end());
|
||||
}
|
||||
|
||||
/*! @brief Clears a sparse set. */
|
||||
void clear() {
|
||||
pop_all();
|
||||
// sanity check to avoid subtle issues due to storage classes
|
||||
ENTT_ASSERT((compact(), size()) == 0u, "Non-empty set");
|
||||
free_list = tombstone;
|
||||
head = policy_to_head();
|
||||
packed.clear();
|
||||
}
|
||||
|
||||
@@ -988,8 +1097,8 @@ private:
|
||||
sparse_container_type sparse;
|
||||
packed_container_type packed;
|
||||
const type_info *info;
|
||||
entity_type free_list;
|
||||
deletion_policy mode;
|
||||
underlying_type head;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -19,11 +19,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Container, std::size_t Size>
|
||||
@@ -161,11 +157,12 @@ public:
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
|
||||
constexpr extended_storage_iterator()
|
||||
: it{} {}
|
||||
|
||||
constexpr extended_storage_iterator(It base, Other... other)
|
||||
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> && ...)>>
|
||||
@@ -211,11 +208,7 @@ template<typename... Lhs, typename... Rhs>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Basic storage implementation.
|
||||
@@ -240,8 +233,6 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
|
||||
using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
|
||||
using underlying_iterator = typename underlying_type::basic_iterator;
|
||||
|
||||
static constexpr bool is_pinned_type_v = !(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>);
|
||||
|
||||
[[nodiscard]] auto &element_at(const std::size_t pos) const {
|
||||
return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
|
||||
}
|
||||
@@ -290,7 +281,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
|
||||
|
||||
for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
|
||||
if constexpr(traits_type::in_place_delete) {
|
||||
if(base_type::at(pos) != tombstone) {
|
||||
if(base_type::data()[pos] != tombstone) {
|
||||
alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
|
||||
}
|
||||
} else {
|
||||
@@ -311,6 +302,7 @@ private:
|
||||
}
|
||||
|
||||
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_v = !(std::is_move_constructible_v<Type> && std::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_v, "Pinned type");
|
||||
|
||||
@@ -841,7 +833,12 @@ public:
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return allocator_type{base_type::get_allocator()};
|
||||
// std::allocator<void> has no cross constructors (waiting for C++20)
|
||||
if constexpr(std::is_void_v<value_type> && !std::is_constructible_v<allocator_type, typename base_type::allocator_type>) {
|
||||
return allocator_type{};
|
||||
} else {
|
||||
return allocator_type{base_type::get_allocator()};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -958,42 +955,13 @@ class basic_storage<Entity, Entity, Allocator>
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
|
||||
using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
|
||||
using underlying_iterator = typename underlying_type::basic_iterator;
|
||||
using local_traits_type = entt_traits<Entity>;
|
||||
|
||||
auto entity_at(const std::size_t pos) const noexcept {
|
||||
ENTT_ASSERT(pos < local_traits_type::to_entity(null), "Invalid element");
|
||||
return local_traits_type::combine(static_cast<typename local_traits_type::entity_type>(pos), {});
|
||||
}
|
||||
|
||||
private:
|
||||
void swap_or_move([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) override {
|
||||
ENTT_ASSERT(((lhs < length) + (rhs < length)) != 1u, "Cross swapping is not supported");
|
||||
ENTT_ASSERT(pos < underlying_type::traits_type::to_entity(null), "Invalid element");
|
||||
return underlying_type::traits_type::combine(static_cast<typename underlying_type::traits_type::entity_type>(pos), {});
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Erases entities from a 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.
|
||||
*/
|
||||
void pop(underlying_iterator first, underlying_iterator last) override {
|
||||
for(; first != last; ++first) {
|
||||
if(const auto pos = base_type::index(*first); pos < length) {
|
||||
base_type::bump(local_traits_type::next(*first));
|
||||
|
||||
if(pos != --length) {
|
||||
base_type::swap_at(pos, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Erases all entities of a sparse set. */
|
||||
void pop_all() override {
|
||||
length = 0u;
|
||||
base_type::pop_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns an entity to a storage.
|
||||
* @param hint A valid identifier.
|
||||
@@ -1008,8 +976,6 @@ public:
|
||||
using base_type = basic_sparse_set<Entity, Allocator>;
|
||||
/*! @brief Type of the objects assigned to entities. */
|
||||
using value_type = Entity;
|
||||
/*! @brief Component traits. */
|
||||
using traits_type = component_traits<value_type>;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
/*! @brief Unsigned integer type. */
|
||||
@@ -1035,16 +1001,14 @@ public:
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit basic_storage(const allocator_type &allocator)
|
||||
: base_type{type_id<value_type>(), deletion_policy::swap_and_pop, allocator},
|
||||
length{} {}
|
||||
: base_type{type_id<void>(), deletion_policy::swap_only, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_storage(basic_storage &&other) noexcept
|
||||
: base_type{std::move(other)},
|
||||
length{std::exchange(other.length, size_type{})} {}
|
||||
: base_type{std::move(other)} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
@@ -1052,8 +1016,7 @@ public:
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_storage(basic_storage &&other, const allocator_type &allocator) noexcept
|
||||
: base_type{std::move(other), allocator},
|
||||
length{std::exchange(other.length, size_type{})} {}
|
||||
: base_type{std::move(other), allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
@@ -1062,7 +1025,6 @@ public:
|
||||
*/
|
||||
basic_storage &operator=(basic_storage &&other) noexcept {
|
||||
base_type::operator=(std::move(other));
|
||||
length = std::exchange(other.length, size_type{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -1076,7 +1038,7 @@ public:
|
||||
* @param entt A valid identifier.
|
||||
*/
|
||||
void get([[maybe_unused]] const entity_type entt) const noexcept {
|
||||
ENTT_ASSERT(base_type::index(entt) < length, "The requested entity is not a live one");
|
||||
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1090,30 +1052,18 @@ public:
|
||||
* @return Returns an empty tuple.
|
||||
*/
|
||||
[[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
|
||||
ENTT_ASSERT(base_type::index(entt) < length, "The requested entity is not a live one");
|
||||
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
|
||||
return std::tuple{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given storage.
|
||||
* @param other Storage to exchange the content with.
|
||||
*/
|
||||
void swap(basic_storage &other) {
|
||||
using std::swap;
|
||||
base_type::swap(other);
|
||||
swap(length, other.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a new identifier or recycles a destroyed one.
|
||||
* @return A valid identifier.
|
||||
*/
|
||||
entity_type emplace() {
|
||||
if(length == base_type::size()) {
|
||||
return *base_type::try_emplace(entity_at(length++), true);
|
||||
}
|
||||
|
||||
return base_type::operator[](length++);
|
||||
const auto len = base_type::free_list();
|
||||
const auto entt = (len == base_type::size()) ? entity_at(len) : base_type::data()[len];
|
||||
return *base_type::try_emplace(entt, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1128,23 +1078,20 @@ public:
|
||||
entity_type emplace(const entity_type hint) {
|
||||
if(hint == null || hint == tombstone) {
|
||||
return emplace();
|
||||
} else if(const auto curr = local_traits_type::construct(local_traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone) {
|
||||
const auto pos = static_cast<size_type>(local_traits_type::to_entity(hint));
|
||||
} else if(const auto curr = underlying_type::traits_type::construct(underlying_type::traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone) {
|
||||
const auto pos = static_cast<size_type>(underlying_type::traits_type::to_entity(hint));
|
||||
const auto entt = *base_type::try_emplace(hint, true);
|
||||
|
||||
while(!(pos < base_type::size())) {
|
||||
base_type::try_emplace(entity_at(base_type::size()), true);
|
||||
base_type::try_emplace(entity_at(base_type::size() - 1u), false);
|
||||
}
|
||||
|
||||
base_type::swap_at(pos, length++);
|
||||
} else if(const auto idx = base_type::index(curr); idx < length) {
|
||||
return entt;
|
||||
} else if(const auto idx = base_type::index(curr); idx < base_type::free_list()) {
|
||||
return emplace();
|
||||
} else {
|
||||
base_type::swap_at(idx, length++);
|
||||
return *base_type::try_emplace(hint, true);
|
||||
}
|
||||
|
||||
base_type::bump(hint);
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1155,7 +1102,7 @@ public:
|
||||
*/
|
||||
template<typename... Func>
|
||||
void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
|
||||
ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity");
|
||||
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
|
||||
(std::forward<Func>(func)(), ...);
|
||||
}
|
||||
|
||||
@@ -1167,12 +1114,12 @@ public:
|
||||
*/
|
||||
template<typename It>
|
||||
void insert(It first, It last) {
|
||||
for(const auto sz = base_type::size(); first != last && length != sz; ++first, ++length) {
|
||||
*first = base_type::operator[](length);
|
||||
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);
|
||||
}
|
||||
|
||||
for(; first != last; ++first) {
|
||||
*first = *base_type::try_emplace(entity_at(length++), true);
|
||||
*first = *base_type::try_emplace(entity_at(base_type::free_list()), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1184,33 +1131,25 @@ public:
|
||||
* @return The number of elements within the newly created range.
|
||||
*/
|
||||
template<typename It>
|
||||
size_type pack(It first, It last) {
|
||||
size_type len = length;
|
||||
|
||||
for(; first != last; ++first, --len) {
|
||||
const auto pos = base_type::index(*first);
|
||||
ENTT_ASSERT(pos < length, "Invalid element");
|
||||
base_type::swap_at(pos, static_cast<size_type>(len - 1u));
|
||||
}
|
||||
|
||||
return (length - len);
|
||||
[[deprecated("use sort_as instead")]] size_type pack(It first, It last) {
|
||||
base_type::sort_as(first, last);
|
||||
return static_cast<size_type>(std::distance(first, last));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements considered still in use.
|
||||
* @return The number of elements considered still in use.
|
||||
*/
|
||||
[[nodiscard]] size_type in_use() const noexcept {
|
||||
return length;
|
||||
[[deprecated("use free_list() instead")]] [[nodiscard]] size_type in_use() const noexcept {
|
||||
return base_type::free_list();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the number of elements considered still in use.
|
||||
* @param len The number of elements considered still in use.
|
||||
*/
|
||||
void in_use(const size_type len) noexcept {
|
||||
ENTT_ASSERT(!(len > base_type::size()), "Invalid length");
|
||||
length = len;
|
||||
[[deprecated("use free_list(len) instead")]] void in_use(const size_type len) noexcept {
|
||||
base_type::free_list(len);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1221,12 +1160,12 @@ public:
|
||||
* @return An iterable object to use to _visit_ the storage.
|
||||
*/
|
||||
[[nodiscard]] iterable each() noexcept {
|
||||
return {internal::extended_storage_iterator{base_type::end() - length}, internal::extended_storage_iterator{base_type::end()}};
|
||||
return {internal::extended_storage_iterator{base_type::begin(0)}, internal::extended_storage_iterator{base_type::end(0)}};
|
||||
}
|
||||
|
||||
/*! @copydoc each */
|
||||
[[nodiscard]] const_iterable each() const noexcept {
|
||||
return {internal::extended_storage_iterator{base_type::cend() - length}, internal::extended_storage_iterator{base_type::cend()}};
|
||||
return {internal::extended_storage_iterator{base_type::cbegin(0)}, internal::extended_storage_iterator{base_type::cend(0)}};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1237,16 +1176,13 @@ public:
|
||||
* @return A reverse iterable object to use to _visit_ the storage.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterable reach() noexcept {
|
||||
return {internal::extended_storage_iterator{base_type::rbegin()}, internal::extended_storage_iterator{base_type::rbegin() + length}};
|
||||
return {internal::extended_storage_iterator{base_type::rbegin()}, internal::extended_storage_iterator{base_type::rend(0)}};
|
||||
}
|
||||
|
||||
/*! @copydoc reach */
|
||||
[[nodiscard]] const_reverse_iterable reach() const noexcept {
|
||||
return {internal::extended_storage_iterator{base_type::crbegin()}, internal::extended_storage_iterator{base_type::crbegin() + length}};
|
||||
return {internal::extended_storage_iterator{base_type::crbegin()}, internal::extended_storage_iterator{base_type::crend(0)}};
|
||||
}
|
||||
|
||||
private:
|
||||
size_type length;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,11 +13,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
@@ -30,6 +26,7 @@ public:
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
|
||||
constexpr edge_iterator() noexcept
|
||||
: it{},
|
||||
@@ -87,11 +84,7 @@ template<typename Container>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Basic implementation of a directed adjacency matrix.
|
||||
|
||||
@@ -134,8 +134,8 @@ public:
|
||||
*/
|
||||
explicit basic_flow(const allocator_type &allocator)
|
||||
: index{0u, allocator},
|
||||
vertices{},
|
||||
deps{},
|
||||
vertices{allocator},
|
||||
deps{allocator},
|
||||
sync_on{} {}
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
|
||||
@@ -19,145 +19,284 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct is_dynamic_sequence_container: std::false_type {};
|
||||
struct fixed_size_sequence_container: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct is_dynamic_sequence_container<Type, std::void_t<decltype(&Type::clear)>>: std::true_type {};
|
||||
struct fixed_size_sequence_container<Type, std::void_t<decltype(&Type::clear)>>: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool fixed_size_sequence_container_v = fixed_size_sequence_container<Type>::value;
|
||||
|
||||
template<typename, typename = void>
|
||||
struct is_key_only_meta_associative_container: std::true_type {};
|
||||
struct key_only_associative_container: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct is_key_only_meta_associative_container<Type, std::void_t<typename Type::mapped_type>>: std::false_type {};
|
||||
struct key_only_associative_container<Type, std::void_t<typename Type::mapped_type>>: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct basic_meta_sequence_container_traits {
|
||||
using iterator = meta_sequence_container::iterator;
|
||||
using size_type = std::size_t;
|
||||
inline constexpr bool key_only_associative_container_v = key_only_associative_container<Type>::value;
|
||||
|
||||
[[nodiscard]] static size_type size(const any &container) noexcept {
|
||||
return any_cast<const Type &>(container).size();
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool resize([[maybe_unused]] any &container, [[maybe_unused]] size_type sz) {
|
||||
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
cont->resize(sz);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator iter(const meta_ctx &ctx, any &container, const bool as_end) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{ctx, as_end ? cont->end() : cont->begin()};
|
||||
}
|
||||
|
||||
const Type &as_const = any_cast<const Type &>(container);
|
||||
return iterator{ctx, as_end ? as_const.end() : as_const.begin()};
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator insert_or_erase([[maybe_unused]] const meta_ctx &ctx, [[maybe_unused]] any &container, [[maybe_unused]] const any &handle, [[maybe_unused]] meta_any &value) {
|
||||
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
typename Type::const_iterator it{};
|
||||
|
||||
if(auto *non_const = any_cast<typename Type::iterator>(&handle); non_const) {
|
||||
it = *non_const;
|
||||
} else {
|
||||
it = any_cast<const typename Type::const_iterator &>(handle);
|
||||
}
|
||||
|
||||
if(value) {
|
||||
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
|
||||
if(value.allow_cast<typename Type::const_reference>() || value.allow_cast<typename Type::value_type>()) {
|
||||
const auto *element = value.try_cast<std::remove_reference_t<typename Type::const_reference>>();
|
||||
return iterator{ctx, cont->insert(it, element ? *element : value.cast<typename Type::value_type>())};
|
||||
}
|
||||
} else {
|
||||
return iterator{ctx, cont->erase(it)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return iterator{};
|
||||
}
|
||||
};
|
||||
template<typename, typename = void>
|
||||
struct reserve_aware_container: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct basic_meta_associative_container_traits {
|
||||
using iterator = meta_associative_container::iterator;
|
||||
using size_type = std::size_t;
|
||||
struct reserve_aware_container<Type, std::void_t<decltype(&Type::reserve)>>: std::true_type {};
|
||||
|
||||
static constexpr auto key_only = is_key_only_meta_associative_container<Type>::value;
|
||||
|
||||
[[nodiscard]] static size_type size(const any &container) noexcept {
|
||||
return any_cast<const Type &>(container).size();
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool clear(any &container) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
cont->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator iter(const meta_ctx &ctx, any &container, const bool as_end) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{ctx, std::bool_constant<key_only>{}, as_end ? cont->end() : cont->begin()};
|
||||
}
|
||||
|
||||
const auto &as_const = any_cast<const Type &>(container);
|
||||
return iterator{ctx, std::bool_constant<key_only>{}, as_end ? as_const.end() : as_const.begin()};
|
||||
}
|
||||
|
||||
[[nodiscard]] static size_type insert_or_erase(any &container, meta_any &key, meta_any &value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
|
||||
if(value) {
|
||||
if constexpr(key_only) {
|
||||
return cont->insert(key.cast<const typename Type::key_type &>()).second;
|
||||
} else {
|
||||
return value.allow_cast<const typename Type::mapped_type &>() && cont->emplace(key.cast<const typename Type::key_type &>(), value.cast<const typename Type::mapped_type &>()).second;
|
||||
}
|
||||
} else {
|
||||
return cont->erase(key.cast<const typename Type::key_type &>());
|
||||
}
|
||||
}
|
||||
|
||||
return 0u;
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator find(const meta_ctx &ctx, any &container, meta_any &key) {
|
||||
if(key.allow_cast<const typename Type::key_type &>()) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{ctx, std::bool_constant<key_only>{}, cont->find(key.cast<const typename Type::key_type &>())};
|
||||
}
|
||||
|
||||
return iterator{ctx, std::bool_constant<key_only>{}, any_cast<const Type &>(container).find(key.cast<const typename Type::key_type &>())};
|
||||
}
|
||||
|
||||
return iterator{};
|
||||
}
|
||||
};
|
||||
template<typename Type>
|
||||
inline constexpr bool reserve_aware_container_v = reserve_aware_container<Type>::value;
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
* @brief General purpose implementation of meta sequence container traits.
|
||||
* @tparam Type Type of underlying sequence container.
|
||||
*/
|
||||
template<typename 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 True in case of key-only containers, false otherwise. */
|
||||
static constexpr bool fixed_size = internal::fixed_size_sequence_container_v<Type>;
|
||||
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename meta_sequence_container::size_type;
|
||||
/*! @brief Meta iterator type. */
|
||||
using iterator = typename meta_sequence_container::iterator;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a container.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @return Number of elements.
|
||||
*/
|
||||
[[nodiscard]] static size_type size(const void *container) {
|
||||
return static_cast<const Type *>(container)->size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears a container.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] static bool clear([[maybe_unused]] void *container) {
|
||||
if constexpr(fixed_size) {
|
||||
return false;
|
||||
} else {
|
||||
static_cast<Type *>(container)->clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increases the capacity of a container.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param sz Desired capacity.
|
||||
* @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>) {
|
||||
static_cast<Type *>(container)->reserve(sz);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resizes a container.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param sz The new number of elements.
|
||||
* @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 {
|
||||
static_cast<Type *>(container)->resize(sz);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a possibly const iterator to the beginning.
|
||||
* @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.
|
||||
*/
|
||||
static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
|
||||
return container ? 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 ? iterator{area, static_cast<Type *>(container)->end()}
|
||||
: iterator{area, static_cast<const Type *>(as_const)->end()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns one element to a container and constructs its object from
|
||||
* a given opaque instance.
|
||||
* @param area The context to pass to the newly created iterator.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param value Optional opaque instance of the object to construct (as
|
||||
* value type).
|
||||
* @param cref Optional opaque instance of the object to construct (as
|
||||
* decayed const reference type).
|
||||
* @param it Iterator before which the element will be inserted.
|
||||
* @return A possibly invalid iterator to the inserted element.
|
||||
*/
|
||||
[[nodiscard]] static iterator insert(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{area};
|
||||
} else {
|
||||
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 ? *static_cast<const typename Type::value_type *>(value) : *static_cast<const std::remove_reference_t<typename Type::const_reference> *>(cref))};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases an element from a container.
|
||||
* @param area The context to pass to the newly created iterator.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param it An opaque iterator to the element to erase.
|
||||
* @return A possibly invalid iterator following the last removed element.
|
||||
*/
|
||||
[[nodiscard]] static iterator erase(const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) {
|
||||
if constexpr(fixed_size) {
|
||||
return iterator{area};
|
||||
} else {
|
||||
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()))};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief General purpose implementation of meta associative container traits.
|
||||
* @tparam Type Type of underlying associative container.
|
||||
*/
|
||||
template<typename 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 True in case of key-only containers, false otherwise. */
|
||||
static constexpr bool key_only = internal::key_only_associative_container_v<Type>;
|
||||
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename meta_associative_container::size_type;
|
||||
/*! @brief Meta iterator type. */
|
||||
using iterator = typename meta_associative_container::iterator;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a container.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @return Number of elements.
|
||||
*/
|
||||
[[nodiscard]] static size_type size(const void *container) {
|
||||
return static_cast<const Type *>(container)->size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clears a container.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] static bool clear(void *container) {
|
||||
static_cast<Type *>(container)->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Increases the capacity of a container.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param sz Desired capacity.
|
||||
* @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>) {
|
||||
static_cast<Type *>(container)->reserve(sz);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a possibly const iterator to the beginning.
|
||||
* @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.
|
||||
*/
|
||||
static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
|
||||
return container ? 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 ? 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()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an element into a container, if the key does not exist.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param key An opaque key value of an element to insert.
|
||||
* @param value Optional opaque value to insert (key-value containers).
|
||||
* @return True if the insertion took place, false otherwise.
|
||||
*/
|
||||
[[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;
|
||||
} else {
|
||||
return static_cast<Type *>(container)->emplace(*static_cast<const typename Type::key_type *>(key), *static_cast<const typename Type::mapped_type *>(value)).second;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes an element from a container.
|
||||
* @param container Opaque pointer to a container of the given type.
|
||||
* @param key An opaque key value of an element to remove.
|
||||
* @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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an element with a given key.
|
||||
* @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.
|
||||
* @param key Opaque key value of an element to search for.
|
||||
* @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 ? 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))};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::vector`s of any type.
|
||||
@@ -165,7 +304,7 @@ struct basic_meta_associative_container_traits {
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_sequence_container_traits<std::vector<Args...>>
|
||||
: internal::basic_meta_sequence_container_traits<std::vector<Args...>> {};
|
||||
: basic_meta_sequence_container_traits<std::vector<Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::array`s of any type.
|
||||
@@ -174,7 +313,7 @@ struct meta_sequence_container_traits<std::vector<Args...>>
|
||||
*/
|
||||
template<typename Type, auto N>
|
||||
struct meta_sequence_container_traits<std::array<Type, N>>
|
||||
: internal::basic_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.
|
||||
@@ -182,7 +321,7 @@ struct meta_sequence_container_traits<std::array<Type, N>>
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_sequence_container_traits<std::list<Args...>>
|
||||
: internal::basic_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.
|
||||
@@ -190,7 +329,7 @@ struct meta_sequence_container_traits<std::list<Args...>>
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_sequence_container_traits<std::deque<Args...>>
|
||||
: internal::basic_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.
|
||||
@@ -198,7 +337,7 @@ struct meta_sequence_container_traits<std::deque<Args...>>
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<std::map<Args...>>
|
||||
: internal::basic_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
|
||||
@@ -207,7 +346,7 @@ struct meta_associative_container_traits<std::map<Args...>>
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<std::unordered_map<Args...>>
|
||||
: internal::basic_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.
|
||||
@@ -215,7 +354,7 @@ struct meta_associative_container_traits<std::unordered_map<Args...>>
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<std::set<Args...>>
|
||||
: internal::basic_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
|
||||
@@ -224,7 +363,7 @@ struct meta_associative_container_traits<std::set<Args...>>
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<std::unordered_set<Args...>>
|
||||
: internal::basic_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.
|
||||
@@ -232,7 +371,7 @@ struct meta_associative_container_traits<std::unordered_set<Args...>>
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<dense_map<Args...>>
|
||||
: internal::basic_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.
|
||||
@@ -240,7 +379,7 @@ struct meta_associative_container_traits<dense_map<Args...>>
|
||||
*/
|
||||
template<typename... Args>
|
||||
struct meta_associative_container_traits<dense_set<Args...>>
|
||||
: internal::basic_meta_associative_container_traits<dense_set<Args...>> {};
|
||||
: basic_meta_associative_container_traits<dense_set<Args...>> {};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
|
||||
@@ -9,11 +9,7 @@ namespace entt {
|
||||
|
||||
class meta_ctx;
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
struct meta_type_node;
|
||||
@@ -21,16 +17,12 @@ struct meta_type_node;
|
||||
struct meta_context {
|
||||
dense_map<id_type, meta_type_node, identity> value{};
|
||||
|
||||
[[nodiscard]] static inline meta_context &from(meta_ctx &ctx);
|
||||
[[nodiscard]] static inline const meta_context &from(const meta_ctx &ctx);
|
||||
[[nodiscard]] inline static meta_context &from(meta_ctx &ctx);
|
||||
[[nodiscard]] inline static const meta_context &from(const meta_ctx &ctx);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/*! @brief Disambiguation tag for constructors and the like. */
|
||||
class meta_ctx_arg_t final {};
|
||||
@@ -40,15 +32,11 @@ inline constexpr meta_ctx_arg_t meta_ctx_arg{};
|
||||
|
||||
/*! @brief Opaque meta context type. */
|
||||
class meta_ctx: private internal::meta_context {
|
||||
/*! @brief Attorney idiom like model to access the base class. */
|
||||
// attorney idiom like model to access the base class
|
||||
friend struct internal::meta_context;
|
||||
};
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
[[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) {
|
||||
return ctx;
|
||||
}
|
||||
@@ -56,11 +44,7 @@ class meta_ctx: private internal::meta_context {
|
||||
[[nodiscard]] inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) {
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
} // namespace entt
|
||||
|
||||
|
||||
@@ -22,11 +22,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
[[nodiscard]] inline decltype(auto) owner(meta_ctx &ctx, const type_info &info) {
|
||||
@@ -57,11 +53,7 @@ inline meta_func_node &meta_extend(internal::meta_type_node &parent, const id_ty
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Basic meta factory to be used for reflection purposes.
|
||||
@@ -115,7 +107,7 @@ public:
|
||||
/**
|
||||
* @brief Assigns a custom unique identifier to a meta type.
|
||||
* @param id A custom unique identifier.
|
||||
* @return An extended meta factory for the given type.
|
||||
* @return A meta factory for the given type.
|
||||
*/
|
||||
auto type(const id_type id) noexcept {
|
||||
auto &&elem = internal::owner(*ctx, *info);
|
||||
@@ -192,7 +184,7 @@ public:
|
||||
*
|
||||
* @tparam Candidate The actual function to use as a constructor.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @return An extended meta factory for the parent type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<auto Candidate, typename Policy = as_is_t>
|
||||
auto ctor() noexcept {
|
||||
@@ -212,7 +204,7 @@ public:
|
||||
* type that can be invoked with parameters whose types are those given.
|
||||
*
|
||||
* @tparam Args Types of arguments to use to construct an instance.
|
||||
* @return An extended meta factory for the parent type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename... Args>
|
||||
auto ctor() noexcept {
|
||||
@@ -264,7 +256,7 @@ 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.
|
||||
* @return An extended meta factory for the parent type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<auto Data, typename Policy = as_is_t>
|
||||
auto data(const id_type id) noexcept {
|
||||
@@ -329,7 +321,7 @@ public:
|
||||
* @tparam Getter The actual function to use as a getter.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param id Unique identifier.
|
||||
* @return An extended meta factory for the parent type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<auto Setter, auto Getter, typename Policy = as_is_t>
|
||||
auto data(const id_type id) noexcept {
|
||||
@@ -386,7 +378,7 @@ public:
|
||||
* @tparam Getter The actual getter function.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param id Unique identifier.
|
||||
* @return An extended meta factory for the parent type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename Setter, auto Getter, typename Policy = as_is_t>
|
||||
auto data(const id_type id) noexcept {
|
||||
@@ -405,7 +397,7 @@ 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.
|
||||
* @return An extended meta factory for the parent type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<auto Candidate, typename Policy = as_is_t>
|
||||
auto func(const id_type id) noexcept {
|
||||
@@ -434,7 +426,7 @@ public:
|
||||
* @tparam Value Optional type of the property value.
|
||||
* @param id Property key.
|
||||
* @param value Optional property value.
|
||||
* @return An extended meta factory for the given type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename... Value>
|
||||
meta_factory prop(id_type id, [[maybe_unused]] Value &&...value) {
|
||||
|
||||
@@ -36,11 +36,15 @@ public:
|
||||
/*! @brief Meta iterator type. */
|
||||
using iterator = meta_iterator;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
meta_sequence_container() noexcept
|
||||
: meta_sequence_container{locator<meta_ctx>::value_or()} {}
|
||||
|
||||
/**
|
||||
* @brief Context aware constructor.
|
||||
* @param area The context from which to search for meta types.
|
||||
*/
|
||||
meta_sequence_container(const meta_ctx &area = locator<meta_ctx>::value_or()) noexcept
|
||||
meta_sequence_container(const meta_ctx &area) noexcept
|
||||
: ctx{&area} {}
|
||||
|
||||
/**
|
||||
@@ -49,19 +53,26 @@ public:
|
||||
* @param instance The container to wrap.
|
||||
*/
|
||||
template<typename Type>
|
||||
void rebind(any instance) noexcept {
|
||||
void rebind(Type &instance) noexcept {
|
||||
value_type_node = &internal::resolve<typename Type::value_type>;
|
||||
size_fn = &meta_sequence_container_traits<Type>::size;
|
||||
resize_fn = &meta_sequence_container_traits<Type>::resize;
|
||||
iter_fn = &meta_sequence_container_traits<Type>::iter;
|
||||
insert_or_erase_fn = &meta_sequence_container_traits<Type>::insert_or_erase;
|
||||
storage = std::move(instance);
|
||||
const_reference_node = &internal::resolve<std::remove_const_t<std::remove_reference_t<typename Type::const_reference>>>;
|
||||
size_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::size;
|
||||
clear_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::clear;
|
||||
reserve_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::reserve;
|
||||
resize_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::resize;
|
||||
begin_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::begin;
|
||||
end_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::end;
|
||||
insert_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::insert;
|
||||
erase_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::erase;
|
||||
const_only = std::is_const_v<Type>;
|
||||
data = &instance;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline meta_type value_type() const noexcept;
|
||||
[[nodiscard]] inline size_type size() const noexcept;
|
||||
inline bool resize(const size_type);
|
||||
inline bool clear();
|
||||
inline bool reserve(const size_type);
|
||||
[[nodiscard]] inline iterator begin();
|
||||
[[nodiscard]] inline iterator end();
|
||||
inline iterator insert(iterator, meta_any);
|
||||
@@ -72,11 +83,17 @@ public:
|
||||
private:
|
||||
const meta_ctx *ctx{};
|
||||
internal::meta_type_node (*value_type_node)(const internal::meta_context &){};
|
||||
size_type (*size_fn)(const any &) noexcept {};
|
||||
bool (*resize_fn)(any &, size_type){};
|
||||
iterator (*iter_fn)(const meta_ctx &, any &, const bool){};
|
||||
iterator (*insert_or_erase_fn)(const meta_ctx &, any &, const any &, meta_any &){};
|
||||
any storage{};
|
||||
internal::meta_type_node (*const_reference_node)(const internal::meta_context &){};
|
||||
size_type (*size_fn)(const void *){};
|
||||
bool (*clear_fn)(void *){};
|
||||
bool (*reserve_fn)(void *, const size_type){};
|
||||
bool (*resize_fn)(void *, const size_type){};
|
||||
iterator (*begin_fn)(const meta_ctx &, void *, const void *){};
|
||||
iterator (*end_fn)(const meta_ctx &, void *, const void *){};
|
||||
iterator (*insert_fn)(const meta_ctx &, void *, const void *, const void *, const iterator &){};
|
||||
iterator (*erase_fn)(const meta_ctx &, void *, const iterator &){};
|
||||
const void *data{};
|
||||
bool const_only{};
|
||||
};
|
||||
|
||||
/*! @brief Proxy object for associative containers. */
|
||||
@@ -89,11 +106,15 @@ public:
|
||||
/*! @brief Meta iterator type. */
|
||||
using iterator = meta_iterator;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
meta_associative_container() noexcept
|
||||
: meta_associative_container{locator<meta_ctx>::value_or()} {}
|
||||
|
||||
/**
|
||||
* @brief Context aware constructor.
|
||||
* @param area The context from which to search for meta types.
|
||||
*/
|
||||
meta_associative_container(const meta_ctx &area = locator<meta_ctx>::value_or()) noexcept
|
||||
meta_associative_container(const meta_ctx &area) noexcept
|
||||
: ctx{&area} {}
|
||||
|
||||
/**
|
||||
@@ -102,20 +123,24 @@ public:
|
||||
* @param instance The container to wrap.
|
||||
*/
|
||||
template<typename Type>
|
||||
void rebind(any instance) noexcept {
|
||||
if constexpr(!meta_associative_container_traits<Type>::key_only) {
|
||||
void rebind(Type &instance) noexcept {
|
||||
key_type_node = &internal::resolve<typename Type::key_type>;
|
||||
value_type_node = &internal::resolve<typename Type::value_type>;
|
||||
|
||||
if constexpr(!meta_associative_container_traits<std::remove_const_t<Type>>::key_only) {
|
||||
mapped_type_node = &internal::resolve<typename Type::mapped_type>;
|
||||
}
|
||||
|
||||
key_only_container = meta_associative_container_traits<Type>::key_only;
|
||||
key_type_node = &internal::resolve<typename Type::key_type>;
|
||||
value_type_node = &internal::resolve<typename Type::value_type>;
|
||||
size_fn = &meta_associative_container_traits<Type>::size;
|
||||
clear_fn = &meta_associative_container_traits<Type>::clear;
|
||||
iter_fn = &meta_associative_container_traits<Type>::iter;
|
||||
insert_or_erase_fn = &meta_associative_container_traits<Type>::insert_or_erase;
|
||||
find_fn = &meta_associative_container_traits<Type>::find;
|
||||
storage = std::move(instance);
|
||||
size_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::size;
|
||||
clear_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::clear;
|
||||
reserve_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::reserve;
|
||||
begin_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::begin;
|
||||
end_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::end;
|
||||
insert_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::insert;
|
||||
erase_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::erase;
|
||||
find_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::find;
|
||||
const_only = std::is_const_v<Type>;
|
||||
data = &instance;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline bool key_only() const noexcept;
|
||||
@@ -124,9 +149,9 @@ public:
|
||||
[[nodiscard]] inline meta_type value_type() const noexcept;
|
||||
[[nodiscard]] inline size_type size() const noexcept;
|
||||
inline bool clear();
|
||||
inline bool reserve(const size_type);
|
||||
[[nodiscard]] inline iterator begin();
|
||||
[[nodiscard]] inline iterator end();
|
||||
inline bool insert(meta_any);
|
||||
inline bool insert(meta_any, meta_any);
|
||||
inline size_type erase(meta_any);
|
||||
[[nodiscard]] inline iterator find(meta_any);
|
||||
@@ -134,67 +159,63 @@ public:
|
||||
|
||||
private:
|
||||
const meta_ctx *ctx{};
|
||||
bool key_only_container{};
|
||||
internal::meta_type_node (*key_type_node)(const internal::meta_context &){};
|
||||
internal::meta_type_node (*mapped_type_node)(const internal::meta_context &){};
|
||||
internal::meta_type_node (*value_type_node)(const internal::meta_context &){};
|
||||
size_type (*size_fn)(const any &) noexcept {};
|
||||
bool (*clear_fn)(any &){};
|
||||
iterator (*iter_fn)(const meta_ctx &, any &, const bool){};
|
||||
size_type (*insert_or_erase_fn)(any &, meta_any &, meta_any &){};
|
||||
iterator (*find_fn)(const meta_ctx &, any &, meta_any &){};
|
||||
any storage{};
|
||||
size_type (*size_fn)(const void *){};
|
||||
bool (*clear_fn)(void *){};
|
||||
bool (*reserve_fn)(void *, const size_type){};
|
||||
iterator (*begin_fn)(const meta_ctx &, void *, const void *){};
|
||||
iterator (*end_fn)(const meta_ctx &, void *, const void *){};
|
||||
bool (*insert_fn)(void *, const void *, const void *){};
|
||||
size_type (*erase_fn)(void *, const void *){};
|
||||
iterator (*find_fn)(const meta_ctx &, void *, const void *, const void *){};
|
||||
const void *data{};
|
||||
bool const_only{};
|
||||
};
|
||||
|
||||
/*! @brief Possible modes of a meta any object. */
|
||||
using meta_any_policy = any_policy;
|
||||
|
||||
/*! @brief Opaque wrapper for values of any type. */
|
||||
class meta_any {
|
||||
enum class operation : std::uint8_t {
|
||||
deref,
|
||||
seq,
|
||||
assoc
|
||||
};
|
||||
|
||||
using vtable_type = void(const operation, const any &, void *);
|
||||
using vtable_type = void(const internal::meta_traits op, const bool, const void *, void *);
|
||||
|
||||
template<typename Type>
|
||||
static void basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const any &value, [[maybe_unused]] void *other) {
|
||||
static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
|
||||
static std::enable_if_t<std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>> basic_vtable([[maybe_unused]] const internal::meta_traits req, [[maybe_unused]] const bool const_only, [[maybe_unused]] const void *value, [[maybe_unused]] void *other) {
|
||||
if constexpr(is_meta_pointer_like_v<Type>) {
|
||||
if(req == internal::meta_traits::is_meta_pointer_like) {
|
||||
if constexpr(std::is_function_v<typename std::pointer_traits<Type>::element_type>) {
|
||||
static_cast<meta_any *>(other)->emplace<Type>(*static_cast<const Type *>(value));
|
||||
} else if constexpr(!std::is_void_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>>) {
|
||||
using in_place_type = decltype(adl_meta_pointer_like<Type>::dereference(*static_cast<const Type *>(value)));
|
||||
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
switch(op) {
|
||||
case operation::deref:
|
||||
if constexpr(is_meta_pointer_like_v<Type>) {
|
||||
if constexpr(std::is_function_v<typename std::pointer_traits<Type>::element_type>) {
|
||||
static_cast<meta_any *>(other)->emplace<Type>(any_cast<Type>(value));
|
||||
} else if constexpr(!std::is_same_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>, void>) {
|
||||
using in_place_type = decltype(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(value)));
|
||||
|
||||
if constexpr(std::is_constructible_v<bool, Type>) {
|
||||
if(const auto &pointer_like = any_cast<const Type &>(value); pointer_like) {
|
||||
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(pointer_like));
|
||||
}
|
||||
} else {
|
||||
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(value)));
|
||||
if constexpr(std::is_constructible_v<bool, Type>) {
|
||||
if(const auto &pointer_like = *static_cast<const Type *>(value); pointer_like) {
|
||||
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(pointer_like));
|
||||
}
|
||||
} else {
|
||||
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(*static_cast<const Type *>(value)));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case operation::seq:
|
||||
if constexpr(is_complete_v<meta_sequence_container_traits<Type>>) {
|
||||
static_cast<meta_sequence_container *>(other)->rebind<Type>(std::move(const_cast<any &>(value)));
|
||||
}
|
||||
break;
|
||||
case operation::assoc:
|
||||
if constexpr(is_complete_v<meta_associative_container_traits<Type>>) {
|
||||
static_cast<meta_associative_container *>(other)->rebind<Type>(std::move(const_cast<any &>(value)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr(is_complete_v<meta_sequence_container_traits<Type>>) {
|
||||
if(req == internal::meta_traits::is_meta_sequence_container) {
|
||||
const_only ? static_cast<meta_sequence_container *>(other)->rebind(*static_cast<const Type *>(value)) : static_cast<meta_sequence_container *>(other)->rebind(*static_cast<Type *>(const_cast<void *>(value)));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr(is_complete_v<meta_associative_container_traits<Type>>) {
|
||||
if(req == internal::meta_traits::is_meta_associative_container) {
|
||||
const_only ? static_cast<meta_associative_container *>(other)->rebind(*static_cast<const Type *>(value)) : static_cast<meta_associative_container *>(other)->rebind(*static_cast<Type *>(const_cast<void *>(value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void release() {
|
||||
if(node.dtor.dtor && owner()) {
|
||||
if(node.dtor.dtor && (storage.policy() == any_policy::owner)) {
|
||||
node.dtor.dtor(storage.data());
|
||||
}
|
||||
}
|
||||
@@ -418,10 +439,6 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Tries to cast an instance to a given type.
|
||||
*
|
||||
* @warning
|
||||
* Attempting to perform an invalid cast results is undefined behavior.
|
||||
*
|
||||
* @tparam Type Type to which to cast the instance.
|
||||
* @return A reference to the contained instance.
|
||||
*/
|
||||
@@ -456,7 +473,7 @@ public:
|
||||
*/
|
||||
[[nodiscard]] bool allow_cast(const meta_type &type) {
|
||||
if(auto other = std::as_const(*this).allow_cast(type); other) {
|
||||
if(other.owner()) {
|
||||
if((other.storage.policy() == any_policy::owner)) {
|
||||
std::swap(*this, other);
|
||||
}
|
||||
|
||||
@@ -488,7 +505,7 @@ public:
|
||||
* @return True if there exists a viable conversion, false otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
bool allow_cast() {
|
||||
[[nodiscard]] bool allow_cast() {
|
||||
auto other = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
|
||||
return allow_cast(meta_type{*ctx, other}) && (!(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) || storage.data() != nullptr);
|
||||
}
|
||||
@@ -521,17 +538,15 @@ public:
|
||||
* @return A sequence container proxy for the underlying object.
|
||||
*/
|
||||
[[nodiscard]] meta_sequence_container as_sequence_container() noexcept {
|
||||
any detached = storage.as_ref();
|
||||
meta_sequence_container proxy{*ctx};
|
||||
vtable(operation::seq, detached, &proxy);
|
||||
vtable(internal::meta_traits::is_meta_sequence_container, policy() == meta_any_policy::cref, std::as_const(*this).data(), &proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/*! @copydoc as_sequence_container */
|
||||
[[nodiscard]] meta_sequence_container as_sequence_container() const noexcept {
|
||||
any detached = storage.as_ref();
|
||||
meta_sequence_container proxy{*ctx};
|
||||
vtable(operation::seq, detached, &proxy);
|
||||
vtable(internal::meta_traits::is_meta_sequence_container, true, data(), &proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@@ -540,17 +555,15 @@ public:
|
||||
* @return An associative container proxy for the underlying object.
|
||||
*/
|
||||
[[nodiscard]] meta_associative_container as_associative_container() noexcept {
|
||||
any detached = storage.as_ref();
|
||||
meta_associative_container proxy{*ctx};
|
||||
vtable(operation::assoc, detached, &proxy);
|
||||
vtable(internal::meta_traits::is_meta_associative_container, policy() == meta_any_policy::cref, std::as_const(*this).data(), &proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
/*! @copydoc as_associative_container */
|
||||
[[nodiscard]] meta_associative_container as_associative_container() const noexcept {
|
||||
any detached = storage.as_ref();
|
||||
meta_associative_container proxy{*ctx};
|
||||
vtable(operation::assoc, detached, &proxy);
|
||||
vtable(internal::meta_traits::is_meta_associative_container, true, data(), &proxy);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@@ -561,7 +574,7 @@ public:
|
||||
*/
|
||||
[[nodiscard]] meta_any operator*() const noexcept {
|
||||
meta_any ret{meta_ctx_arg, *ctx};
|
||||
vtable(operation::deref, storage, &ret);
|
||||
vtable(internal::meta_traits::is_meta_pointer_like, true, storage.data(), &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -594,8 +607,16 @@ public:
|
||||
}
|
||||
|
||||
/*! @copydoc any::owner */
|
||||
[[nodiscard]] bool owner() const noexcept {
|
||||
return storage.owner();
|
||||
[[deprecated("use policy() and meta_any_policy instead")]] [[nodiscard]] bool owner() const noexcept {
|
||||
return (storage.policy() == any_policy::owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the current mode of a meta any object.
|
||||
* @return The current mode of the meta any object.
|
||||
*/
|
||||
[[nodiscard]] meta_any_policy policy() const noexcept {
|
||||
return storage.policy();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -632,8 +653,7 @@ template<typename Type>
|
||||
* @brief Opaque pointers to instances of any type.
|
||||
*
|
||||
* A handle doesn't perform copies and isn't responsible for the contained
|
||||
* object. It doesn't prolong the lifetime of the pointed instance.<br/>
|
||||
* Handles are used to generate references to actual objects when needed.
|
||||
* object. It doesn't prolong the lifetime of the pointed instance.
|
||||
*/
|
||||
struct meta_handle {
|
||||
/*! Default constructor. */
|
||||
@@ -993,8 +1013,7 @@ struct meta_func {
|
||||
* @brief Invokes the underlying function, if possible.
|
||||
*
|
||||
* @warning
|
||||
* The context of the arguments is **not** changed.<br/>
|
||||
* It's up to the caller to bind them to the right context(s).
|
||||
* The context of the arguments is **never** changed.
|
||||
*
|
||||
* @param instance An opaque instance of the underlying type.
|
||||
* @param args Parameters to use to invoke the function.
|
||||
@@ -1014,12 +1033,8 @@ struct meta_func {
|
||||
*/
|
||||
template<typename... Args>
|
||||
meta_any invoke(meta_handle instance, Args &&...args) const {
|
||||
if constexpr(sizeof...(Args) == 0u) {
|
||||
return invoke(std::move(instance), static_cast<meta_any *>(nullptr), size_type{});
|
||||
} else {
|
||||
meta_any arguments[sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
|
||||
return invoke(std::move(instance), arguments, sizeof...(Args));
|
||||
}
|
||||
meta_any arguments[sizeof...(Args) + !sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
|
||||
return invoke(std::move(instance), arguments, sizeof...(Args));
|
||||
}
|
||||
|
||||
/*! @copydoc meta_data::prop */
|
||||
@@ -1239,13 +1254,12 @@ public:
|
||||
* doesn't refer to a pointer type.
|
||||
*/
|
||||
[[nodiscard]] meta_type remove_pointer() const noexcept {
|
||||
return {*ctx, node.remove_pointer(internal::meta_context::from(*ctx))};
|
||||
return {*ctx, node.remove_pointer(internal::meta_context::from(*ctx))}; // NOLINT
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a type is a pointer-like type or not.
|
||||
* @return True if the underlying type is a pointer-like one, false
|
||||
* otherwise.
|
||||
* @return True if the underlying type is pointer-like, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool is_pointer_like() const noexcept {
|
||||
return static_cast<bool>(node.traits & internal::meta_traits::is_meta_pointer_like);
|
||||
@@ -1302,6 +1316,25 @@ public:
|
||||
return index < template_arity() ? meta_type{*ctx, node.templ.arg(internal::meta_context::from(*ctx), index)} : meta_type{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a type supports direct casting to another type.
|
||||
* @param other The meta type to test for.
|
||||
* @return True if direct casting is allowed, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool can_cast(const meta_type &other) const noexcept {
|
||||
// casting this is UB in all cases but we aren't going to use the resulting pointer, so...
|
||||
return (internal::try_cast(internal::meta_context::from(*ctx), node, other.node, this) != nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a type supports conversion it to another type.
|
||||
* @param other The meta type to test for.
|
||||
* @return True if the conversion is allowed, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool can_convert(const meta_type &other) const noexcept {
|
||||
return (internal::try_convert(internal::meta_context::from(*ctx), node, other.info(), other.is_arithmetic() || other.is_enum(), nullptr, [](const void *, auto &&...args) { return ((static_cast<void>(args), 1) + ... + 0u); }) != 0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a range to visit registered top-level base meta types.
|
||||
* @return An iterable range to visit registered top-level base meta types.
|
||||
@@ -1326,19 +1359,8 @@ public:
|
||||
* @return The registered meta data for the given identifier, if any.
|
||||
*/
|
||||
[[nodiscard]] meta_data data(const id_type id) const {
|
||||
if(node.details) {
|
||||
if(const auto it = node.details->data.find(id); it != node.details->data.cend()) {
|
||||
return meta_data{*ctx, it->second};
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &&curr: base()) {
|
||||
if(auto elem = curr.second.data(id); elem) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
return meta_data{};
|
||||
const auto *elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), node, id);
|
||||
return elem ? meta_data{*ctx, *elem} : meta_data{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1353,36 +1375,21 @@ public:
|
||||
/**
|
||||
* @brief Lookup utility for meta functions (bases are also visited).
|
||||
*
|
||||
* In case of overloaded functions, the first one with the required
|
||||
* identifier is returned.
|
||||
* In case of overloaded functions, a random one is returned.
|
||||
*
|
||||
* @param id Unique identifier.
|
||||
* @return The registered meta function for the given identifier, if any.
|
||||
*/
|
||||
[[nodiscard]] meta_func func(const id_type id) const {
|
||||
if(node.details) {
|
||||
if(const auto it = node.details->func.find(id); it != node.details->func.cend()) {
|
||||
return meta_func{*ctx, it->second};
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &&curr: base()) {
|
||||
if(auto elem = curr.second.func(id); elem) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
return meta_func{};
|
||||
const auto *elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), node, id);
|
||||
return elem ? meta_func{*ctx, *elem} : meta_func{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates an instance of the underlying type, if possible.
|
||||
*
|
||||
* If suitable, the implicitly generated default constructor is used.
|
||||
*
|
||||
* @warning
|
||||
* The context of the arguments is **not** changed.<br/>
|
||||
* It's up to the caller to bind them to the right context(s).
|
||||
* The context of the arguments is **never** changed.
|
||||
*
|
||||
* @param args Parameters to use to construct the instance.
|
||||
* @param sz Number of parameters to use to construct the instance.
|
||||
@@ -1410,12 +1417,8 @@ public:
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] meta_any construct(Args &&...args) const {
|
||||
if constexpr(sizeof...(Args) == 0u) {
|
||||
return construct(static_cast<meta_any *>(nullptr), size_type{});
|
||||
} else {
|
||||
meta_any arguments[sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
|
||||
return construct(arguments, sizeof...(Args));
|
||||
}
|
||||
meta_any arguments[sizeof...(Args) + !sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
|
||||
return construct(arguments, sizeof...(Args));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1436,8 +1439,7 @@ public:
|
||||
* @brief Invokes a function given an identifier, if possible.
|
||||
*
|
||||
* @warning
|
||||
* The context of the arguments is **not** changed.<br/>
|
||||
* It's up to the caller to bind them to the right context(s).
|
||||
* The context of the arguments is **never** changed.
|
||||
*
|
||||
* @param id Unique identifier.
|
||||
* @param instance An opaque instance of the underlying type.
|
||||
@@ -1465,7 +1467,6 @@ public:
|
||||
|
||||
/**
|
||||
* @copybrief invoke
|
||||
*
|
||||
* @param id Unique identifier.
|
||||
* @tparam Args Types of arguments to use to invoke the function.
|
||||
* @param instance An opaque instance of the underlying type.
|
||||
@@ -1474,12 +1475,8 @@ public:
|
||||
*/
|
||||
template<typename... Args>
|
||||
meta_any invoke(const id_type id, meta_handle instance, Args &&...args) const {
|
||||
if constexpr(sizeof...(Args) == 0u) {
|
||||
return invoke(id, std::move(instance), static_cast<meta_any *>(nullptr), size_type{});
|
||||
} else {
|
||||
meta_any arguments[sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
|
||||
return invoke(id, std::move(instance), arguments, sizeof...(Args));
|
||||
}
|
||||
meta_any arguments[sizeof...(Args) + !sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
|
||||
return invoke(id, std::move(instance), arguments, sizeof...(Args));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1522,19 +1519,8 @@ public:
|
||||
* @return The registered meta property for the given key, if any.
|
||||
*/
|
||||
[[nodiscard]] meta_prop prop(const id_type key) const {
|
||||
if(node.details) {
|
||||
if(const auto it = node.details->prop.find(key); it != node.details->prop.cend()) {
|
||||
return meta_prop{*ctx, it->second};
|
||||
}
|
||||
}
|
||||
|
||||
for(auto &&curr: base()) {
|
||||
if(auto elem = curr.second.prop(key); elem) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
||||
return meta_prop{};
|
||||
const auto *elem = internal::look_for<&internal::meta_type_descriptor::prop>(internal::meta_context::from(*ctx), node, key);
|
||||
return elem ? meta_prop{*ctx, *elem} : meta_prop{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1593,39 +1579,27 @@ bool meta_any::set(const id_type id, Type &&value) {
|
||||
}
|
||||
|
||||
[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const {
|
||||
if(node.info && *node.info == type.info()) {
|
||||
return as_ref();
|
||||
}
|
||||
|
||||
if(const auto *value = data(); node.details) {
|
||||
if(auto it = node.details->conv.find(type.info().hash()); it != node.details->conv.cend()) {
|
||||
return it->second.conv(*ctx, data());
|
||||
return internal::try_convert(internal::meta_context::from(*ctx), node, type.info(), type.is_arithmetic() || type.is_enum(), data(), [this, &type]([[maybe_unused]] const void *instance, auto &&...args) {
|
||||
if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, internal::meta_type_node> || ...)) {
|
||||
return (args.from_void(*ctx, nullptr, instance), ...);
|
||||
} else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, internal::meta_conv_node> || ...)) {
|
||||
return (args.conv(*ctx, instance), ...);
|
||||
} else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, decltype(internal::meta_type_node::conversion_helper)> || ...)) {
|
||||
// exploits the fact that arithmetic types and enums are also default constructible
|
||||
auto other = type.construct();
|
||||
const auto value = (args(nullptr, instance), ...);
|
||||
other.node.conversion_helper(other.data(), &value);
|
||||
return other;
|
||||
} else {
|
||||
// forwards to force a compile-time error in case of available arguments
|
||||
return meta_any{meta_ctx_arg, *ctx, std::forward<decltype(args)>(args)...};
|
||||
}
|
||||
|
||||
for(auto &&curr: node.details->base) {
|
||||
const auto &as_const = curr.second.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.second.cast(value));
|
||||
|
||||
if(auto other = as_const.allow_cast(type); other) {
|
||||
return other;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(node.conversion_helper && (type.is_arithmetic() || type.is_enum())) {
|
||||
// exploits the fact that arithmetic types and enums are also default constructible
|
||||
auto other = type.construct();
|
||||
ENTT_ASSERT(other.node.conversion_helper, "Conversion helper not found");
|
||||
const auto value = node.conversion_helper(nullptr, storage.data());
|
||||
other.node.conversion_helper(other.storage.data(), &value);
|
||||
return other;
|
||||
}
|
||||
|
||||
return meta_any{meta_ctx_arg, *ctx};
|
||||
});
|
||||
}
|
||||
|
||||
inline bool meta_any::assign(const meta_any &other) {
|
||||
auto value = other.allow_cast({*ctx, node});
|
||||
return value && storage.assign(std::move(value.storage));
|
||||
return value && storage.assign(value.storage);
|
||||
}
|
||||
|
||||
inline bool meta_any::assign(meta_any &&other) {
|
||||
@@ -1652,33 +1626,14 @@ inline bool meta_any::assign(meta_any &&other) {
|
||||
return index < arity() ? node->arg(*ctx, index) : meta_type{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
class meta_sequence_container::meta_iterator final {
|
||||
friend class meta_sequence_container;
|
||||
|
||||
enum class operation : std::uint8_t {
|
||||
incr,
|
||||
deref
|
||||
};
|
||||
|
||||
using vtable_type = void(const operation, const any &, const std::ptrdiff_t, meta_any *);
|
||||
using vtable_type = void(const void *, const std::ptrdiff_t, meta_any *);
|
||||
|
||||
template<typename It>
|
||||
static void basic_vtable(const operation op, const any &value, const std::ptrdiff_t offset, meta_any *other) {
|
||||
switch(op) {
|
||||
case operation::incr: {
|
||||
auto &it = any_cast<It &>(const_cast<any &>(value));
|
||||
it = std::next(it, offset);
|
||||
} break;
|
||||
case operation::deref: {
|
||||
const auto &it = any_cast<const It &>(value);
|
||||
other->emplace<decltype(*it)>(*it);
|
||||
} break;
|
||||
}
|
||||
static void basic_vtable(const void *value, const std::ptrdiff_t offset, meta_any *other) {
|
||||
const auto &it = *static_cast<const It *>(value);
|
||||
other ? other->emplace<decltype(*it)>(*it) : std::advance(const_cast<It &>(it), offset);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -1687,43 +1642,45 @@ public:
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::bidirectional_iterator_tag;
|
||||
|
||||
constexpr meta_iterator() noexcept
|
||||
: ctx{},
|
||||
vtable{},
|
||||
handle{} {}
|
||||
meta_iterator() noexcept
|
||||
: meta_iterator{locator<meta_ctx>::value_or()} {}
|
||||
|
||||
meta_iterator(const meta_ctx &area) noexcept
|
||||
: ctx{&area} {}
|
||||
|
||||
template<typename It>
|
||||
explicit meta_iterator(const meta_ctx &area, It iter) noexcept
|
||||
meta_iterator(const meta_ctx &area, It iter) noexcept
|
||||
: ctx{&area},
|
||||
vtable{&basic_vtable<It>},
|
||||
handle{iter} {}
|
||||
|
||||
meta_iterator &operator++() noexcept {
|
||||
vtable(operation::incr, handle, 1, nullptr);
|
||||
vtable(handle.data(), 1, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
meta_iterator operator++(int value) noexcept {
|
||||
meta_iterator orig = *this;
|
||||
vtable(operation::incr, handle, ++value, nullptr);
|
||||
vtable(handle.data(), ++value, nullptr);
|
||||
return orig;
|
||||
}
|
||||
|
||||
meta_iterator &operator--() noexcept {
|
||||
vtable(operation::incr, handle, -1, nullptr);
|
||||
vtable(handle.data(), -1, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
meta_iterator operator--(int value) noexcept {
|
||||
meta_iterator orig = *this;
|
||||
vtable(operation::incr, handle, --value, nullptr);
|
||||
vtable(handle.data(), --value, nullptr);
|
||||
return orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
reference other{meta_ctx_arg, *ctx};
|
||||
vtable(operation::deref, handle, 0, &other);
|
||||
vtable(handle.data(), 0, &other);
|
||||
return other;
|
||||
}
|
||||
|
||||
@@ -1743,35 +1700,30 @@ public:
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
[[nodiscard]] const any &base() const noexcept {
|
||||
return handle;
|
||||
}
|
||||
|
||||
private:
|
||||
const meta_ctx *ctx;
|
||||
vtable_type *vtable;
|
||||
any handle;
|
||||
const meta_ctx *ctx{};
|
||||
vtable_type *vtable{};
|
||||
any handle{};
|
||||
};
|
||||
|
||||
class meta_associative_container::meta_iterator final {
|
||||
enum class operation : std::uint8_t {
|
||||
incr,
|
||||
deref
|
||||
};
|
||||
|
||||
using vtable_type = void(const operation, const any &, std::pair<meta_any, meta_any> *);
|
||||
using vtable_type = void(const void *, std::pair<meta_any, meta_any> *);
|
||||
|
||||
template<bool KeyOnly, typename It>
|
||||
static void basic_vtable(const operation op, const any &value, std::pair<meta_any, meta_any> *other) {
|
||||
switch(op) {
|
||||
case operation::incr:
|
||||
++any_cast<It &>(const_cast<any &>(value));
|
||||
break;
|
||||
case operation::deref:
|
||||
const auto &it = any_cast<const It &>(value);
|
||||
static void basic_vtable(const void *value, std::pair<meta_any, meta_any> *other) {
|
||||
if(const auto &it = *static_cast<const It *>(value); other) {
|
||||
if constexpr(KeyOnly) {
|
||||
other->first.emplace<decltype(*it)>(*it);
|
||||
} else {
|
||||
other->first.emplace<decltype((it->first))>(it->first);
|
||||
other->second.emplace<decltype((it->second))>(it->second);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
++const_cast<It &>(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1781,31 +1733,34 @@ public:
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::forward_iterator_tag;
|
||||
|
||||
constexpr meta_iterator() noexcept
|
||||
: ctx{},
|
||||
vtable{},
|
||||
handle{} {}
|
||||
meta_iterator() noexcept
|
||||
: meta_iterator{locator<meta_ctx>::value_or()} {}
|
||||
|
||||
meta_iterator(const meta_ctx &area) noexcept
|
||||
: ctx{&area} {}
|
||||
|
||||
template<bool KeyOnly, typename It>
|
||||
meta_iterator(const meta_ctx &area, std::integral_constant<bool, KeyOnly>, It iter) noexcept
|
||||
meta_iterator(const meta_ctx &area, std::bool_constant<KeyOnly>, It iter) noexcept
|
||||
: ctx{&area},
|
||||
vtable{&basic_vtable<KeyOnly, It>},
|
||||
handle{iter} {}
|
||||
|
||||
meta_iterator &operator++() noexcept {
|
||||
vtable(operation::incr, handle, nullptr);
|
||||
vtable(handle.data(), nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
meta_iterator operator++(int) noexcept {
|
||||
meta_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
vtable(handle.data(), nullptr);
|
||||
return orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
reference other{{meta_ctx_arg, *ctx}, {meta_ctx_arg, *ctx}};
|
||||
vtable(operation::deref, handle, &other);
|
||||
vtable(handle.data(), &other);
|
||||
return other;
|
||||
}
|
||||
|
||||
@@ -1826,15 +1781,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
const meta_ctx *ctx;
|
||||
vtable_type *vtable;
|
||||
any handle;
|
||||
const meta_ctx *ctx{};
|
||||
vtable_type *vtable{};
|
||||
any handle{};
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Returns the meta value type of a container.
|
||||
@@ -1849,7 +1800,7 @@ private:
|
||||
* @return The size of the container.
|
||||
*/
|
||||
[[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const noexcept {
|
||||
return size_fn(storage);
|
||||
return size_fn(data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1858,7 +1809,7 @@ private:
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
inline bool meta_sequence_container::resize(const size_type sz) {
|
||||
return resize_fn(storage, sz);
|
||||
return !const_only && resize_fn(const_cast<void *>(data), sz);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1866,7 +1817,16 @@ inline bool meta_sequence_container::resize(const size_type sz) {
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
inline bool meta_sequence_container::clear() {
|
||||
return resize_fn(storage, 0u);
|
||||
return !const_only && clear_fn(const_cast<void *>(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserves storage for at least the given number of elements.
|
||||
* @param sz The new capacity of the container.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
inline bool meta_sequence_container::reserve(const size_type sz) {
|
||||
return !const_only && reserve_fn(const_cast<void *>(data), sz);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1874,7 +1834,7 @@ inline bool meta_sequence_container::clear() {
|
||||
* @return An iterator to the first element of the container.
|
||||
*/
|
||||
[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() {
|
||||
return iter_fn(*ctx, storage, false);
|
||||
return begin_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1882,7 +1842,7 @@ inline bool meta_sequence_container::clear() {
|
||||
* @return An iterator that is past the last element of the container.
|
||||
*/
|
||||
[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() {
|
||||
return iter_fn(*ctx, storage, true);
|
||||
return end_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1892,7 +1852,13 @@ inline bool meta_sequence_container::clear() {
|
||||
* @return A possibly invalid iterator to the inserted element.
|
||||
*/
|
||||
inline meta_sequence_container::iterator meta_sequence_container::insert(iterator it, meta_any value) {
|
||||
return insert_or_erase_fn(*ctx, storage, it.handle, value);
|
||||
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
|
||||
if(const auto vtype = value_type_node(internal::meta_context::from(*ctx)); !const_only && (value.allow_cast({*ctx, vtype}) || value.allow_cast({*ctx, const_reference_node(internal::meta_context::from(*ctx))}))) {
|
||||
const bool is_value_type = (value.type().info() == *vtype.info);
|
||||
return insert_fn(*ctx, const_cast<void *>(data), is_value_type ? std::as_const(value).data() : nullptr, is_value_type ? nullptr : std::as_const(value).data(), it);
|
||||
}
|
||||
|
||||
return iterator{*ctx};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1901,7 +1867,7 @@ inline meta_sequence_container::iterator meta_sequence_container::insert(iterato
|
||||
* @return A possibly invalid iterator following the last removed element.
|
||||
*/
|
||||
inline meta_sequence_container::iterator meta_sequence_container::erase(iterator it) {
|
||||
return insert(it, {});
|
||||
return const_only ? iterator{*ctx} : erase_fn(*ctx, const_cast<void *>(data), it);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1921,15 +1887,15 @@ inline meta_sequence_container::iterator meta_sequence_container::erase(iterator
|
||||
* @return False if the proxy is invalid, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline meta_sequence_container::operator bool() const noexcept {
|
||||
return static_cast<bool>(storage);
|
||||
return (data != nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a container is also key-only, false otherwise.
|
||||
* @return True if the associative container is also key-only, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline bool meta_associative_container::key_only() const noexcept {
|
||||
return key_only_container;
|
||||
[[deprecated("use mapped_type() instead")]] [[nodiscard]] inline bool meta_associative_container::key_only() const noexcept {
|
||||
return (mapped_type_node == nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1955,42 +1921,39 @@ inline meta_sequence_container::iterator meta_sequence_container::erase(iterator
|
||||
|
||||
/*! @copydoc meta_sequence_container::size */
|
||||
[[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const noexcept {
|
||||
return size_fn(storage);
|
||||
return size_fn(data);
|
||||
}
|
||||
|
||||
/*! @copydoc meta_sequence_container::clear */
|
||||
inline bool meta_associative_container::clear() {
|
||||
return clear_fn(storage);
|
||||
return !const_only && clear_fn(const_cast<void *>(data));
|
||||
}
|
||||
|
||||
/*! @copydoc meta_sequence_container::reserve */
|
||||
inline bool meta_associative_container::reserve(const size_type sz) {
|
||||
return !const_only && reserve_fn(const_cast<void *>(data), sz);
|
||||
}
|
||||
|
||||
/*! @copydoc meta_sequence_container::begin */
|
||||
[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() {
|
||||
return iter_fn(*ctx, storage, false);
|
||||
return begin_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
|
||||
}
|
||||
|
||||
/*! @copydoc meta_sequence_container::end */
|
||||
[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() {
|
||||
return iter_fn(*ctx, storage, true);
|
||||
return end_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts a key only element into a container.
|
||||
* @brief Inserts a key-only or key/value element into a container.
|
||||
* @param key The key of the element to insert.
|
||||
* @param value The value of the element to insert, if needed.
|
||||
* @return A bool denoting whether the insertion took place.
|
||||
*/
|
||||
inline bool meta_associative_container::insert(meta_any key) {
|
||||
meta_any value{*ctx, std::in_place_type<void>};
|
||||
return (insert_or_erase_fn(storage, key, value) != 0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts a key/value element into a container.
|
||||
* @param key The key of the element to insert.
|
||||
* @param value The value of the element to insert.
|
||||
* @return A bool denoting whether the insertion took place.
|
||||
*/
|
||||
inline bool meta_associative_container::insert(meta_any key, meta_any value) {
|
||||
return (insert_or_erase_fn(storage, key, value) != 0u);
|
||||
inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) {
|
||||
return !const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})
|
||||
&& (!mapped_type_node || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))}))
|
||||
&& insert_fn(const_cast<void *>(data), std::as_const(key).data(), std::as_const(value).data());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1999,7 +1962,7 @@ inline bool meta_associative_container::insert(meta_any key, meta_any value) {
|
||||
* @return A bool denoting whether the removal took place.
|
||||
*/
|
||||
inline meta_associative_container::size_type meta_associative_container::erase(meta_any key) {
|
||||
return insert(std::move(key), meta_any{meta_ctx_arg, *ctx});
|
||||
return (!const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(const_cast<void *>(data), std::as_const(key).data()) : 0u;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2008,7 +1971,7 @@ inline meta_associative_container::size_type meta_associative_container::erase(m
|
||||
* @return An iterator to the element with the given key, if any.
|
||||
*/
|
||||
[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) {
|
||||
return find_fn(*ctx, storage, key);
|
||||
return key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) ? find_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data, std::as_const(key).data()) : iterator{*ctx};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2016,7 +1979,7 @@ inline meta_associative_container::size_type meta_associative_container::erase(m
|
||||
* @return False if the proxy is invalid, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline meta_associative_container::operator bool() const noexcept {
|
||||
return static_cast<bool>(storage);
|
||||
return (data != nullptr);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -22,11 +22,7 @@ class meta_any;
|
||||
class meta_type;
|
||||
struct meta_handle;
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
enum class meta_traits : std::uint32_t {
|
||||
@@ -131,6 +127,23 @@ struct meta_type_node {
|
||||
std::shared_ptr<meta_type_descriptor> details{};
|
||||
};
|
||||
|
||||
template<auto Member>
|
||||
auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id) {
|
||||
if(node.details) {
|
||||
if(const auto it = (node.details.get()->*Member).find(id); it != (node.details.get()->*Member).cend()) {
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
for(auto &&curr: node.details->base) {
|
||||
if(auto *elem = look_for<Member>(context, curr.second.type(context), id); elem) {
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<typename std::remove_reference_t<decltype(node.details.get()->*Member)>::mapped_type *>(nullptr);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
meta_type_node resolve(const meta_context &) noexcept;
|
||||
|
||||
@@ -159,6 +172,31 @@ 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) {
|
||||
if(auto it = from.details->conv.find(to.hash()); it != from.details->conv.cend()) {
|
||||
return func(instance, it->second);
|
||||
}
|
||||
|
||||
for(auto &&curr: from.details->base) {
|
||||
if(auto other = try_convert(context, curr.second.type(context), to, arithmetic_or_enum, curr.second.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;
|
||||
@@ -204,7 +242,7 @@ template<typename Type>
|
||||
};
|
||||
}
|
||||
|
||||
if constexpr(!std::is_same_v<Type, void> && !std::is_function_v<Type>) {
|
||||
if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
|
||||
node.from_void = +[](const meta_ctx &ctx, void *element, const void *as_const) {
|
||||
if(element) {
|
||||
return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *static_cast<std::decay_t<Type> *>(element)};
|
||||
@@ -225,11 +263,7 @@ template<typename Type>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
} // namespace entt
|
||||
|
||||
|
||||
@@ -7,58 +7,34 @@ namespace entt {
|
||||
|
||||
/*! @brief Empty class type used to request the _as ref_ policy. */
|
||||
struct as_ref_t final {
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
/*! @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>>;
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as cref_ policy. */
|
||||
struct as_cref_t final {
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
template<typename Type>
|
||||
static constexpr bool value = std::is_reference_v<Type>;
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as-is_ policy. */
|
||||
struct as_is_t final {
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
template<typename>
|
||||
static constexpr bool value = true;
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as void_ policy. */
|
||||
struct as_void_t final {
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
template<typename>
|
||||
static constexpr bool value = true;
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,11 +10,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, typename It>
|
||||
@@ -24,6 +20,7 @@ struct meta_range_iterator final {
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using iterator_concept = std::random_access_iterator_tag;
|
||||
|
||||
constexpr meta_range_iterator() noexcept
|
||||
: it{},
|
||||
@@ -131,11 +128,7 @@ template<typename... Args>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Iterable range to use to iterate all types of meta objects.
|
||||
|
||||
@@ -313,16 +313,12 @@ template<typename Type, auto Data, typename Policy = as_is_t>
|
||||
return meta_getter<Type, Data, Policy>(locator<meta_ctx>::value_or(), std::move(instance));
|
||||
}
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
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_same_v<decltype(std::invoke(std::forward<Candidate>(candidate), args...)), void>) {
|
||||
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>};
|
||||
} else {
|
||||
@@ -339,7 +335,7 @@ template<typename Type, typename Policy, typename Candidate, std::size_t... Inde
|
||||
return meta_invoke_with_args<Policy>(ctx, std::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>>() && ...)) {
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) { // NOLINT
|
||||
return meta_invoke_with_args<Policy>(ctx, std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
} else {
|
||||
@@ -361,11 +357,7 @@ template<typename Type, typename... Args, std::size_t... Index>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Tries to _invoke_ an object given a list of erased parameters.
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
#ifndef ENTT_PLATFORM_ANDROID_NDK_R17_HPP
|
||||
#define ENTT_PLATFORM_ANDROID_NDK_R17_HPP
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
#ifdef __ANDROID__
|
||||
# include <android/ndk-version.h>
|
||||
# if __NDK_MAJOR__ == 17
|
||||
@@ -58,10 +54,6 @@ using invoke_result_t = typename std::invoke_result<Func, Args...>::type;
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
#endif
|
||||
|
||||
@@ -190,7 +190,6 @@ decltype(auto) poly_call(Poly &&self, Args &&...args) {
|
||||
*/
|
||||
template<typename Concept, std::size_t Len, std::size_t Align>
|
||||
class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, Len, Align>>> {
|
||||
/*! @brief A poly base is allowed to snoop into a poly object. */
|
||||
friend struct poly_base<basic_poly>;
|
||||
|
||||
public:
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
#define ENTT_PROCESS_FWD_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<typename, typename>
|
||||
class process;
|
||||
|
||||
template<typename = std::uint32_t>
|
||||
template<typename = std::uint32_t, typename = std::allocator<void>>
|
||||
class basic_scheduler;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
@@ -175,13 +176,13 @@ public:
|
||||
* The function is idempotent and it does nothing if the process isn't
|
||||
* alive.
|
||||
*
|
||||
* @param immediately Requests an immediate operation.
|
||||
* @param immediate Requests an immediate operation.
|
||||
*/
|
||||
void abort(const bool immediately = false) {
|
||||
void abort(const bool immediate = false) {
|
||||
if(alive()) {
|
||||
current = state::aborted;
|
||||
|
||||
if(immediately) {
|
||||
if(immediate) {
|
||||
tick({});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,56 @@
|
||||
#ifndef ENTT_PROCESS_SCHEDULER_HPP
|
||||
#define ENTT_PROCESS_SCHEDULER_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "process.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Delta>
|
||||
struct basic_process_handler {
|
||||
virtual ~basic_process_handler() = default;
|
||||
|
||||
virtual bool update(const Delta, void *) = 0;
|
||||
virtual void abort(const bool) = 0;
|
||||
|
||||
// std::shared_ptr because of its type erased allocator which is useful here
|
||||
std::shared_ptr<basic_process_handler> next;
|
||||
};
|
||||
|
||||
template<typename Delta, typename Type>
|
||||
struct process_handler final: basic_process_handler<Delta> {
|
||||
template<typename... Args>
|
||||
process_handler(Args &&...args)
|
||||
: process{std::forward<Args>(args)...} {}
|
||||
|
||||
bool update(const Delta delta, void *data) override {
|
||||
if(process.tick(delta, data); process.rejected()) {
|
||||
this->next.reset();
|
||||
}
|
||||
|
||||
return (process.rejected() || process.finished());
|
||||
}
|
||||
|
||||
void abort(const bool immediate) override {
|
||||
process.abort(immediate);
|
||||
}
|
||||
|
||||
Type process;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Cooperative scheduler for processes.
|
||||
*
|
||||
@@ -37,95 +76,90 @@ namespace entt {
|
||||
* @sa process
|
||||
*
|
||||
* @tparam Delta Type to use to provide elapsed time.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Delta>
|
||||
template<typename Delta, typename Allocator>
|
||||
class basic_scheduler {
|
||||
struct process_handler {
|
||||
using instance_type = std::unique_ptr<void, void (*)(void *)>;
|
||||
using update_fn_type = bool(basic_scheduler &, std::size_t, Delta, void *);
|
||||
using abort_fn_type = void(basic_scheduler &, std::size_t, bool);
|
||||
using next_type = std::unique_ptr<process_handler>;
|
||||
template<typename Type>
|
||||
using handler_type = internal::process_handler<Delta, Type>;
|
||||
|
||||
instance_type instance;
|
||||
update_fn_type *update;
|
||||
abort_fn_type *abort;
|
||||
next_type next;
|
||||
};
|
||||
// std::shared_ptr because of its type erased allocator which is useful here
|
||||
using process_type = std::shared_ptr<internal::basic_process_handler<Delta>>;
|
||||
|
||||
struct continuation {
|
||||
continuation(process_handler *ref) noexcept
|
||||
: handler{ref} {}
|
||||
|
||||
template<typename Proc, typename... Args>
|
||||
continuation then(Args &&...args) {
|
||||
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
|
||||
auto proc = typename process_handler::instance_type{new Proc{std::forward<Args>(args)...}, &basic_scheduler::deleter<Proc>};
|
||||
handler->next.reset(new process_handler{std::move(proc), &basic_scheduler::update<Proc>, &basic_scheduler::abort<Proc>, nullptr});
|
||||
handler = handler->next.get();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
continuation then(Func &&func) {
|
||||
return then<process_adaptor<std::decay_t<Func>, Delta>>(std::forward<Func>(func));
|
||||
}
|
||||
|
||||
private:
|
||||
process_handler *handler;
|
||||
};
|
||||
|
||||
template<typename Proc>
|
||||
[[nodiscard]] static bool update(basic_scheduler &owner, std::size_t pos, const Delta delta, void *data) {
|
||||
auto *process = static_cast<Proc *>(owner.handlers[pos].instance.get());
|
||||
process->tick(delta, data);
|
||||
|
||||
if(process->rejected()) {
|
||||
return true;
|
||||
} else if(process->finished()) {
|
||||
if(auto &&handler = owner.handlers[pos]; handler.next) {
|
||||
handler = std::move(*handler.next);
|
||||
// forces the process to exit the uninitialized state
|
||||
return handler.update(owner, pos, {}, nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Proc>
|
||||
static void abort(basic_scheduler &owner, std::size_t pos, const bool immediately) {
|
||||
static_cast<Proc *>(owner.handlers[pos].instance.get())->abort(immediately);
|
||||
}
|
||||
|
||||
template<typename Proc>
|
||||
static void deleter(void *proc) {
|
||||
delete static_cast<Proc *>(proc);
|
||||
}
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
using container_allocator = typename alloc_traits::template rebind_alloc<process_type>;
|
||||
using container_type = std::vector<process_type, container_allocator>;
|
||||
|
||||
public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using delta_type = Delta;
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using delta_type = Delta;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_scheduler()
|
||||
: handlers{} {}
|
||||
: basic_scheduler{allocator_type{}} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_scheduler(basic_scheduler &&) = default;
|
||||
/**
|
||||
* @brief Constructs a scheduler with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit basic_scheduler(const allocator_type &allocator)
|
||||
: handlers{allocator, allocator} {}
|
||||
|
||||
/*! @brief Default move assignment operator. @return This scheduler. */
|
||||
basic_scheduler &operator=(basic_scheduler &&) = default;
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_scheduler(basic_scheduler &&other) noexcept
|
||||
: handlers{std::move(other.handlers)} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
basic_scheduler(basic_scheduler &&other, const allocator_type &allocator) noexcept
|
||||
: handlers{container_type{std::move(other.handlers.first()), allocator}, allocator} {
|
||||
ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying a scheduler is not allowed");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This scheduler.
|
||||
*/
|
||||
basic_scheduler &operator=(basic_scheduler &&other) noexcept {
|
||||
ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying a scheduler is not allowed");
|
||||
handlers = std::move(other.handlers);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given scheduler.
|
||||
* @param other Scheduler to exchange the content with.
|
||||
*/
|
||||
void swap(basic_scheduler &other) {
|
||||
using std::swap;
|
||||
swap(handlers, other.handlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return handlers.second();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Number of processes currently scheduled.
|
||||
* @return Number of processes currently scheduled.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return handlers.size();
|
||||
return handlers.first().size();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +167,7 @@ public:
|
||||
* @return True if there are scheduled processes, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept {
|
||||
return handlers.empty();
|
||||
return handlers.first().empty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,15 +177,15 @@ public:
|
||||
* and never executed again.
|
||||
*/
|
||||
void clear() {
|
||||
handlers.clear();
|
||||
handlers.first().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Schedules a process for the next tick.
|
||||
*
|
||||
* Returned value is an opaque object that can be used to attach a child to
|
||||
* the given process. The child is automatically scheduled when the process
|
||||
* terminates and only if the process returns with success.
|
||||
* Returned value can be used to attach a continuation for the last process.
|
||||
* The continutation is scheduled automatically when the process terminates
|
||||
* and only if the process returns with success.
|
||||
*
|
||||
* Example of use (pseudocode):
|
||||
*
|
||||
@@ -169,16 +203,15 @@ public:
|
||||
* @tparam Proc Type of process to schedule.
|
||||
* @tparam Args Types of arguments to use to initialize the process.
|
||||
* @param args Parameters to use to initialize the process.
|
||||
* @return An opaque object to use to concatenate processes.
|
||||
* @return This process scheduler.
|
||||
*/
|
||||
template<typename Proc, typename... Args>
|
||||
auto attach(Args &&...args) {
|
||||
basic_scheduler &attach(Args &&...args) {
|
||||
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
|
||||
auto proc = typename process_handler::instance_type{new Proc{std::forward<Args>(args)...}, &basic_scheduler::deleter<Proc>};
|
||||
auto &&ref = handlers.emplace_back(process_handler{std::move(proc), &basic_scheduler::update<Proc>, &basic_scheduler::abort<Proc>, nullptr});
|
||||
auto &ref = handlers.first().emplace_back(std::allocate_shared<handler_type<Proc>>(handlers.second(), std::forward<Args>(args)...));
|
||||
// forces the process to exit the uninitialized state
|
||||
ref.update(*this, handlers.size() - 1u, {}, nullptr);
|
||||
return continuation{&handlers.back()};
|
||||
ref->update({}, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -207,9 +240,9 @@ public:
|
||||
* void();
|
||||
* @endcode
|
||||
*
|
||||
* Returned value is an opaque object that can be used to attach a child to
|
||||
* the given process. The child is automatically scheduled when the process
|
||||
* terminates and only if the process returns with success.
|
||||
* Returned value can be used to attach a continuation for the last process.
|
||||
* The continutation is scheduled automatically when the process terminates
|
||||
* and only if the process returns with success.
|
||||
*
|
||||
* Example of use (pseudocode):
|
||||
*
|
||||
@@ -230,14 +263,43 @@ public:
|
||||
*
|
||||
* @tparam Func Type of process to schedule.
|
||||
* @param func Either a lambda or a functor to use as a process.
|
||||
* @return An opaque object to use to concatenate processes.
|
||||
* @return This process scheduler.
|
||||
*/
|
||||
template<typename Func>
|
||||
auto attach(Func &&func) {
|
||||
basic_scheduler &attach(Func &&func) {
|
||||
using Proc = process_adaptor<std::decay_t<Func>, Delta>;
|
||||
return attach<Proc>(std::forward<Func>(func));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a process as a continuation of the last scheduled process.
|
||||
* @tparam Proc Type of process to use as a continuation.
|
||||
* @tparam Args Types of arguments to use to initialize the process.
|
||||
* @param args Parameters to use to initialize the process.
|
||||
* @return This process scheduler.
|
||||
*/
|
||||
template<typename Proc, typename... Args>
|
||||
basic_scheduler &then(Args &&...args) {
|
||||
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
|
||||
ENTT_ASSERT(!handlers.first().empty(), "Process not available");
|
||||
auto *curr = handlers.first().back().get();
|
||||
for(; curr->next; curr = curr->next.get()) {}
|
||||
curr->next = std::allocate_shared<handler_type<Proc>>(handlers.second(), std::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets a process as a continuation of the last scheduled process.
|
||||
* @tparam Func Type of process to use as a continuation.
|
||||
* @param func Either a lambda or a functor to use as a process.
|
||||
* @return This process scheduler.
|
||||
*/
|
||||
template<typename Func>
|
||||
basic_scheduler &then(Func &&func) {
|
||||
using Proc = process_adaptor<std::decay_t<Func>, Delta>;
|
||||
return then<Proc>(std::forward<Func>(func));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates all scheduled processes.
|
||||
*
|
||||
@@ -250,12 +312,17 @@ public:
|
||||
* @param data Optional data.
|
||||
*/
|
||||
void update(const delta_type delta, void *data = nullptr) {
|
||||
for(auto pos = handlers.size(); pos; --pos) {
|
||||
const auto curr = pos - 1u;
|
||||
|
||||
if(const auto dead = handlers[curr].update(*this, curr, delta, data); dead) {
|
||||
std::swap(handlers[curr], handlers.back());
|
||||
handlers.pop_back();
|
||||
for(auto next = handlers.first().size(); next; --next) {
|
||||
if(const auto pos = next - 1u; handlers.first()[pos]->update(delta, data)) {
|
||||
// updating might spawn/reallocate, cannot hold refs until here
|
||||
if(auto &curr = handlers.first()[pos]; curr->next) {
|
||||
curr = std::move(curr->next);
|
||||
// forces the process to exit the uninitialized state
|
||||
curr->update({}, nullptr);
|
||||
} else {
|
||||
curr = std::move(handlers.first().back());
|
||||
handlers.first().pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,17 +335,16 @@ public:
|
||||
* Once a process is fully aborted and thus finished, it's discarded along
|
||||
* with its child, if any.
|
||||
*
|
||||
* @param immediately Requests an immediate operation.
|
||||
* @param immediate Requests an immediate operation.
|
||||
*/
|
||||
void abort(const bool immediately = false) {
|
||||
for(auto pos = handlers.size(); pos; --pos) {
|
||||
const auto curr = pos - 1u;
|
||||
handlers[curr].abort(*this, curr, immediately);
|
||||
void abort(const bool immediate = false) {
|
||||
for(auto &&curr: handlers.first()) {
|
||||
curr->abort(immediate);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<process_handler> handlers{};
|
||||
compressed_pair<container_type, allocator_type> handlers;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
@@ -19,11 +19,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, typename It>
|
||||
@@ -37,6 +33,7 @@ public:
|
||||
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;
|
||||
|
||||
constexpr resource_cache_iterator() noexcept = default;
|
||||
|
||||
@@ -144,11 +141,7 @@ template<typename... Lhs, typename... Rhs>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Basic cache for resources of any type.
|
||||
|
||||
@@ -20,7 +20,6 @@ namespace entt {
|
||||
*/
|
||||
template<typename Type>
|
||||
class resource {
|
||||
/*! @brief Resource handles are friends with each other. */
|
||||
template<typename>
|
||||
friend class resource;
|
||||
|
||||
|
||||
@@ -12,11 +12,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
@@ -43,11 +39,7 @@ template<typename... Class, typename Ret, typename... Args>
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Basic delegate implementation.
|
||||
|
||||
@@ -17,11 +17,7 @@
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
namespace internal {
|
||||
|
||||
struct basic_dispatcher_handler {
|
||||
@@ -82,7 +78,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t size() const noexcept override {
|
||||
[[nodiscard]] std::size_t size() const noexcept override {
|
||||
return events.size();
|
||||
}
|
||||
|
||||
@@ -92,11 +88,7 @@ private:
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Basic dispatcher implementation.
|
||||
@@ -190,7 +182,6 @@ public:
|
||||
*/
|
||||
basic_dispatcher &operator=(basic_dispatcher &&other) noexcept {
|
||||
ENTT_ASSERT(alloc_traits::is_always_equal::value || pools.second() == other.pools.second(), "Copying a dispatcher is not allowed");
|
||||
|
||||
pools = std::move(other.pools);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ class sigh;
|
||||
*/
|
||||
template<typename Ret, typename... Args, typename Allocator>
|
||||
class sigh<Ret(Args...), Allocator> {
|
||||
/*! @brief A sink is allowed to modify a signal. */
|
||||
friend class sink<sigh<Ret(Args...), Allocator>>;
|
||||
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
@@ -225,7 +224,6 @@ private:
|
||||
* the sink that generated it.
|
||||
*/
|
||||
class connection {
|
||||
/*! @brief A sink is allowed to create connection objects. */
|
||||
template<typename>
|
||||
friend class sink;
|
||||
|
||||
|
||||
1
test/.bazelrc
Normal file
1
test/.bazelrc
Normal file
@@ -0,0 +1 @@
|
||||
import "%workspace%/../.bazelrc"
|
||||
0
test/BUILD.bazel
Normal file
0
test/BUILD.bazel
Normal file
@@ -1,6 +1,4 @@
|
||||
#
|
||||
# Tests configuration
|
||||
#
|
||||
|
||||
include(FetchContent)
|
||||
include(CheckCXXSourceCompiles)
|
||||
@@ -34,9 +32,16 @@ else()
|
||||
add_library(GTest::Main ALIAS gtest_main)
|
||||
|
||||
target_compile_features(gtest PUBLIC cxx_std_17)
|
||||
set_target_properties(gtest PROPERTIES CXX_CLANG_TIDY "")
|
||||
|
||||
target_compile_features(gtest_main PUBLIC cxx_std_17)
|
||||
set_target_properties(gtest_main PROPERTIES CXX_CLANG_TIDY "")
|
||||
|
||||
target_compile_features(gmock PUBLIC cxx_std_17)
|
||||
set_target_properties(gmock PROPERTIES CXX_CLANG_TIDY "")
|
||||
|
||||
target_compile_features(gmock_main PUBLIC cxx_std_17)
|
||||
set_target_properties(gmock_main PROPERTIES CXX_CLANG_TIDY "")
|
||||
endif()
|
||||
|
||||
include_directories($<TARGET_PROPERTY:EnTT,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
@@ -64,10 +69,20 @@ function(SETUP_TARGET TARGET_NAME)
|
||||
>
|
||||
# documentation diagnostic turned on for clang-cl only
|
||||
$<$<STREQUAL:"${CMAKE_CXX_COMPILER_ID}","Clang">:-Wdocumentation>
|
||||
# warnings from compilers that think I don't know what I'm doing
|
||||
$<$<STREQUAL:"${CMAKE_CXX_COMPILER_ID}","Clang">:-Wcomma>
|
||||
/EHsc /wd4324 /wd4996
|
||||
$<$<CONFIG:Debug>:/Od>
|
||||
# disabling INCREMENTAL is required by SizeBench
|
||||
$<$<CONFIG:Debug>:/Od /INCREMENTAL:NO>
|
||||
$<$<CONFIG:Release>:/O2>
|
||||
)
|
||||
|
||||
target_link_options(
|
||||
${TARGET_NAME}
|
||||
PRIVATE
|
||||
# disabling INCREMENTAL is required by SizeBench
|
||||
$<$<CONFIG:Debug>:/INCREMENTAL:NO>
|
||||
)
|
||||
else()
|
||||
target_compile_options(
|
||||
${TARGET_NAME}
|
||||
@@ -105,6 +120,7 @@ function(SETUP_BASIC_TEST TEST_NAME TEST_SOURCES)
|
||||
target_link_libraries(${TEST_NAME} PRIVATE GTest::Main Threads::Threads)
|
||||
SETUP_TARGET(${TEST_NAME} ${ARGN})
|
||||
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
|
||||
set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT 60)
|
||||
endfunction()
|
||||
|
||||
function(SETUP_LIB_SHARED_TEST TEST_NAME SUB_PATH)
|
||||
@@ -112,6 +128,7 @@ function(SETUP_LIB_SHARED_TEST TEST_NAME SUB_PATH)
|
||||
add_library(_${TARGET_NAME} SHARED $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/${SUB_PATH}/lib.cpp)
|
||||
SETUP_TARGET(_${TARGET_NAME} ENTT_API_EXPORT)
|
||||
SETUP_BASIC_TEST(lib_${TARGET_NAME} lib/${TEST_NAME}/${SUB_PATH}/main.cpp ENTT_API_IMPORT)
|
||||
set_target_properties(lib_${TARGET_NAME} PROPERTIES CXX_CLANG_TIDY "")
|
||||
target_link_libraries(lib_${TARGET_NAME} PRIVATE _${TARGET_NAME})
|
||||
endfunction()
|
||||
|
||||
@@ -120,6 +137,8 @@ function(SETUP_LIB_PLUGIN_TEST TEST_NAME SUB_PATH)
|
||||
add_library(_${TARGET_NAME} MODULE $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/${SUB_PATH}/plugin.cpp)
|
||||
SETUP_TARGET(_${TARGET_NAME} ${ARGVN})
|
||||
SETUP_BASIC_TEST(lib_${TARGET_NAME} lib/${TEST_NAME}/${SUB_PATH}/main.cpp PLUGIN="$<TARGET_FILE:_${TARGET_NAME}>" ${ARGVN})
|
||||
set_target_properties(_${TARGET_NAME} PROPERTIES CXX_CLANG_TIDY "")
|
||||
set_target_properties(lib_${TARGET_NAME} PROPERTIES CXX_CLANG_TIDY "")
|
||||
target_include_directories(_${TARGET_NAME} PRIVATE ${cr_INCLUDE_DIR})
|
||||
target_include_directories(lib_${TARGET_NAME} PRIVATE ${cr_INCLUDE_DIR})
|
||||
target_link_libraries(lib_${TARGET_NAME} PRIVATE ${CMAKE_DL_LIBS})
|
||||
@@ -130,6 +149,7 @@ endfunction()
|
||||
|
||||
if(ENTT_BUILD_BENCHMARK)
|
||||
SETUP_BASIC_TEST(benchmark benchmark/benchmark.cpp)
|
||||
set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
|
||||
endif()
|
||||
|
||||
# Test example
|
||||
@@ -137,6 +157,7 @@ endif()
|
||||
if(ENTT_BUILD_EXAMPLE)
|
||||
SETUP_BASIC_TEST(custom_identifier example/custom_identifier.cpp)
|
||||
SETUP_BASIC_TEST(entity_copy example/entity_copy.cpp)
|
||||
SETUP_BASIC_TEST(reserved_bits example/reserved_bits.cpp)
|
||||
SETUP_BASIC_TEST(signal_less example/signal_less.cpp)
|
||||
endif()
|
||||
|
||||
@@ -180,7 +201,7 @@ if(ENTT_BUILD_SNAPSHOT)
|
||||
FetchContent_Declare(
|
||||
cereal
|
||||
GIT_REPOSITORY https://github.com/USCiLab/cereal.git
|
||||
GIT_TAG v1.2.2
|
||||
GIT_TAG v1.3.2
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
@@ -192,6 +213,8 @@ if(ENTT_BUILD_SNAPSHOT)
|
||||
endif()
|
||||
|
||||
SETUP_BASIC_TEST(cereal snapshot/snapshot.cpp)
|
||||
|
||||
set_target_properties(cereal PROPERTIES CXX_CLANG_TIDY "")
|
||||
target_include_directories(cereal PRIVATE ${cereal_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
@@ -237,6 +260,8 @@ SETUP_BASIC_TEST(snapshot entt/entity/snapshot.cpp)
|
||||
SETUP_BASIC_TEST(sparse_set entt/entity/sparse_set.cpp)
|
||||
SETUP_BASIC_TEST(storage entt/entity/storage.cpp)
|
||||
SETUP_BASIC_TEST(storage_entity entt/entity/storage_entity.cpp)
|
||||
SETUP_BASIC_TEST(storage_no_instance entt/entity/storage_no_instance.cpp)
|
||||
SETUP_BASIC_TEST(storage_utility entt/entity/storage_utility.cpp)
|
||||
SETUP_BASIC_TEST(view entt/entity/view.cpp)
|
||||
|
||||
# Test graph
|
||||
|
||||
11
test/MODULE.bazel
Normal file
11
test/MODULE.bazel
Normal file
@@ -0,0 +1,11 @@
|
||||
module(name = "entt_test")
|
||||
|
||||
bazel_dep(name = "rules_cc", version = "0.0.8")
|
||||
bazel_dep(name = "bazel_skylib", version = "1.4.2")
|
||||
bazel_dep(name = "googletest", version = "1.14.0")
|
||||
bazel_dep(name = "entt")
|
||||
|
||||
local_path_override(
|
||||
module_name = "entt",
|
||||
path = "..",
|
||||
)
|
||||
1
test/WORKSPACE.bazel
Normal file
1
test/WORKSPACE.bazel
Normal file
@@ -0,0 +1 @@
|
||||
# SEE: MODULE.bazel
|
||||
File diff suppressed because it is too large
Load Diff
10
test/entt/common/BUILD.bazel
Normal file
10
test/entt/common/BUILD.bazel
Normal file
@@ -0,0 +1,10 @@
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library")
|
||||
load("@entt//bazel:copts.bzl", "COPTS")
|
||||
|
||||
package(default_visibility = ["//:__subpackages__"])
|
||||
|
||||
cc_library(
|
||||
name = "common",
|
||||
copts = COPTS,
|
||||
hdrs = glob(["*.h", "*.hpp"]),
|
||||
)
|
||||
25
test/entt/common/aggregate.h
Normal file
25
test/entt/common/aggregate.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef ENTT_COMMON_AGGREGATE_H
|
||||
#define ENTT_COMMON_AGGREGATE_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace test {
|
||||
|
||||
struct aggregate {
|
||||
int value{};
|
||||
};
|
||||
|
||||
inline bool operator==(const aggregate &lhs, const aggregate &rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
inline bool operator<(const aggregate &lhs, const aggregate &rhs) {
|
||||
return lhs.value < rhs.value;
|
||||
}
|
||||
|
||||
// ensure aggregate-ness :)
|
||||
static_assert(std::is_aggregate_v<test::aggregate>, "Not an aggregate type");
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
@@ -16,6 +16,11 @@ struct basic_test_allocator: std::allocator<Type> {
|
||||
|
||||
using std::allocator<Type>::allocator;
|
||||
|
||||
// necessary to avoid a warning by clang-cl :)
|
||||
basic_test_allocator(const basic_test_allocator &other)
|
||||
: base{other} {
|
||||
}
|
||||
|
||||
basic_test_allocator &operator=(const basic_test_allocator &other) {
|
||||
// necessary to avoid call suppression
|
||||
base::operator=(other);
|
||||
|
||||
16
test/entt/common/boxed_int.h
Normal file
16
test/entt/common/boxed_int.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef ENTT_COMMON_BOXED_INT_H
|
||||
#define ENTT_COMMON_BOXED_INT_H
|
||||
|
||||
namespace test {
|
||||
|
||||
struct boxed_int {
|
||||
int value{};
|
||||
};
|
||||
|
||||
inline bool operator==(const boxed_int &lhs, const boxed_int &rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
@@ -5,10 +5,12 @@ namespace test {
|
||||
|
||||
#ifdef NDEBUG
|
||||
# define ENTT_DEBUG_TEST(Case, Test) TEST(Case, DISABLED_##Test)
|
||||
# define ENTT_DEBUG_TEST_P(Case, Test) TEST_P(Case, DISABLED_##Test)
|
||||
# define ENTT_DEBUG_TEST_F(Case, Test) TEST_F(Case, DISABLED_##Test)
|
||||
# define ENTT_DEBUG_TYPED_TEST(Case, Test) TYPED_TEST(Case, DISABLED_##Test)
|
||||
#else
|
||||
# define ENTT_DEBUG_TEST(Case, Test) TEST(Case, Test)
|
||||
# define ENTT_DEBUG_TEST_P(Case, Test) TEST_P(Case, Test)
|
||||
# define ENTT_DEBUG_TEST_F(Case, Test) TEST_F(Case, Test)
|
||||
# define ENTT_DEBUG_TYPED_TEST(Case, Test) TYPED_TEST(Case, Test)
|
||||
#endif
|
||||
|
||||
12
test/entt/common/custom_entity.h
Normal file
12
test/entt/common/custom_entity.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef ENTT_COMMON_CUSTOM_ENTITY_H
|
||||
#define ENTT_COMMON_CUSTOM_ENTITY_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace test {
|
||||
|
||||
enum custom_entity : std::uint32_t {};
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
10
test/entt/common/empty.h
Normal file
10
test/entt/common/empty.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef ENTT_COMMON_EMPTY_H
|
||||
#define ENTT_COMMON_EMPTY_H
|
||||
|
||||
namespace test {
|
||||
|
||||
struct empty {};
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
11
test/entt/common/linter.hpp
Normal file
11
test/entt/common/linter.hpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef ENTT_COMMON_LINTER_HPP
|
||||
#define ENTT_COMMON_LINTER_HPP
|
||||
|
||||
namespace test {
|
||||
|
||||
template<typename Type>
|
||||
void is_initialized(Type &) {}
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
12
test/entt/common/non_comparable.h
Normal file
12
test/entt/common/non_comparable.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef ENTT_COMMON_NON_COMPARABLE_H
|
||||
#define ENTT_COMMON_NON_COMPARABLE_H
|
||||
|
||||
namespace test {
|
||||
|
||||
struct non_comparable {
|
||||
bool operator==(const non_comparable &) const = delete;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
17
test/entt/common/non_default_constructible.h
Normal file
17
test/entt/common/non_default_constructible.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef ENTT_COMMON_NON_DEFAULT_CONSTRUCTIBLE_H
|
||||
#define ENTT_COMMON_NON_DEFAULT_CONSTRUCTIBLE_H
|
||||
|
||||
namespace test {
|
||||
|
||||
struct non_default_constructible {
|
||||
non_default_constructible() = delete;
|
||||
|
||||
non_default_constructible(int v)
|
||||
: value{v} {}
|
||||
|
||||
int value;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
20
test/entt/common/non_movable.h
Normal file
20
test/entt/common/non_movable.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef ENTT_COMMON_NON_MOVABLE_H
|
||||
#define ENTT_COMMON_NON_MOVABLE_H
|
||||
|
||||
namespace test {
|
||||
|
||||
struct non_movable {
|
||||
non_movable() = default;
|
||||
|
||||
non_movable(const non_movable &) = default;
|
||||
non_movable(non_movable &&) = delete;
|
||||
|
||||
non_movable &operator=(const non_movable &) = default;
|
||||
non_movable &operator=(non_movable &&) = delete;
|
||||
|
||||
int value{};
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
21
test/entt/common/pointer_stable.h
Normal file
21
test/entt/common/pointer_stable.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef ENTT_COMMON_POINTER_STABLE_H
|
||||
#define ENTT_COMMON_POINTER_STABLE_H
|
||||
|
||||
namespace test {
|
||||
|
||||
struct pointer_stable {
|
||||
static constexpr auto in_place_delete = true;
|
||||
int value{};
|
||||
};
|
||||
|
||||
inline bool operator==(const pointer_stable &lhs, const pointer_stable &rhs) {
|
||||
return lhs.value == rhs.value;
|
||||
}
|
||||
|
||||
inline bool operator<(const pointer_stable &lhs, const pointer_stable &rhs) {
|
||||
return lhs.value < rhs.value;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
@@ -2,19 +2,22 @@
|
||||
#define ENTT_COMMON_THROWING_ALLOCATOR_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <entt/container/dense_map.hpp>
|
||||
#include <entt/core/fwd.hpp>
|
||||
#include <entt/core/type_info.hpp>
|
||||
|
||||
namespace test {
|
||||
|
||||
struct throwing_allocator_exception {};
|
||||
|
||||
template<typename Type>
|
||||
class throwing_allocator: std::allocator<Type> {
|
||||
class throwing_allocator {
|
||||
template<typename Other>
|
||||
friend class throwing_allocator;
|
||||
|
||||
using base = std::allocator<Type>;
|
||||
struct test_exception {};
|
||||
|
||||
public:
|
||||
using value_type = Type;
|
||||
using pointer = value_type *;
|
||||
@@ -23,33 +26,42 @@ public:
|
||||
using const_void_pointer = const void *;
|
||||
using propagate_on_container_move_assignment = std::true_type;
|
||||
using propagate_on_container_swap = std::true_type;
|
||||
using exception_type = test_exception;
|
||||
using container_type = entt::dense_map<entt::id_type, std::size_t>;
|
||||
|
||||
template<typename Other>
|
||||
struct rebind {
|
||||
using other = throwing_allocator<Other>;
|
||||
};
|
||||
|
||||
throwing_allocator() = default;
|
||||
throwing_allocator()
|
||||
: allocator{},
|
||||
config{std::allocate_shared<container_type>(allocator)} {}
|
||||
|
||||
template<typename Other>
|
||||
throwing_allocator(const throwing_allocator<Other> &other)
|
||||
: base{other} {}
|
||||
: allocator{other.allocator},
|
||||
config{other.config} {}
|
||||
|
||||
pointer allocate(std::size_t length) {
|
||||
if(trigger_on_allocate) {
|
||||
trigger_on_allocate = false;
|
||||
throw test_exception{};
|
||||
if(const auto hash = entt::type_id<Type>().hash(); config->contains(hash)) {
|
||||
if(auto &elem = (*config)[hash]; elem == 0u) {
|
||||
config->erase(hash);
|
||||
throw throwing_allocator_exception{};
|
||||
} else {
|
||||
--elem;
|
||||
}
|
||||
}
|
||||
|
||||
trigger_on_allocate = trigger_after_allocate;
|
||||
trigger_after_allocate = false;
|
||||
|
||||
return base::allocate(length);
|
||||
return allocator.allocate(length);
|
||||
}
|
||||
|
||||
void deallocate(pointer mem, std::size_t length) {
|
||||
base::deallocate(mem, length);
|
||||
allocator.deallocate(mem, length);
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
void throw_counter(const std::size_t len) {
|
||||
(*config)[entt::type_id<Other>().hash()] = len;
|
||||
}
|
||||
|
||||
bool operator==(const throwing_allocator<Type> &) const {
|
||||
@@ -60,8 +72,9 @@ public:
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
static inline bool trigger_on_allocate{};
|
||||
static inline bool trigger_after_allocate{};
|
||||
private:
|
||||
std::allocator<Type> allocator;
|
||||
std::shared_ptr<container_type> config;
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
|
||||
@@ -3,44 +3,40 @@
|
||||
|
||||
namespace test {
|
||||
|
||||
class throwing_type {
|
||||
struct test_exception {};
|
||||
struct throwing_type_exception {};
|
||||
|
||||
public:
|
||||
using exception_type = test_exception;
|
||||
static constexpr auto moved_from_value = -1;
|
||||
|
||||
throwing_type(int value)
|
||||
: data{value} {}
|
||||
struct throwing_type {
|
||||
throwing_type(bool mode)
|
||||
: trigger{mode} {}
|
||||
|
||||
throwing_type(const throwing_type &other)
|
||||
: data{other.data} {
|
||||
if(data == trigger_on_value) {
|
||||
data = moved_from_value;
|
||||
throw exception_type{};
|
||||
: trigger{other.trigger} {
|
||||
if(trigger) {
|
||||
throw throwing_type_exception{};
|
||||
}
|
||||
}
|
||||
|
||||
throwing_type &operator=(const throwing_type &other) {
|
||||
if(other.data == trigger_on_value) {
|
||||
data = moved_from_value;
|
||||
throw exception_type{};
|
||||
}
|
||||
|
||||
data = other.data;
|
||||
trigger = other.trigger;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator int() const {
|
||||
return data;
|
||||
void throw_on_copy(const bool mode) noexcept {
|
||||
trigger = mode;
|
||||
}
|
||||
|
||||
static inline int trigger_on_value{};
|
||||
bool throw_on_copy() const noexcept {
|
||||
return trigger;
|
||||
}
|
||||
|
||||
private:
|
||||
int data{};
|
||||
bool trigger{};
|
||||
};
|
||||
|
||||
inline bool operator==(const throwing_type &lhs, const throwing_type &rhs) {
|
||||
return lhs.throw_on_copy() == rhs.throw_on_copy();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user