Compare commits
645 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e0747fd50 | ||
|
|
1bcc87c916 | ||
|
|
45797907d3 | ||
|
|
3498dea486 | ||
|
|
a4aab8458b | ||
|
|
534744d615 | ||
|
|
dc5450b95e | ||
|
|
9e0e276740 | ||
|
|
1c9c02f3ce | ||
|
|
7774f9f402 | ||
|
|
5607219945 | ||
|
|
69ef3efd2d | ||
|
|
36c118922b | ||
|
|
1d014953e3 | ||
|
|
c5cb1d9bcc | ||
|
|
86d12cf317 | ||
|
|
db9e59ede1 | ||
|
|
cc9b1b0a05 | ||
|
|
5c29de2013 | ||
|
|
559db104f8 | ||
|
|
365c57be4c | ||
|
|
6f0c84fc68 | ||
|
|
75782d9e99 | ||
|
|
69ddf4936e | ||
|
|
4b3108283f | ||
|
|
12d177a6c8 | ||
|
|
54717dc7e2 | ||
|
|
631c909abd | ||
|
|
208746f28f | ||
|
|
61c5f8ae22 | ||
|
|
4e0cca3a08 | ||
|
|
b86ffc2370 | ||
|
|
33574c9885 | ||
|
|
672c542f99 | ||
|
|
f741fe48a1 | ||
|
|
4347ebcee2 | ||
|
|
4e3e5a5361 | ||
|
|
8e6439c3d1 | ||
|
|
b54d358feb | ||
|
|
78baa7b12d | ||
|
|
19f1dd22e9 | ||
|
|
73f583f68a | ||
|
|
52de43e329 | ||
|
|
49ddacaac0 | ||
|
|
4533b3a1c0 | ||
|
|
f30ea02794 | ||
|
|
7112dda299 | ||
|
|
02636a7108 | ||
|
|
36a9456e0d | ||
|
|
113893dcea | ||
|
|
1abbe9c7b2 | ||
|
|
7205ac791c | ||
|
|
3335b81ad4 | ||
|
|
d9c9438f3c | ||
|
|
37250843e1 | ||
|
|
072ab88721 | ||
|
|
c208e6b107 | ||
|
|
65f3185b39 | ||
|
|
34f73f8a2b | ||
|
|
cb4142a97d | ||
|
|
80d08d5a34 | ||
|
|
052aecf533 | ||
|
|
7bde714f18 | ||
|
|
5ff429f656 | ||
|
|
92f27299e1 | ||
|
|
f9013375f8 | ||
|
|
f18b0045ba | ||
|
|
18173cc4c0 | ||
|
|
6a1ffdd7a5 | ||
|
|
8db78b2190 | ||
|
|
3fcccae241 | ||
|
|
6ff8add164 | ||
|
|
58a8c3c82a | ||
|
|
92c5c656c7 | ||
|
|
61856cd648 | ||
|
|
687f82b5c2 | ||
|
|
920c864bed | ||
|
|
1360c985b7 | ||
|
|
b6f953e13b | ||
|
|
796b96071b | ||
|
|
ec56ccc690 | ||
|
|
95931b67e1 | ||
|
|
706bbb83c9 | ||
|
|
43099f47d0 | ||
|
|
eca86999c3 | ||
|
|
a00b44a5fd | ||
|
|
5b8dcff2a4 | ||
|
|
e4d36e4982 | ||
|
|
adfdbf138d | ||
|
|
8d1ba26492 | ||
|
|
792625f763 | ||
|
|
5e8eae4ef8 | ||
|
|
148212da96 | ||
|
|
23ddb12529 | ||
|
|
186a5e8f7b | ||
|
|
dfb5fe1e04 | ||
|
|
640f75373e | ||
|
|
46e5d96ced | ||
|
|
ad3fbe2052 | ||
|
|
cd6c60fd46 | ||
|
|
f7be386d5a | ||
|
|
89b2131052 | ||
|
|
e5d1ca2e3c | ||
|
|
32b8224afd | ||
|
|
00e7ab1db8 | ||
|
|
e376a53b09 | ||
|
|
17a9cd5666 | ||
|
|
fc3de662c3 | ||
|
|
8de568c2fc | ||
|
|
55661883d9 | ||
|
|
b59d3ebeaa | ||
|
|
2866dcdd03 | ||
|
|
b147f9d58c | ||
|
|
8e2a6470ac | ||
|
|
19230f7672 | ||
|
|
764dfbe46a | ||
|
|
0ec7631310 | ||
|
|
0b39ece990 | ||
|
|
97500dff57 | ||
|
|
dc6299a029 | ||
|
|
58b1e2fb98 | ||
|
|
0302fdaaba | ||
|
|
09b260e0af | ||
|
|
24b7e998b2 | ||
|
|
19068ea5c7 | ||
|
|
b5cd3eb468 | ||
|
|
91a2b5a5f7 | ||
|
|
0096f6d962 | ||
|
|
87cfe41b15 | ||
|
|
c490086097 | ||
|
|
5b3fd7537e | ||
|
|
2cab2583c0 | ||
|
|
a40a3b594d | ||
|
|
0fa586a3d8 | ||
|
|
25977cc569 | ||
|
|
0be7064493 | ||
|
|
0b13dc254a | ||
|
|
c1e953ab6e | ||
|
|
a069764af1 | ||
|
|
3dbe6c3902 | ||
|
|
9f0b380024 | ||
|
|
193b102013 | ||
|
|
511fde91fa | ||
|
|
16e3cfc589 | ||
|
|
ed2012a36c | ||
|
|
46598fde32 | ||
|
|
94d0c5fa5c | ||
|
|
4e72291588 | ||
|
|
74cdf000b4 | ||
|
|
565dc3327b | ||
|
|
462af21793 | ||
|
|
94af659c86 | ||
|
|
b63c9fc67b | ||
|
|
f519b55a47 | ||
|
|
2fb039b429 | ||
|
|
4bce5aed77 | ||
|
|
eca6032306 | ||
|
|
dd2f515af1 | ||
|
|
df25482643 | ||
|
|
df016b3bf9 | ||
|
|
8699e96609 | ||
|
|
b0dcaaf744 | ||
|
|
7db001995c | ||
|
|
c88adf9314 | ||
|
|
b13713ce98 | ||
|
|
66b89d170f | ||
|
|
4311e2e686 | ||
|
|
fd566eff7a | ||
|
|
efaa3f9e55 | ||
|
|
b625ff0902 | ||
|
|
fee80321ef | ||
|
|
4b9331f086 | ||
|
|
df9316b896 | ||
|
|
dae5f86d4e | ||
|
|
75a0cefcb3 | ||
|
|
2271aa5b89 | ||
|
|
b668e2a967 | ||
|
|
ce44c59547 | ||
|
|
84802d931d | ||
|
|
8183c4383e | ||
|
|
af249098cd | ||
|
|
8fdd063f00 | ||
|
|
fe328f6a75 | ||
|
|
ef7163acd6 | ||
|
|
6e45f0d5b8 | ||
|
|
ff41faa3fe | ||
|
|
acb2d332ea | ||
|
|
0fb86f21e4 | ||
|
|
e4991d367e | ||
|
|
3144cfafd5 | ||
|
|
c538067544 | ||
|
|
f8e137a1dc | ||
|
|
36ea38fd91 | ||
|
|
baae5a7215 | ||
|
|
a4b267227e | ||
|
|
58dd159699 | ||
|
|
80082f9d51 | ||
|
|
7975ffc10b | ||
|
|
012083a4a1 | ||
|
|
3c67723e83 | ||
|
|
7f0598b3cb | ||
|
|
c5b27e0ae0 | ||
|
|
4e7ad31f18 | ||
|
|
c7a3e9d4ac | ||
|
|
a05e7a84c4 | ||
|
|
389cb85410 | ||
|
|
81ae2bed25 | ||
|
|
0ab71bc2e7 | ||
|
|
81e6bbe643 | ||
|
|
c4723f3b24 | ||
|
|
df4d8e0411 | ||
|
|
4f1820bcad | ||
|
|
e375097e43 | ||
|
|
c51bec0034 | ||
|
|
081c3fdb5b | ||
|
|
f1e7602775 | ||
|
|
acd75ffe1c | ||
|
|
fc813cb59b | ||
|
|
044d14f542 | ||
|
|
28b9f07b99 | ||
|
|
6f20dd4e45 | ||
|
|
2fc05e5b90 | ||
|
|
9afde31f97 | ||
|
|
e835ce0697 | ||
|
|
6030f56c76 | ||
|
|
ba89b53c63 | ||
|
|
1bfb877a3b | ||
|
|
72776d6fb6 | ||
|
|
7bb93420c4 | ||
|
|
bb1b0e0581 | ||
|
|
45ddcf0df9 | ||
|
|
9c4d7a286f | ||
|
|
7b290b43b5 | ||
|
|
2e2782b030 | ||
|
|
48f23bd1ba | ||
|
|
3ece33b26a | ||
|
|
efa98379b0 | ||
|
|
324aeba70f | ||
|
|
7b6715c7b5 | ||
|
|
1ea392b6c9 | ||
|
|
8b1a3849e6 | ||
|
|
e1d7e98c92 | ||
|
|
04b2e1152c | ||
|
|
d392eba4a0 | ||
|
|
799dec4f1c | ||
|
|
11df6ec927 | ||
|
|
03e363f5d9 | ||
|
|
39211889b0 | ||
|
|
db44549276 | ||
|
|
49e702c0c7 | ||
|
|
c9c5214b3e | ||
|
|
24a537d154 | ||
|
|
c32ecf171b | ||
|
|
a62ae21628 | ||
|
|
12f05e8f72 | ||
|
|
81fb727d20 | ||
|
|
e7655c761d | ||
|
|
464fcf4300 | ||
|
|
73b67ea9df | ||
|
|
04a9c80c14 | ||
|
|
80b5ed3d22 | ||
|
|
be5ad379b6 | ||
|
|
13d901fbfa | ||
|
|
f7e7273e91 | ||
|
|
4b3bd265a6 | ||
|
|
42dcec961b | ||
|
|
6b2a3b2916 | ||
|
|
930f9ca436 | ||
|
|
a96a767b9b | ||
|
|
36627dbe78 | ||
|
|
f86bc31cbb | ||
|
|
4a08ca4b5e | ||
|
|
e857aa0640 | ||
|
|
d3c98ad334 | ||
|
|
00dadfe14d | ||
|
|
f26fa92d47 | ||
|
|
7458072df2 | ||
|
|
89aa2a1902 | ||
|
|
7ab08779dc | ||
|
|
46b686910b | ||
|
|
940a799207 | ||
|
|
778cee3b27 | ||
|
|
fb3252732b | ||
|
|
608f7b75e2 | ||
|
|
83853c3dee | ||
|
|
8a0343ad6b | ||
|
|
92d43ce620 | ||
|
|
6943822fed | ||
|
|
aa146c4125 | ||
|
|
b8ec6babb5 | ||
|
|
505f4a2b4f | ||
|
|
1bb0d017c3 | ||
|
|
f33ce615d9 | ||
|
|
0edb49d7c6 | ||
|
|
1fa5a03605 | ||
|
|
fc6bda5cd8 | ||
|
|
59589b6a71 | ||
|
|
57b0624a0a | ||
|
|
2f22395eea | ||
|
|
21bc8d4dfb | ||
|
|
2e74fd8196 | ||
|
|
fee48ab04c | ||
|
|
591f885e67 | ||
|
|
ef803016c0 | ||
|
|
bac51045e5 | ||
|
|
cb5e9393a4 | ||
|
|
097509dd2a | ||
|
|
6cd44248c7 | ||
|
|
1fd61fbcef | ||
|
|
cd2245ef03 | ||
|
|
5ddc746915 | ||
|
|
f7d67067ad | ||
|
|
d1a824f76e | ||
|
|
d7b0fc09d7 | ||
|
|
2d07a6ec1f | ||
|
|
014ba5a7aa | ||
|
|
2f12e524dd | ||
|
|
ea6af75e8e | ||
|
|
a595c6ec6f | ||
|
|
98f785d199 | ||
|
|
a0ed0c864f | ||
|
|
d4ac42749e | ||
|
|
86414671d6 | ||
|
|
6cb935982d | ||
|
|
39ad040d8a | ||
|
|
4cc3824653 | ||
|
|
6d3e0600a1 | ||
|
|
b52c9c1676 | ||
|
|
f7506251fe | ||
|
|
5b06f298f1 | ||
|
|
dc5488a198 | ||
|
|
23d162e9e4 | ||
|
|
de6b660b12 | ||
|
|
60c175a51d | ||
|
|
c0a39c8064 | ||
|
|
61f4f93cc6 | ||
|
|
764404a472 | ||
|
|
04da85c88a | ||
|
|
9551b7a597 | ||
|
|
f1d537d035 | ||
|
|
b43e723c84 | ||
|
|
5466039c1a | ||
|
|
74e11117be | ||
|
|
e0abab2dc4 | ||
|
|
08ff3ff55c | ||
|
|
0b79d99cac | ||
|
|
38f655e7b8 | ||
|
|
6f546ffe95 | ||
|
|
ef8211a46e | ||
|
|
52ea5e4074 | ||
|
|
99621cf08a | ||
|
|
a9ae9ce758 | ||
|
|
fc5a529df8 | ||
|
|
bc1081550d | ||
|
|
e311ab1605 | ||
|
|
994ade0638 | ||
|
|
cf9522bd3b | ||
|
|
7fd1858db0 | ||
|
|
c41509151b | ||
|
|
4e12853d4a | ||
|
|
e1fadbc9b9 | ||
|
|
3c4d13d8b9 | ||
|
|
732159db07 | ||
|
|
00894eaccf | ||
|
|
17818178cf | ||
|
|
89c0abfada | ||
|
|
8bbdd92739 | ||
|
|
f724ceb052 | ||
|
|
b7ac85005f | ||
|
|
8ec899a8e7 | ||
|
|
1013c6a50e | ||
|
|
2cd5d3bab3 | ||
|
|
d9494960a2 | ||
|
|
c0eb6590da | ||
|
|
a9cefcb823 | ||
|
|
d1ff491010 | ||
|
|
2aa34f05d3 | ||
|
|
135d6915ee | ||
|
|
6282195b80 | ||
|
|
adec4f08c6 | ||
|
|
b24fe2f122 | ||
|
|
7b35bcb68a | ||
|
|
4b629045c3 | ||
|
|
c6ba1d05d1 | ||
|
|
3adac90573 | ||
|
|
0332188b6b | ||
|
|
790a1e2812 | ||
|
|
3bd1e13321 | ||
|
|
0cd642ca11 | ||
|
|
d5995998b0 | ||
|
|
62babb9c22 | ||
|
|
b98c69521b | ||
|
|
6cd37b3809 | ||
|
|
238170d0e2 | ||
|
|
6fb5b25530 | ||
|
|
d63f9e1eff | ||
|
|
461865bf3b | ||
|
|
e95d9b9cf6 | ||
|
|
c52b2a4fa9 | ||
|
|
d0ec5d2da0 | ||
|
|
6134058abc | ||
|
|
bd4121c260 | ||
|
|
fbab047d7f | ||
|
|
e216144d07 | ||
|
|
94d5b11191 | ||
|
|
d3c89da2eb | ||
|
|
754a8a637e | ||
|
|
ab24a50de7 | ||
|
|
8099dde34b | ||
|
|
99198fb07f | ||
|
|
18d02a0c95 | ||
|
|
e6cac7d5fb | ||
|
|
d8d6f00fee | ||
|
|
ef5c1a1099 | ||
|
|
2d92d8ee67 | ||
|
|
ae60266477 | ||
|
|
88da5261fc | ||
|
|
15efe9f702 | ||
|
|
badbc5c66e | ||
|
|
d6eea41e13 | ||
|
|
6a2c54adf5 | ||
|
|
75d4bc7c18 | ||
|
|
834f7feb27 | ||
|
|
5d2af3f9e1 | ||
|
|
60e8e4a82a | ||
|
|
92e23476ab | ||
|
|
4560fef058 | ||
|
|
c5d6574617 | ||
|
|
de61a0ca45 | ||
|
|
98470caae1 | ||
|
|
53486c067b | ||
|
|
5b805852fa | ||
|
|
94d02eeb4e | ||
|
|
dbfec1b247 | ||
|
|
a9a1a71145 | ||
|
|
91537bf5f3 | ||
|
|
1baad08288 | ||
|
|
1c5b846488 | ||
|
|
6867760cc4 | ||
|
|
516a9209b7 | ||
|
|
e352c953dc | ||
|
|
f455846d18 | ||
|
|
6d45ac942d | ||
|
|
48939abafa | ||
|
|
fbc9595f12 | ||
|
|
ed2c714419 | ||
|
|
ef7731fb8b | ||
|
|
b5ec03f585 | ||
|
|
a8b224a364 | ||
|
|
3f3943a233 | ||
|
|
4171b4ae47 | ||
|
|
baa4c44632 | ||
|
|
ffed8f37de | ||
|
|
8978a0d159 | ||
|
|
4d09be0cd3 | ||
|
|
987be01bd6 | ||
|
|
7f59fc6321 | ||
|
|
feeb122c0d | ||
|
|
0754f108c9 | ||
|
|
ea82f86749 | ||
|
|
7bd217386a | ||
|
|
1f1e02fee1 | ||
|
|
6d1e4fb3da | ||
|
|
9090f84611 | ||
|
|
8e5ddba173 | ||
|
|
86fccb5071 | ||
|
|
414c3baf15 | ||
|
|
bbbddbf617 | ||
|
|
7638b5a95e | ||
|
|
3df6b05c00 | ||
|
|
8566c58f2b | ||
|
|
33ccb71526 | ||
|
|
2b07b92039 | ||
|
|
959bc269e4 | ||
|
|
8609068dbf | ||
|
|
d6cea80768 | ||
|
|
0f2d6fb324 | ||
|
|
f5d303045c | ||
|
|
ad61b0c84e | ||
|
|
18373bb679 | ||
|
|
c30dfe3bfe | ||
|
|
4993961c16 | ||
|
|
89aece7c28 | ||
|
|
ec96946513 | ||
|
|
e49aa0d424 | ||
|
|
b5c929572a | ||
|
|
394822aa50 | ||
|
|
d12ba5e527 | ||
|
|
ab316bcb2e | ||
|
|
93fc08df45 | ||
|
|
266dd02ef5 | ||
|
|
61c1e359e9 | ||
|
|
32c83986e5 | ||
|
|
f64af2e69d | ||
|
|
6e925c7cdd | ||
|
|
5f50f776c6 | ||
|
|
946ccf3db4 | ||
|
|
7a0aea390b | ||
|
|
ff0e6315f9 | ||
|
|
b7fb485349 | ||
|
|
45cbe66d5d | ||
|
|
bc7a6399c1 | ||
|
|
2d5a3f24aa | ||
|
|
1639429edd | ||
|
|
f81abf4883 | ||
|
|
dcddb7d50e | ||
|
|
42a763031c | ||
|
|
0964ca5918 | ||
|
|
4e870b83cd | ||
|
|
0b19c9be0b | ||
|
|
ac655902a0 | ||
|
|
e4fb293b55 | ||
|
|
d3df64ef4b | ||
|
|
93e3d14f34 | ||
|
|
bc687d412d | ||
|
|
71e85b44b0 | ||
|
|
d4b59aff97 | ||
|
|
e3c21e1f3d | ||
|
|
e012250e0a | ||
|
|
c6bf82664c | ||
|
|
c61e98009f | ||
|
|
44bccaaad6 | ||
|
|
aebca14dea | ||
|
|
4576f27f6e | ||
|
|
0c213fca40 | ||
|
|
891f596191 | ||
|
|
eb2b724902 | ||
|
|
1f8c896181 | ||
|
|
12b39e1fbe | ||
|
|
206d31f27a | ||
|
|
6709331182 | ||
|
|
9460e04ea5 | ||
|
|
462bfea733 | ||
|
|
a2d61dfaeb | ||
|
|
538425e35c | ||
|
|
2e86c1f1a2 | ||
|
|
8aa4d46ce0 | ||
|
|
cdf67a1421 | ||
|
|
93d905d93d | ||
|
|
2c35203647 | ||
|
|
216871fe56 | ||
|
|
03511f39b1 | ||
|
|
5ad0832b22 | ||
|
|
d49e7ba4b2 | ||
|
|
a621b36389 | ||
|
|
d093df02ac | ||
|
|
2e1529e78d | ||
|
|
90be1db402 | ||
|
|
29265e4181 | ||
|
|
2689a7ef13 | ||
|
|
88b58cf23d | ||
|
|
e2e433480b | ||
|
|
b8bc3e4e94 | ||
|
|
c28f52b816 | ||
|
|
ca34309f75 | ||
|
|
ea614a0f3f | ||
|
|
3e7dc7af29 | ||
|
|
0b3e3fd19a | ||
|
|
d3372dc05c | ||
|
|
7d141cb183 | ||
|
|
755699c31b | ||
|
|
acf3d4cd74 | ||
|
|
92414c91b5 | ||
|
|
ff67f402bb | ||
|
|
f048a3f1d8 | ||
|
|
9d39cb51cf | ||
|
|
7624a9d34c | ||
|
|
0fe73fb6ed | ||
|
|
ae11652493 | ||
|
|
0ab46870ae | ||
|
|
a5381374b8 | ||
|
|
7fae655651 | ||
|
|
3d9959c8e5 | ||
|
|
bc86576aa8 | ||
|
|
7c2bce8baf | ||
|
|
b062bbf58d | ||
|
|
8e5a048913 | ||
|
|
ff642ffff7 | ||
|
|
656c12cebd | ||
|
|
48f3fcf3bd | ||
|
|
d797af695b | ||
|
|
75e0161c5f | ||
|
|
c0662816f1 | ||
|
|
415a31ce23 | ||
|
|
6e603e2e51 | ||
|
|
9af318a767 | ||
|
|
30827120f6 | ||
|
|
6194e12616 | ||
|
|
59a27fb652 | ||
|
|
f8ec57c2f6 | ||
|
|
844ef5e232 | ||
|
|
5bf3f7b77e | ||
|
|
00c0afd093 | ||
|
|
5228739c87 | ||
|
|
0f6d1268c7 | ||
|
|
b2a4515d2b | ||
|
|
3576c80d33 | ||
|
|
77afd2d36c | ||
|
|
e6ddd5d9c2 | ||
|
|
b9bf1a234e | ||
|
|
0ce9122449 | ||
|
|
dc41657872 | ||
|
|
64d9380031 | ||
|
|
eca7484e30 | ||
|
|
2b5c393a13 | ||
|
|
0817d416a3 | ||
|
|
ccff753305 | ||
|
|
11481a430a | ||
|
|
e252b22735 | ||
|
|
a32ca8eb1d | ||
|
|
1979a2279f | ||
|
|
1434f942dd | ||
|
|
955d325f07 | ||
|
|
3fac3fe2d7 | ||
|
|
6ff217e74e | ||
|
|
cd667fe34b | ||
|
|
3d6202ecfd | ||
|
|
c40f0ef2bb | ||
|
|
c4b169edd1 | ||
|
|
c6bba98828 | ||
|
|
e5d4f1bb58 | ||
|
|
cf522d60ca | ||
|
|
daf72a7c61 | ||
|
|
f116ad0594 | ||
|
|
e59d40834d | ||
|
|
d06328af7f | ||
|
|
baa9d7d836 | ||
|
|
b030df55ee | ||
|
|
64eb8a2d0d | ||
|
|
7d7c36e0c7 | ||
|
|
9ad5768050 | ||
|
|
1cafbcff38 | ||
|
|
4bbf93fd0c | ||
|
|
120918bc37 | ||
|
|
253448cffb | ||
|
|
26f19fb90e | ||
|
|
e8f982e909 | ||
|
|
0fa433187e | ||
|
|
b0069299ea | ||
|
|
375d5d3e9b | ||
|
|
2d9398ae1a | ||
|
|
fc69e91636 | ||
|
|
5c56cbd672 | ||
|
|
a42255158d | ||
|
|
f3d10a97df |
41
.clang-format
Normal file
41
.clang-format
Normal file
@@ -0,0 +1,41 @@
|
||||
BasedOnStyle: llvm
|
||||
---
|
||||
AccessModifierOffset: -4
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeTernaryOperators: true
|
||||
ColumnLimit: 0
|
||||
DerivePointerAlignment: false
|
||||
IncludeCategories:
|
||||
- Regex: '<[[:alnum:]_]+>'
|
||||
Priority: 1
|
||||
- Regex: '<(gtest|gmock)/'
|
||||
Priority: 2
|
||||
- Regex: '<[[:alnum:]_./]+>'
|
||||
Priority: 3
|
||||
- Regex: '<entt/'
|
||||
Priority: 4
|
||||
- Regex: '.*'
|
||||
Priority: 5
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
PointerAlignment: Right
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceAroundPointerQualifiers: After
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: Never
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
Standard: Latest
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
139
.github/workflows/build.yml
vendored
139
.github/workflows/build.yml
vendored
@@ -9,34 +9,36 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [
|
||||
g++-7, g++-8, g++-9, g++,
|
||||
clang++-8, clang++-9, clang++
|
||||
]
|
||||
compiler:
|
||||
- pkg: g++-7
|
||||
exe: g++-7
|
||||
- pkg: g++-8
|
||||
exe: g++-8
|
||||
- pkg: g++-9
|
||||
exe: g++-9
|
||||
- pkg: g++
|
||||
exe: g++
|
||||
- pkg: clang-8
|
||||
exe: clang++-8
|
||||
- pkg: clang-9
|
||||
exe: clang++-9
|
||||
- pkg: clang-10
|
||||
exe: clang++-10
|
||||
- pkg: clang
|
||||
exe: clang++
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install g++-7
|
||||
if: ${{ matrix.compiler == 'g++-7' }}
|
||||
- name: Install compiler
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install g++-7 -y
|
||||
- name: Install g++-8
|
||||
if: ${{ matrix.compiler == 'g++-8' }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install g++-8 -y
|
||||
- name: Install clang-8
|
||||
if: ${{ matrix.compiler == 'clang++-8' }}
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install clang-8 -y
|
||||
sudo apt-get install ${{ matrix.compiler.pkg }} -y
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
CXX: ${{ matrix.compiler.exe }}
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
|
||||
make -j4
|
||||
@@ -44,27 +46,52 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 10 -C Debug -j4
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
linux-extra:
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [g++, clang++]
|
||||
id_type: [uint32, uint64]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
include:
|
||||
- id_type: uint64
|
||||
id_type_variable: -DENTT_ID_TYPE=std::uint64_t
|
||||
- cxx_std: cxx_std_20
|
||||
cxx_std_variable: -DENTT_CXX_STD=cxx_std_20
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=ON ${{ matrix.id_type_variable }} ${{ matrix.cxx_std_variable }} ..
|
||||
make -j4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
windows:
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, windows-2016]
|
||||
toolset: [clang-cl, default, v141]
|
||||
include:
|
||||
- toolset: clang-cl
|
||||
toolset_option: -T"ClangCl"
|
||||
- toolset: v141
|
||||
toolset_option: -T"v141"
|
||||
exclude:
|
||||
- os: windows-2016
|
||||
toolset: clang-cl
|
||||
- os: windows-2016
|
||||
toolset: v141
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -77,7 +104,35 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 10 -C Debug -j4
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
windows-extra:
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
id_type: [uint32, uint64]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
include:
|
||||
- id_type: uint64
|
||||
id_type_variable: -DENTT_ID_TYPE=std::uint64_t
|
||||
- cxx_std: cxx_std_20
|
||||
cxx_std_variable: -DENTT_CXX_STD=cxx_std_20
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=ON ${{ matrix.id_type_variable }} ${{ matrix.cxx_std_variable }} ..
|
||||
cmake --build . -j 4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
macos:
|
||||
timeout-minutes: 10
|
||||
@@ -94,4 +149,32 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 10 -C Debug -j4
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
macos-extra:
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
id_type: [uint32, uint64]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
include:
|
||||
- id_type: uint64
|
||||
id_type_variable: -DENTT_ID_TYPE=std::uint64_t
|
||||
- cxx_std: cxx_std_20
|
||||
cxx_std_variable: -DENTT_CXX_STD=cxx_std_20
|
||||
|
||||
runs-on: macOS-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=ON ${{ matrix.id_type_variable }} ${{ matrix.cxx_std_variable }} ..
|
||||
make -j4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
6
.github/workflows/coverage.yml
vendored
6
.github/workflows/coverage.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 10 -C Debug -j4
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
- name: Collect data
|
||||
working-directory: build
|
||||
run: |
|
||||
@@ -30,9 +30,9 @@ jobs:
|
||||
lcov -c -d . -o coverage.info
|
||||
lcov -l coverage.info
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v1
|
||||
uses: codecov/codecov-action@v2
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
file: build/coverage.info
|
||||
files: build/coverage.info
|
||||
name: EnTT
|
||||
fail_ci_if_error: true
|
||||
|
||||
11
.github/workflows/sanitizer.yml
vendored
11
.github/workflows/sanitizer.yml
vendored
@@ -10,6 +10,13 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [clang++]
|
||||
id_type: [uint32, uint64]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
include:
|
||||
- id_type: uint64
|
||||
id_type_variable: -DENTT_ID_TYPE=std::uint64_t
|
||||
- cxx_std: cxx_std_20
|
||||
cxx_std_variable: -DENTT_CXX_STD=cxx_std_20
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -20,10 +27,10 @@ jobs:
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
run: |
|
||||
cmake -DENTT_USE_SANITIZER=ON -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
|
||||
cmake -DENTT_USE_SANITIZER=ON -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.id_type_variable }} ${{ matrix.cxx_std_variable }} ..
|
||||
make -j4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 10 -C Debug -j4
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@ conan/test_package/build
|
||||
.vscode
|
||||
.vs
|
||||
CMakeSettings.json
|
||||
cpp.hint
|
||||
|
||||
# Bazel
|
||||
/bazel-*
|
||||
|
||||
160
CMakeLists.txt
160
CMakeLists.txt
@@ -30,7 +30,7 @@ project(
|
||||
VERSION ${ENTT_VERSION}
|
||||
DESCRIPTION "Gaming meets modern C++ - a fast and reliable entity-component system (ECS) and much more"
|
||||
HOMEPAGE_URL "https://github.com/skypjack/entt"
|
||||
LANGUAGES CXX
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
@@ -42,37 +42,64 @@ message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||
message(VERBOSE "* Copyright (c) 2017-2021 Michele Caini <michele.caini@gmail.com>")
|
||||
message(VERBOSE "*")
|
||||
|
||||
option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if availbale." ON)
|
||||
option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags" OFF)
|
||||
|
||||
#
|
||||
# Compiler stuff
|
||||
#
|
||||
|
||||
if(NOT WIN32 AND ENTT_USE_LIBCPP)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CMakePushCheckState)
|
||||
option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if availbale." OFF)
|
||||
option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags if availbale." OFF)
|
||||
|
||||
cmake_push_check_state()
|
||||
if(ENTT_USE_LIBCPP)
|
||||
if(NOT WIN32)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CMakePushCheckState)
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++")
|
||||
cmake_push_check_state()
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include<type_traits>
|
||||
int main() { return std::is_same_v<int, char>; }
|
||||
" ENTT_HAS_LIBCPP)
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++")
|
||||
|
||||
if(NOT ENTT_HAS_LIBCPP)
|
||||
message(VERBOSE "The option ENTT_USE_LIBCPP is set (by default) but libc++ is not available. The flag will not be added to the target.")
|
||||
check_cxx_source_compiles("
|
||||
#include<type_traits>
|
||||
int main() { return std::is_same_v<int, char>; }
|
||||
" ENTT_HAS_LIBCPP)
|
||||
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
|
||||
cmake_pop_check_state()
|
||||
if(NOT ENTT_HAS_LIBCPP)
|
||||
message(VERBOSE "The option ENTT_USE_LIBCPP is set but libc++ is not available. The flag will not be added to the target.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENTT_USE_SANITIZER)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||
set(ENTT_HAS_SANITIZER TRUE CACHE BOOL "" FORCE)
|
||||
mark_as_advanced(ENTT_HAS_SANITIZER)
|
||||
endif()
|
||||
|
||||
if(NOT ENTT_HAS_SANITIZER)
|
||||
message(VERBOSE "The option ENTT_USE_SANITIZER is set but sanitizer support is not available. The flags will not be added to the target.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# Add EnTT target
|
||||
#
|
||||
|
||||
option(ENTT_INCLUDE_HEADERS "Add all EnTT headers to the EnTT target." OFF)
|
||||
option(ENTT_INCLUDE_NATVIS "Add EnTT natvis files to the EnTT target." OFF)
|
||||
|
||||
if(ENTT_INCLUDE_NATVIS)
|
||||
if(MSVC)
|
||||
set(ENTT_HAS_NATVIS TRUE CACHE BOOL "" FORCE)
|
||||
mark_as_advanced(ENTT_HAS_NATVIS)
|
||||
endif()
|
||||
|
||||
if(NOT ENTT_HAS_NATVIS)
|
||||
message(VERBOSE "The option ENTT_INCLUDE_NATVIS is set but natvis files are not supported. They will not be added to the target.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
add_library(EnTT INTERFACE)
|
||||
@@ -85,7 +112,101 @@ target_include_directories(
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
if(ENTT_USE_SANITIZER)
|
||||
target_compile_features(EnTT INTERFACE cxx_std_17)
|
||||
|
||||
if(ENTT_INCLUDE_HEADERS)
|
||||
target_sources(
|
||||
EnTT
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/config.h>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/version.h>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_hash_map.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_hash_set.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/algorithm.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/any.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/attribute.h>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/compressed_pair.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/enum.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/family.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/hashed_string.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/ident.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/iterator.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/memory.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/monostate.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/tuple.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_info.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_traits.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/utility.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/component.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/entity.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/group.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/handle.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/helper.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/observer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/organizer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/registry.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/runtime_view.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/snapshot.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/sparse_set.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/storage.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/utility.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/view.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/locator/locator.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/adl_pointer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/container.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/ctx.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/factory.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/meta.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/node.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/pointer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/policy.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/range.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/resolve.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/template.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/type_traits.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/utility.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/platform/android-ndk-r17.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/poly.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/process.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/scheduler.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/cache.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/handle.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/loader.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/delegate.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/dispatcher.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/emitter.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/sigh.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entt.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/fwd.hpp>
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENTT_HAS_NATVIS)
|
||||
target_sources(
|
||||
EnTT
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/config.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/container.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/core.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/entity.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/locator.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/meta.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/platform.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/poly.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/process.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/resource.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/signal.natvis>
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENTT_HAS_SANITIZER)
|
||||
target_compile_options(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
|
||||
target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
|
||||
endif()
|
||||
@@ -94,8 +215,6 @@ if(ENTT_HAS_LIBCPP)
|
||||
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
|
||||
endif()
|
||||
|
||||
target_compile_features(EnTT INTERFACE cxx_std_17)
|
||||
|
||||
#
|
||||
# Install pkg-config file
|
||||
#
|
||||
@@ -174,6 +293,9 @@ if(ENTT_BUILD_TESTING)
|
||||
option(ENTT_BUILD_LIB "Build lib tests." OFF)
|
||||
option(ENTT_BUILD_SNAPSHOT "Build snapshot test with Cereal." OFF)
|
||||
|
||||
set(ENTT_ID_TYPE std::uint32_t CACHE STRING "Type of identifiers to use for the tests")
|
||||
set(ENTT_CXX_STD cxx_std_17 CACHE STRING "C++ standard revision to use for the tests")
|
||||
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2021 Michele Caini
|
||||
Copyright (c) 2017-2021 Michele Caini, author of EnTT
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
40
README.md
40
README.md
@@ -49,6 +49,7 @@ Many thanks to [these people](https://skypjack.github.io/sponsorship/) and
|
||||
* [Integration](#integration)
|
||||
* [Requirements](#requirements)
|
||||
* [CMake](#cmake)
|
||||
* [Natvis support](#natvis-support)
|
||||
* [Packaging Tools](#packaging-tools)
|
||||
* [pkg-config](#pkg-config)
|
||||
* [Documentation](#documentation)
|
||||
@@ -73,30 +74,33 @@ This project started off as a pure entity-component system. Over time the
|
||||
codebase has grown as more and more classes and functionalities were added.<br/>
|
||||
Here is a brief, yet incomplete list of what it offers today:
|
||||
|
||||
* Statically generated integer **identifiers** for types (assigned either at
|
||||
compile-time or at runtime).
|
||||
* Built-in **RTTI system** mostly similar to the standard one.
|
||||
* A `constexpr` utility for human readable **resource names**.
|
||||
* A minimal **configuration system** built using the monostate pattern.
|
||||
* An incredibly fast **entity-component system** based on sparse sets, with its
|
||||
own _pay for what you use_ policy to adjust performance and memory usage
|
||||
according to the users' requirements.
|
||||
* Minimal **configuration system** built using the monostate pattern.
|
||||
* Incredibly fast **entity-component system** with its own _pay for what you
|
||||
use_ policy.
|
||||
* Views and groups to iterate entities and components and allow different access
|
||||
patterns, from **perfect SoA** to fully random.
|
||||
* A lot of **facilities** built on top of the entity-component system to help
|
||||
the users and avoid reinventing the wheel (dependencies, snapshot, handles,
|
||||
support for **reactive systems** and so on).
|
||||
the users and avoid reinventing the wheel.
|
||||
* The smallest and most basic implementation of a **service locator** ever seen.
|
||||
* A built-in, non-intrusive and macro-free runtime **reflection system**.
|
||||
* **Static polymorphism** made simple and within everyone's reach.
|
||||
* A few homemade containers, like a sparse set based **dense hash map**.
|
||||
* A **cooperative scheduler** for processes of any type.
|
||||
* All that is needed for **resource management** (cache, loaders, handles).
|
||||
* Delegates, **signal handlers** (with built-in support for collectors) and a
|
||||
tiny event dispatcher for immediate and delayed events to integrate in loops.
|
||||
* Delegates, **signal handlers** and a tiny event dispatcher.
|
||||
* A general purpose **event emitter** as a CRTP idiom based class template.
|
||||
* And **much more**! Check out the
|
||||
[**wiki**](https://github.com/skypjack/entt/wiki).
|
||||
|
||||
Consider this list a work in progress as well as the project. The whole API is
|
||||
**Breaking news**:
|
||||
|
||||
* The ECS allows attaching multiple components of the same type to an entity.
|
||||
* All tools work perfectly across boundaries (DLL-friendly)!!
|
||||
:slightly_smiling_face:
|
||||
|
||||
Consider these lists a work in progress as well as the project. The whole API is
|
||||
fully documented in-code for those who are brave enough to read it.
|
||||
|
||||
It is also known that `EnTT` is used in **Minecraft**.<br/>
|
||||
@@ -246,6 +250,14 @@ Covering all possible cases would require a treaty and not a simple README file,
|
||||
but I'm confident that anyone reading this section also knows what it's about
|
||||
and can use `EnTT` from a `CMake` project without problems.
|
||||
|
||||
## Natvis support
|
||||
|
||||
When using `CMake`, just enable the option `ENTT_INCLUDE_NATVIS` and enjoy
|
||||
it.<br/>
|
||||
Otherwise, most of the tools are covered via Natvis and all files can be found
|
||||
in the `natvis` directory, divided by module.<br/>
|
||||
If you spot errors or have suggestions, any contribution is welcome!
|
||||
|
||||
## Packaging Tools
|
||||
|
||||
`EnTT` is available for some of the most known packaging tools. In particular:
|
||||
@@ -265,6 +277,12 @@ and can use `EnTT` from a `CMake` project without problems.
|
||||
$ vcpkg install entt
|
||||
```
|
||||
|
||||
Or you can use the `experimental` feature to test the latest changes:
|
||||
|
||||
```
|
||||
vcpkg install entt[experimental] --head
|
||||
```
|
||||
|
||||
The `EnTT` port in `vcpkg` is kept up to date by Microsoft team members and
|
||||
community contributors.<br/>
|
||||
If the version is out of date, please
|
||||
|
||||
40
TODO
40
TODO
@@ -1,31 +1,25 @@
|
||||
* long term feature: shared_ptr less locator and resource cache
|
||||
* custom allocators and EnTT allocator-aware in general (long term feature, I don't actually need it at the moment) - see #22
|
||||
* debugging tools (#60): the issue online already contains interesting tips on this, look at it
|
||||
* work stealing job system (see #100) + mt scheduler based on const awareness for types
|
||||
* allow to replace std:: with custom implementations
|
||||
* add examples (and credits) from @alanjfs :)
|
||||
* custom pools example (multi instance, tables, enable/disable, and so on...)
|
||||
|
||||
WIP:
|
||||
* HP: see msvc only issue at https://godbolt.org/z/8KW9PhG4c
|
||||
* HP: scheduler, use any (or poly?) instead of unique_ptr
|
||||
* HP: any and the like: remove constructor that accepts reference wrapper, allow only in-place T& and entt::make_any<T>(...)
|
||||
* HP: resource, forward the id to the loader from the cache and if constexpr the call to load, update doc and describe customization points
|
||||
* HP: make it possible to create views of the type `view<T, T>`, add get by index and such, allow to register custom pools by name with the registry
|
||||
* HP: add user data to type_info
|
||||
* HP: make pools available (registry/view/group), review operator| for views
|
||||
* HP: any_vector for context variables
|
||||
* HP: make const registry::view thread safe, switch to a view<T...>{registry} model (long term goal)
|
||||
* HP: weak reference wrapper example with custom storage
|
||||
* HP: paginate pools
|
||||
* HP: headless (sparse set only) view
|
||||
* HP: write documentation for custom storages and views!!
|
||||
* HP: registry: use a poly object for pools, no more pool_data type.
|
||||
* HP: make runtime views use opaque storage and therefore return also elements.
|
||||
* HP: add exclude-only views to combine with packs
|
||||
* HP: entity-aware observer, add observer functions aside observer class
|
||||
* add the possibility of disabling entities without deleting components thanks to the new full check
|
||||
* add registry::storage id -> basic_sparse_set (no template arg), add example of use
|
||||
* fast-contains for sparse sets (low prio but nice-to-have)
|
||||
* runtime events (dispatcher/emitter), runtime context variables...
|
||||
* runtime_view/registry, remove reference to basic_sparse_set<E>
|
||||
* dedicated entity storage, in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
|
||||
* custom allocators all over
|
||||
|
||||
WIP:
|
||||
* customizable any_vtable, sfinae-friendly definition and op::custom for user-def
|
||||
* resource, forward the id to the loader from the cache and if constexpr the call to load, update doc and describe customization points
|
||||
* add user data to type_info
|
||||
* headless (sparse set only) view
|
||||
* write documentation for custom storages and views!!
|
||||
* make runtime views use opaque storage and therefore return also elements.
|
||||
* add exclude-only views to combine with packs
|
||||
* entity-aware observer, add observer functions aside observer class
|
||||
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
|
||||
* pagination doesn't work nicely across boundaries probably, give it a look. RO operations are fine, adding components maybe not.
|
||||
* snapshot: support for range-based archives
|
||||
* page size 0 -> page less mode
|
||||
* add example: 64 bit ids with 32 bits reserved for users' purposes
|
||||
|
||||
@@ -17,6 +17,7 @@ add_custom_target(
|
||||
SOURCES
|
||||
dox/extra.dox
|
||||
md/config.md
|
||||
md/container.md
|
||||
md/core.md
|
||||
md/entity.md
|
||||
md/faq.md
|
||||
|
||||
154
docs/doxy.in
154
docs/doxy.in
@@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.8.20
|
||||
# Doxyfile 1.9.1
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project.
|
||||
@@ -313,7 +313,10 @@ OPTIMIZE_OUTPUT_SLICE = NO
|
||||
# Note: For files without extension you can use no_extension as a placeholder.
|
||||
#
|
||||
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
|
||||
# the files are not read by doxygen.
|
||||
# the files are not read by doxygen. When specifying no_extension you should add
|
||||
# * to the FILE_PATTERNS.
|
||||
#
|
||||
# Note see also the list of default file extension mappings.
|
||||
|
||||
EXTENSION_MAPPING =
|
||||
|
||||
@@ -523,6 +526,13 @@ EXTRACT_LOCAL_METHODS = NO
|
||||
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
|
||||
# If this flag is set to YES, the name of an unnamed parameter in a declaration
|
||||
# will be determined by the corresponding definition. By default unnamed
|
||||
# parameters remain unnamed in the output.
|
||||
# The default value is: YES.
|
||||
|
||||
RESOLVE_UNNAMED_PARAMS = YES
|
||||
|
||||
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
|
||||
# undocumented members inside documented classes or files. If set to NO these
|
||||
# members will be included in the various overviews, but no documentation
|
||||
@@ -560,11 +570,18 @@ HIDE_IN_BODY_DOCS = NO
|
||||
|
||||
INTERNAL_DOCS = NO
|
||||
|
||||
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
|
||||
# names in lower-case letters. If set to YES, upper-case letters are also
|
||||
# allowed. This is useful if you have classes or files whose names only differ
|
||||
# in case and if your file system supports case sensitive file names. Windows
|
||||
# (including Cygwin) and Mac users are advised to set this option to NO.
|
||||
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
|
||||
# able to match the capabilities of the underlying filesystem. In case the
|
||||
# filesystem is case sensitive (i.e. it supports files in the same directory
|
||||
# whose names only differ in casing), the option must be set to YES to properly
|
||||
# deal with such files in case they appear in the input. For filesystems that
|
||||
# are not case sensitive the option should be be set to NO to properly deal with
|
||||
# output files written for symbols that only differ in casing, such as for two
|
||||
# classes, one named CLASS and the other named Class, and to also support
|
||||
# references to files without having to specify the exact matching casing. On
|
||||
# Windows (including Cygwin) and MacOS, users should typically set this option
|
||||
# to NO, whereas on Linux or other Unix flavors it should typically be set to
|
||||
# YES.
|
||||
# The default value is: system dependent.
|
||||
|
||||
CASE_SENSE_NAMES = YES
|
||||
@@ -803,7 +820,10 @@ WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = YES
|
||||
|
||||
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
|
||||
# a warning is encountered.
|
||||
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
|
||||
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
|
||||
# at the end of the doxygen process doxygen will return with a non-zero status.
|
||||
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
|
||||
# The default value is: NO.
|
||||
|
||||
WARN_AS_ERROR = NO
|
||||
@@ -841,8 +861,8 @@ INPUT = @DOXY_SOURCE_DIRECTORY@ \
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
|
||||
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
|
||||
# possible encodings.
|
||||
# documentation (see:
|
||||
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
|
||||
# The default value is: UTF-8.
|
||||
|
||||
INPUT_ENCODING = UTF-8
|
||||
@@ -855,13 +875,15 @@ INPUT_ENCODING = UTF-8
|
||||
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
|
||||
# read by doxygen.
|
||||
#
|
||||
# Note the list of default checked file patterns might differ from the list of
|
||||
# default file extension mappings.
|
||||
#
|
||||
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
|
||||
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
|
||||
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
|
||||
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
|
||||
# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen
|
||||
# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
|
||||
# *.vhdl, *.ucf, *.qsf and *.ice.
|
||||
# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
|
||||
# *.ucf, *.qsf and *.ice.
|
||||
|
||||
FILE_PATTERNS = *.h \
|
||||
*.hpp \
|
||||
@@ -1079,16 +1101,22 @@ USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
|
||||
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
|
||||
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
|
||||
# cost of reduced performance. This can be particularly helpful with template
|
||||
# rich C++ code for which doxygen's built-in parser lacks the necessary type
|
||||
# information.
|
||||
# clang parser (see:
|
||||
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
|
||||
# performance. This can be particularly helpful with template rich C++ code for
|
||||
# which doxygen's built-in parser lacks the necessary type information.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
# generated with the -Duse_libclang=ON option for CMake.
|
||||
# The default value is: NO.
|
||||
|
||||
CLANG_ASSISTED_PARSING = NO
|
||||
|
||||
# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
|
||||
# YES then doxygen will add the directory of each input to the include path.
|
||||
# The default value is: YES.
|
||||
|
||||
CLANG_ADD_INC_PATHS = YES
|
||||
|
||||
# If clang assisted parsing is enabled you can provide the compiler with command
|
||||
# line options that you would normally use when invoking the compiler. Note that
|
||||
# the include paths will already be set by doxygen for the files and directories
|
||||
@@ -1102,7 +1130,7 @@ CLANG_OPTIONS =
|
||||
# file is the compilation database (see:
|
||||
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
|
||||
# options used when the source files were built. This is equivalent to
|
||||
# specifying the "-p" option to a clang tool, such as clang-check. These options
|
||||
# specifying the -p option to a clang tool, such as clang-check. These options
|
||||
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
|
||||
# will be added as well.
|
||||
# Note: The availability of this option depends on whether or not doxygen was
|
||||
@@ -1121,13 +1149,6 @@ CLANG_DATABASE_PATH =
|
||||
|
||||
ALPHABETICAL_INDEX = YES
|
||||
|
||||
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
|
||||
# which the alphabetical index list will be split.
|
||||
# Minimum value: 1, maximum value: 20, default value: 5.
|
||||
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
|
||||
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
|
||||
# In case all classes in a project start with a common prefix, all classes will
|
||||
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
|
||||
# can be used to specify a prefix (or a list of prefixes) that should be ignored
|
||||
@@ -1298,10 +1319,11 @@ HTML_INDEX_NUM_ENTRIES = 100
|
||||
|
||||
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
|
||||
# generated that can be used as input for Apple's Xcode 3 integrated development
|
||||
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
|
||||
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
|
||||
# Makefile in the HTML output directory. Running make will produce the docset in
|
||||
# that directory and running make install will install the docset in
|
||||
# environment (see:
|
||||
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
|
||||
# create a documentation set, doxygen will generate a Makefile in the HTML
|
||||
# output directory. Running make will produce the docset in that directory and
|
||||
# running make install will install the docset in
|
||||
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
|
||||
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
|
||||
# genXcode/_index.html for more information.
|
||||
@@ -1343,8 +1365,8 @@ DOCSET_PUBLISHER_NAME = Publisher
|
||||
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
|
||||
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
|
||||
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
|
||||
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
|
||||
# Windows.
|
||||
# (see:
|
||||
# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
|
||||
#
|
||||
# The HTML Help Workshop contains a compiler that can convert all HTML output
|
||||
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
|
||||
@@ -1419,7 +1441,8 @@ QCH_FILE =
|
||||
|
||||
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
|
||||
# Project output. For more information please see Qt Help Project / Namespace
|
||||
# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
||||
# (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
|
||||
# The default value is: org.doxygen.Project.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1427,8 +1450,8 @@ QHP_NAMESPACE = org.doxygen.Project
|
||||
|
||||
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
|
||||
# Help Project output. For more information please see Qt Help Project / Virtual
|
||||
# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
|
||||
# folders).
|
||||
# Folders (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
|
||||
# The default value is: doc.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
@@ -1436,16 +1459,16 @@ QHP_VIRTUAL_FOLDER = doc
|
||||
|
||||
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
|
||||
# filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# Filters (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_CUST_FILTER_NAME =
|
||||
|
||||
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
|
||||
# custom filter to add. For more information please see Qt Help Project / Custom
|
||||
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
|
||||
# filters).
|
||||
# Filters (see:
|
||||
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
@@ -1457,9 +1480,9 @@ QHP_CUST_FILTER_ATTRS =
|
||||
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
|
||||
# The QHG_LOCATION tag can be used to specify the location of Qt's
|
||||
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
|
||||
# generated .qhp file.
|
||||
# The QHG_LOCATION tag can be used to specify the location (absolute path
|
||||
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
|
||||
# run qhelpgenerator on the generated .qhp file.
|
||||
# This tag requires that the tag GENERATE_QHP is set to YES.
|
||||
|
||||
QHG_LOCATION =
|
||||
@@ -1586,7 +1609,7 @@ USE_MATHJAX = NO
|
||||
|
||||
# When MathJax is enabled you can set the default output format to be used for
|
||||
# the MathJax output. See the MathJax site (see:
|
||||
# http://docs.mathjax.org/en/latest/output.html) for more details.
|
||||
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
|
||||
# Possible values are: HTML-CSS (which is slower, but has the best
|
||||
# compatibility), NativeMML (i.e. MathML) and SVG.
|
||||
# The default value is: HTML-CSS.
|
||||
@@ -1616,7 +1639,8 @@ MATHJAX_EXTENSIONS =
|
||||
|
||||
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
|
||||
# of code that will be used on startup of the MathJax code. See the MathJax site
|
||||
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
|
||||
# (see:
|
||||
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
|
||||
# example see the documentation.
|
||||
# This tag requires that the tag USE_MATHJAX is set to YES.
|
||||
|
||||
@@ -1663,7 +1687,8 @@ SERVER_BASED_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: https://xapian.org/).
|
||||
# Xapian (see:
|
||||
# https://xapian.org/).
|
||||
#
|
||||
# See the section "External Indexing and Searching" for details.
|
||||
# The default value is: NO.
|
||||
@@ -1676,8 +1701,9 @@ EXTERNAL_SEARCH = NO
|
||||
#
|
||||
# Doxygen ships with an example indexer (doxyindexer) and search engine
|
||||
# (doxysearch.cgi) which are based on the open source search engine library
|
||||
# Xapian (see: https://xapian.org/). See the section "External Indexing and
|
||||
# Searching" for details.
|
||||
# Xapian (see:
|
||||
# https://xapian.org/). See the section "External Indexing and Searching" for
|
||||
# details.
|
||||
# This tag requires that the tag SEARCHENGINE is set to YES.
|
||||
|
||||
SEARCHENGINE_URL =
|
||||
@@ -2277,7 +2303,7 @@ HIDE_UNDOC_RELATIONS = YES
|
||||
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
|
||||
# Bell Labs. The other options in this section have no effect if this option is
|
||||
# set to NO
|
||||
# The default value is: NO.
|
||||
# The default value is: YES.
|
||||
|
||||
HAVE_DOT = YES
|
||||
|
||||
@@ -2356,10 +2382,32 @@ UML_LOOK = NO
|
||||
# but if the number exceeds 15, the total amount of fields shown is limited to
|
||||
# 10.
|
||||
# Minimum value: 0, maximum value: 100, default value: 10.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
# This tag requires that the tag UML_LOOK is set to YES.
|
||||
|
||||
UML_LIMIT_NUM_FIELDS = 10
|
||||
|
||||
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
|
||||
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
|
||||
# tag is set to YES, doxygen will add type and arguments for attributes and
|
||||
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
|
||||
# will not generate fields with class member information in the UML graphs. The
|
||||
# class diagrams will look similar to the default class diagrams but using UML
|
||||
# notation for the relationships.
|
||||
# Possible values are: NO, YES and NONE.
|
||||
# The default value is: NO.
|
||||
# This tag requires that the tag UML_LOOK is set to YES.
|
||||
|
||||
DOT_UML_DETAILS = NO
|
||||
|
||||
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
|
||||
# to display on a single line. If the actual line length exceeds this threshold
|
||||
# significantly it will wrapped across multiple lines. Some heuristics are apply
|
||||
# to avoid ugly line breaks.
|
||||
# Minimum value: 0, maximum value: 1000, default value: 17.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_WRAP_THRESHOLD = 17
|
||||
|
||||
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
|
||||
# collaboration graphs will show the relations between templates and their
|
||||
# instances.
|
||||
@@ -2433,7 +2481,9 @@ DIRECTORY_GRAPH = YES
|
||||
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
|
||||
# to make the SVG files visible in IE 9+ (other browsers do not have this
|
||||
# requirement).
|
||||
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
|
||||
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
|
||||
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
|
||||
# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
|
||||
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
|
||||
# png:gdiplus:gdiplus.
|
||||
# The default value is: png.
|
||||
@@ -2549,9 +2599,11 @@ DOT_MULTI_TARGETS = NO
|
||||
|
||||
GENERATE_LEGEND = YES
|
||||
|
||||
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
|
||||
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
|
||||
# files that are used to generate the various graphs.
|
||||
#
|
||||
# Note: This setting is not only used for dot files but also for msc and
|
||||
# plantuml temporary files.
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag HAVE_DOT is set to YES.
|
||||
|
||||
DOT_CLEANUP = YES
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Definitions](#definitions)
|
||||
* [ENTT_NOEXCEPT](#entt_noexcept)
|
||||
* [ENTT_NOEXCEPTION](#entt_noexcept)
|
||||
* [ENTT_USE_ATOMIC](#entt_use_atomic)
|
||||
* [ENTT_ID_TYPE](#entt_id_type)
|
||||
* [ENTT_PAGE_SIZE](#entt_page_size)
|
||||
* [ENTT_SPARSE_PAGE](#entt_sparse_page)
|
||||
* [ENTT_PACKED_PAGE](#entt_packed_page)
|
||||
* [ENTT_ASSERT](#entt_assert)
|
||||
* [ENTT_DISABLE_ASSERT](#entt_disable_assert)
|
||||
* [ENTT_NO_ETO](#entt_no_eto)
|
||||
@@ -37,11 +38,11 @@ Each parameter can result in internal library definitions. It's not recommended
|
||||
to try to also modify these definitions, since there is no guarantee that they
|
||||
will remain stable over time unlike the options below.
|
||||
|
||||
## ENTT_NOEXCEPT
|
||||
## ENTT_NOEXCEPTION
|
||||
|
||||
The purpose of this parameter is to suppress the use of `noexcept` by this
|
||||
library.<br/>
|
||||
To do this, simply define the variable without assigning any value to it.
|
||||
This parameter can be used to switch off exception handling in `EnTT`.<br/>
|
||||
To do this, simply define the variable without assigning any value to it. This
|
||||
is roughly equivalent to setting the compiler flag `-ff-noexceptions`.
|
||||
|
||||
## ENTT_USE_ATOMIC
|
||||
|
||||
@@ -59,14 +60,23 @@ the library.<br/>
|
||||
By default, its type is `std::uint32_t`. However, users can define a different
|
||||
default type if necessary.
|
||||
|
||||
## ENTT_PAGE_SIZE
|
||||
## ENTT_SPARSE_PAGE
|
||||
|
||||
As is known, the ECS module of `EnTT` is based on _sparse sets_. What is less
|
||||
known perhaps is that these are paged to reduce memory consumption.<br/>
|
||||
It's known that the ECS module of `EnTT` is based on _sparse sets_. What is less
|
||||
known perhaps is that the sparse arrays are paged to reduce memory usage.<br/>
|
||||
Default size of pages (that is, the number of elements they contain) is 4096 but
|
||||
users can adjust it if appropriate. In all case, the chosen value **must** be a
|
||||
power of 2.
|
||||
|
||||
## ENTT_PACKED_PAGE
|
||||
|
||||
Similar to sparse arrays, packed arrays of components are paginated as well. In
|
||||
However, int this case the aim isn't to reduce memory usage but to have pointer
|
||||
stability upon component creation.<br/>
|
||||
Default size of pages (that is, the number of elements they contain) is 1024 but
|
||||
users can adjust it if appropriate. In all case, the chosen value **must** be a
|
||||
power of 2.
|
||||
|
||||
## ENTT_ASSERT
|
||||
|
||||
For performance reasons, `EnTT` doesn't use exceptions or any other control
|
||||
|
||||
56
docs/md/container.md
Normal file
56
docs/md/container.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Crash Course: containers
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Containers](#containers)
|
||||
* [Dense hash map](#dense-hash-map)
|
||||
* [Dense hash set](#dense-hash-set)
|
||||
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
The standard C++ library offers a wide range of containers and it's really
|
||||
difficult to do better (although it's very easy to do worse, as many examples
|
||||
available online demonstrate).<br/>
|
||||
`EnTT` doesn't try in any way to replace what is offered by the standard. Quite
|
||||
the opposite, given the widespread use that is made of standard containers.<br/>
|
||||
However, the library also tries to fill a gap in features and functionality by
|
||||
making available some containers initially developed for internal use.
|
||||
|
||||
This section of the library is likely to grow larger over time. However, for the
|
||||
moment it's quite small and mainly aimed at satisfying some internal needs.<br/>
|
||||
For all containers made available, full test coverage and stability over time is
|
||||
guaranteed as usual.
|
||||
|
||||
# Containers
|
||||
|
||||
## Dense hash map
|
||||
|
||||
The dense hash map made available in `EnTT` is a map that aims to return a
|
||||
packed array of elements, so as to reduce the number of jumps in memory during
|
||||
the iteration.<br/>
|
||||
The implementation is based on _sparse sets_ and each bucket is identified by an
|
||||
implicit list within the packed array itself.
|
||||
|
||||
The interface is in all respects similar to its counterpart in the standard
|
||||
library, that is, `std::unordered_map`.<br/>
|
||||
Therefore, there is no need to go into the API description.
|
||||
|
||||
## Dense hash set
|
||||
|
||||
The dense hash set made available in `EnTT` is a set that aims to return a
|
||||
packed array of elements, so as to reduce the number of jumps in memory during
|
||||
the iteration.<br/>
|
||||
The implementation is based on _sparse sets_ and each bucket is identified by an
|
||||
implicit list within the packed array itself.
|
||||
|
||||
The interface is in all respects similar to its counterpart in the standard
|
||||
library, that is, `std::unordered_set`.<br/>
|
||||
Therefore, there is no need to go into the API description.
|
||||
267
docs/md/core.md
267
docs/md/core.md
@@ -17,7 +17,8 @@
|
||||
* [Small buffer optimization](#small-buffer-optimization)
|
||||
* [Alignment requirement](#alignment-requirement)
|
||||
* [Type support](#type-support)
|
||||
* [Type info](#type-info)
|
||||
* [Built-in RTTI support](#built-in-rtti-support)
|
||||
* [Type info](#type-info)
|
||||
* [Almost unique identifiers](#almost-unique-identifiers)
|
||||
* [Type traits](#type-traits)
|
||||
* [Size of](#size-of)
|
||||
@@ -27,6 +28,8 @@
|
||||
* [Integral constant](#integral-constant)
|
||||
* [Tag](#tag)
|
||||
* [Type list and value list](#type-list-and-value-list)
|
||||
* [Compressed pair](#compressed-pair)
|
||||
* [Enum as bitmask](#enum-as-bitmask)
|
||||
* [Utilities](#utilities)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
@@ -247,15 +250,44 @@ entt::any any{0};
|
||||
entt::any in_place{std::in_place_type<int>, 42};
|
||||
```
|
||||
|
||||
The `any` class takes the burden of destroying the contained element when
|
||||
required, regardless of the storage strategy used for the specific object.<br/>
|
||||
Alternatively, the `make_any` function serves the same purpose but requires to
|
||||
always be explicit about the type:
|
||||
|
||||
```cpp
|
||||
entt::any any = entt::make_any<int>(42);
|
||||
```
|
||||
|
||||
In both cases, the `any` class takes the burden of destroying the contained
|
||||
element when required, regardless of the storage strategy used for the specific
|
||||
object.<br/>
|
||||
Furthermore, an instance of `any` is not tied to an actual type. Therefore, the
|
||||
wrapper will be reconfigured by assigning it an object of a different type than
|
||||
the one contained, so as to be able to handle the new instance.<br/>
|
||||
the one contained, so as to be able to handle the new instance.
|
||||
|
||||
There exists also a way to directly assign a value to the variable contained by
|
||||
an `entt::any`, without necessarily replacing it. This is especially useful when
|
||||
the object is used in _aliasing mode_, as described below:
|
||||
|
||||
```cpp
|
||||
entt::any any{42};
|
||||
entt::any value{3};
|
||||
|
||||
// assigns by copy
|
||||
any.assign(value);
|
||||
|
||||
// assigns by move
|
||||
any.assign(std::move(value));
|
||||
```
|
||||
|
||||
The `any` class will also perform a check on the type information and whether or
|
||||
not the original type was copy or move assignable, as appropriate.<br/>
|
||||
In all cases, the `assign` function returns a boolean value to indicate the
|
||||
success or failure of the operation.
|
||||
|
||||
When in doubt about the type of object contained, the `type` member function of
|
||||
`any` returns an instance of `type_info` associated with its element, or an
|
||||
invalid `type_info` object if the container is empty. The type is also used
|
||||
internally when comparing two `any` objects:
|
||||
`any` returns a const reference to the `type_info` associated with its element,
|
||||
or `type_id<void>()` if the container is empty. The type is also used internally
|
||||
when comparing two `any` objects:
|
||||
|
||||
```cpp
|
||||
if(any == empty) { /* ... */ }
|
||||
@@ -263,7 +295,7 @@ if(any == empty) { /* ... */ }
|
||||
|
||||
In this case, before proceeding with a comparison, it's verified that the _type_
|
||||
of the two objects is actually the same.<br/>
|
||||
Refer to the `EnTT` type system documentation for more details on how
|
||||
Refer to the `EnTT` type system documentation for more details about how
|
||||
`type_info` works and on possible risks of a comparison.
|
||||
|
||||
A particularly interesting feature of this class is that it can also be used as
|
||||
@@ -272,20 +304,17 @@ an opaque container for const and non-const references:
|
||||
```cpp
|
||||
int value = 42;
|
||||
|
||||
// reference construction
|
||||
entt::any any{std::ref(value)};
|
||||
entt::any cany{std::cref(value)};
|
||||
entt::any any{std::in_place_type<int &>(value)};
|
||||
entt::any cany = entt::make_any<const int &>(value);
|
||||
entt::any fwd = entt::forward_as_any(value);
|
||||
|
||||
// alias construction
|
||||
int value = 42;
|
||||
entt::any in_place{std::in_place_type<int &>, &value};
|
||||
any.emplace<const int &>(value);
|
||||
```
|
||||
|
||||
In other words, whenever `any` intercepts a `reference_wrapper` or is explicitly
|
||||
told that users want to construct an alias, it acts as a pointer to the original
|
||||
instance rather than making a copy of it or moving it internally. The contained
|
||||
object is never destroyed and users must ensure that its lifetime exceeds that
|
||||
of the container.<br/>
|
||||
In other words, whenever `any` is explicitly told to construct an _alias_, it
|
||||
acts as a pointer to the original instance rather than making a copy of it or
|
||||
moving it internally. The contained object is never destroyed and users must
|
||||
ensure that its lifetime exceeds that of the container.<br/>
|
||||
Similarly, it's possible to create non-owning copies of `any` from an existing
|
||||
object:
|
||||
|
||||
@@ -362,33 +391,22 @@ that won't be able to interoperate with each other.
|
||||
It also offers additional features that are not yet available in the standard
|
||||
library or that will never be.
|
||||
|
||||
## Type info
|
||||
## Built-in RTTI support
|
||||
|
||||
The `type_info` class isn't a drop-in replacement for `std::type_info` but can
|
||||
provide similar information which are not implementation defined and don't
|
||||
require to enable RTTI.<br/>
|
||||
Therefore, they can sometimes be even more reliable than those obtained
|
||||
otherwise.
|
||||
Runtime type identification support (or RTTI) is one of the most frequently
|
||||
disabled features in the C++ world, especially in the gaming sector. Regardless
|
||||
of the reasons for this, it's often a shame not to be able to rely on opaque
|
||||
type information at runtime.<br/>
|
||||
The library tries to fill this gap by offering a built-in system that doesn't
|
||||
serve as a replacement but comes very close to being one and offers similar
|
||||
information to that provided by its counterpart.
|
||||
|
||||
A type info object is an opaque class that is also copy and move constructible.
|
||||
This class is returned by the `type_id` function template:
|
||||
Basically, the whole system relies on a handful of classes. In particular:
|
||||
|
||||
```cpp
|
||||
auto info = entt::type_id<a_type>();
|
||||
```
|
||||
|
||||
These are the information made available by this object:
|
||||
|
||||
* The unique, sequential identifier associated with a given type:
|
||||
* The unique sequential identifier associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto index = entt::type_id<a_type>().seq();
|
||||
```
|
||||
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto index = entt::type_seq<a_type>::value();
|
||||
auto index = entt::type_index<a_type>::value();
|
||||
```
|
||||
|
||||
The returned value isn't guaranteed to be stable across different runs.
|
||||
@@ -402,13 +420,13 @@ These are the information made available by this object:
|
||||
and therefore the generation of custom runtime sequences of indices for their
|
||||
own purposes, if necessary.
|
||||
|
||||
An external generator can also be used if needed. In fact, `type_seq` can be
|
||||
An external generator can also be used if needed. In fact, `type_index` can be
|
||||
specialized by type and is also _sfinae-friendly_ in order to allow more
|
||||
refined specializations such as:
|
||||
|
||||
```cpp
|
||||
template<typename Type>
|
||||
struct entt::type_seq<Type, std::void_d<decltype(Type::index())>> {
|
||||
struct entt::type_index<Type, std::void_d<decltype(Type::index())>> {
|
||||
static entt::id_type value() ENTT_NOEXCEPT {
|
||||
return Type::index();
|
||||
}
|
||||
@@ -421,21 +439,13 @@ These are the information made available by this object:
|
||||
|
||||
* The hash value associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto hash = entt::type_id<a_type>().hash();
|
||||
```
|
||||
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto hash = entt::type_hash<a_type>::value();
|
||||
```
|
||||
|
||||
In general, the `value` function exposed by `type_hash` is also `constexpr`
|
||||
but this isn't guaranteed for all compilers and platforms (although it's valid
|
||||
with the most well-known and popular ones).<br/>
|
||||
The `hash` function offered by the type info object isn't `constexpr` in any
|
||||
case instead.
|
||||
with the most well-known and popular ones).
|
||||
|
||||
This function **can** use non-standard features of the language for its own
|
||||
purposes. This makes it possible to provide compile-time identifiers that
|
||||
@@ -445,18 +455,12 @@ These are the information made available by this object:
|
||||
that identifiers remain stable across executions. Moreover, they are generated
|
||||
at runtime and are no longer a compile-time thing.
|
||||
|
||||
As for `type_seq`, also `type_hash` is a _sfinae-friendly_ class that can be
|
||||
As for `type_index`, also `type_hash` is a _sfinae-friendly_ class that can be
|
||||
specialized in order to customize its behavior globally or on a per-type or
|
||||
per-traits basis.
|
||||
|
||||
* The name associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto name = entt::type_id<my_type>().name();
|
||||
```
|
||||
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto name = entt::type_name<a_type>::value();
|
||||
```
|
||||
@@ -484,10 +488,71 @@ These are the information made available by this object:
|
||||
means of the `ENTT_STANDARD_CPP` definition. In this case, the name will be
|
||||
empty by default.
|
||||
|
||||
As for `type_seq`, also `type_name` is a _sfinae-friendly_ class that can be
|
||||
As for `type_index`, also `type_name` is a _sfinae-friendly_ class that can be
|
||||
specialized in order to customize its behavior globally or on a per-type or
|
||||
per-traits basis.
|
||||
|
||||
These are then combined into utilities that aim to offer an API that is somewhat
|
||||
similar to that offered by the language.
|
||||
|
||||
### Type info
|
||||
|
||||
The `type_info` class isn't a drop-in replacement for `std::type_info` but can
|
||||
provide similar information which are not implementation defined and don't
|
||||
require to enable RTTI.<br/>
|
||||
Therefore, they can sometimes be even more reliable than those obtained
|
||||
otherwise.
|
||||
|
||||
A type info object is an opaque class that is also copy and move constructible.
|
||||
Objects of this class are returned by the `type_id` function template:
|
||||
|
||||
```cpp
|
||||
auto info = entt::type_id<a_type>();
|
||||
```
|
||||
|
||||
These are the information made available by a `type_info` object:
|
||||
|
||||
* The index associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto idx = entt::type_id<a_type>().index();
|
||||
```
|
||||
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto idx = entt::type_index<std::remove_const_t<std::remove_reference_t<a_type>>>::value();
|
||||
```
|
||||
|
||||
* The hash value associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto hash = entt::type_id<a_type>().hash();
|
||||
```
|
||||
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto hash = entt::type_hash<std::remove_const_t<std::remove_reference_t<a_type>>>::value();
|
||||
```
|
||||
|
||||
* The name associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto name = entt::type_id<my_type>().name();
|
||||
```
|
||||
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto name = entt::type_name<std::remove_const_t<std::remove_reference_t<a_type>>>::value();
|
||||
```
|
||||
|
||||
Where all accessed features are available at compile-time, the `type_info` class
|
||||
is also fully `constexpr`. However, this cannot be guaranteed in advance and
|
||||
depends mainly on the compiler in use and any specializations of the classes
|
||||
described above.
|
||||
|
||||
### Almost unique identifiers
|
||||
|
||||
Since the default non-standard, compile-time implementation of `type_hash` makes
|
||||
@@ -628,7 +693,7 @@ Here is a (possibly incomplete) list of the functionalities that come with a
|
||||
type list:
|
||||
|
||||
* `type_list_element[_t]` to get the N-th element of a type list.
|
||||
* `type_list_cast[_t]` and a handy `operator+` to concatenate type lists.
|
||||
* `type_list_cat[_t]` and a handy `operator+` to concatenate type lists.
|
||||
* `type_list_unique[_t]` to remove duplicate types from a type list.
|
||||
* `type_list_contains[_v]` to know if a type list contains a given type.
|
||||
* `type_list_diff[_t]` to remove types from type lists.
|
||||
@@ -639,6 +704,86 @@ Many of these functionalities also exist in their version dedicated to value
|
||||
lists. We therefore have `value_list_element[_v]` as well as
|
||||
`value_list_cat[_t]`and so on.
|
||||
|
||||
# Compressed pair
|
||||
|
||||
Primarily designed for internal use and far from being feature complete, the
|
||||
`compressed_pair` class does exactly what it promises: it tries to reduce the
|
||||
size of a pair by exploiting _Empty Base Class Optimization_ (or _EBCO_).<br/>
|
||||
This class **is not** a drop-in replacement for `std::pair`. However, it offers
|
||||
enough functionalities to be a good alternative for when reducing memory usage
|
||||
is more important than having some cool and probably useless feature.
|
||||
|
||||
Although the API is very close to that of `std::pair` (apart from the fact that
|
||||
the template parameters are inferred from the constructor and therefore there is
|
||||
no` entt::make_compressed_pair`), the major difference is that `first` and
|
||||
`second` are functions for implementation needs:
|
||||
|
||||
```cpp
|
||||
entt::compressed_pair pair{0, 3.};
|
||||
pair.first() = 42;
|
||||
```
|
||||
|
||||
There isn't much to describe then. It's recommended to rely on documentation and
|
||||
intuition. At the end of the day, it's just a pair and nothing more.
|
||||
|
||||
# Enum as bitmask
|
||||
|
||||
Sometimes it's useful to be able to use enums as bitmasks. However, enum classes
|
||||
aren't really suitable for the purpose out of the box. Main problem is that they
|
||||
don't convert implicitly to their underlying type.<br/>
|
||||
All that remains is to make a choice between using old-fashioned enums (with all
|
||||
their problems that I don't want to discuss here) or writing _ugly_ code.
|
||||
|
||||
Fortunately, there is also a third way: adding enough operators in the global
|
||||
scope to treat enum classes as bitmask transparently.<br/>
|
||||
The ultimate goal is to be able to write code like the following (or maybe
|
||||
something more meaningful, but this should give a grasp and remain simple at the
|
||||
same time):
|
||||
|
||||
```cpp
|
||||
enum class my_flag {
|
||||
unknown = 0x01,
|
||||
enabled = 0x02,
|
||||
disabled = 0x04
|
||||
};
|
||||
|
||||
const my_flag flags = my_flag::enabled;
|
||||
const bool is_enabled = !!(flags & my_flag::enabled);
|
||||
```
|
||||
|
||||
The problem with adding all operators to the global scope is that these will
|
||||
come into play even when not required, with the risk of introducing errors that
|
||||
are difficult to deal with.<br/>
|
||||
However, C++ offers enough tools to get around this problem. In particular, the
|
||||
library requires users to register all enum classes for which bitmask support
|
||||
should be enabled:
|
||||
|
||||
```cpp
|
||||
template<>
|
||||
struct entt::enum_as_bitmask<my_flag>
|
||||
: std::true_type
|
||||
{};
|
||||
```
|
||||
|
||||
This is handy when dealing with enum classes defined by third party libraries
|
||||
and over which the users have no control. However, it's also verbose and can be
|
||||
avoided by adding a specific value to the enum class itself:
|
||||
|
||||
```cpp
|
||||
enum class my_flag {
|
||||
unknown = 0x01,
|
||||
enabled = 0x02,
|
||||
disabled = 0x04,
|
||||
_entt_enum_as_bitmask
|
||||
};
|
||||
```
|
||||
|
||||
In this case, there is no need to specialize the `enum_as_bitmask` traits, since
|
||||
`EnTT` will automatically detect the flag and enable the bitmask support.<br/>
|
||||
Once the enum class has been registered (in one way or the other) all the most
|
||||
common operators will be available, such as `&`, `|` but also `&=` and `|=`.
|
||||
Refer to the official documentation for the full list of operators.
|
||||
|
||||
# Utilities
|
||||
|
||||
It's not possible to escape the temptation to add utilities of some kind to a
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -77,45 +77,30 @@ not different techniques depending on how the data are laid out.
|
||||
I tried to describe some of the techniques that fit well with the model of
|
||||
`EnTT`. [Here](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) is the
|
||||
first post of a series that tries to explore the problem. More will probably
|
||||
come in future.
|
||||
|
||||
Long story short, you can always define a tree where the nodes expose implicit
|
||||
lists of children by means of the following type:
|
||||
|
||||
```cpp
|
||||
struct relationship {
|
||||
std::size_t children{};
|
||||
entt::entity first{entt::null};
|
||||
entt::entity prev{entt::null};
|
||||
entt::entity next{entt::null};
|
||||
entt::entity parent{entt::null};
|
||||
// ... other data members ...
|
||||
};
|
||||
```
|
||||
|
||||
The sort functionalities of `EnTT`, the groups and all the other features of the
|
||||
library can help then to get the best in terms of data locality and therefore
|
||||
performance from this component.
|
||||
come in future.<br/>
|
||||
In addition, `EnTT` also offers the possibility to create stable storage types
|
||||
and therefore have pointer stability for one, all or some components. This is by
|
||||
far the most convenient solution when it comes to creating hierarchies and
|
||||
whatnot. See the documentation for the ECS part of the library and in particular
|
||||
what concerns the `component_traits` class for further details.
|
||||
|
||||
## Custom entity identifiers: yay or nay?
|
||||
|
||||
Custom entity identifiers are definitely a good idea in two cases at least:
|
||||
|
||||
* If `std::uint32_t` is too large or isn't large enough for your purposes, since
|
||||
this is the underlying type of `entt::entity`.
|
||||
* If `std::uint32_t` isn't large enough for your purposes, since this is the
|
||||
underlying type of `entt::entity`.
|
||||
* If you want to avoid conflicts when using multiple registries.
|
||||
|
||||
Identifiers can be defined through enum classes and custom types for which a
|
||||
specialization of `entt_traits` exists. For this purpose, `entt_traits` is also
|
||||
defined as a _sfinae-friendly_ class template.<br/>
|
||||
Identifiers can be defined through enum classes and class types that define an
|
||||
`entity_type` member of type `std::uint32_t` or `std::uint64_t`.<br/>
|
||||
In fact, this is a definition equivalent to that of `entt::entity`:
|
||||
|
||||
```cpp
|
||||
enum class entity: std::uint32_t {};
|
||||
```
|
||||
|
||||
In theory, integral types can also be used as entity identifiers, even though
|
||||
this may break in future and isn't recommended in general.
|
||||
There is no limit to the number of identifiers that can be defined.
|
||||
|
||||
## Warning C4307: integral constant overflow
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# Table of Contents
|
||||
|
||||
* [Working across boundaries](#working-across-boundaries)
|
||||
* [The EnTT way](#the-entt-way)
|
||||
* [Smooth until proven otherwise](#smooth-until-proven-otherwise)
|
||||
* [Meta context](#meta-context)
|
||||
* [Memory management](#memory-management)
|
||||
<!--
|
||||
@@ -19,48 +19,31 @@
|
||||
general and on GNU/Linux when default visibility was set to hidden. The
|
||||
limitation was mainly due to a custom utility used to assign unique, sequential
|
||||
identifiers with different types.<br/>
|
||||
Fortunately, nowadays using `EnTT` across boundaries is easier. However, use in
|
||||
standalone applications is favored and user intervention is otherwise required.
|
||||
Fortunately, nowadays using `EnTT` across boundaries is much easier.
|
||||
|
||||
## The EnTT way
|
||||
## Smooth until proven otherwise
|
||||
|
||||
Many classes in `EnTT` make extensive use of type erasure for their purposes.
|
||||
This isn't a problem in itself (in fact, it's the basis of an API so convenient
|
||||
This isn't a problem on itself (in fact, it's the basis of an API so convenient
|
||||
to use). However, a way is needed to recognize the objects whose type has been
|
||||
erased on the other side of a boundary.<br/>
|
||||
The `type_hash` class template is how identifiers are generated and thus made
|
||||
available to the rest of the library. The `type_seq` class template makes all
|
||||
types _indexable_ instead, so as to speed up the lookup.
|
||||
available to the rest of the library. In general, this class doesn't arouse much
|
||||
interest. The only exception is when a conflict between identifiers occurs
|
||||
(definitely uncommon though) or when the default solution proposed by `EnTT`
|
||||
isn't suitable for the user's purposes.<br/>
|
||||
The section dedicated to `type_info` contains all the details to get around the
|
||||
issue in a concise and elegant way. Please refer to the specific documentation.
|
||||
|
||||
In general, these classes don't arouse much interest. The only exceptions are:
|
||||
|
||||
* When a conflict between identifiers occurs (definitely uncommon though) or
|
||||
when the default solution proposed by `EnTT` isn't suitable for the user's
|
||||
purposes.<br/>
|
||||
The section dedicated to `type_info` contains all the details to get around
|
||||
the problem in a concise and elegant way. Please refer to the specific
|
||||
documentation.
|
||||
|
||||
* When working with linked libraries that also export all required symbols.<br/>
|
||||
Compile definitions `ENTT_API_EXPORT` and `ENTT_API_IMPORT` should be passed
|
||||
respectively where there is a need to import or export the symbols defined by
|
||||
`EnTT`, so as to make everything work nicely across boundaries.
|
||||
|
||||
* When working with plugins or shared libraries that don't export any symbol. In
|
||||
this case, `type_seq` confuses the other classes by giving potentially wrong
|
||||
information to them.<br/>
|
||||
To avoid problems, it's required to provide a custom generator. Briefly, it's
|
||||
necessary to specialize the `type_seq` class and make it point to a context
|
||||
that is also shared between the main application and the dynamically loaded
|
||||
libraries or plugins.<br/>
|
||||
This will make the type system available to the whole application, not just to
|
||||
a particular tool such as the registry or the dispatcher. It means that a call
|
||||
to `type_seq::value()` will return the same identifier for the same type from
|
||||
both sides of a boundary and can be used reliably for any purpose.
|
||||
When working with linked libraries, compile definitions `ENTT_API_EXPORT` and
|
||||
`ENTT_API_IMPORT` can be used where there is a need to import or export symbols,
|
||||
so as to make everything work nicely across boundaries.<br/>
|
||||
On the other hand, everything should run smoothly when working with plugins or
|
||||
shared libraries that don't export any symbols.
|
||||
|
||||
For anyone who needs more details, the test suite contains multiple examples
|
||||
covering the most common cases (see the `lib` directory for all details).<br/>
|
||||
It goes without saying that it's impossible to cover all the possible cases.
|
||||
It goes without saying that it's impossible to cover **all** possible cases.
|
||||
However, what is offered should hopefully serve as a basis for all of them.
|
||||
|
||||
## Meta context
|
||||
|
||||
@@ -23,11 +23,11 @@ I hope this list can grow much more in the future:
|
||||
* [TiltedOnline](https://github.com/tiltedphoques/TiltedOnline) by
|
||||
[Tilted Phoques](https://github.com/tiltedphoques): Skyrim and Fallout 4 mod
|
||||
to play online.
|
||||
* [Apparently](https://www.youtube.com/watch?v=P8xvOA3ikrQ&t=1105s)
|
||||
[Call of Duty: Vanguard](https://www.callofduty.com/vanguard): I can neither
|
||||
confirm nor deny but there is a license I know in the credits.
|
||||
* [Antkeeper](https://github.com/antkeeper/antkeeper-source): an ant colony
|
||||
simulation [game](https://antkeeper.com/).
|
||||
* [War of Rights](https://store.steampowered.com/app/424030/War_of_Rights/): a
|
||||
multiplayer game set during the perilous days of the American Civil War, by
|
||||
Campfire Games.
|
||||
* [Openblack](https://github.com/openblack/openblack): open source
|
||||
reimplementation of the game _Black & White_ (2001).
|
||||
* [Land of the Rair](https://github.com/LandOfTheRair/core2): the new backend
|
||||
@@ -70,8 +70,16 @@ I hope this list can grow much more in the future:
|
||||
arcade game about shooting dirty rocks in space, inspired by Asteroids.
|
||||
* [Wanderer](https://github.com/albin-johansson/wanderer): a 2D exploration
|
||||
based indie game.
|
||||
* [Spelunky® Classic remake](https://github.com/dbeef/spelunky-psp): A truly
|
||||
* [Spelunky® Classic remake](https://github.com/dbeef/spelunky-psp): a truly
|
||||
multiplatform experience with a rewrite from scratch.
|
||||
* [CubbyTower](https://github.com/utilForever/CubbyTower): a simple tower
|
||||
defense game using C++ with Entity Component System (ECS).
|
||||
* [Runeterra](https://github.com/utilForever/Runeterra): Legends of Runeterra
|
||||
simulator using C++ with some reinforcement learning.
|
||||
* [Black Sun](https://store.steampowered.com/app/1670930/Black_Sun/): fly your
|
||||
space ship through a large 2D open world.
|
||||
* [PokeMaster](https://github.com/utilForever/PokeMaster): Pokemon Battle
|
||||
simulator using C++ with some reinforcement learning.
|
||||
|
||||
* Engines and the like:
|
||||
* [Aether Engine](https://hadean.com/spatial-simulation/)
|
||||
@@ -92,6 +100,9 @@ I hope this list can grow much more in the future:
|
||||
vrooooommm.
|
||||
* [Antara Gaming SDK](https://github.com/KomodoPlatform/antara-gaming-sdk):
|
||||
the Komodo Gaming Software Development Kit.
|
||||
* [XVP](https://ravingbots.com/xvp-expansive-vehicle-physics-for-unreal-engine/):
|
||||
[_eXpansive Vehicle Physics_](https://github.com/raving-bots/xvp/wiki/Plugin-integration-guide)
|
||||
plugin for Unreal Engine.
|
||||
* [Apparently](https://teamwisp.github.io/credits/)
|
||||
[Wisp](https://teamwisp.github.io/product/) by
|
||||
[Team Wisp](https://teamwisp.github.io/): an advanced real-time ray tracing
|
||||
@@ -112,6 +123,23 @@ I hope this list can grow much more in the future:
|
||||
modular, tiny and fast C++ game engine, aimed to develop 3D desktop games.
|
||||
* [Spike](https://github.com/FahimFuad/Spike): a powerful game engine which
|
||||
can run on a toaster.
|
||||
* [Helena Framework](https://github.com/NIKEA-SOFT/HelenaFramework): a modern
|
||||
framework in C++17 for backend development.
|
||||
* [Unity/EnTT](https://github.com/TongTungGiang/unity-entt): tech demo of a
|
||||
native simulation layer using `EnTT` and `Unity` as a rendering engine.
|
||||
* [OverEngine](https://github.com/OverShifted/OverEngine): an over-engineered
|
||||
game engine.
|
||||
* [Electro](https://github.com/Electro-Technologies/Electro): high performance
|
||||
3D game engine with a high emphasis on rendering.
|
||||
* [Kawaii](https://github.com/Mathieu-Lala/Kawaii_Engine): a modern data
|
||||
oriented game engine.
|
||||
* [Becketron](https://github.com/Doctor-Foxling/Becketron): a game engine
|
||||
written mostly in C++.
|
||||
* [Spatial Engine](https://github.com/luizgabriel/Spatial.Engine): A
|
||||
cross-platform engine created on top of google's filament rendering engine.
|
||||
* [Kaguya](https://github.com/KaiH0717/Kaguya): D3D12 Rendering Engine.
|
||||
* [OpenAWE](https://github.com/OpenAWE-Project/OpenAWE): Open implementation
|
||||
of the Alan Wake Engine.
|
||||
|
||||
* Articles, videos and blog posts:
|
||||
* [Some posts](https://skypjack.github.io/tags/#entt) on my personal
|
||||
@@ -176,6 +204,8 @@ I hope this list can grow much more in the future:
|
||||
controller emulator and renderer.
|
||||
* [Ragdoll](https://ragdolldynamics.com/): real-time physics for Autodesk Maya
|
||||
2020.
|
||||
* [Project Lagrange](https://github.com/adobe/lagrange): a robust geometry
|
||||
processing library by [Adobe](https://github.com/adobe).
|
||||
* [AtomicDEX](https://github.com/KomodoPlatform/atomicDEX-Desktop): a secure
|
||||
wallet and non-custodial decentralized exchange rolled into one application.
|
||||
* [Apparently](https://www.linkedin.com/in/skypjack/)
|
||||
|
||||
165
docs/md/meta.md
165
docs/md/meta.md
@@ -13,6 +13,7 @@
|
||||
* [Container support](#container-support)
|
||||
* [Pointer-like types](#pointer-like-types)
|
||||
* [Template information](#template-information)
|
||||
* [Automatic conversions](#automatic-conversions)
|
||||
* [Implicitly generated default constructor](#implicitly-generated-default-constructor)
|
||||
* [Policies: the more, the less](#policies-the-more-the-less)
|
||||
* [Named constants and enums](#named-constants-and-enums)
|
||||
@@ -109,9 +110,10 @@ decorated version of it. This object can be used to add the following:
|
||||
entt::meta<my_type>().ctor<int, char>().ctor<&factory>();
|
||||
```
|
||||
|
||||
* _Destructors_. Free functions can be set as destructors of reflected types.
|
||||
The purpose is to give users the ability to free up resources that require
|
||||
special treatment before an object is actually destroyed.<br/>
|
||||
* _Destructors_. Free functions and member functions can be used as destructors
|
||||
of reflected types. The purpose is to give users the ability to free up
|
||||
resources that require special treatment before an object is actually
|
||||
destroyed.<br/>
|
||||
Use the `dtor` member function for this purpose:
|
||||
|
||||
```cpp
|
||||
@@ -146,6 +148,12 @@ decorated version of it. This object can be used to add the following:
|
||||
entt::meta<my_type>().data<nullptr, &my_type::data_member>("member"_hs);
|
||||
```
|
||||
|
||||
Multiple setters are also supported by means of a `value_list` object:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().data<entt::value_list<&from_int, &from_string>, &my_type::data_member>("member"_hs);
|
||||
```
|
||||
|
||||
Refer to the inline documentation for all the details.
|
||||
|
||||
* _Member functions_. Both real member functions of the underlying type and free
|
||||
@@ -210,9 +218,10 @@ Among the few relevant differences, `meta_any` adds support for containers and
|
||||
pointer-like types (see the following sections for more details), while `any`
|
||||
does not.<br/>
|
||||
Similar to `any`, this class can also be used to create _aliases_ for unmanaged
|
||||
objects either upon construction using `std::ref` and `std::cref` or from an
|
||||
existing instance by means of the `as_ref` function. However, unlike `any`,
|
||||
`meta_any` treats an empty instance and one initialized with `void` differently:
|
||||
objects either with `forward_as_meta` or using the `std::in_place_type<T &>`
|
||||
disambiguation tag, as well as from an existing object by means of the `as_ref`
|
||||
member function. However, unlike `any`, `meta_any` treats an empty instance and
|
||||
one initialized with `void` differently:
|
||||
|
||||
```cpp
|
||||
entt::meta_any empty{};
|
||||
@@ -266,19 +275,6 @@ Refer to the inline documentation for all the details.
|
||||
|
||||
The meta objects that compose a meta type are accessed in the following ways:
|
||||
|
||||
* _Meta constructors_. They are accessed by types of arguments:
|
||||
|
||||
```cpp
|
||||
auto ctor = entt::resolve<my_type>().ctor<int, char>();
|
||||
```
|
||||
|
||||
The returned type is `meta_ctor` and may be invalid if there is no constructor
|
||||
that accepts the supplied arguments or at least some types from which they are
|
||||
derived or to which they can be converted.<br/>
|
||||
A meta constructor offers an API to know the number of its arguments and their
|
||||
expected meta types. Furthermor, it's possible to invoke it and therefore to
|
||||
construct new instances of the underlying type.
|
||||
|
||||
* _Meta data_. They are accessed by _name_:
|
||||
|
||||
```cpp
|
||||
@@ -327,7 +323,7 @@ Furthermore, all them are also returned by specific overloads that provide the
|
||||
caller with iterable ranges of top-level elements. As an example:
|
||||
|
||||
```cpp
|
||||
for(auto data = entt::resolve<my_type>().data()) {
|
||||
for(auto data: entt::resolve<my_type>().data()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
@@ -386,7 +382,7 @@ object for a sequence container:
|
||||
|
||||
```cpp
|
||||
std::vector<int> vec{1, 2, 3};
|
||||
entt::meta_any any{std::ref(vec)};
|
||||
entt::meta_any any = entt::forward_as_meta(vec);
|
||||
|
||||
if(any.type().is_sequence_container()) {
|
||||
if(auto view = any.as_sequence_container(); view) {
|
||||
@@ -714,6 +710,56 @@ correspondence between real types and meta types.<br/>
|
||||
Therefore, the specialization will be used as is and the information it contains
|
||||
will be associated with the appropriate type when required.
|
||||
|
||||
## Automatic conversions
|
||||
|
||||
In C++, there are a number of conversions allowed between arithmetic types that
|
||||
make it convenient to work with this kind of data.<br/>
|
||||
If this were to be translated into explicit registrations with the reflection
|
||||
system, it would result in a long series of instructions such as the following:
|
||||
|
||||
```cpp
|
||||
entt::meta<int>()
|
||||
.conv<bool>()
|
||||
.conv<char>()
|
||||
// ...
|
||||
.conv<double>();
|
||||
```
|
||||
|
||||
Repeated for each type eligible to undergo this type of conversions. This is
|
||||
both error prone and repetitive.<br/>
|
||||
Similarly, the language allows users to silently convert unscoped enums to their
|
||||
underlying types and offers what it takes to do the same for scoped enums. It
|
||||
would result in the following if it were to be done explicitly:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_enum>()
|
||||
.conv<std::underlying_type_t<my_enum>>();
|
||||
```
|
||||
|
||||
Fortunately, all of this can also be avoided. `EnTT` offers implicit support for
|
||||
these types of conversions:
|
||||
|
||||
```cpp
|
||||
entt::meta_any any{42};
|
||||
any.allow_cast<double>();
|
||||
double value = any.cast<double>();
|
||||
```
|
||||
|
||||
With no need for registration, the conversion takes place automatically under
|
||||
the hood. The same goes for a call to `allow_cast` involving a meta type:
|
||||
|
||||
```cpp
|
||||
entt::meta_type type = entt::resolve<int>();
|
||||
entt::meta_any any{my_enum::a_value};
|
||||
any.allow_cast(type);
|
||||
int value = any.cast<int>();
|
||||
```
|
||||
|
||||
This should make working with arithmetic types and scoped or unscoped enums as
|
||||
easy as it is in C++.<br/>
|
||||
It's also worth noting that it's still possible to set up conversion functions
|
||||
manually and these will always be preferred over the automatic ones.
|
||||
|
||||
## Implicitly generated default constructor
|
||||
|
||||
In many cases, it's useful to be able to create objects of default constructible
|
||||
@@ -725,14 +771,7 @@ them.
|
||||
For this reason and only for default constructible types, default constructors
|
||||
are automatically defined and associated with their meta types, whether they are
|
||||
explicitly or implicitly generated.<br/>
|
||||
Therefore, it won't be necessary to do this in order to construct an integer
|
||||
from its meta type:
|
||||
|
||||
```cpp
|
||||
entt::meta<int>().ctor<>();
|
||||
```
|
||||
|
||||
Instead, just do this:
|
||||
Therefore, this is all is needed to construct an integer from its meta type:
|
||||
|
||||
```cpp
|
||||
entt::resolve<int>().construct();
|
||||
@@ -741,11 +780,8 @@ entt::resolve<int>().construct();
|
||||
Where the meta type can be for example the one returned from a meta container,
|
||||
useful for building keys without knowing or having to register the actual types.
|
||||
|
||||
In all cases, when users register custom defaul constructors, they are preferred
|
||||
both during searches and when the `construct` member function is invoked.<br/>
|
||||
However, the implicitly generated default constructor will always be returned,
|
||||
either if one is not explicitly specified or if all constructors are iterated
|
||||
for some reason (in this case, it will always be the last element).
|
||||
In all cases, when users register default constructors, they are preferred both
|
||||
during searches and when the `construct` member function is invoked.
|
||||
|
||||
## Policies: the more, the less
|
||||
|
||||
@@ -770,9 +806,11 @@ There are a few alternatives available at the moment:
|
||||
* The _as-void_ policy, associated with the type `entt::as_void_t`.<br/>
|
||||
Its purpose is to discard the return value of a meta object, whatever it is,
|
||||
thus making it appear as if its type were `void`:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
|
||||
```
|
||||
|
||||
If the use with functions is obvious, it must be said that it's also possible
|
||||
to use this policy with constructors and data members. In the first case, the
|
||||
constructor will be invoked but the returned wrapper will actually be empty.
|
||||
@@ -784,9 +822,11 @@ There are a few alternatives available at the moment:
|
||||
Accessing the object contained in the wrapper for which the _reference_ was
|
||||
requested will make it possible to directly access the instance used to
|
||||
initialize the wrapper itself:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().data<&my_type::data_member, entt::as_ref_t>("member"_hs);
|
||||
```
|
||||
|
||||
These policies work with constructors (for example, when objects are taken
|
||||
from an external container rather than created on demand), data members and
|
||||
functions in general.<br/>
|
||||
@@ -880,38 +920,15 @@ Multiple formats are supported when it comes to defining a property:
|
||||
|
||||
A tuple contains one or more properties. All of them are treated individually.
|
||||
|
||||
* Annotations:
|
||||
Note that it's not possible to invoke `prop` multiple times for the same meta
|
||||
object and trying to do that will result in a compilation error.<br/>
|
||||
However, the `props` function is available to associate several properties at
|
||||
once. In this case, properties in the key/value form aren't allowed, since they
|
||||
would be interpreted as two different properties rather than a single one.
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().type("reflected_type"_hs).prop(&property_generator);
|
||||
```
|
||||
|
||||
An annotation is an invocable object that returns one or more properties. All
|
||||
of them are treated individually.
|
||||
|
||||
It's possible to invoke the `prop` function several times if needed, one for
|
||||
each property to associate with the last meta object created:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>()
|
||||
.type("reflected_type"_hs)
|
||||
.prop(entt::hashed_string{"Name"}, "Reflected Type")
|
||||
.data<&my_type::data_member>("member"_hs)
|
||||
.prop(std::make_pair("tooltip"_hs, "Member"))
|
||||
.prop(my_enum::a_value, 42);
|
||||
```
|
||||
|
||||
Alternatively, the `props` function is available to associate several properties
|
||||
at a time. However, in this case properties in the key/value form aren't
|
||||
allowed, since they would be interpreted as two different properties rather than
|
||||
a single one.
|
||||
|
||||
The meta objects for which properties are supported are currently the meta
|
||||
types, meta constructors, meta data and meta functions. It's not possible to
|
||||
attach properties to other types of meta objects and the factory returned as a
|
||||
result of their construction won't allow such an operation.
|
||||
|
||||
These types offer a couple of member functions named `prop` to iterate all
|
||||
The meta objects for which properties are supported are currently meta types,
|
||||
meta data and meta functions.<br/>
|
||||
These types also offer a couple of member functions named `prop` to iterate all
|
||||
properties at once or to search a specific property by key:
|
||||
|
||||
```cpp
|
||||
@@ -941,7 +958,21 @@ objects from it and making its identifier no longer visible. The underlying node
|
||||
will remain available though, as if it were implicitly generated:
|
||||
|
||||
```cpp
|
||||
entt::resolve<my_type>().reset();
|
||||
entt::meta_reset<my_type>();
|
||||
```
|
||||
|
||||
The type can be re-registered later with a completely different name and form.
|
||||
It's also possible to reset types by their unique identifiers if required:
|
||||
|
||||
```cpp
|
||||
entt::meta_reset("my_type"_hs);
|
||||
```
|
||||
|
||||
Finally, there exists a non-template overload of the `meta_reset` function that
|
||||
doesn't accept argument and resets all searchable types (that is, all types that
|
||||
were assigned an unique identifier):
|
||||
|
||||
```cpp
|
||||
entt::meta_reset();
|
||||
```
|
||||
|
||||
All types can be re-registered later with a completely different name and form.
|
||||
|
||||
@@ -120,7 +120,7 @@ external call:
|
||||
struct Drawable: entt::type_list<> {
|
||||
template<typename Base>
|
||||
struct type: Base {
|
||||
bool draw() const { entt::poly_call<0>(*this); }
|
||||
void draw() const { entt::poly_call<0>(*this); }
|
||||
};
|
||||
|
||||
// ...
|
||||
@@ -312,13 +312,13 @@ instance->draw();
|
||||
|
||||
The `poly` class template offers a wide range of constructors, from the default
|
||||
one (which will return an uninitialized `poly` object) to the copy and move
|
||||
constructor, as well as the ability to create objects in-place.<br/>
|
||||
Among others, there is a constructor that allows users to wrap unmanaged objects
|
||||
in a `poly` instance (either const or non-const ones):
|
||||
constructors, as well as the ability to create objects in-place.<br/>
|
||||
Among others, there is also a constructor that allows users to wrap unmanaged
|
||||
objects in a `poly` instance (either const or non-const ones):
|
||||
|
||||
```cpp
|
||||
circle shape;
|
||||
drawable instance{std::ref(shape)};
|
||||
drawable instance{std::in_place_type<circle &>, shape};
|
||||
```
|
||||
|
||||
Similarly, it's possible to create non-owning copies of `poly` from an existing
|
||||
|
||||
@@ -28,9 +28,9 @@ A typical process must inherit from the `process` class template that stays true
|
||||
to the CRTP idiom. Moreover, derived classes must specify what's the intended
|
||||
type for elapsed times.
|
||||
|
||||
A process should expose publicly the following member functions whether
|
||||
required (note that it isn't required to define a function unless the derived
|
||||
class wants to _override_ the default behavior):
|
||||
A process should expose publicly the following member functions whether needed
|
||||
(note that it isn't required to define a function unless the derived class wants
|
||||
to _override_ the default behavior):
|
||||
|
||||
* `void update(Delta, void *);`
|
||||
|
||||
|
||||
@@ -44,11 +44,19 @@ I hope this list can grow much more in the future:
|
||||
by `EnTT`.
|
||||
|
||||
* Javascript:
|
||||
* [\@javelin/ecs](https://github.com/3mcd/javelin/tree/master/packages/ecs): an
|
||||
archetype ECS in TypeScript.
|
||||
* [\@javelin/ecs](https://github.com/3mcd/javelin/tree/master/packages/ecs):
|
||||
an archetype ECS in TypeScript.
|
||||
* [ecsy](https://github.com/MozillaReality/ecsy): I haven't had the time to
|
||||
investigate the underlying design of `ecsy` but it looks cool anyway.
|
||||
|
||||
* Perl:
|
||||
* [Game::Entities](https://gitlab.com/jjatria/perl-game-entities): a simple
|
||||
entity registry for ECS designs inspired by `EnTT`.
|
||||
|
||||
* Raku:
|
||||
* [Game::Entities](https://gitlab.com/jjatria/raku-game-entities): a simple
|
||||
entity registry for ECS designs inspired by `EnTT`.
|
||||
|
||||
* Rust:
|
||||
* [Legion](https://github.com/TomGillen/legion): a chunk based archetype ECS.
|
||||
* [Shipyard](https://github.com/leudz/shipyard): it borrows some ideas from
|
||||
|
||||
3
natvis/entt/config.natvis
Normal file
3
natvis/entt/config.natvis
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
33
natvis/entt/container.natvis
Normal file
33
natvis/entt/container.natvis
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::dense_hash_map<*>">
|
||||
<Intrinsic Name="size" Expression="packed.first_base::value.size()"/>
|
||||
<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/>
|
||||
<DisplayString>{{ size={ size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" ExcludeView="simple">packed.first_base::value.capacity()</Item>
|
||||
<Item Name="[bucket_count]" ExcludeView="simple">bucket_count()</Item>
|
||||
<Item Name="[load_factor]" ExcludeView="simple">(float)size() / (float)bucket_count()</Item>
|
||||
<Item Name="[max_load_factor]" ExcludeView="simple">threshold</Item>
|
||||
<IndexListItems>
|
||||
<Size>size()</Size>
|
||||
<ValueNode>packed.first_base::value[$i].element</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::dense_hash_set<*>">
|
||||
<Intrinsic Name="size" Expression="packed.first_base::value.size()"/>
|
||||
<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/>
|
||||
<DisplayString>{{ size={ size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" ExcludeView="simple">packed.first_base::value.capacity()</Item>
|
||||
<Item Name="[bucket_count]" ExcludeView="simple">bucket_count()</Item>
|
||||
<Item Name="[load_factor]" ExcludeView="simple">(float)size() / (float)bucket_count()</Item>
|
||||
<Item Name="[max_load_factor]" ExcludeView="simple">threshold</Item>
|
||||
<IndexListItems>
|
||||
<Size>size()</Size>
|
||||
<ValueNode>packed.first_base::value[$i].element</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
31
natvis/entt/core.natvis
Normal file
31
natvis/entt/core.natvis
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::basic_any<*>">
|
||||
<DisplayString>{{ type={ info->alias,na }, policy={ mode,en } }}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::compressed_pair<*>">
|
||||
<Intrinsic Name="first" Optional="true" Expression="((first_base*)this)->value"/>
|
||||
<Intrinsic Name="first" Optional="true" Expression="*(first_base::base_type*)this"/>
|
||||
<Intrinsic Name="second" Optional="true" Expression="((second_base*)this)->value"/>
|
||||
<Intrinsic Name="second" Optional="true" Expression="*(second_base::base_type*)this"/>
|
||||
<DisplayString >({ first() }, { second() })</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[first]">first()</Item>
|
||||
<Item Name="[second]">second()</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_hashed_string<*>">
|
||||
<DisplayString Condition="str != nullptr">{{ hash={ hash } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[data]">str,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::type_info">
|
||||
<DisplayString>{{ name={ alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[hash]">identifier</Item>
|
||||
<Item Name="[index]">seq</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
119
natvis/entt/entity.natvis
Normal file
119
natvis/entt/entity.natvis
Normal file
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::basic_registry<*>">
|
||||
<Intrinsic Name="pools_size" Expression="pools.packed.first_base::value.size()"/>
|
||||
<Intrinsic Name="vars_size" Expression="vars.packed.first_base::value.size()"/>
|
||||
<Intrinsic Name="to_entity" Expression="*((entity_traits::entity_type *)&entity) & entity_traits::entity_mask">
|
||||
<Parameter Name="entity" Type="entity_traits::value_type &"/>
|
||||
</Intrinsic>
|
||||
<DisplayString>{{ size={ entities.size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item IncludeView="simple" Name="[entities]">entities,view(simple)nr</Item>
|
||||
<Synthetic Name="[entities]" ExcludeView="simple">
|
||||
<DisplayString>{ entities.size() }</DisplayString>
|
||||
<Expand>
|
||||
<CustomListItems>
|
||||
<Variable Name="pos" InitialValue="0" />
|
||||
<Variable Name="last" InitialValue="entities.size()"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="to_entity(entities[pos]) == pos">
|
||||
<Item Name="[{ pos }]">entities[pos]</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[destroyed]" ExcludeView="simple">
|
||||
<DisplayString>{ to_entity(free_list) != entity_traits::entity_mask }</DisplayString>
|
||||
<Expand>
|
||||
<CustomListItems>
|
||||
<Variable Name="it" InitialValue="to_entity(free_list)" />
|
||||
<Loop>
|
||||
<Break Condition="it == entity_traits::entity_mask"/>
|
||||
<Item Name="[{ it }]">entities[it]</Item>
|
||||
<Exec>it = to_entity(entities[it])</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[pools]">
|
||||
<DisplayString>{ pools_size() }</DisplayString>
|
||||
<Expand>
|
||||
<IndexListItems ExcludeView="simple">
|
||||
<Size>pools_size()</Size>
|
||||
<ValueNode>*pools.packed.first_base::value[$i].element.second</ValueNode>
|
||||
</IndexListItems>
|
||||
<IndexListItems IncludeView="simple">
|
||||
<Size>pools_size()</Size>
|
||||
<ValueNode>*pools.packed.first_base::value[$i].element.second,view(simple)</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Item Name="[groups]" ExcludeView="simple">groups.size()</Item>
|
||||
<Synthetic Name="[vars]">
|
||||
<DisplayString>{ vars_size() }</DisplayString>
|
||||
<Expand>
|
||||
<IndexListItems>
|
||||
<Size>vars_size()</Size>
|
||||
<ValueNode>vars.packed.first_base::value[$i].element.second</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_sparse_set<*>">
|
||||
<DisplayString>{{ size={ packed.size() }, type={ info->alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" ExcludeView="simple">packed.capacity()</Item>
|
||||
<Item Name="[policy]">mode,en</Item>
|
||||
<ExpandedItem IncludeView="simple">packed,view(simple)</ExpandedItem>
|
||||
<CustomListItems ExcludeView="simple">
|
||||
<Variable Name="pos" InitialValue="0" />
|
||||
<Variable Name="last" InitialValue="packed.size()"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="*((entity_traits::entity_type *)&packed[pos]) < ~entity_traits::entity_mask">
|
||||
<Item Name="[{ pos }]">packed[pos]</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_storage<*>">
|
||||
<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::info->alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" Optional="true" ExcludeView="simple">packed.first_base::value.capacity() * comp_traits::page_size</Item>
|
||||
<Item Name="[page size]" Optional="true" ExcludeView="simple">comp_traits::page_size</Item>
|
||||
<Item Name="[base]" ExcludeView="simple">(base_type*)this,nand</Item>
|
||||
<Item Name="[base]" IncludeView="simple">(base_type*)this,view(simple)nand</Item>
|
||||
<!-- having SFINAE-like techniques in natvis is priceless :) -->
|
||||
<CustomListItems Condition="packed.first_base::value.size() != 0" Optional="true">
|
||||
<Variable Name="pos" InitialValue="0" />
|
||||
<Variable Name="last" InitialValue="base_type::packed.size()"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="*((base_type::entity_traits::entity_type *)&base_type::packed[pos]) < ~base_type::entity_traits::entity_mask">
|
||||
<Item Name="[{ pos }]">packed.first_base::value[pos / comp_traits::page_size][pos & (comp_traits::page_size - 1)]</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_view<*>">
|
||||
<DisplayString>{{ size_hint={ view->packed.size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[pools]">pools,na</Item>
|
||||
<Item Name="[filter]">filter,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::null_t">
|
||||
<DisplayString><null></DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::tombstone_t">
|
||||
<DisplayString><tombstone></DisplayString>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
3
natvis/entt/locator.natvis
Normal file
3
natvis/entt/locator.natvis
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
197
natvis/entt/meta.natvis
Normal file
197
natvis/entt/meta.natvis
Normal file
@@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::meta_any">
|
||||
<DisplayString Condition="node != nullptr">{{ type={ node->info->alias,na }, policy={ storage.mode,en } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node != nullptr">*node</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_associative_container">
|
||||
<DisplayString Condition="mapped_type_node != nullptr">{{ key_type={ key_type_node->info->alias,na }, mapped_type={ mapped_type_node->info->alias,na } }}</DisplayString>
|
||||
<DisplayString Condition="key_type_node != nullptr">{{ key_type={ key_type_node->info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_base_node">
|
||||
<DisplayString Condition="type != nullptr">{{ type={ type->info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_conv_node">
|
||||
<DisplayString Condition="type != nullptr">{{ type={ type->info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_ctor_node">
|
||||
<DisplayString Condition="arg != nullptr">{{ arity={ arity } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_data_node">
|
||||
<Intrinsic Name="has_property" Expression="!!(traits & property)">
|
||||
<Parameter Name="property" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString Condition="type != nullptr">{{ type={ type->info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[id]">id</Item>
|
||||
<Item Name="[arity]">arity</Item>
|
||||
<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item>
|
||||
<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item>
|
||||
<Synthetic Name="[prop]" Condition="prop != nullptr">
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<HeadPointer>prop</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_data">
|
||||
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_func_node" >
|
||||
<Intrinsic Name="has_property" Expression="!!(traits & property)">
|
||||
<Parameter Name="property" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString Condition="ret != nullptr">{{ arity={ arity }, ret={ ret->info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[id]">id</Item>
|
||||
<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item>
|
||||
<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item>
|
||||
<Synthetic Name="[prop]" Condition="prop != nullptr">
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<HeadPointer>prop</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_func">
|
||||
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_handle">
|
||||
<DisplayString>{ any }</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_prop_node">
|
||||
<DisplayString Condition="value.node != nullptr">{{ key_type={ id.node->info->alias,na }, mapped_type={ value.node->info->alias,na } }}</DisplayString>
|
||||
<DisplayString Condition="id.node != nullptr">{{ key_type={ id.node->info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[key]">id</Item>
|
||||
<Item Name="[value]">value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_prop">
|
||||
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_sequence_container">
|
||||
<DisplayString Condition="value_type_node != nullptr">{{ value_type={ value_type_node->info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_template_node">
|
||||
<DisplayString Condition="type != nullptr">{{ type={ type->info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[arity]">arity</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_type_node">
|
||||
<Intrinsic Name="has_property" Expression="!!(traits & property)">
|
||||
<Parameter Name="property" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString Condition="info != nullptr">{{ type={ info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[id]">id</Item>
|
||||
<Item Name="[sizeof]">size_of</Item>
|
||||
<Item Name="[is_arithmetic]">has_property(entt::internal::meta_traits::is_arithmetic)</Item>
|
||||
<Item Name="[is_array]">has_property(entt::internal::meta_traits::is_array)</Item>
|
||||
<Item Name="[is_enum]">has_property(entt::internal::meta_traits::is_enum)</Item>
|
||||
<Item Name="[is_class]">has_property(entt::internal::meta_traits::is_class)</Item>
|
||||
<Item Name="[is_pointer]">has_property(entt::internal::meta_traits::is_pointer)</Item>
|
||||
<Item Name="[is_meta_pointer_like]">has_property(entt::internal::meta_traits::is_meta_pointer_like)</Item>
|
||||
<Item Name="[is_meta_sequence_container]">has_property(entt::internal::meta_traits::is_meta_sequence_container)</Item>
|
||||
<Item Name="[is_meta_associative_container]">has_property(entt::internal::meta_traits::is_meta_associative_container)</Item>
|
||||
<Item Name="[default_constructor]">default_constructor != nullptr</Item>
|
||||
<Item Name="[conversion_helper]">conversion_helper != nullptr</Item>
|
||||
<Item Name="[template_info]" Condition="templ != nullptr">*templ</Item>
|
||||
<Synthetic Name="[ctor]" Condition="ctor != nullptr">
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<HeadPointer>ctor</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[base]" Condition="base != nullptr">
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<HeadPointer>base</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[conv]" Condition="conv != nullptr">
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<HeadPointer>conv</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[data]" Condition="data != nullptr">
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<HeadPointer>data</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[func]" Condition="func != nullptr">
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<HeadPointer>func</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[prop]" Condition="prop != nullptr">
|
||||
<Expand>
|
||||
<LinkedListItems>
|
||||
<HeadPointer>prop</HeadPointer>
|
||||
<NextPointer>next</NextPointer>
|
||||
<ValueNode>*this</ValueNode>
|
||||
</LinkedListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_type">
|
||||
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
3
natvis/entt/platform.natvis
Normal file
3
natvis/entt/platform.natvis
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
6
natvis/entt/poly.natvis
Normal file
6
natvis/entt/poly.natvis
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::basic_poly<*>">
|
||||
<DisplayString>{ storage }</DisplayString>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
3
natvis/entt/process.natvis
Normal file
3
natvis/entt/process.natvis
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
3
natvis/entt/resource.natvis
Normal file
3
natvis/entt/resource.natvis
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
52
natvis/entt/signal.natvis
Normal file
52
natvis/entt/signal.natvis
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::connection">
|
||||
<DisplayString>{{ bound={ signal != nullptr } }}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::delegate<*>">
|
||||
<DisplayString>{{ type={ "$T1" } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[empty]">fn == nullptr</Item>
|
||||
<Item Name="[data]">data</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::dispatcher">
|
||||
<DisplayString>{{ size={ pools.size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Synthetic Name="[pools]">
|
||||
<DisplayString>{ pools.size() }</DisplayString>
|
||||
<Expand>
|
||||
<IndexListItems>
|
||||
<Size>pools.size()</Size>
|
||||
<ValueNode>*pools.packed.first_base::value[$i].element.second</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::dispatcher::pool_handler<*>">
|
||||
<DisplayString>{{ size={ events.size() }, event={ "$T1" } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[signal]">signal</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::scoped_connection">
|
||||
<DisplayString>{ conn }</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::sigh<*>">
|
||||
<DisplayString>{{ size={ calls.size() }, type={ "$T1" } }}</DisplayString>
|
||||
<Expand>
|
||||
<IndexListItems>
|
||||
<Size>calls.size()</Size>
|
||||
<ValueNode>calls[$i]</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::sink<*>">
|
||||
<DisplayString>{{ type={ "$T1" } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[signal]">signal,na</Item>
|
||||
<Item Name="[offset]">offset</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,62 +1,69 @@
|
||||
#ifndef ENTT_CONFIG_CONFIG_H
|
||||
#define ENTT_CONFIG_CONFIG_H
|
||||
|
||||
|
||||
#ifndef ENTT_NOEXCEPT
|
||||
# define ENTT_NOEXCEPT noexcept
|
||||
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
|
||||
# define ENTT_NOEXCEPT noexcept
|
||||
# define ENTT_THROW throw
|
||||
# define ENTT_TRY try
|
||||
# define ENTT_CATCH catch(...)
|
||||
#else
|
||||
# define ENTT_NOEXCEPT
|
||||
# define ENTT_THROW
|
||||
# define ENTT_TRY if(true)
|
||||
# define ENTT_CATCH if(false)
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
|
||||
# include <new>
|
||||
# define ENTT_LAUNDER(expr) std::launder(expr)
|
||||
#else
|
||||
# define ENTT_LAUNDER(expr) expr
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_USE_ATOMIC
|
||||
# define ENTT_MAYBE_ATOMIC(Type) Type
|
||||
# define ENTT_MAYBE_ATOMIC(Type) Type
|
||||
#else
|
||||
# include <atomic>
|
||||
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
||||
# include <atomic>
|
||||
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_ID_TYPE
|
||||
# include <cstdint>
|
||||
# define ENTT_ID_TYPE std::uint32_t
|
||||
# include <cstdint>
|
||||
# define ENTT_ID_TYPE std::uint32_t
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ENTT_PAGE_SIZE
|
||||
static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two");
|
||||
#else
|
||||
# define ENTT_PAGE_SIZE 4096
|
||||
#ifndef ENTT_SPARSE_PAGE
|
||||
# define ENTT_SPARSE_PAGE 4096
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_PACKED_PAGE
|
||||
# define ENTT_PACKED_PAGE 1024
|
||||
#endif
|
||||
|
||||
#ifdef ENTT_DISABLE_ASSERT
|
||||
# undef ENTT_ASSERT
|
||||
# define ENTT_ASSERT(...) (void(0))
|
||||
# undef ENTT_ASSERT
|
||||
# define ENTT_ASSERT(...) (void(0))
|
||||
#elif !defined ENTT_ASSERT
|
||||
# include <cassert>
|
||||
# define ENTT_ASSERT(condition) assert(condition)
|
||||
# include <cassert>
|
||||
# define ENTT_ASSERT(condition, ...) assert(condition)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_NO_ETO
|
||||
# include <type_traits>
|
||||
# define ENTT_IS_EMPTY(Type) std::is_empty<Type>
|
||||
#ifdef ENTT_NO_ETO
|
||||
# define ENTT_IGNORE_IF_EMPTY false
|
||||
#else
|
||||
# include <type_traits>
|
||||
# define ENTT_IS_EMPTY(Type) std::false_type
|
||||
# define ENTT_IGNORE_IF_EMPTY true
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_STANDARD_CPP
|
||||
# if defined __clang__ || defined __GNUC__
|
||||
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
# define ENTT_PRETTY_FUNCTION_PREFIX '='
|
||||
# define ENTT_PRETTY_FUNCTION_SUFFIX ']'
|
||||
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
# define ENTT_PRETTY_FUNCTION_PREFIX '='
|
||||
# define ENTT_PRETTY_FUNCTION_SUFFIX ']'
|
||||
# elif defined _MSC_VER
|
||||
# define ENTT_PRETTY_FUNCTION __FUNCSIG__
|
||||
# define ENTT_PRETTY_FUNCTION_PREFIX '<'
|
||||
# define ENTT_PRETTY_FUNCTION_SUFFIX '>'
|
||||
# endif
|
||||
# define ENTT_PRETTY_FUNCTION __FUNCSIG__
|
||||
# define ENTT_PRETTY_FUNCTION_PREFIX '<'
|
||||
# define ENTT_PRETTY_FUNCTION_SUFFIX '>'
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#ifndef ENTT_CONFIG_VERSION_H
|
||||
#define ENTT_CONFIG_VERSION_H
|
||||
|
||||
|
||||
#define ENTT_VERSION_MAJOR 3
|
||||
#define ENTT_VERSION_MINOR 7
|
||||
#define ENTT_VERSION_PATCH 1
|
||||
|
||||
#define ENTT_VERSION_MINOR 9
|
||||
#define ENTT_VERSION_PATCH 0
|
||||
|
||||
#endif
|
||||
|
||||
959
src/entt/container/dense_hash_map.hpp
Normal file
959
src/entt/container/dense_hash_map.hpp
Normal file
@@ -0,0 +1,959 @@
|
||||
#ifndef ENTT_CONTAINER_DENSE_HASH_MAP_HPP
|
||||
#define ENTT_CONTAINER_DENSE_HASH_MAP_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "../core/memory.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Key, typename Type>
|
||||
struct dense_hash_map_node final {
|
||||
template<typename... Args>
|
||||
dense_hash_map_node(const std::size_t pos, Args &&...args)
|
||||
: next{pos},
|
||||
element{std::forward<Args>(args)...} {}
|
||||
|
||||
std::size_t next;
|
||||
std::pair<Key, Type> element;
|
||||
};
|
||||
|
||||
template<typename It>
|
||||
class dense_hash_map_iterator {
|
||||
friend dense_hash_map_iterator<const std::remove_pointer_t<It> *>;
|
||||
|
||||
using iterator_traits = std::iterator_traits<decltype(std::addressof(std::declval<It>()->element))>;
|
||||
|
||||
public:
|
||||
using value_type = typename iterator_traits::value_type;
|
||||
using pointer = typename iterator_traits::pointer;
|
||||
using reference = typename iterator_traits::reference;
|
||||
using difference_type = typename iterator_traits::difference_type;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
dense_hash_map_iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
dense_hash_map_iterator(const It iter) ENTT_NOEXCEPT
|
||||
: it{iter} {}
|
||||
|
||||
template<bool Const = std::is_const_v<std::remove_pointer_t<It>>, typename = std::enable_if_t<Const>>
|
||||
dense_hash_map_iterator(const dense_hash_map_iterator<std::remove_const_t<std::remove_pointer_t<It>> *> &other)
|
||||
: it{other.it} {}
|
||||
|
||||
dense_hash_map_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return ++it, *this;
|
||||
}
|
||||
|
||||
dense_hash_map_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
dense_hash_map_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
dense_hash_map_iterator &operator--() ENTT_NOEXCEPT {
|
||||
return --it, *this;
|
||||
}
|
||||
|
||||
dense_hash_map_iterator operator--(int) ENTT_NOEXCEPT {
|
||||
dense_hash_map_iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
dense_hash_map_iterator &operator+=(const difference_type value) ENTT_NOEXCEPT {
|
||||
it += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
dense_hash_map_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
|
||||
dense_hash_map_iterator copy = *this;
|
||||
return (copy += value);
|
||||
}
|
||||
|
||||
dense_hash_map_iterator &operator-=(const difference_type value) ENTT_NOEXCEPT {
|
||||
return (*this += -value);
|
||||
}
|
||||
|
||||
dense_hash_map_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
|
||||
return (*this + -value);
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator[](const difference_type value) const {
|
||||
return it[value].element;
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const {
|
||||
return std::addressof(it->element);
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend auto operator-(const dense_hash_map_iterator<ILhs> &, const dense_hash_map_iterator<IRhs> &) ENTT_NOEXCEPT;
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend bool operator==(const dense_hash_map_iterator<ILhs> &, const dense_hash_map_iterator<IRhs> &) ENTT_NOEXCEPT;
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend bool operator<(const dense_hash_map_iterator<ILhs> &, const dense_hash_map_iterator<IRhs> &) ENTT_NOEXCEPT;
|
||||
|
||||
private:
|
||||
It it;
|
||||
};
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] auto operator-(const dense_hash_map_iterator<ILhs> &lhs, const dense_hash_map_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.it - rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator==(const dense_hash_map_iterator<ILhs> &lhs, const dense_hash_map_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator!=(const dense_hash_map_iterator<ILhs> &lhs, const dense_hash_map_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator<(const dense_hash_map_iterator<ILhs> &lhs, const dense_hash_map_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.it < rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator>(const dense_hash_map_iterator<ILhs> &lhs, const dense_hash_map_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator<=(const dense_hash_map_iterator<ILhs> &lhs, const dense_hash_map_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator>=(const dense_hash_map_iterator<ILhs> &lhs, const dense_hash_map_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
class dense_hash_map_local_iterator {
|
||||
friend dense_hash_map_local_iterator<const std::remove_pointer_t<It> *>;
|
||||
|
||||
using iterator_traits = std::iterator_traits<decltype(std::addressof(std::declval<It>()->element))>;
|
||||
|
||||
public:
|
||||
using value_type = typename iterator_traits::value_type;
|
||||
using pointer = typename iterator_traits::pointer;
|
||||
using reference = typename iterator_traits::reference;
|
||||
using difference_type = typename iterator_traits::difference_type;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
dense_hash_map_local_iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
dense_hash_map_local_iterator(It iter, const std::size_t pos) ENTT_NOEXCEPT
|
||||
: it{iter},
|
||||
offset{pos} {}
|
||||
|
||||
template<bool Const = std::is_const_v<std::remove_pointer_t<It>>, typename = std::enable_if_t<Const>>
|
||||
dense_hash_map_local_iterator(const dense_hash_map_local_iterator<std::remove_const_t<std::remove_pointer_t<It>> *> &other)
|
||||
: it{other.it},
|
||||
offset{other.offset} {}
|
||||
|
||||
dense_hash_map_local_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return offset = it[offset].next, *this;
|
||||
}
|
||||
|
||||
dense_hash_map_local_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
dense_hash_map_local_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const {
|
||||
return std::addressof(it[offset].element);
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t index() const ENTT_NOEXCEPT {
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
std::size_t offset;
|
||||
};
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator==(const dense_hash_map_local_iterator<ILhs> &lhs, const dense_hash_map_local_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.index() == rhs.index();
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator!=(const dense_hash_map_local_iterator<ILhs> &lhs, const dense_hash_map_local_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Associative container for key-value pairs with unique keys.
|
||||
*
|
||||
* Internally, elements are organized into buckets. Which bucket an element is
|
||||
* placed into depends entirely on the hash of its key. Keys with the same hash
|
||||
* code appear in the same bucket.
|
||||
*
|
||||
* @tparam Key Key type of the associative container.
|
||||
* @tparam Type Mapped type of the associative container.
|
||||
* @tparam Hash Type of function to use to hash the keys.
|
||||
* @tparam KeyEqual Type of function to use to compare the keys for equality.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Key, typename Type, typename Hash, typename KeyEqual, typename Allocator>
|
||||
class dense_hash_map final {
|
||||
static constexpr float default_threshold = 0.875f;
|
||||
static constexpr std::size_t minimum_capacity = 8u;
|
||||
|
||||
using allocator_traits = std::allocator_traits<Allocator>;
|
||||
using alloc = typename allocator_traits::template rebind_alloc<std::pair<const Key, Type>>;
|
||||
using alloc_traits = typename std::allocator_traits<alloc>;
|
||||
|
||||
using node_type = internal::dense_hash_map_node<const Key, Type>;
|
||||
using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
|
||||
using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
|
||||
|
||||
[[nodiscard]] std::size_t hash_to_bucket(const std::size_t hash) const ENTT_NOEXCEPT {
|
||||
return fast_mod(hash, bucket_count());
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &key, std::size_t bucket) {
|
||||
for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
|
||||
if(packed.second()(it->first, key)) {
|
||||
return begin() + it.index();
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &key, std::size_t bucket) const {
|
||||
for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
|
||||
if(packed.second()(it->first, key)) {
|
||||
return cbegin() + it.index();
|
||||
}
|
||||
}
|
||||
|
||||
return cend();
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] auto get_or_emplace(const Key &key, Args &&...args) {
|
||||
const auto hash = sparse.second()(key);
|
||||
auto index = hash_to_bucket(hash);
|
||||
|
||||
if(auto it = constrained_find(key, index); it != end()) {
|
||||
return std::make_pair(it, false);
|
||||
}
|
||||
|
||||
if(const auto count = size() + 1u; count > (bucket_count() * max_load_factor())) {
|
||||
rehash(bucket_count() * 2u);
|
||||
index = hash_to_bucket(hash);
|
||||
}
|
||||
|
||||
packed.first().emplace_back(sparse.first()[index], std::forward<Args>(args)...);
|
||||
// update goes after emplace to enforce exception guarantees
|
||||
sparse.first()[index] = size() - 1u;
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
}
|
||||
|
||||
void move_and_pop(const std::size_t pos) {
|
||||
if(const auto last = size() - 1u; pos != last) {
|
||||
size_type *curr = sparse.first().data() + bucket(packed.first().back().element.first);
|
||||
for(; *curr != last; curr = &packed.first()[*curr].next) {}
|
||||
*curr = pos;
|
||||
|
||||
using node_allocator_traits = typename alloc_traits::template rebind_traits<decltype(node_type::element)>;
|
||||
typename node_allocator_traits::allocator_type allocator = packed.first().get_allocator();
|
||||
auto *ptr = std::addressof(packed.first()[pos].element);
|
||||
|
||||
std::destroy_at(ptr);
|
||||
packed.first()[pos].next = packed.first().back().next;
|
||||
// no exception guarantees when mapped type has a throwing move constructor (we're technically doomed)
|
||||
node_allocator_traits::construct(allocator, ptr, std::move(packed.first().back().element));
|
||||
}
|
||||
|
||||
packed.first().pop_back();
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Key type of the container. */
|
||||
using key_type = Key;
|
||||
/*! @brief Mapped type of the container. */
|
||||
using mapped_type = Type;
|
||||
/*! @brief Key-value type of the container. */
|
||||
using value_type = std::pair<const Key, Type>;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Type of function to use to hash the keys. */
|
||||
using hasher = Hash;
|
||||
/*! @brief Type of function to use to compare the keys for equality. */
|
||||
using key_equal = KeyEqual;
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = internal::dense_hash_map_iterator<typename packed_container_type::pointer>;
|
||||
/*! @brief Constant random access iterator type. */
|
||||
using const_iterator = internal::dense_hash_map_iterator<typename packed_container_type::const_pointer>;
|
||||
/*! @brief Forward iterator type. */
|
||||
using local_iterator = internal::dense_hash_map_local_iterator<typename packed_container_type::pointer>;
|
||||
/*! @brief Constant forward iterator type. */
|
||||
using const_local_iterator = internal::dense_hash_map_local_iterator<typename packed_container_type::const_pointer>;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
dense_hash_map()
|
||||
: dense_hash_map(minimum_capacity) {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit dense_hash_map(const allocator_type &allocator)
|
||||
: dense_hash_map{minimum_capacity, hasher{}, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator and user
|
||||
* supplied minimal number of buckets.
|
||||
* @param bucket_count Minimal number of buckets.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_hash_map(const size_type bucket_count, const allocator_type &allocator)
|
||||
: dense_hash_map{bucket_count, hasher{}, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator, hash
|
||||
* function and user supplied minimal number of buckets.
|
||||
* @param bucket_count Minimal number of buckets.
|
||||
* @param hash Hash function to use.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_hash_map(const size_type bucket_count, const hasher &hash, const allocator_type &allocator)
|
||||
: dense_hash_map{bucket_count, hash, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator, hash
|
||||
* function, compare function and user supplied minimal number of buckets.
|
||||
* @param bucket_count Minimal number of buckets.
|
||||
* @param hash Hash function to use.
|
||||
* @param equal Compare function to use.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit dense_hash_map(const size_type bucket_count, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type())
|
||||
: sparse{allocator, hash},
|
||||
packed{allocator, equal},
|
||||
threshold{default_threshold} {
|
||||
rehash(bucket_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
dense_hash_map(const dense_hash_map &other)
|
||||
: dense_hash_map{other, alloc_traits::select_on_container_copy_construction(other.get_allocator())} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_hash_map(const dense_hash_map &other, const allocator_type &allocator)
|
||||
: sparse{sparse_container_type{other.sparse.first(), allocator}, other.sparse.second()},
|
||||
// cannot copy the container directly due to a nasty issue of apple clang :(
|
||||
packed{packed_container_type{other.packed.first().begin(), other.packed.first().end(), allocator}, other.packed.second()},
|
||||
threshold{other.threshold} {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
dense_hash_map(dense_hash_map &&other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_hash_map(dense_hash_map &&other, const allocator_type &allocator) ENTT_NOEXCEPT
|
||||
: sparse{sparse_container_type{std::move(other.sparse.first()), allocator}, std::move(other.sparse.second())},
|
||||
// cannot move the container directly due to a nasty issue of apple clang :(
|
||||
packed{packed_container_type{std::make_move_iterator(other.packed.first().begin()), std::make_move_iterator(other.packed.first().end()), allocator}, std::move(other.packed.second())},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~dense_hash_map() = default;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This container.
|
||||
*/
|
||||
dense_hash_map &operator=(const dense_hash_map &other) {
|
||||
threshold = other.threshold;
|
||||
sparse.first().clear();
|
||||
packed.first().clear();
|
||||
rehash(other.bucket_count());
|
||||
packed.first().reserve(other.packed.first().size());
|
||||
insert(other.cbegin(), other.cend());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This container.
|
||||
*/
|
||||
dense_hash_map &operator=(dense_hash_map &&other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const ENTT_NOEXCEPT {
|
||||
return sparse.first().get_allocator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning.
|
||||
*
|
||||
* The returned iterator points to the first instance of the internal array.
|
||||
* If the array is empty, the returned iterator will be equal to `end()`.
|
||||
*
|
||||
* @return An iterator to the first instance of the internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT {
|
||||
return packed.first().data();
|
||||
}
|
||||
|
||||
/*! @copydoc cbegin */
|
||||
[[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] iterator begin() ENTT_NOEXCEPT {
|
||||
return packed.first().data();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end.
|
||||
*
|
||||
* The returned iterator points to the element following the last instance
|
||||
* of the internal array. Attempting to dereference the returned iterator
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @return An iterator to the element following the last instance of the
|
||||
* internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT {
|
||||
return packed.first().data() + size();
|
||||
}
|
||||
|
||||
/*! @copydoc cend */
|
||||
[[nodiscard]] const_iterator end() const ENTT_NOEXCEPT {
|
||||
return cend();
|
||||
}
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] iterator end() ENTT_NOEXCEPT {
|
||||
return packed.first().data() + size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a container is empty.
|
||||
* @return True if the container is empty, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
|
||||
return packed.first().empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a container.
|
||||
* @return Number of elements in a container.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
|
||||
return packed.first().size();
|
||||
}
|
||||
|
||||
/*! @brief Clears the container. */
|
||||
void clear() ENTT_NOEXCEPT {
|
||||
sparse.first().clear();
|
||||
packed.first().clear();
|
||||
rehash(0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an element into the container, if the key does not exist.
|
||||
* @param value A key-value pair eventually convertible to the value type.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
std::pair<iterator, bool> insert(const value_type &value) {
|
||||
return emplace(value);
|
||||
}
|
||||
|
||||
/*! @copydoc insert */
|
||||
std::pair<iterator, bool> insert(value_type &&value) {
|
||||
return emplace(std::move(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc insert
|
||||
* @tparam Arg Type of the key-value pair to insert into the container.
|
||||
*/
|
||||
template<typename Arg>
|
||||
std::enable_if_t<std::is_constructible_v<value_type, Arg &&>, std::pair<iterator, bool>>
|
||||
insert(Arg &&value) {
|
||||
return emplace(std::forward<Arg>(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts elements into the container, if their keys do not exist.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
*/
|
||||
template<typename It>
|
||||
void insert(It first, It last) {
|
||||
for(; first != last; ++first) {
|
||||
emplace(*first);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an element into the container or assigns to the current
|
||||
* element if the key already exists.
|
||||
* @tparam Arg Type of the value to insert or assign.
|
||||
* @param key A key used both to look up and to insert if not found.
|
||||
* @param value A value to insert or assign.
|
||||
* @return A pair consisting of an iterator to the element and a bool
|
||||
* denoting whether the insertion took place.
|
||||
*/
|
||||
template<typename Arg>
|
||||
std::pair<iterator, bool> insert_or_assign(const key_type &key, Arg &&value) {
|
||||
auto result = try_emplace(key, std::forward<Arg>(value));
|
||||
|
||||
if(!result.second) {
|
||||
result.first->second = std::forward<Arg>(value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*! @copydoc insert_or_assign */
|
||||
template<typename Arg>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type &&key, Arg &&value) {
|
||||
auto result = try_emplace(std::move(key), std::forward<Arg>(value));
|
||||
|
||||
if(!result.second) {
|
||||
result.first->second = std::forward<Arg>(value);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an element in-place, if the key does not exist.
|
||||
* @tparam Args Types of arguments to forward to the constructor of the
|
||||
* element.
|
||||
* @param args Arguments to forward to the constructor of the element.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
template<typename... Args>
|
||||
std::pair<iterator, bool> emplace(Args &&...args) {
|
||||
if constexpr(sizeof...(Args) == 0u) {
|
||||
return get_or_emplace(key_type{});
|
||||
} else if constexpr(sizeof...(Args) == 1u) {
|
||||
return get_or_emplace(args.first..., std::forward<Args>(args)...);
|
||||
} else if constexpr(sizeof...(Args) == 2u) {
|
||||
return get_or_emplace(std::get<0u>(std::tie(args...)), std::forward<Args>(args)...);
|
||||
} else {
|
||||
static_assert(sizeof...(Args) == 3u, "Invalid arguments");
|
||||
return emplace(std::pair<key_type, mapped_type>{std::forward<Args>(args)...});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts in-place if the key does not exist, does nothing if the
|
||||
* key exists.
|
||||
* @tparam Args Types of arguments to forward to the constructor of the
|
||||
* element.
|
||||
* @param key A key used both to look up and to insert if not found.
|
||||
* @param args Arguments to forward to the constructor of the element.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
template<typename... Args>
|
||||
std::pair<iterator, bool> try_emplace(const key_type &key, Args &&...args) {
|
||||
return get_or_emplace(key, std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/*! @copydoc try_emplace */
|
||||
template<typename... Args>
|
||||
std::pair<iterator, bool> try_emplace(key_type &&key, Args &&...args) {
|
||||
return get_or_emplace(key, std::piecewise_construct, std::forward_as_tuple(std::move(key)), std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes an element from a given position.
|
||||
* @param pos An iterator to the element to remove.
|
||||
* @return An iterator following the removed element.
|
||||
*/
|
||||
iterator erase(const_iterator pos) {
|
||||
const auto dist = std::distance(cbegin(), pos);
|
||||
erase(pos->first);
|
||||
return begin() + dist;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the given elements from a container.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
* @return An iterator following the last removed element.
|
||||
*/
|
||||
iterator erase(const_iterator first, const_iterator last) {
|
||||
const auto dist = std::distance(cbegin(), first);
|
||||
|
||||
for(auto rfirst = std::make_reverse_iterator(last), rlast = std::make_reverse_iterator(first); rfirst != rlast; ++rfirst) {
|
||||
erase(rfirst->first);
|
||||
}
|
||||
|
||||
return dist > static_cast<decltype(dist)>(size()) ? end() : (begin() + dist);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the element associated with a given key.
|
||||
* @param key A key value of an element to remove.
|
||||
* @return Number of elements removed (either 0 or 1).
|
||||
*/
|
||||
size_type erase(const key_type &key) {
|
||||
for(size_type *curr = sparse.first().data() + bucket(key); *curr != std::numeric_limits<size_type>::max(); curr = &packed.first()[*curr].next) {
|
||||
if(packed.second()(packed.first()[*curr].element.first, key)) {
|
||||
const auto index = *curr;
|
||||
*curr = packed.first()[*curr].next;
|
||||
move_and_pop(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given container.
|
||||
* @param other Container to exchange the content with.
|
||||
*/
|
||||
void swap(dense_hash_map &other) {
|
||||
using std::swap;
|
||||
swap(sparse, other.sparse);
|
||||
swap(packed, other.packed);
|
||||
swap(threshold, other.threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accesses a given element with bounds checking.
|
||||
* @param key A key of an element to find.
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
[[nodiscard]] Type &at(const key_type &key) {
|
||||
auto it = find(key);
|
||||
ENTT_ASSERT(it != end(), "Invalid key");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/*! @copydoc at */
|
||||
[[nodiscard]] const Type &at(const key_type &key) const {
|
||||
auto it = find(key);
|
||||
ENTT_ASSERT(it != cend(), "Invalid key");
|
||||
return it->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accesses or inserts a given element.
|
||||
* @param key A key of an element to find or insert.
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
[[nodiscard]] Type &operator[](const key_type &key) {
|
||||
return try_emplace(key).first->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Accesses or inserts a given element.
|
||||
* @param key A key of an element to find or insert.
|
||||
* @return A reference to the mapped value of the requested element.
|
||||
*/
|
||||
[[nodiscard]] Type &operator[](key_type &&key) {
|
||||
return try_emplace(std::move(key)).first->second;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an element with a given key.
|
||||
* @param key Key value of an element to search for.
|
||||
* @return An iterator to an element with the given key. If no such element
|
||||
* is found, a past-the-end iterator is returned.
|
||||
*/
|
||||
[[nodiscard]] iterator find(const key_type &key) {
|
||||
return constrained_find(key, bucket(key));
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
[[nodiscard]] const_iterator find(const key_type &key) const {
|
||||
return constrained_find(key, bucket(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an element with a key that compares _equivalent_ to a given
|
||||
* value.
|
||||
* @tparam Other Type of the key value of an element to search for.
|
||||
* @param key Key value of an element to search for.
|
||||
* @return An iterator to an element with the given key. If no such element
|
||||
* is found, a past-the-end iterator is returned.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
|
||||
find(const Other &key) {
|
||||
return constrained_find(key, bucket(key));
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
|
||||
find(const Other &key) const {
|
||||
return constrained_find(key, bucket(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the container contains an element with a given key.
|
||||
* @param key Key value of an element to search for.
|
||||
* @return True if there is such an element, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const key_type &key) const {
|
||||
return (find(key) != cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the container contains an element with a key that
|
||||
* compares _equivalent_ to a given value.
|
||||
* @tparam Other Type of the key value of an element to search for.
|
||||
* @param key Key value of an element to search for.
|
||||
* @return True if there is such an element, false otherwise.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>>
|
||||
contains(const Other &key) const {
|
||||
return (find(key) != cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator cbegin(const size_type index) const {
|
||||
return {packed.first().data(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator begin(const size_type index) const {
|
||||
return cbegin(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] local_iterator begin(const size_type index) {
|
||||
return {packed.first().data(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
|
||||
return {packed.first().data(), std::numeric_limits<size_type>::max()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator end([[maybe_unused]] const size_type index) const {
|
||||
return cend(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
|
||||
return {packed.first().data(), std::numeric_limits<size_type>::max()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of buckets.
|
||||
* @return The number of buckets.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket_count() const {
|
||||
return sparse.first().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum number of buckets.
|
||||
* @return The maximum number of buckets.
|
||||
*/
|
||||
[[nodiscard]] size_type max_bucket_count() const {
|
||||
return sparse.first().max_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a given bucket.
|
||||
* @param index The index of the bucket to examine.
|
||||
* @return The number of elements in the given bucket.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket_size(const size_type index) const {
|
||||
return static_cast<size_type>(std::distance(begin(index), end(index)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the bucket for a given key.
|
||||
* @param key The value of the key to examine.
|
||||
* @return The bucket for the given key.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket(const key_type &key) const {
|
||||
return hash_to_bucket(sparse.second()(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the average number of elements per bucket.
|
||||
* @return The average number of elements per bucket.
|
||||
*/
|
||||
[[nodiscard]] float load_factor() const {
|
||||
return size() / static_cast<float>(bucket_count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum average number of elements per bucket.
|
||||
* @return The maximum average number of elements per bucket.
|
||||
*/
|
||||
[[nodiscard]] float max_load_factor() const {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the desired maximum average number of elements per bucket.
|
||||
* @param value A desired maximum average number of elements per bucket.
|
||||
*/
|
||||
void max_load_factor(const float value) {
|
||||
ENTT_ASSERT(value > 0.f, "Invalid load factor");
|
||||
threshold = value;
|
||||
rehash(0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserves at least the specified number of buckets and regenerates
|
||||
* the hash table.
|
||||
* @param count New number of buckets.
|
||||
*/
|
||||
void rehash(const size_type count) {
|
||||
auto value = (std::max)(count, minimum_capacity);
|
||||
value = (std::max)(value, static_cast<size_type>(size() / max_load_factor()));
|
||||
|
||||
if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
|
||||
sparse.first().resize(sz);
|
||||
std::fill(sparse.first().begin(), sparse.first().end(), std::numeric_limits<size_type>::max());
|
||||
|
||||
for(size_type pos{}, last = size(); pos < last; ++pos) {
|
||||
const auto index = bucket(packed.first()[pos].element.first);
|
||||
packed.first()[pos].next = std::exchange(sparse.first()[index], pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserves space for at least the specified number of elements and
|
||||
* regenerates the hash table.
|
||||
* @param count New number of elements.
|
||||
*/
|
||||
void reserve(const size_type count) {
|
||||
packed.first().reserve(count);
|
||||
rehash(static_cast<size_type>(std::ceil(count / max_load_factor())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function used to hash the keys.
|
||||
* @return The function used to hash the keys.
|
||||
*/
|
||||
[[nodiscard]] hasher hash_function() const {
|
||||
return sparse.second();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function used to compare keys for equality.
|
||||
* @return The function used to compare keys for equality.
|
||||
*/
|
||||
[[nodiscard]] key_equal key_eq() const {
|
||||
return packed.second();
|
||||
}
|
||||
|
||||
private:
|
||||
compressed_pair<sparse_container_type, hasher> sparse;
|
||||
compressed_pair<packed_container_type, key_equal> packed;
|
||||
float threshold;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
849
src/entt/container/dense_hash_set.hpp
Normal file
849
src/entt/container/dense_hash_set.hpp
Normal file
@@ -0,0 +1,849 @@
|
||||
#ifndef ENTT_CONTAINER_DENSE_HASH_SET_HPP
|
||||
#define ENTT_CONTAINER_DENSE_HASH_SET_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "../core/memory.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type>
|
||||
struct dense_hash_set_node final {
|
||||
template<typename... Args>
|
||||
dense_hash_set_node(const std::size_t pos, Args &&...args)
|
||||
: next{pos},
|
||||
element{std::forward<Args>(args)...} {}
|
||||
|
||||
std::size_t next;
|
||||
Type element;
|
||||
};
|
||||
|
||||
template<typename It>
|
||||
class dense_hash_set_iterator {
|
||||
friend dense_hash_set_iterator<const std::remove_pointer_t<It> *>;
|
||||
|
||||
using iterator_traits = std::iterator_traits<decltype(std::addressof(std::as_const(std::declval<It>()->element)))>;
|
||||
|
||||
public:
|
||||
using value_type = typename iterator_traits::value_type;
|
||||
using pointer = typename iterator_traits::pointer;
|
||||
using reference = typename iterator_traits::reference;
|
||||
using difference_type = typename iterator_traits::difference_type;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
dense_hash_set_iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
dense_hash_set_iterator(const It iter) ENTT_NOEXCEPT
|
||||
: it{iter} {}
|
||||
|
||||
template<bool Const = std::is_const_v<std::remove_pointer_t<It>>, typename = std::enable_if_t<Const>>
|
||||
dense_hash_set_iterator(const dense_hash_set_iterator<std::remove_const_t<std::remove_pointer_t<It>> *> &other)
|
||||
: it{other.it} {}
|
||||
|
||||
dense_hash_set_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return ++it, *this;
|
||||
}
|
||||
|
||||
dense_hash_set_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
dense_hash_set_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
dense_hash_set_iterator &operator--() ENTT_NOEXCEPT {
|
||||
return --it, *this;
|
||||
}
|
||||
|
||||
dense_hash_set_iterator operator--(int) ENTT_NOEXCEPT {
|
||||
dense_hash_set_iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
dense_hash_set_iterator &operator+=(const difference_type value) ENTT_NOEXCEPT {
|
||||
it += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
dense_hash_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
|
||||
dense_hash_set_iterator copy = *this;
|
||||
return (copy += value);
|
||||
}
|
||||
|
||||
dense_hash_set_iterator &operator-=(const difference_type value) ENTT_NOEXCEPT {
|
||||
return (*this += -value);
|
||||
}
|
||||
|
||||
dense_hash_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
|
||||
return (*this + -value);
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator[](const difference_type value) const {
|
||||
return it[value].element;
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const {
|
||||
return std::addressof(it->element);
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend auto operator-(const dense_hash_set_iterator<ILhs> &, const dense_hash_set_iterator<IRhs> &) ENTT_NOEXCEPT;
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend bool operator==(const dense_hash_set_iterator<ILhs> &, const dense_hash_set_iterator<IRhs> &) ENTT_NOEXCEPT;
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend bool operator<(const dense_hash_set_iterator<ILhs> &, const dense_hash_set_iterator<IRhs> &) ENTT_NOEXCEPT;
|
||||
|
||||
private:
|
||||
It it;
|
||||
};
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] auto operator-(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.it - rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator==(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator!=(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator<(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.it < rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator>(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator<=(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator>=(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
class dense_hash_set_local_iterator {
|
||||
friend dense_hash_set_local_iterator<const std::remove_pointer_t<It> *>;
|
||||
|
||||
using iterator_traits = std::iterator_traits<decltype(std::addressof(std::as_const(std::declval<It>()->element)))>;
|
||||
|
||||
public:
|
||||
using value_type = typename iterator_traits::value_type;
|
||||
using pointer = typename iterator_traits::pointer;
|
||||
using reference = typename iterator_traits::reference;
|
||||
using difference_type = typename iterator_traits::difference_type;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
dense_hash_set_local_iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
dense_hash_set_local_iterator(It iter, const std::size_t pos) ENTT_NOEXCEPT
|
||||
: it{iter},
|
||||
offset{pos} {}
|
||||
|
||||
template<bool Const = std::is_const_v<std::remove_pointer_t<It>>, typename = std::enable_if_t<Const>>
|
||||
dense_hash_set_local_iterator(const dense_hash_set_local_iterator<std::remove_const_t<std::remove_pointer_t<It>> *> &other)
|
||||
: it{other.it},
|
||||
offset{other.offset} {}
|
||||
|
||||
dense_hash_set_local_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return offset = it[offset].next, *this;
|
||||
}
|
||||
|
||||
dense_hash_set_local_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
dense_hash_set_local_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const {
|
||||
return std::addressof(it[offset].element);
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::size_t index() const ENTT_NOEXCEPT {
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
std::size_t offset;
|
||||
};
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator==(const dense_hash_set_local_iterator<ILhs> &lhs, const dense_hash_set_local_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.index() == rhs.index();
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] bool operator!=(const dense_hash_set_local_iterator<ILhs> &lhs, const dense_hash_set_local_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Associative container for unique objects of a given type.
|
||||
*
|
||||
* Internally, elements are organized into buckets. Which bucket an element is
|
||||
* placed into depends entirely on its hash. Elements with the same hash code
|
||||
* appear in the same bucket.
|
||||
*
|
||||
* @tparam Type Value type of the associative container.
|
||||
* @tparam Hash Type of function to use to hash the values.
|
||||
* @tparam KeyEqual Type of function to use to compare the values for equality.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Hash, typename KeyEqual, typename Allocator>
|
||||
class dense_hash_set final {
|
||||
static constexpr float default_threshold = 0.875f;
|
||||
static constexpr std::size_t minimum_capacity = 8u;
|
||||
|
||||
using allocator_traits = std::allocator_traits<Allocator>;
|
||||
using alloc = typename allocator_traits::template rebind_alloc<Type>;
|
||||
using alloc_traits = typename std::allocator_traits<alloc>;
|
||||
|
||||
using node_type = internal::dense_hash_set_node<Type>;
|
||||
using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
|
||||
using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
|
||||
|
||||
[[nodiscard]] std::size_t hash_to_bucket(const std::size_t hash) const ENTT_NOEXCEPT {
|
||||
return fast_mod(hash, bucket_count());
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) {
|
||||
for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
|
||||
if(packed.second()(*it, value)) {
|
||||
return begin() + it.index();
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) const {
|
||||
for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
|
||||
if(packed.second()(*it, value)) {
|
||||
return cbegin() + it.index();
|
||||
}
|
||||
}
|
||||
|
||||
return cend();
|
||||
}
|
||||
|
||||
template<typename Arg>
|
||||
[[nodiscard]] auto get_or_emplace(Arg &&arg) {
|
||||
const auto hash = sparse.second()(arg);
|
||||
auto index = hash_to_bucket(hash);
|
||||
|
||||
if(auto it = constrained_find(arg, index); it != end()) {
|
||||
return std::make_pair(it, false);
|
||||
}
|
||||
|
||||
if(const auto count = size() + 1u; count > (bucket_count() * max_load_factor())) {
|
||||
rehash(bucket_count() * 2u);
|
||||
index = hash_to_bucket(hash);
|
||||
}
|
||||
|
||||
packed.first().emplace_back(sparse.first()[index], std::forward<Arg>(arg));
|
||||
// update goes after emplace to enforce exception guarantees
|
||||
sparse.first()[index] = size() - 1u;
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
bool do_erase(const Other &value) {
|
||||
for(size_type *curr = sparse.first().data() + bucket(value); *curr != std::numeric_limits<size_type>::max(); curr = &packed.first()[*curr].next) {
|
||||
if(packed.second()(packed.first()[*curr].element, value)) {
|
||||
const auto index = *curr;
|
||||
*curr = packed.first()[*curr].next;
|
||||
move_and_pop(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void move_and_pop(const std::size_t pos) {
|
||||
if(const auto last = size() - 1u; pos != last) {
|
||||
size_type *curr = sparse.first().data() + bucket(packed.first().back().element);
|
||||
for(; *curr != last; curr = &packed.first()[*curr].next) {}
|
||||
*curr = pos;
|
||||
|
||||
// basic exception guarantees when value type has a throwing move constructor
|
||||
packed.first()[pos] = std::move(packed.first().back());
|
||||
}
|
||||
|
||||
packed.first().pop_back();
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Key type of the container. */
|
||||
using key_type = Type;
|
||||
/*! @brief Value type of the container. */
|
||||
using value_type = Type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Type of function to use to hash the elements. */
|
||||
using hasher = Hash;
|
||||
/*! @brief Type of function to use to compare the elements for equality. */
|
||||
using key_equal = KeyEqual;
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = internal::dense_hash_set_iterator<typename packed_container_type::pointer>;
|
||||
/*! @brief Constant random access iterator type. */
|
||||
using const_iterator = internal::dense_hash_set_iterator<typename packed_container_type::const_pointer>;
|
||||
/*! @brief Forward iterator type. */
|
||||
using local_iterator = internal::dense_hash_set_local_iterator<typename packed_container_type::pointer>;
|
||||
/*! @brief Constant forward iterator type. */
|
||||
using const_local_iterator = internal::dense_hash_set_local_iterator<typename packed_container_type::const_pointer>;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
dense_hash_set()
|
||||
: dense_hash_set(minimum_capacity) {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit dense_hash_set(const allocator_type &allocator)
|
||||
: dense_hash_set{minimum_capacity, hasher{}, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator and user
|
||||
* supplied minimal number of buckets.
|
||||
* @param bucket_count Minimal number of buckets.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_hash_set(const size_type bucket_count, const allocator_type &allocator)
|
||||
: dense_hash_set{bucket_count, hasher{}, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator, hash
|
||||
* function and user supplied minimal number of buckets.
|
||||
* @param bucket_count Minimal number of buckets.
|
||||
* @param hash Hash function to use.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_hash_set(const size_type bucket_count, const hasher &hash, const allocator_type &allocator)
|
||||
: dense_hash_set{bucket_count, hash, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator, hash
|
||||
* function, compare function and user supplied minimal number of buckets.
|
||||
* @param bucket_count Minimal number of buckets.
|
||||
* @param hash Hash function to use.
|
||||
* @param equal Compare function to use.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit dense_hash_set(const size_type bucket_count, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type())
|
||||
: sparse{allocator, hash},
|
||||
packed{allocator, equal},
|
||||
threshold{default_threshold} {
|
||||
rehash(bucket_count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
dense_hash_set(const dense_hash_set &other)
|
||||
: dense_hash_set{other, alloc_traits::select_on_container_copy_construction(other.get_allocator())} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_hash_set(const dense_hash_set &other, const allocator_type &allocator)
|
||||
: sparse{sparse_container_type{other.sparse.first(), allocator}, other.sparse.second()},
|
||||
// cannot copy the container directly due to a nasty issue of apple clang :(
|
||||
packed{packed_container_type{other.packed.first().begin(), other.packed.first().end(), allocator}, other.packed.second()},
|
||||
threshold{other.threshold} {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
dense_hash_set(dense_hash_set &&other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_hash_set(dense_hash_set &&other, const allocator_type &allocator) ENTT_NOEXCEPT
|
||||
: sparse{sparse_container_type{std::move(other.sparse.first()), allocator}, std::move(other.sparse.second())},
|
||||
// cannot move the container directly due to a nasty issue of apple clang :(
|
||||
packed{packed_container_type{std::make_move_iterator(other.packed.first().begin()), std::make_move_iterator(other.packed.first().end()), allocator}, std::move(other.packed.second())},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
~dense_hash_set() = default;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This container.
|
||||
*/
|
||||
dense_hash_set &operator=(const dense_hash_set &other) {
|
||||
threshold = other.threshold;
|
||||
sparse.first().clear();
|
||||
packed.first().clear();
|
||||
rehash(other.bucket_count());
|
||||
packed.first().reserve(other.packed.first().size());
|
||||
insert(other.cbegin(), other.cend());
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This container.
|
||||
*/
|
||||
dense_hash_set &operator=(dense_hash_set &&other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const ENTT_NOEXCEPT {
|
||||
return sparse.first().get_allocator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning.
|
||||
*
|
||||
* The returned iterator points to the first instance of the internal array.
|
||||
* If the array is empty, the returned iterator will be equal to `end()`.
|
||||
*
|
||||
* @return An iterator to the first instance of the internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT {
|
||||
return packed.first().data();
|
||||
}
|
||||
|
||||
/*! @copydoc cbegin */
|
||||
[[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] iterator begin() ENTT_NOEXCEPT {
|
||||
return packed.first().data();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end.
|
||||
*
|
||||
* The returned iterator points to the element following the last instance
|
||||
* of the internal array. Attempting to dereference the returned iterator
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @return An iterator to the element following the last instance of the
|
||||
* internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT {
|
||||
return packed.first().data() + size();
|
||||
}
|
||||
|
||||
/*! @copydoc cend */
|
||||
[[nodiscard]] const_iterator end() const ENTT_NOEXCEPT {
|
||||
return cend();
|
||||
}
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] iterator end() ENTT_NOEXCEPT {
|
||||
return packed.first().data() + size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a container is empty.
|
||||
* @return True if the container is empty, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
|
||||
return packed.first().empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a container.
|
||||
* @return Number of elements in a container.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
|
||||
return packed.first().size();
|
||||
}
|
||||
|
||||
/*! @brief Clears the container. */
|
||||
void clear() ENTT_NOEXCEPT {
|
||||
sparse.first().clear();
|
||||
packed.first().clear();
|
||||
rehash(0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an element into the container, if it does not exist.
|
||||
* @param value An element to insert into the container.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
std::pair<iterator, bool> insert(const value_type &value) {
|
||||
return emplace(value);
|
||||
}
|
||||
|
||||
/*! @copydoc insert */
|
||||
std::pair<iterator, bool> insert(value_type &&value) {
|
||||
return emplace(std::move(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts elements into the container, if they do not exist.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
*/
|
||||
template<typename It>
|
||||
void insert(It first, It last) {
|
||||
for(; first != last; ++first) {
|
||||
emplace(*first);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an element in-place, if it does not exist.
|
||||
* @tparam Args Types of arguments to forward to the constructor of the
|
||||
* element.
|
||||
* @param args Arguments to forward to the constructor of the element.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
template<typename... Args>
|
||||
std::pair<iterator, bool> emplace(Args &&...args) {
|
||||
if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::remove_const_t<std::remove_reference_t<Args>>, value_type>)) {
|
||||
return get_or_emplace(std::forward<Args>(args)...);
|
||||
} else {
|
||||
return get_or_emplace(value_type{std::forward<Args>(args)...});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes an element from a given position.
|
||||
* @param pos An iterator to the element to remove.
|
||||
* @return An iterator following the removed element.
|
||||
*/
|
||||
iterator erase(const_iterator pos) {
|
||||
const auto dist = std::distance(cbegin(), pos);
|
||||
erase(*pos);
|
||||
return begin() + dist;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the given elements from a container.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
* @return An iterator following the last removed element.
|
||||
*/
|
||||
iterator erase(const_iterator first, const_iterator last) {
|
||||
const auto dist = std::distance(cbegin(), first);
|
||||
|
||||
for(auto rfirst = std::make_reverse_iterator(last), rlast = std::make_reverse_iterator(first); rfirst != rlast; ++rfirst) {
|
||||
erase(*rfirst);
|
||||
}
|
||||
|
||||
return dist > static_cast<decltype(dist)>(size()) ? end() : (begin() + dist);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the element associated with a given value.
|
||||
* @param value Value of an element to remove.
|
||||
* @return Number of elements removed (either 0 or 1).
|
||||
*/
|
||||
size_type erase(const value_type &value) {
|
||||
return do_erase(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given container.
|
||||
* @param other Container to exchange the content with.
|
||||
*/
|
||||
void swap(dense_hash_set &other) {
|
||||
using std::swap;
|
||||
swap(sparse, other.sparse);
|
||||
swap(packed, other.packed);
|
||||
swap(threshold, other.threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an element with a given value.
|
||||
* @param value Value of an element to search for.
|
||||
* @return An iterator to an element with the given value. If no such
|
||||
* element is found, a past-the-end iterator is returned.
|
||||
*/
|
||||
[[nodiscard]] iterator find(const value_type &value) {
|
||||
return constrained_find(value, bucket(value));
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
[[nodiscard]] const_iterator find(const value_type &value) const {
|
||||
return constrained_find(value, bucket(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an element that compares _equivalent_ to a given value.
|
||||
* @tparam Other Type of an element to search for.
|
||||
* @param value Value of an element to search for.
|
||||
* @return An iterator to an element with the given value. If no such
|
||||
* element is found, a past-the-end iterator is returned.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
|
||||
find(const Other &value) {
|
||||
return constrained_find(value, bucket(value));
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
|
||||
find(const Other &value) const {
|
||||
return constrained_find(value, bucket(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the container contains an element with a given value.
|
||||
* @param value Value of an element to search for.
|
||||
* @return True if there is such an element, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const value_type &value) const {
|
||||
return (find(value) != cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the container contains an element that compares
|
||||
* _equivalent_ to a given value.
|
||||
* @tparam Other Type of an element to search for.
|
||||
* @param value Value of an element to search for.
|
||||
* @return True if there is such an element, false otherwise.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>>
|
||||
contains(const Other &value) const {
|
||||
return (find(value) != cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator cbegin(const size_type index) const {
|
||||
return {packed.first().data(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator begin(const size_type index) const {
|
||||
return cbegin(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] local_iterator begin(const size_type index) {
|
||||
return {packed.first().data(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
|
||||
return {packed.first().data(), std::numeric_limits<size_type>::max()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator end([[maybe_unused]] const size_type index) const {
|
||||
return cend(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
|
||||
return {packed.first().data(), std::numeric_limits<size_type>::max()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of buckets.
|
||||
* @return The number of buckets.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket_count() const {
|
||||
return sparse.first().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum number of buckets.
|
||||
* @return The maximum number of buckets.
|
||||
*/
|
||||
[[nodiscard]] size_type max_bucket_count() const {
|
||||
return sparse.first().max_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a given bucket.
|
||||
* @param index The index of the bucket to examine.
|
||||
* @return The number of elements in the given bucket.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket_size(const size_type index) const {
|
||||
return static_cast<size_type>(std::distance(begin(index), end(index)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the bucket for a given element.
|
||||
* @param value The value of the element to examine.
|
||||
* @return The bucket for the given element.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket(const value_type &value) const {
|
||||
return hash_to_bucket(sparse.second()(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the average number of elements per bucket.
|
||||
* @return The average number of elements per bucket.
|
||||
*/
|
||||
[[nodiscard]] float load_factor() const {
|
||||
return size() / static_cast<float>(bucket_count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum average number of elements per bucket.
|
||||
* @return The maximum average number of elements per bucket.
|
||||
*/
|
||||
[[nodiscard]] float max_load_factor() const {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the desired maximum average number of elements per bucket.
|
||||
* @param value A desired maximum average number of elements per bucket.
|
||||
*/
|
||||
void max_load_factor(const float value) {
|
||||
ENTT_ASSERT(value > 0.f, "Invalid load factor");
|
||||
threshold = value;
|
||||
rehash(0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserves at least the specified number of buckets and regenerates
|
||||
* the hash table.
|
||||
* @param count New number of buckets.
|
||||
*/
|
||||
void rehash(const size_type count) {
|
||||
auto value = (std::max)(count, minimum_capacity);
|
||||
value = (std::max)(value, static_cast<size_type>(size() / max_load_factor()));
|
||||
|
||||
if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
|
||||
sparse.first().resize(sz);
|
||||
std::fill(sparse.first().begin(), sparse.first().end(), std::numeric_limits<size_type>::max());
|
||||
|
||||
for(size_type pos{}, last = size(); pos < last; ++pos) {
|
||||
const auto index = bucket(packed.first()[pos].element);
|
||||
packed.first()[pos].next = std::exchange(sparse.first()[index], pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserves space for at least the specified number of elements and
|
||||
* regenerates the hash table.
|
||||
* @param count New number of elements.
|
||||
*/
|
||||
void reserve(const size_type count) {
|
||||
packed.first().reserve(count);
|
||||
rehash(static_cast<size_type>(std::ceil(count / max_load_factor())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function used to hash the elements.
|
||||
* @return The function used to hash the elements.
|
||||
*/
|
||||
[[nodiscard]] hasher hash_function() const {
|
||||
return sparse.second();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function used to compare elements for equality.
|
||||
* @return The function used to compare elements for equality.
|
||||
*/
|
||||
[[nodiscard]] key_equal key_eq() const {
|
||||
return packed.second();
|
||||
}
|
||||
|
||||
private:
|
||||
compressed_pair<sparse_container_type, hasher> sparse;
|
||||
compressed_pair<packed_container_type, key_equal> packed;
|
||||
float threshold;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
25
src/entt/container/fwd.hpp
Normal file
25
src/entt/container/fwd.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef ENTT_CONTAINER_FWD_HPP
|
||||
#define ENTT_CONTAINER_FWD_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<
|
||||
typename Key, typename Type,
|
||||
typename = std::hash<Key>,
|
||||
typename = std::equal_to<Key>,
|
||||
typename = std::allocator<std::pair<const Key, Type>>>
|
||||
class dense_hash_map;
|
||||
|
||||
template<
|
||||
typename Type,
|
||||
typename = std::hash<Type>,
|
||||
typename = std::equal_to<Type>,
|
||||
typename = std::allocator<Type>>
|
||||
class dense_hash_set;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,18 +1,15 @@
|
||||
#ifndef ENTT_CORE_ALGORITHM_HPP
|
||||
#define ENTT_CORE_ALGORITHM_HPP
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "utility.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function object to wrap `std::sort` in a class type.
|
||||
*
|
||||
@@ -36,12 +33,11 @@ struct std_sort {
|
||||
* @param args Arguments to forward to the sort function, if any.
|
||||
*/
|
||||
template<typename It, typename Compare = std::less<>, typename... Args>
|
||||
void operator()(It first, It last, Compare compare = Compare{}, Args &&... args) const {
|
||||
void operator()(It first, It last, Compare compare = Compare{}, Args &&...args) const {
|
||||
std::sort(std::forward<Args>(args)..., std::move(first), std::move(last), std::move(compare));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*! @brief Function object for performing insertion sort. */
|
||||
struct insertion_sort {
|
||||
/**
|
||||
@@ -62,8 +58,8 @@ struct insertion_sort {
|
||||
auto value = std::move(*it);
|
||||
auto pre = it;
|
||||
|
||||
for(; pre > first && compare(value, *(pre-1)); --pre) {
|
||||
*pre = std::move(*(pre-1));
|
||||
for(; pre > first && compare(value, *(pre - 1)); --pre) {
|
||||
*pre = std::move(*(pre - 1));
|
||||
}
|
||||
|
||||
*pre = std::move(value);
|
||||
@@ -72,7 +68,6 @@ struct insertion_sort {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Function object for performing LSD radix sort.
|
||||
* @tparam Bit Number of bits processed per pass.
|
||||
@@ -137,8 +132,6 @@ struct radix_sort {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
#ifndef ENTT_CORE_ANY_HPP
|
||||
#define ENTT_CORE_ANY_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @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.
|
||||
@@ -24,7 +20,21 @@ namespace entt {
|
||||
*/
|
||||
template<std::size_t Len, std::size_t Align>
|
||||
class basic_any {
|
||||
enum class operation { COPY, MOVE, DTOR, COMP, ADDR, CADDR, REF, CREF, TYPE };
|
||||
enum class operation : std::uint8_t {
|
||||
copy,
|
||||
move,
|
||||
transfer,
|
||||
assign,
|
||||
destroy,
|
||||
compare,
|
||||
get
|
||||
};
|
||||
|
||||
enum class policy : std::uint8_t {
|
||||
owner,
|
||||
ref,
|
||||
cref
|
||||
};
|
||||
|
||||
using storage_type = std::aligned_storage_t<Len + !Len, Align>;
|
||||
using vtable_type = const void *(const operation, const basic_any &, const void *);
|
||||
@@ -33,158 +43,82 @@ class basic_any {
|
||||
static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v<Type>;
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static bool compare(const void *lhs, const void *rhs) {
|
||||
if constexpr(!std::is_function_v<Type> && is_equality_comparable_v<Type>) {
|
||||
return *static_cast<const Type *>(lhs) == *static_cast<const Type *>(rhs);
|
||||
static const void *basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &value, [[maybe_unused]] const void *other) {
|
||||
static_assert(!std::is_same_v<Type, void> && std::is_same_v<std::remove_reference_t<std::remove_const_t<Type>>, Type>, "Invalid type");
|
||||
const Type *instance = nullptr;
|
||||
|
||||
if constexpr(in_situ<Type>) {
|
||||
instance = (value.mode == policy::owner) ? ENTT_LAUNDER(reinterpret_cast<const Type *>(&value.storage)) : static_cast<const Type *>(value.instance);
|
||||
} else {
|
||||
return lhs == rhs;
|
||||
instance = static_cast<const Type *>(value.instance);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
static Type & as(const void *to) {
|
||||
return *const_cast<Type *>(static_cast<const Type *>(to));
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] const void *to) {
|
||||
if constexpr(std::is_void_v<Type>) {
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
case operation::MOVE:
|
||||
case operation::REF:
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch(op) {
|
||||
case operation::copy:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*instance);
|
||||
}
|
||||
} else if constexpr(std::is_lvalue_reference_v<Type>) {
|
||||
using base_type = std::decay_t<Type>;
|
||||
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
if constexpr(std::is_copy_constructible_v<base_type>) {
|
||||
as<basic_any>(to) = *static_cast<const base_type *>(from.instance);
|
||||
break;
|
||||
case operation::move:
|
||||
if constexpr(in_situ<Type>) {
|
||||
if(value.mode == policy::owner) {
|
||||
return new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(instance))};
|
||||
}
|
||||
break;
|
||||
case operation::MOVE:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
[[fallthrough]];
|
||||
case operation::DTOR:
|
||||
break;
|
||||
case operation::COMP:
|
||||
return compare<base_type>(from.instance, to) ? to : nullptr;
|
||||
case operation::ADDR:
|
||||
return std::is_const_v<std::remove_reference_t<Type>> ? nullptr : from.instance;
|
||||
case operation::CADDR:
|
||||
return from.instance;
|
||||
case operation::REF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<Type>;
|
||||
break;
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<const base_type &>;
|
||||
break;
|
||||
case operation::TYPE:
|
||||
as<type_info>(to) = type_id<base_type>();
|
||||
break;
|
||||
}
|
||||
} else if constexpr(in_situ<Type>) {
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
|
||||
auto *instance = const_cast<Type *>(std::launder(reinterpret_cast<const Type *>(&from.storage)));
|
||||
#else
|
||||
auto *instance = const_cast<Type *>(reinterpret_cast<const Type *>(&from.storage));
|
||||
#endif
|
||||
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
new (&as<basic_any>(to).storage) Type{std::as_const(*instance)};
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
}
|
||||
break;
|
||||
case operation::MOVE:
|
||||
new (&as<basic_any>(to).storage) Type{std::move(*instance)};
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
break;
|
||||
case operation::DTOR:
|
||||
return (static_cast<basic_any *>(const_cast<void *>(other))->instance = std::exchange(const_cast<basic_any &>(value).instance, nullptr));
|
||||
case operation::transfer:
|
||||
if constexpr(std::is_move_assignable_v<Type>) {
|
||||
*const_cast<Type *>(instance) = std::move(*static_cast<Type *>(const_cast<void *>(other)));
|
||||
return other;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case operation::assign:
|
||||
if constexpr(std::is_copy_assignable_v<Type>) {
|
||||
*const_cast<Type *>(instance) = *static_cast<const Type *>(other);
|
||||
return other;
|
||||
}
|
||||
break;
|
||||
case operation::destroy:
|
||||
if constexpr(in_situ<Type>) {
|
||||
instance->~Type();
|
||||
break;
|
||||
case operation::COMP:
|
||||
return compare<Type>(instance, to) ? to : nullptr;
|
||||
case operation::ADDR:
|
||||
case operation::CADDR:
|
||||
return instance;
|
||||
case operation::REF:
|
||||
as<basic_any>(to).instance = instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<Type &>;
|
||||
break;
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).instance = instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<const Type &>;
|
||||
break;
|
||||
case operation::TYPE:
|
||||
as<type_info>(to) = type_id<Type>();
|
||||
break;
|
||||
} else if constexpr(std::is_array_v<Type>) {
|
||||
delete[] instance;
|
||||
} else {
|
||||
delete instance;
|
||||
}
|
||||
} else {
|
||||
switch(op) {
|
||||
case operation::COPY:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
as<basic_any>(to).instance = new Type{*static_cast<const Type *>(from.instance)};
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
}
|
||||
break;
|
||||
case operation::MOVE:
|
||||
as<basic_any>(to).instance = std::exchange(as<basic_any>(&from).instance, nullptr);
|
||||
as<basic_any>(to).vtable = from.vtable;
|
||||
break;
|
||||
case operation::DTOR:
|
||||
if constexpr(std::is_array_v<Type>) {
|
||||
delete[] static_cast<const Type *>(from.instance);
|
||||
} else {
|
||||
delete static_cast<const Type *>(from.instance);
|
||||
}
|
||||
break;
|
||||
case operation::COMP:
|
||||
return compare<Type>(from.instance, to) ? to : nullptr;
|
||||
case operation::ADDR:
|
||||
case operation::CADDR:
|
||||
return from.instance;
|
||||
case operation::REF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<Type &>;
|
||||
break;
|
||||
case operation::CREF:
|
||||
as<basic_any>(to).instance = from.instance;
|
||||
as<basic_any>(to).vtable = basic_vtable<const Type &>;
|
||||
break;
|
||||
case operation::TYPE:
|
||||
as<type_info>(to) = type_id<Type>();
|
||||
break;
|
||||
break;
|
||||
case operation::compare:
|
||||
if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
|
||||
return *static_cast<const Type *>(instance) == *static_cast<const Type *>(other) ? other : nullptr;
|
||||
} else {
|
||||
return (instance == other) ? other : nullptr;
|
||||
}
|
||||
case operation::get:
|
||||
return instance;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args>
|
||||
void initialize([[maybe_unused]] Args &&... args) {
|
||||
void initialize([[maybe_unused]] Args &&...args) {
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
vtable = basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>;
|
||||
info = &type_id<Type>();
|
||||
|
||||
if constexpr(std::is_lvalue_reference_v<Type>) {
|
||||
static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments");
|
||||
mode = std::is_const_v<std::remove_reference_t<Type>> ? policy::cref : policy::ref;
|
||||
instance = (std::addressof(args), ...);
|
||||
} else if constexpr(in_situ<Type>) {
|
||||
if constexpr(std::is_aggregate_v<Type>) {
|
||||
new (&storage) Type{std::forward<Args>(args)...};
|
||||
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
|
||||
new(&storage) Type{std::forward<Args>(args)...};
|
||||
} else {
|
||||
new (&storage) Type(std::forward<Args>(args)...);
|
||||
new(&storage) Type(std::forward<Args>(args)...);
|
||||
}
|
||||
} else {
|
||||
if constexpr(std::is_aggregate_v<Type>) {
|
||||
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
|
||||
instance = new Type{std::forward<Args>(args)...};
|
||||
} else {
|
||||
instance = new Type(std::forward<Args>(args)...);
|
||||
@@ -193,54 +127,57 @@ class basic_any {
|
||||
}
|
||||
}
|
||||
|
||||
basic_any(const basic_any &other, const policy pol) ENTT_NOEXCEPT
|
||||
: instance{other.data()},
|
||||
info{other.info},
|
||||
vtable{other.vtable},
|
||||
mode{pol} {}
|
||||
|
||||
public:
|
||||
/*! @brief Size of the internal storage. */
|
||||
static constexpr auto length = Len;
|
||||
/*! @brief Alignment requirement. */
|
||||
static constexpr auto alignment = Align;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_any() ENTT_NOEXCEPT
|
||||
: basic_any{std::in_place_type<void>}
|
||||
{}
|
||||
: instance{},
|
||||
info{&type_id<void>()},
|
||||
vtable{},
|
||||
mode{policy::owner} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an any by directly initializing the new object.
|
||||
* @brief Constructs a wrapper by directly initializing the new object.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
explicit basic_any(std::in_place_type_t<Type>, Args &&... args)
|
||||
: instance{},
|
||||
vtable{&basic_vtable<Type>}
|
||||
{
|
||||
explicit basic_any(std::in_place_type_t<Type>, Args &&...args)
|
||||
: basic_any{} {
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an any that holds an unmanaged object.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
*/
|
||||
template<typename Type>
|
||||
basic_any(std::reference_wrapper<Type> value) ENTT_NOEXCEPT
|
||||
: basic_any{std::in_place_type<Type &>, value.get()}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Constructs an any from a given value.
|
||||
* @brief Constructs a wrapper from a given value.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
|
||||
basic_any(Type &&value)
|
||||
: basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)}
|
||||
{}
|
||||
: basic_any{} {
|
||||
initialize<std::decay_t<Type>>(std::forward<Type>(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
basic_any(const basic_any &other)
|
||||
: basic_any{std::in_place_type<void>}
|
||||
{
|
||||
other.vtable(operation::COPY, other, this);
|
||||
: basic_any{} {
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::copy, other, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,14 +185,20 @@ public:
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_any(basic_any &&other) ENTT_NOEXCEPT
|
||||
: basic_any{std::in_place_type<void>}
|
||||
{
|
||||
other.vtable(operation::MOVE, other, this);
|
||||
: instance{},
|
||||
info{other.info},
|
||||
vtable{other.vtable},
|
||||
mode{other.mode} {
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::move, other, this);
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Frees the internal storage, whatever it means. */
|
||||
~basic_any() {
|
||||
vtable(operation::DTOR, *this, nullptr);
|
||||
if(vtable && mode == policy::owner) {
|
||||
vtable(operation::destroy, *this, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,9 +206,13 @@ public:
|
||||
* @param other The instance to copy from.
|
||||
* @return This any object.
|
||||
*/
|
||||
basic_any & operator=(const basic_any &other) {
|
||||
vtable(operation::DTOR, *this, nullptr);
|
||||
other.vtable(operation::COPY, other, this);
|
||||
basic_any &operator=(const basic_any &other) {
|
||||
reset();
|
||||
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::copy, other, this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -274,21 +221,16 @@ public:
|
||||
* @param other The instance to move from.
|
||||
* @return This any object.
|
||||
*/
|
||||
basic_any & operator=(basic_any &&other) {
|
||||
vtable(operation::DTOR, *this, nullptr);
|
||||
other.vtable(operation::MOVE, other, this);
|
||||
return *this;
|
||||
}
|
||||
basic_any &operator=(basic_any &&other) ENTT_NOEXCEPT {
|
||||
reset();
|
||||
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::move, other, this);
|
||||
info = other.info;
|
||||
vtable = other.vtable;
|
||||
mode = other.mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Value assignment operator.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
* @return This any object.
|
||||
*/
|
||||
template<typename Type>
|
||||
basic_any & operator=(std::reference_wrapper<Type> value) ENTT_NOEXCEPT {
|
||||
emplace<Type &>(value.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -306,26 +248,45 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the type of the contained object.
|
||||
* @return The type of the contained object, if any.
|
||||
* @brief Returns the object type if any, `type_id<void>()` otherwise.
|
||||
* @return The object type if any, `type_id<void>()` otherwise.
|
||||
*/
|
||||
[[nodiscard]] type_info type() const ENTT_NOEXCEPT {
|
||||
type_info info{};
|
||||
vtable(operation::TYPE, *this, &info);
|
||||
return info;
|
||||
[[nodiscard]] const type_info &type() const ENTT_NOEXCEPT {
|
||||
return *info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] const void * data() const ENTT_NOEXCEPT {
|
||||
return vtable(operation::CADDR, *this, nullptr);
|
||||
[[nodiscard]] const void *data() const ENTT_NOEXCEPT {
|
||||
return vtable ? vtable(operation::get, *this, nullptr) : nullptr;
|
||||
}
|
||||
|
||||
/*! @copydoc data */
|
||||
[[nodiscard]] void * data() ENTT_NOEXCEPT {
|
||||
return const_cast<void *>(vtable(operation::ADDR, *this, nullptr));
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @param req Expected type.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] const void *data(const type_info &req) const ENTT_NOEXCEPT {
|
||||
return *info == req ? data() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data() ENTT_NOEXCEPT {
|
||||
return (!vtable || mode == policy::cref) ? nullptr : const_cast<void *>(vtable(operation::get, *this, nullptr));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @param req Expected type.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data(const type_info &req) ENTT_NOEXCEPT {
|
||||
return *info == req ? data() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -335,14 +296,50 @@ public:
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
void emplace(Args &&... args) {
|
||||
std::exchange(vtable, &basic_vtable<Type>)(operation::DTOR, *this, nullptr);
|
||||
void emplace(Args &&...args) {
|
||||
reset();
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy assigns a value to the contained object without replacing it.
|
||||
* @param other The value to assign to the contained object.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool assign(const any &other) {
|
||||
if(vtable && mode != policy::cref && *info == *other.info) {
|
||||
return (vtable(operation::assign, *this, other.data()) != nullptr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assigns a value to the contained object without replacing it.
|
||||
* @param other The value to assign to the contained object.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool assign(any &&other) {
|
||||
if(vtable && mode != policy::cref && *info == *other.info) {
|
||||
if(auto *val = other.data(); val) {
|
||||
return (vtable(operation::transfer, *this, val) != nullptr);
|
||||
} else {
|
||||
return (vtable(operation::assign, *this, std::as_const(other).data()) != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! @brief Destroys contained object */
|
||||
void reset() {
|
||||
std::exchange(vtable, &basic_vtable<void>)(operation::DTOR, *this, nullptr);
|
||||
if(vtable && mode == policy::owner) {
|
||||
vtable(operation::destroy, *this, nullptr);
|
||||
}
|
||||
|
||||
info = &type_id<void>();
|
||||
vtable = nullptr;
|
||||
mode = policy::owner;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -350,7 +347,7 @@ public:
|
||||
* @return False if the wrapper is empty, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
|
||||
return !(vtable(operation::CADDR, *this, nullptr) == nullptr);
|
||||
return vtable != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,32 +356,44 @@ public:
|
||||
* @return False if the two objects differ in their content, true otherwise.
|
||||
*/
|
||||
bool operator==(const basic_any &other) const ENTT_NOEXCEPT {
|
||||
return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data());
|
||||
if(vtable && *info == *other.info) {
|
||||
return (vtable(operation::compare, *this, other.data()) != nullptr);
|
||||
}
|
||||
|
||||
return (!vtable && !other.vtable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Aliasing constructor.
|
||||
* @return An any that shares a reference to an unmanaged object.
|
||||
* @return A wrapper that shares a reference to an unmanaged object.
|
||||
*/
|
||||
[[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT {
|
||||
basic_any ref{};
|
||||
vtable(operation::REF, *this, &ref);
|
||||
return ref;
|
||||
return basic_any{*this, (mode == policy::cref ? policy::cref : policy::ref)};
|
||||
}
|
||||
|
||||
/*! @copydoc as_ref */
|
||||
[[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT {
|
||||
basic_any ref{};
|
||||
vtable(operation::CREF, *this, &ref);
|
||||
return ref;
|
||||
return basic_any{*this, policy::cref};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a wrapper owns its object, false otherwise.
|
||||
* @return True if the wrapper owns its object, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool owner() const ENTT_NOEXCEPT {
|
||||
return (mode == policy::owner);
|
||||
}
|
||||
|
||||
private:
|
||||
union { const void *instance; storage_type storage; };
|
||||
union {
|
||||
const void *instance;
|
||||
storage_type storage;
|
||||
};
|
||||
const type_info *info;
|
||||
vtable_type *vtable;
|
||||
policy mode;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if two wrappers differ in their content.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
@@ -398,7 +407,6 @@ template<std::size_t Len, std::size_t Align>
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Performs type-safe access to the contained object.
|
||||
* @tparam Type Type to which conversion is required.
|
||||
@@ -409,48 +417,78 @@ template<std::size_t Len, std::size_t Align>
|
||||
*/
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type any_cast(const basic_any<Len, Align> &data) ENTT_NOEXCEPT {
|
||||
const auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
|
||||
ENTT_ASSERT(instance);
|
||||
const auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(*instance);
|
||||
}
|
||||
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type any_cast(basic_any<Len, Align> &data) ENTT_NOEXCEPT {
|
||||
// forces const on non-reference types to make them work also with wrappers for const references
|
||||
auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
|
||||
ENTT_ASSERT(instance);
|
||||
auto *const instance = any_cast<std::remove_reference_t<const Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(*instance);
|
||||
}
|
||||
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type any_cast(basic_any<Len, Align> &&data) ENTT_NOEXCEPT {
|
||||
// forces const on non-reference types to make them work also with wrappers for const references
|
||||
auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
|
||||
ENTT_ASSERT(instance);
|
||||
return static_cast<Type>(std::move(*instance));
|
||||
if constexpr(std::is_copy_constructible_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
|
||||
if(auto *const instance = any_cast<std::remove_reference_t<Type>>(&data); instance) {
|
||||
return static_cast<Type>(std::move(*instance));
|
||||
} else {
|
||||
return any_cast<Type>(data);
|
||||
}
|
||||
} else {
|
||||
auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(std::move(*instance));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
const Type * any_cast(const basic_any<Len, Align> *data) ENTT_NOEXCEPT {
|
||||
return (data->type() == type_id<Type>() ? static_cast<const Type *>(data->data()) : nullptr);
|
||||
const Type *any_cast(const basic_any<Len, Align> *data) ENTT_NOEXCEPT {
|
||||
const auto &info = type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
|
||||
return static_cast<const Type *>(data->data(info));
|
||||
}
|
||||
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
Type * any_cast(basic_any<Len, Align> *data) ENTT_NOEXCEPT {
|
||||
Type *any_cast(basic_any<Len, Align> *data) ENTT_NOEXCEPT {
|
||||
const auto &info = type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
|
||||
// last attempt to make wrappers for const references return their values
|
||||
return (data->type() == type_id<Type>() ? static_cast<Type *>(static_cast<constness_as_t<basic_any<Len, Align>, Type> *>(data)->data()) : nullptr);
|
||||
return static_cast<Type *>(static_cast<constness_as_t<basic_any<Len, Align>, Type> *>(data)->data(info));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructs a wrapper from a given type, passing it all arguments.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Optional alignment requirement.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
* @return A properly initialized wrapper for an object of the given type.
|
||||
*/
|
||||
template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args>
|
||||
basic_any<Len, Align> make_any(Args &&...args) {
|
||||
return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forwards its argument and avoids copies for lvalue references.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Optional alignment requirement.
|
||||
* @tparam Type Type of argument to use to construct the new instance.
|
||||
* @param value Parameter to use to construct the instance.
|
||||
* @return A properly initialized and not necessarily owning wrapper.
|
||||
*/
|
||||
template<std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename Type>
|
||||
basic_any<Len, Align> forward_as_any(Type &&value) {
|
||||
return basic_any<Len, Align>{std::in_place_type<std::conditional_t<std::is_rvalue_reference_v<Type>, std::decay_t<Type>, Type>>, std::forward<Type>(value)};
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,33 +1,30 @@
|
||||
#ifndef ENTT_CORE_ATTRIBUTE_H
|
||||
#define ENTT_CORE_ATTRIBUTE_H
|
||||
|
||||
|
||||
#ifndef ENTT_EXPORT
|
||||
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
|
||||
# define ENTT_EXPORT __declspec(dllexport)
|
||||
# define ENTT_IMPORT __declspec(dllimport)
|
||||
# define ENTT_HIDDEN
|
||||
# elif defined __GNUC__ && __GNUC__ >= 4
|
||||
# define ENTT_EXPORT __attribute__((visibility("default")))
|
||||
# define ENTT_IMPORT __attribute__((visibility("default")))
|
||||
# define ENTT_HIDDEN __attribute__((visibility("hidden")))
|
||||
# else /* Unsupported compiler */
|
||||
# define ENTT_EXPORT
|
||||
# define ENTT_IMPORT
|
||||
# define ENTT_HIDDEN
|
||||
# endif
|
||||
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
|
||||
# define ENTT_EXPORT __declspec(dllexport)
|
||||
# define ENTT_IMPORT __declspec(dllimport)
|
||||
# define ENTT_HIDDEN
|
||||
# elif defined __GNUC__ && __GNUC__ >= 4
|
||||
# define ENTT_EXPORT __attribute__((visibility("default")))
|
||||
# define ENTT_IMPORT __attribute__((visibility("default")))
|
||||
# define ENTT_HIDDEN __attribute__((visibility("hidden")))
|
||||
# else /* Unsupported compiler */
|
||||
# define ENTT_EXPORT
|
||||
# define ENTT_IMPORT
|
||||
# define ENTT_HIDDEN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENTT_API
|
||||
# if defined ENTT_API_EXPORT
|
||||
# define ENTT_API ENTT_EXPORT
|
||||
# elif defined ENTT_API_IMPORT
|
||||
# define ENTT_API ENTT_IMPORT
|
||||
# else /* No API */
|
||||
# define ENTT_API
|
||||
# endif
|
||||
# if defined ENTT_API_EXPORT
|
||||
# define ENTT_API ENTT_EXPORT
|
||||
# elif defined ENTT_API_IMPORT
|
||||
# define ENTT_API ENTT_IMPORT
|
||||
# else /* No API */
|
||||
# define ENTT_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
269
src/entt/core/compressed_pair.hpp
Normal file
269
src/entt/core/compressed_pair.hpp
Normal file
@@ -0,0 +1,269 @@
|
||||
#ifndef ENTT_CORE_COMPRESSED_PAIR_HPP
|
||||
#define ENTT_CORE_COMPRESSED_PAIR_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, std::size_t, typename = void>
|
||||
struct compressed_pair_element {
|
||||
using reference = Type &;
|
||||
using const_reference = const Type &;
|
||||
|
||||
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<Type>>>
|
||||
compressed_pair_element()
|
||||
: value{} {}
|
||||
|
||||
template<typename Args, typename = std::enable_if_t<!std::is_same_v<std::remove_const_t<std::remove_reference_t<Args>>, compressed_pair_element>>>
|
||||
compressed_pair_element(Args &&args)
|
||||
: value{std::forward<Args>(args)} {}
|
||||
|
||||
template<typename... Args, std::size_t... Index>
|
||||
compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>)
|
||||
: value{std::get<Index>(args)...} {}
|
||||
|
||||
[[nodiscard]] reference get() ENTT_NOEXCEPT {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] const_reference get() const ENTT_NOEXCEPT {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
Type value;
|
||||
};
|
||||
|
||||
template<typename Type, std::size_t Tag>
|
||||
struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Type>>>: Type {
|
||||
using reference = Type &;
|
||||
using const_reference = const Type &;
|
||||
using base_type = Type;
|
||||
|
||||
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<base_type>>>
|
||||
compressed_pair_element()
|
||||
: base_type{} {}
|
||||
|
||||
template<typename Args, typename = std::enable_if_t<!std::is_same_v<std::remove_const_t<std::remove_reference_t<Args>>, compressed_pair_element>>>
|
||||
compressed_pair_element(Args &&args)
|
||||
: base_type{std::forward<Args>(args)} {}
|
||||
|
||||
template<typename... Args, std::size_t... Index>
|
||||
compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>)
|
||||
: base_type{std::get<Index>(args)...} {}
|
||||
|
||||
[[nodiscard]] reference get() ENTT_NOEXCEPT {
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const_reference get() const ENTT_NOEXCEPT {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief A compressed pair.
|
||||
*
|
||||
* A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to
|
||||
* reduce its final size to a minimum.
|
||||
*
|
||||
* @tparam First The type of the first element that the pair stores.
|
||||
* @tparam Second The type of the second element that the pair stores.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
class compressed_pair final
|
||||
: internal::compressed_pair_element<First, 0u>,
|
||||
internal::compressed_pair_element<Second, 1u> {
|
||||
using first_base = internal::compressed_pair_element<First, 0u>;
|
||||
using second_base = internal::compressed_pair_element<Second, 1u>;
|
||||
|
||||
public:
|
||||
/*! @brief The type of the first element that the pair stores. */
|
||||
using first_type = First;
|
||||
/*! @brief The type of the second element that the pair stores. */
|
||||
using second_type = Second;
|
||||
|
||||
/**
|
||||
* @brief Default constructor, conditionally enabled.
|
||||
*
|
||||
* This constructor is only available when the types that the pair stores
|
||||
* are both at least default constructible.
|
||||
*
|
||||
* @tparam Dummy Dummy template parameter used for internal purposes.
|
||||
*/
|
||||
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>>
|
||||
constexpr compressed_pair()
|
||||
: first_base{},
|
||||
second_base{} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
constexpr compressed_pair(const compressed_pair &other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
constexpr compressed_pair(compressed_pair &&other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Constructs a pair from its values.
|
||||
* @tparam Arg Type of value to use to initialize the first element.
|
||||
* @tparam Other Type of value to use to initialize the second element.
|
||||
* @param arg Value to use to initialize the first element.
|
||||
* @param other Value to use to initialize the second element.
|
||||
*/
|
||||
template<typename Arg, typename Other>
|
||||
constexpr compressed_pair(Arg &&arg, Other &&other)
|
||||
: first_base{std::forward<Arg>(arg)},
|
||||
second_base{std::forward<Other>(other)} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a pair by forwarding the arguments to its parts.
|
||||
* @tparam Args Types of arguments to use to initialize the first element.
|
||||
* @tparam Other Types of arguments to use to initialize the second element.
|
||||
* @param args Arguments to use to initialize the first element.
|
||||
* @param other Arguments to use to initialize the second element.
|
||||
*/
|
||||
template<typename... Args, typename... Other>
|
||||
constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other)
|
||||
: first_base{std::move(args), std::index_sequence_for<Args...>{}},
|
||||
second_base{std::move(other), std::index_sequence_for<Other...>{}} {}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This compressed pair object.
|
||||
*/
|
||||
constexpr compressed_pair &operator=(const compressed_pair &other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This compressed pair object.
|
||||
*/
|
||||
constexpr compressed_pair &operator=(compressed_pair &&other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Returns the first element that a pair stores.
|
||||
* @return The first element that a pair stores.
|
||||
*/
|
||||
[[nodiscard]] first_type &first() ENTT_NOEXCEPT {
|
||||
return static_cast<first_base &>(*this).get();
|
||||
}
|
||||
|
||||
/*! @copydoc first */
|
||||
[[nodiscard]] const first_type &first() const ENTT_NOEXCEPT {
|
||||
return static_cast<const first_base &>(*this).get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the second element that a pair stores.
|
||||
* @return The second element that a pair stores.
|
||||
*/
|
||||
[[nodiscard]] second_type &second() ENTT_NOEXCEPT {
|
||||
return static_cast<second_base &>(*this).get();
|
||||
}
|
||||
|
||||
/*! @copydoc second */
|
||||
[[nodiscard]] const second_type &second() const ENTT_NOEXCEPT {
|
||||
return static_cast<const second_base &>(*this).get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swaps two compressed pair objects.
|
||||
* @param other The compressed pair to swap with.
|
||||
*/
|
||||
void swap(compressed_pair &other) {
|
||||
using std::swap;
|
||||
swap(first(), other.first());
|
||||
swap(second(), other.second());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts an element from the compressed pair.
|
||||
* @tparam Index An integer value that is either 0 or 1.
|
||||
* @return Returns a reference to the first element if `Index` is 0 and a
|
||||
* reference to the second element if `Index` is 1.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
decltype(auto) get() ENTT_NOEXCEPT {
|
||||
if constexpr(Index == 0u) {
|
||||
return first();
|
||||
} else {
|
||||
static_assert(Index == 1u, "Index out of bounds");
|
||||
return second();
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
template<std::size_t Index>
|
||||
decltype(auto) get() const ENTT_NOEXCEPT {
|
||||
if constexpr(Index == 0u) {
|
||||
return first();
|
||||
} else {
|
||||
static_assert(Index == 1u, "Index out of bounds");
|
||||
return second();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Type Type of value to use to initialize the first element.
|
||||
* @tparam Other Type of value to use to initialize the second element.
|
||||
*/
|
||||
template<typename Type, typename Other>
|
||||
compressed_pair(Type &&, Other &&) -> compressed_pair<std::decay_t<Type>, std::decay_t<Other>>;
|
||||
|
||||
/**
|
||||
* @brief Swaps two compressed pair objects.
|
||||
* @tparam First The type of the first element that the pairs store.
|
||||
* @tparam Second The type of the second element that the pairs store.
|
||||
* @param lhs A valid compressed pair object.
|
||||
* @param rhs A valid compressed pair object.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
inline void swap(compressed_pair<First, Second> &lhs, compressed_pair<First, Second> &rhs) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
// disable structured binding support for clang 6, it messes when specializing tuple_size
|
||||
#if !defined __clang_major__ || __clang_major__ > 6
|
||||
namespace std {
|
||||
|
||||
template<typename First, typename Second>
|
||||
struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_t, 2u> {};
|
||||
|
||||
template<size_t Index, typename First, typename Second>
|
||||
struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {
|
||||
static_assert(Index < 2u, "Index out of bounds");
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
#endif
|
||||
|
||||
#endif
|
||||
112
src/entt/core/enum.hpp
Normal file
112
src/entt/core/enum.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#ifndef ENTT_CORE_FLAG_HPP
|
||||
#define ENTT_CORE_FLAG_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Enable bitmask support for enum classes.
|
||||
* @tparam Type The enum type for which to enable bitmask support.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct enum_as_bitmask: std::false_type {};
|
||||
|
||||
/*! @copydoc enum_as_bitmask */
|
||||
template<typename Type>
|
||||
struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>: std::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The enum class type for which to enable bitmask support.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
/**
|
||||
* @brief Operator available for enums for which bitmask support is enabled.
|
||||
* @tparam Type Enum class type.
|
||||
* @param lhs The first value to use.
|
||||
* @param rhs The second value to use.
|
||||
* @return The result of invoking the operator on the underlying types of the
|
||||
* two values provided.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator|(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
|
||||
return Type{static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs)};
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator&(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
|
||||
return Type{static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs)};
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator^(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
|
||||
return Type{static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs)};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator available for enums for which bitmask support is enabled.
|
||||
* @tparam Type Enum class type.
|
||||
* @param value The value to use.
|
||||
* @return The result of invoking the operator on the underlying types of the
|
||||
* value provided.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator~(const Type value) ENTT_NOEXCEPT {
|
||||
return Type{~static_cast<std::underlying_type_t<Type>>(value)};
|
||||
}
|
||||
|
||||
/*! @copydoc operator~ */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, bool>
|
||||
operator!(const Type value) ENTT_NOEXCEPT {
|
||||
return !static_cast<std::underlying_type_t<Type>>(value);
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type &>
|
||||
operator|=(Type &lhs, const Type rhs) ENTT_NOEXCEPT {
|
||||
return (lhs = (lhs | rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type &>
|
||||
operator&=(Type &lhs, const Type rhs) ENTT_NOEXCEPT {
|
||||
return (lhs = (lhs & rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type &>
|
||||
operator^=(Type &lhs, const Type rhs) ENTT_NOEXCEPT {
|
||||
return (lhs = (lhs ^ rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator==(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
|
||||
return (static_cast<std::underlying_type_t<Type>>(lhs) == static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator!=(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,14 +1,11 @@
|
||||
#ifndef ENTT_CORE_FAMILY_HPP
|
||||
#define ENTT_CORE_FAMILY_HPP
|
||||
|
||||
|
||||
#include "../config/config.h"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dynamic identifier generator.
|
||||
*
|
||||
@@ -30,8 +27,6 @@ public:
|
||||
inline static const family_type type = identifier++;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,27 +1,20 @@
|
||||
#ifndef ENTT_CORE_FWD_HPP
|
||||
#define ENTT_CORE_FWD_HPP
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
template<std::size_t Len, std::size_t = alignof(typename std::aligned_storage_t<Len + !Len>)>
|
||||
template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(typename std::aligned_storage_t<Len + !Len>)>
|
||||
class basic_any;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for type identifiers. */
|
||||
using id_type = ENTT_ID_TYPE;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using any = basic_any<sizeof(double[2])>;
|
||||
|
||||
|
||||
}
|
||||
using any = basic_any<>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
#ifndef ENTT_CORE_HASHED_STRING_HPP
|
||||
#define ENTT_CORE_HASHED_STRING_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "../config/config.h"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename>
|
||||
struct fnv1a_traits;
|
||||
|
||||
|
||||
template<>
|
||||
struct fnv1a_traits<std::uint32_t> {
|
||||
using type = std::uint32_t;
|
||||
@@ -31,7 +25,6 @@ struct fnv1a_traits<std::uint32_t> {
|
||||
static constexpr std::uint32_t prime = 16777619;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct fnv1a_traits<std::uint64_t> {
|
||||
using type = std::uint64_t;
|
||||
@@ -39,16 +32,13 @@ struct fnv1a_traits<std::uint64_t> {
|
||||
static constexpr std::uint64_t prime = 1099511628211ull;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Zero overhead unique identifier.
|
||||
*
|
||||
@@ -58,11 +48,15 @@ struct fnv1a_traits<std::uint64_t> {
|
||||
* Because of that, a hashed string can also be used in constant expressions if
|
||||
* required.
|
||||
*
|
||||
* @warning
|
||||
* This class doesn't take ownership of user-supplied strings nor does it make a
|
||||
* copy of them.
|
||||
*
|
||||
* @tparam Char Character type.
|
||||
*/
|
||||
template<typename Char>
|
||||
class basic_hashed_string {
|
||||
using traits_type = internal::fnv1a_traits<id_type>;
|
||||
using hs_traits = internal::fnv1a_traits<id_type>;
|
||||
|
||||
struct const_wrapper {
|
||||
// non-explicit constructor on purpose
|
||||
@@ -72,10 +66,10 @@ class basic_hashed_string {
|
||||
|
||||
// Fowler–Noll–Vo hash function v. 1a - the good
|
||||
[[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT {
|
||||
auto value = traits_type::offset;
|
||||
auto value = hs_traits::offset;
|
||||
|
||||
while(*curr != 0) {
|
||||
value = (value ^ static_cast<traits_type::type>(*(curr++))) * traits_type::prime;
|
||||
value = (value ^ static_cast<hs_traits::type>(*(curr++))) * hs_traits::prime;
|
||||
}
|
||||
|
||||
return value;
|
||||
@@ -94,8 +88,8 @@ public:
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
[[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
|
||||
id_type partial{traits_type::offset};
|
||||
while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
|
||||
id_type partial{hs_traits::offset};
|
||||
while(size--) { partial = (partial ^ (str++)[0]) * hs_traits::prime; }
|
||||
return partial;
|
||||
}
|
||||
|
||||
@@ -107,7 +101,7 @@ public:
|
||||
* characters.<br/>
|
||||
* Example of use:
|
||||
* @code{.cpp}
|
||||
* const auto value = basic_hashed_string<char>::to_value("my.png");
|
||||
* const auto value = basic_hashed_string<char>::value("my.png");
|
||||
* @endcode
|
||||
*
|
||||
* @tparam N Number of characters of the identifier.
|
||||
@@ -130,8 +124,8 @@ public:
|
||||
|
||||
/*! @brief Constructs an empty hashed string. */
|
||||
constexpr basic_hashed_string() ENTT_NOEXCEPT
|
||||
: str{nullptr}, hash{}
|
||||
{}
|
||||
: str{nullptr},
|
||||
hash{} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a hashed string from an array of const characters.
|
||||
@@ -149,23 +143,27 @@ public:
|
||||
*/
|
||||
template<std::size_t N>
|
||||
constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT
|
||||
: str{curr}, hash{helper(curr)}
|
||||
{}
|
||||
: str{curr},
|
||||
hash{helper(curr)} {}
|
||||
|
||||
/**
|
||||
* @brief Explicit constructor on purpose to avoid constructing a hashed
|
||||
* string directly from a `const value_type *`.
|
||||
*
|
||||
* @warning
|
||||
* The lifetime of the string is not extended nor is it copied.
|
||||
*
|
||||
* @param wrapper Helps achieving the purpose by relying on overloading.
|
||||
*/
|
||||
explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
|
||||
: str{wrapper.str}, hash{helper(wrapper.str)}
|
||||
{}
|
||||
: str{wrapper.str},
|
||||
hash{helper(wrapper.str)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns the human-readable representation of a hashed string.
|
||||
* @return The string used to initialize the instance.
|
||||
*/
|
||||
[[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] constexpr const value_type *data() const ENTT_NOEXCEPT {
|
||||
return str;
|
||||
}
|
||||
|
||||
@@ -178,21 +176,16 @@ public:
|
||||
}
|
||||
|
||||
/*! @copydoc data */
|
||||
[[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); }
|
||||
[[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT {
|
||||
return data();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the numeric representation of a hashed string.
|
||||
* @return The numeric representation of the instance.
|
||||
*/
|
||||
[[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); }
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @param other Hashed string with which to compare.
|
||||
* @return True if the two hashed strings are identical, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT {
|
||||
return hash == other.hash;
|
||||
[[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT {
|
||||
return value();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -200,7 +193,6 @@ private:
|
||||
hash_type hash;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
*
|
||||
@@ -212,9 +204,7 @@ private:
|
||||
* @param str Human-readable identifer.
|
||||
*/
|
||||
template<typename Char, std::size_t N>
|
||||
basic_hashed_string(const Char (&str)[N])
|
||||
-> basic_hashed_string<Char>;
|
||||
|
||||
basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>;
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
@@ -224,22 +214,81 @@ basic_hashed_string(const Char (&str)[N])
|
||||
* @return True if the two hashed strings are identical, false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator==(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.value() == rhs.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the two hashed strings differ, false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is less than the second, false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator<(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.value() < rhs.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is less than or equal to the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator<=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is greater than the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator>(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is greater than or equal to the second,
|
||||
* false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator>=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
/*! @brief Aliases for common character types. */
|
||||
using hashed_string = basic_hashed_string<char>;
|
||||
|
||||
|
||||
/*! @brief Aliases for common character types. */
|
||||
using hashed_wstring = basic_hashed_string<wchar_t>;
|
||||
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
|
||||
/**
|
||||
* @brief User defined literal for hashed strings.
|
||||
* @param str The literal without its suffix.
|
||||
@@ -249,7 +298,6 @@ inline namespace literals {
|
||||
return entt::hashed_string{str};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief User defined literal for hashed wstrings.
|
||||
* @param str The literal without its suffix.
|
||||
@@ -259,11 +307,8 @@ inline namespace literals {
|
||||
return entt::hashed_wstring{str};
|
||||
}
|
||||
|
||||
} // namespace literals
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
#ifndef ENTT_CORE_IDENT_HPP
|
||||
#define ENTT_CORE_IDENT_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "fwd.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Types identifiers.
|
||||
*
|
||||
@@ -57,8 +54,6 @@ public:
|
||||
static constexpr identifier_type type = get<std::decay_t<Type>>(std::index_sequence_for<Types...>{});
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
116
src/entt/core/iterator.hpp
Normal file
116
src/entt/core/iterator.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
#ifndef ENTT_CORE_ITERATOR_HPP
|
||||
#define ENTT_CORE_ITERATOR_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Helper type to use as pointer with input iterators.
|
||||
* @tparam Type of wrapped value.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct input_iterator_pointer final {
|
||||
/*! @brief Pointer type. */
|
||||
using pointer = decltype(std::addressof(std::declval<Type &>()));
|
||||
|
||||
/*! @brief Default copy constructor, deleted on purpose. */
|
||||
input_iterator_pointer(const input_iterator_pointer &) = delete;
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
input_iterator_pointer(input_iterator_pointer &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Constructs a proxy object by move.
|
||||
* @param val Value to use to initialize the proxy object.
|
||||
*/
|
||||
input_iterator_pointer(Type &&val)
|
||||
: value{std::move(val)} {}
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator, deleted on purpose.
|
||||
* @return This proxy object.
|
||||
*/
|
||||
input_iterator_pointer &operator=(const input_iterator_pointer &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @return This proxy object.
|
||||
*/
|
||||
input_iterator_pointer &operator=(input_iterator_pointer &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Access operator for accessing wrapped values.
|
||||
* @return A pointer to the wrapped value.
|
||||
*/
|
||||
[[nodiscard]] pointer operator->() ENTT_NOEXCEPT {
|
||||
return std::addressof(value);
|
||||
}
|
||||
|
||||
private:
|
||||
Type value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Utility class to create an iterable object from a pair of iterators.
|
||||
* @tparam It Type of iterators.
|
||||
*/
|
||||
template<typename It>
|
||||
struct iterable_adaptor final {
|
||||
/*! @brief Type of the objects returned during iteration. */
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
/*! @brief Iterator type. */
|
||||
using iterator = It;
|
||||
/*! @brief Const iterator type. */
|
||||
using const_iterator = iterator;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
iterable_adaptor() = default;
|
||||
|
||||
/**
|
||||
* @brief Creates an iterable object from a pair of iterators.
|
||||
* @param from Begin iterator.
|
||||
* @param to End iterator.
|
||||
*/
|
||||
iterable_adaptor(It from, It to)
|
||||
: first{from},
|
||||
last{to} {}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning.
|
||||
* @return An iterator to the first element of the range.
|
||||
*/
|
||||
[[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT {
|
||||
return first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end.
|
||||
* @return An iterator to the element following the last element of the
|
||||
* range.
|
||||
*/
|
||||
[[nodiscard]] const_iterator end() const ENTT_NOEXCEPT {
|
||||
return last;
|
||||
}
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT {
|
||||
return begin();
|
||||
}
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT {
|
||||
return end();
|
||||
}
|
||||
|
||||
private:
|
||||
It first;
|
||||
It last;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
108
src/entt/core/memory.hpp
Normal file
108
src/entt/core/memory.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef ENTT_CORE_MEMORY_HPP
|
||||
#define ENTT_CORE_MEMORY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
|
||||
* @tparam Type Pointer type.
|
||||
* @param ptr Fancy or raw pointer.
|
||||
* @return A raw pointer that represents the address of the original pointer.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto to_address(Type &&ptr) ENTT_NOEXCEPT {
|
||||
if constexpr(std::is_pointer_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
|
||||
return ptr;
|
||||
} else {
|
||||
return to_address(std::forward<Type>(ptr).operator->());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to design allocation-aware containers.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param lhs A valid allocator.
|
||||
* @param rhs Another valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
|
||||
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
|
||||
lhs = rhs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to design allocation-aware containers.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param lhs A valid allocator.
|
||||
* @param rhs Another valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
|
||||
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
|
||||
lhs = std::move(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to design allocation-aware containers.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param lhs A valid allocator.
|
||||
* @param rhs Another valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
|
||||
ENTT_ASSERT(std::allocator_traits<Allocator>::propagate_on_container_swap::value || lhs == rhs, "Cannot swap the containers");
|
||||
|
||||
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
|
||||
using std::swap;
|
||||
swap(lhs, rhs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a value is a power of two or not.
|
||||
* @param value A value that may or may not be a power of two.
|
||||
* @return True if the value is a power of two, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr bool is_power_of_two(const std::size_t value) ENTT_NOEXCEPT {
|
||||
return value && ((value & (value - 1)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the smallest power of two greater than or equal to a value.
|
||||
* @param value The value to use.
|
||||
* @return The smallest power of two greater than or equal to the given value.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr std::size_t next_power_of_two(const std::size_t value) ENTT_NOEXCEPT {
|
||||
ENTT_ASSERT(value < (std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)), "Numeric limits exceeded");
|
||||
std::size_t curr = value - (value != 0u);
|
||||
|
||||
for(int next = 1; next < std::numeric_limits<std::size_t>::digits; next = next * 2) {
|
||||
curr |= curr >> next;
|
||||
}
|
||||
|
||||
return ++curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fast module utility function (powers of two only).
|
||||
* @param value A value for which to calculate the modulus.
|
||||
* @param mod _Modulus_, it must be a power of two.
|
||||
* @return The common remainder.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) ENTT_NOEXCEPT {
|
||||
ENTT_ASSERT(is_power_of_two(mod), "Value must be a power of two");
|
||||
return value & (mod - 1u);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,14 +1,11 @@
|
||||
#ifndef ENTT_CORE_MONOSTATE_HPP
|
||||
#define ENTT_CORE_MONOSTATE_HPP
|
||||
|
||||
|
||||
#include "../config/config.h"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Minimal implementation of the monostate pattern.
|
||||
*
|
||||
@@ -47,7 +44,6 @@ private:
|
||||
inline static ENTT_MAYBE_ATOMIC(Type) value{};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Value Value used to differentiate between different variables.
|
||||
@@ -55,8 +51,6 @@ private:
|
||||
template<id_type Value>
|
||||
inline monostate<Value> monostate_v = {};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
29
src/entt/core/tuple.hpp
Normal file
29
src/entt/core/tuple.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef ENTT_CORE_TUPLE_HPP
|
||||
#define ENTT_CORE_TUPLE_HPP
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Utility function to unwrap tuples of a single element.
|
||||
* @tparam Type Tuple type of any sizes.
|
||||
* @param value A tuple object of the given type.
|
||||
* @return The tuple itself if it contains more than one element, the first
|
||||
* element otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
constexpr decltype(auto) unwrap_tuple(Type &&value) ENTT_NOEXCEPT {
|
||||
if constexpr(std::tuple_size_v<std::remove_reference_t<Type>> == 1u) {
|
||||
return std::get<0>(std::forward<Type>(value));
|
||||
} else {
|
||||
return std::forward<Type>(value);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,40 +1,35 @@
|
||||
#ifndef ENTT_CORE_TYPE_INFO_HPP
|
||||
#define ENTT_CORE_TYPE_INFO_HPP
|
||||
|
||||
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/attribute.h"
|
||||
#include "hashed_string.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include "hashed_string.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
struct ENTT_API type_seq final {
|
||||
struct ENTT_API type_index final {
|
||||
[[nodiscard]] static id_type next() ENTT_NOEXCEPT {
|
||||
static ENTT_MAYBE_ATOMIC(id_type) value{};
|
||||
return value++;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT {
|
||||
#if defined ENTT_PRETTY_FUNCTION
|
||||
std::string_view pretty_function{ENTT_PRETTY_FUNCTION};
|
||||
auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1);
|
||||
auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1);
|
||||
auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first);
|
||||
return value;
|
||||
#else
|
||||
@@ -42,21 +37,18 @@ template<typename Type>
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
|
||||
[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT {
|
||||
constexpr auto value = stripped_type_name<Type>();
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static std::string_view type_name(char) ENTT_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) ENTT_NOEXCEPT {
|
||||
constexpr auto stripped = stripped_type_name<Type>();
|
||||
@@ -64,7 +56,6 @@ template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT {
|
||||
static const auto value = [](const auto stripped) {
|
||||
@@ -73,36 +64,34 @@ template<typename Type>
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Type sequential identifier.
|
||||
* @tparam Type Type for which to generate a sequential identifier.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct ENTT_API type_seq final {
|
||||
struct ENTT_API type_index final {
|
||||
/**
|
||||
* @brief Returns the sequential identifier of a given type.
|
||||
* @return The sequential identifier of a given type.
|
||||
*/
|
||||
[[nodiscard]] static id_type value() ENTT_NOEXCEPT {
|
||||
static const id_type value = internal::type_seq::next();
|
||||
static const id_type value = internal::type_index::next();
|
||||
return value;
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); }
|
||||
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Type hash.
|
||||
* @tparam Type Type for which to generate a hash value.
|
||||
@@ -118,15 +107,16 @@ struct type_hash final {
|
||||
return internal::type_hash<Type>(0);
|
||||
#else
|
||||
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
|
||||
return type_seq<Type>::value();
|
||||
return type_index<Type>::value();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); }
|
||||
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Type name.
|
||||
* @tparam Type Type for which to generate a name.
|
||||
@@ -142,119 +132,136 @@ struct type_name final {
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); }
|
||||
[[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*! @brief Implementation specific information about a type. */
|
||||
class type_info final {
|
||||
template<typename>
|
||||
friend type_info type_id() ENTT_NOEXCEPT;
|
||||
template<typename Type>
|
||||
friend const type_info &type_id() ENTT_NOEXCEPT;
|
||||
|
||||
type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT
|
||||
: seq_value{seq_v},
|
||||
hash_value{hash_v},
|
||||
name_value{name_v}
|
||||
{}
|
||||
template<typename Type>
|
||||
constexpr type_info(std::in_place_type_t<Type>) ENTT_NOEXCEPT
|
||||
: seq{type_index<std::remove_reference_t<std::remove_const_t<Type>>>::value()},
|
||||
identifier{type_hash<std::remove_reference_t<std::remove_const_t<Type>>>::value()},
|
||||
alias{type_name<std::remove_reference_t<std::remove_const_t<Type>>>::value()} {}
|
||||
|
||||
public:
|
||||
/*! @brief Default constructor. */
|
||||
type_info() ENTT_NOEXCEPT
|
||||
: type_info({}, {}, {})
|
||||
{}
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
type_info(const type_info &) ENTT_NOEXCEPT = default;
|
||||
/*! @brief Default move constructor. */
|
||||
type_info(type_info &&) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator.
|
||||
* @return This type info object.
|
||||
* @brief Type index.
|
||||
* @return Type index.
|
||||
*/
|
||||
type_info & operator=(const type_info &) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @return This type info object.
|
||||
*/
|
||||
type_info & operator=(type_info &&) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Checks if a type info object is properly initialized.
|
||||
* @return True if the object is properly initialized, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
|
||||
return name_value.data() != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Type sequential identifier.
|
||||
* @return Type sequential identifier.
|
||||
*/
|
||||
[[nodiscard]] id_type seq() const ENTT_NOEXCEPT {
|
||||
return seq_value;
|
||||
[[nodiscard]] constexpr id_type index() const ENTT_NOEXCEPT {
|
||||
return seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Type hash.
|
||||
* @return Type hash.
|
||||
*/
|
||||
[[nodiscard]] id_type hash() const ENTT_NOEXCEPT {
|
||||
return hash_value;
|
||||
[[nodiscard]] constexpr id_type hash() const ENTT_NOEXCEPT {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Type name.
|
||||
* @return Type name.
|
||||
*/
|
||||
[[nodiscard]] std::string_view name() const ENTT_NOEXCEPT {
|
||||
return name_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares the contents of two type info objects.
|
||||
* @param other Object with which to compare.
|
||||
* @return False if the two contents differ, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT {
|
||||
return hash_value == other.hash_value;
|
||||
[[nodiscard]] constexpr std::string_view name() const ENTT_NOEXCEPT {
|
||||
return alias;
|
||||
}
|
||||
|
||||
private:
|
||||
id_type seq_value;
|
||||
id_type hash_value;
|
||||
std::string_view name_value;
|
||||
id_type seq;
|
||||
id_type identifier;
|
||||
std::string_view alias;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares the contents of two type info objects.
|
||||
* @param lhs A type info object.
|
||||
* @param rhs A type info object.
|
||||
* @return True if the two contents differ, false otherwise.
|
||||
* @return True if the two type info objects are identical, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
|
||||
[[nodiscard]] inline constexpr bool operator==(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.hash() == rhs.hash();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares the contents of two type info objects.
|
||||
* @param lhs A type info object.
|
||||
* @param rhs A type info object.
|
||||
* @return True if the two type info objects differ, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is less than the second, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator<(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.index() < rhs.index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the type info object for a given type.
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is less than or equal to the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator<=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is greater than the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator>(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is greater than or equal to the second,
|
||||
* false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator>=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the type info object associated to a given type.
|
||||
*
|
||||
* The type doesn't need to be a complete type. If the type is a reference, the
|
||||
* result refers to the referenced type. In all cases, top-level cv-qualifiers
|
||||
* are ignored.
|
||||
*
|
||||
* @tparam Type Type for which to generate a type info object.
|
||||
* @return The type info object for the given type.
|
||||
* @return A properly initialized type info object.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] type_info type_id() ENTT_NOEXCEPT {
|
||||
return type_info{
|
||||
type_seq<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
|
||||
type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
|
||||
type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] const type_info &type_id() ENTT_NOEXCEPT {
|
||||
if constexpr(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
static type_info instance{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>};
|
||||
return instance;
|
||||
} else {
|
||||
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
#ifndef ENTT_CORE_TYPE_TRAITS_HPP
|
||||
#define ENTT_CORE_TYPE_TRAITS_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class to disambiguate overloaded functions.
|
||||
* @tparam N Number of choices available.
|
||||
@@ -19,17 +17,13 @@ namespace entt {
|
||||
template<std::size_t N>
|
||||
struct choice_t
|
||||
// Unfortunately, doxygen cannot parse such a construct.
|
||||
/*! @cond TURN_OFF_DOXYGEN */
|
||||
: choice_t<N-1>
|
||||
/*! @endcond */
|
||||
: /*! @cond TURN_OFF_DOXYGEN */ choice_t<N - 1> /*! @endcond */
|
||||
{};
|
||||
|
||||
|
||||
/*! @copybrief choice_t */
|
||||
template<>
|
||||
struct choice_t<0> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Variable template for the choice trick.
|
||||
* @tparam N Number of choices available.
|
||||
@@ -37,7 +31,6 @@ struct choice_t<0> {};
|
||||
template<std::size_t N>
|
||||
inline constexpr choice_t<N> choice{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Identity type trait.
|
||||
*
|
||||
@@ -52,7 +45,6 @@ struct type_identity {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type A type.
|
||||
@@ -60,7 +52,6 @@ struct type_identity {
|
||||
template<typename Type>
|
||||
using type_identity_t = typename type_identity<Type>::type;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains.
|
||||
* @tparam Type The type of which to return the size.
|
||||
@@ -69,21 +60,17 @@ using type_identity_t = typename type_identity<Type>::type;
|
||||
template<typename Type, typename = void>
|
||||
struct size_of: std::integral_constant<std::size_t, 0u> {};
|
||||
|
||||
|
||||
/*! @copydoc size_of */
|
||||
template<typename Type>
|
||||
struct size_of<Type, std::void_t<decltype(sizeof(Type))>>
|
||||
: std::integral_constant<std::size_t, sizeof(Type)>
|
||||
{};
|
||||
|
||||
: std::integral_constant<std::size_t, sizeof(Type)> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type of which to return the size.
|
||||
*/
|
||||
template<class Type>
|
||||
inline constexpr auto size_of_v = size_of<Type>::value;
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr std::size_t size_of_v = size_of<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Using declaration to be used to _repeat_ the same type a number of
|
||||
@@ -91,8 +78,7 @@ inline constexpr auto size_of_v = size_of<Type>::value;
|
||||
* @tparam Type A type to repeat.
|
||||
*/
|
||||
template<typename Type, typename>
|
||||
using unpack_as_t = Type;
|
||||
|
||||
using unpack_as_type = Type;
|
||||
|
||||
/**
|
||||
* @brief Helper variable template to be used to _repeat_ the same value a
|
||||
@@ -100,8 +86,7 @@ using unpack_as_t = Type;
|
||||
* @tparam Value A value to repeat.
|
||||
*/
|
||||
template<auto Value, typename>
|
||||
inline constexpr auto unpack_as_v = Value;
|
||||
|
||||
inline constexpr auto unpack_as_value = Value;
|
||||
|
||||
/**
|
||||
* @brief Wraps a static constant.
|
||||
@@ -110,7 +95,6 @@ inline constexpr auto unpack_as_v = Value;
|
||||
template<auto Value>
|
||||
using integral_constant = std::integral_constant<decltype(Value), Value>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias template to facilitate the creation of named values.
|
||||
* @tparam Value A constant value at least convertible to `id_type`.
|
||||
@@ -118,7 +102,6 @@ using integral_constant = std::integral_constant<decltype(Value), Value>;
|
||||
template<id_type Value>
|
||||
using tag = integral_constant<Value>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A class to use to push around lists of types, nothing more.
|
||||
* @tparam Type Types provided by the type list.
|
||||
@@ -131,12 +114,10 @@ struct type_list {
|
||||
static constexpr auto size = sizeof...(Type);
|
||||
};
|
||||
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<std::size_t, typename>
|
||||
struct type_list_element;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the types of a type list.
|
||||
* @tparam Index Index of the type to return.
|
||||
@@ -145,9 +126,7 @@ struct type_list_element;
|
||||
*/
|
||||
template<std::size_t Index, typename Type, typename... Other>
|
||||
struct type_list_element<Index, type_list<Type, Other...>>
|
||||
: type_list_element<Index - 1u, type_list<Other...>>
|
||||
{};
|
||||
|
||||
: type_list_element<Index - 1u, type_list<Other...>> {};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the types of a type list.
|
||||
@@ -160,7 +139,6 @@ struct type_list_element<0u, type_list<Type, Other...>> {
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Index Index of the type to return.
|
||||
@@ -169,7 +147,6 @@ struct type_list_element<0u, type_list<Type, Other...>> {
|
||||
template<std::size_t Index, typename List>
|
||||
using type_list_element_t = typename type_list_element<Index, List>::type;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
* @tparam Type Types provided by the first type list.
|
||||
@@ -177,14 +154,14 @@ using type_list_element_t = typename type_list_element<Index, List>::type;
|
||||
* @return A type list composed by the types of both the type lists.
|
||||
*/
|
||||
template<typename... Type, typename... Other>
|
||||
constexpr type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) { return {}; }
|
||||
|
||||
constexpr type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct type_list_cat;
|
||||
|
||||
|
||||
/*! @brief Concatenates multiple type lists. */
|
||||
template<>
|
||||
struct type_list_cat<> {
|
||||
@@ -192,7 +169,6 @@ struct type_list_cat<> {
|
||||
using type = type_list<>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
* @tparam Type Types provided by the first type list.
|
||||
@@ -205,7 +181,6 @@ struct type_list_cat<type_list<Type...>, type_list<Other...>, List...> {
|
||||
using type = typename type_list_cat<type_list<Type..., Other...>, List...>::type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
* @tparam Type Types provided by the type list.
|
||||
@@ -216,7 +191,6 @@ struct type_list_cat<type_list<Type...>> {
|
||||
using type = type_list<Type...>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Type lists to concatenate.
|
||||
@@ -224,12 +198,10 @@ struct type_list_cat<type_list<Type...>> {
|
||||
template<typename... List>
|
||||
using type_list_cat_t = typename type_list_cat<List...>::type;
|
||||
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename>
|
||||
struct type_list_unique;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Removes duplicates types from a type list.
|
||||
* @tparam Type One of the types provided by the given type list.
|
||||
@@ -241,11 +213,9 @@ struct type_list_unique<type_list<Type, Other...>> {
|
||||
using type = std::conditional_t<
|
||||
std::disjunction_v<std::is_same<Type, Other>...>,
|
||||
typename type_list_unique<type_list<Other...>>::type,
|
||||
type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>
|
||||
>;
|
||||
type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>>;
|
||||
};
|
||||
|
||||
|
||||
/*! @brief Removes duplicates types from a type list. */
|
||||
template<>
|
||||
struct type_list_unique<type_list<>> {
|
||||
@@ -253,7 +223,6 @@ struct type_list_unique<type_list<>> {
|
||||
using type = type_list<>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type A type list.
|
||||
@@ -261,7 +230,6 @@ struct type_list_unique<type_list<>> {
|
||||
template<typename Type>
|
||||
using type_list_unique_t = typename type_list_unique<Type>::type;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a type list contains a
|
||||
* given type, false otherwise.
|
||||
@@ -271,7 +239,6 @@ using type_list_unique_t = typename type_list_unique<Type>::type;
|
||||
template<typename List, typename Type>
|
||||
struct type_list_contains;
|
||||
|
||||
|
||||
/**
|
||||
* @copybrief type_list_contains
|
||||
* @tparam Type Types provided by the type list.
|
||||
@@ -280,21 +247,18 @@ struct type_list_contains;
|
||||
template<typename... Type, typename Other>
|
||||
struct type_list_contains<type_list<Type...>, Other>: std::disjunction<std::is_same<Type, Other>...> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam List Type list.
|
||||
* @tparam Type Type to look for.
|
||||
*/
|
||||
template<class List, typename Type>
|
||||
inline constexpr auto type_list_contains_v = type_list_contains<List, Type>::value;
|
||||
|
||||
template<typename List, typename Type>
|
||||
inline constexpr bool type_list_contains_v = type_list_contains<List, Type>::value;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct type_list_diff;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Computes the difference between two type lists.
|
||||
* @tparam Type Types provided by the first type list.
|
||||
@@ -306,7 +270,6 @@ struct type_list_diff<type_list<Type...>, type_list<Other...>> {
|
||||
using type = type_list_cat_t<std::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Type lists between which to compute the difference.
|
||||
@@ -314,7 +277,6 @@ struct type_list_diff<type_list<Type...>, type_list<Other...>> {
|
||||
template<typename... List>
|
||||
using type_list_diff_t = typename type_list_diff<List...>::type;
|
||||
|
||||
|
||||
/**
|
||||
* @brief A class to use to push around lists of constant values, nothing more.
|
||||
* @tparam Value Values provided by the value list.
|
||||
@@ -327,12 +289,10 @@ struct value_list {
|
||||
static constexpr auto size = sizeof...(Value);
|
||||
};
|
||||
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<std::size_t, typename>
|
||||
struct value_list_element;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the values of a value list.
|
||||
* @tparam Index Index of the value to return.
|
||||
@@ -341,9 +301,7 @@ struct value_list_element;
|
||||
*/
|
||||
template<std::size_t Index, auto Value, auto... Other>
|
||||
struct value_list_element<Index, value_list<Value, Other...>>
|
||||
: value_list_element<Index - 1u, value_list<Other...>>
|
||||
{};
|
||||
|
||||
: value_list_element<Index - 1u, value_list<Other...>> {};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the types of a type list.
|
||||
@@ -356,7 +314,6 @@ struct value_list_element<0u, value_list<Value, Other...>> {
|
||||
static constexpr auto value = Value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Index Index of the value to return.
|
||||
@@ -365,7 +322,6 @@ struct value_list_element<0u, value_list<Value, Other...>> {
|
||||
template<std::size_t Index, typename List>
|
||||
inline constexpr auto value_list_element_v = value_list_element<Index, List>::value;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
* @tparam Value Values provided by the first value list.
|
||||
@@ -373,14 +329,14 @@ inline constexpr auto value_list_element_v = value_list_element<Index, List>::va
|
||||
* @return A value list composed by the values of both the value lists.
|
||||
*/
|
||||
template<auto... Value, auto... Other>
|
||||
constexpr value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) { return {}; }
|
||||
|
||||
constexpr value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct value_list_cat;
|
||||
|
||||
|
||||
/*! @brief Concatenates multiple value lists. */
|
||||
template<>
|
||||
struct value_list_cat<> {
|
||||
@@ -388,7 +344,6 @@ struct value_list_cat<> {
|
||||
using type = value_list<>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
* @tparam Value Values provided by the first value list.
|
||||
@@ -401,7 +356,6 @@ struct value_list_cat<value_list<Value...>, value_list<Other...>, List...> {
|
||||
using type = typename value_list_cat<value_list<Value..., Other...>, List...>::type;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
* @tparam Value Values provided by the value list.
|
||||
@@ -412,7 +366,6 @@ struct value_list_cat<value_list<Value...>> {
|
||||
using type = value_list<Value...>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Value lists to concatenate.
|
||||
@@ -420,70 +373,10 @@ struct value_list_cat<value_list<Value...>> {
|
||||
template<typename... List>
|
||||
using value_list_cat_t = typename value_list_cat<List...>::type;
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename>
|
||||
[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; }
|
||||
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>)
|
||||
-> decltype(std::declval<Type>() == std::declval<Type>()) { return true; }
|
||||
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>)
|
||||
-> decltype(std::declval<typename Type::value_type>(), std::declval<Type>() == std::declval<Type>()) {
|
||||
return is_equality_comparable<typename Type::value_type>(choice<2>);
|
||||
}
|
||||
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>)
|
||||
-> decltype(std::declval<typename Type::mapped_type>(), std::declval<Type>() == std::declval<Type>()) {
|
||||
return is_equality_comparable<typename Type::key_type>(choice<2>) && is_equality_comparable<typename Type::mapped_type>(choice<2>);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 Potentially equality comparable type.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_equality_comparable: std::bool_constant<internal::is_equality_comparable<Type>(choice<2>)> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Potentially equality comparable type.
|
||||
*/
|
||||
template<class Type>
|
||||
inline constexpr auto is_equality_comparable_v = is_equality_comparable<Type>::value;
|
||||
|
||||
|
||||
/*! @brief Same as std::is_invocable, but with tuples. */
|
||||
template<typename, typename>
|
||||
struct is_applicable: std::false_type {};
|
||||
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable
|
||||
* @tparam Func A valid function type.
|
||||
@@ -493,31 +386,27 @@ struct is_applicable: std::false_type {};
|
||||
template<typename Func, template<typename...> class Tuple, typename... Args>
|
||||
struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
|
||||
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Tuple Tuple-like type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
* @copybrief is_applicable
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Tuple Tuple-like type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Func, template<typename...> class Tuple, typename... Args>
|
||||
struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args...> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Func, typename Args>
|
||||
inline constexpr auto is_applicable_v = is_applicable<Func, Args>::value;
|
||||
|
||||
inline constexpr bool is_applicable_v = is_applicable<Func, Args>::value;
|
||||
|
||||
/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */
|
||||
template<typename, typename, typename>
|
||||
struct is_applicable_r: std::false_type {};
|
||||
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable_r
|
||||
* @tparam Ret The type to which the return type of the function should be
|
||||
@@ -528,7 +417,6 @@ struct is_applicable_r: std::false_type {};
|
||||
template<typename Ret, typename Func, typename... Args>
|
||||
struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret, Func, Args...> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Ret The type to which the return type of the function should be
|
||||
@@ -537,47 +425,198 @@ struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret,
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Ret, typename Func, typename Args>
|
||||
inline constexpr auto is_applicable_r_v = is_applicable_r<Ret, Func, Args>::value;
|
||||
|
||||
inline constexpr bool is_applicable_r_v = is_applicable_r<Ret, Func, Args>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is
|
||||
* complete, false otherwise.
|
||||
* @tparam Type Potential complete type.
|
||||
*/
|
||||
* @brief Provides the member constant `value` to true if a given type is
|
||||
* complete, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_complete: std::false_type {};
|
||||
|
||||
|
||||
/*! @copydoc is_complete */
|
||||
template<typename Type>
|
||||
struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Potential complete type.
|
||||
*/
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr auto is_complete_v = is_complete<Type>::value;
|
||||
|
||||
inline constexpr bool is_complete_v = is_complete<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is empty
|
||||
* and the empty type optimization is enabled, false otherwise.
|
||||
* @tparam Type Potential empty type.
|
||||
* @brief Provides the member constant `value` to true if a given type is an
|
||||
* iterator, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_empty: ENTT_IS_EMPTY(Type) {};
|
||||
struct is_iterator: std::false_type {};
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_iterator_category: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/*! @copydoc is_iterator */
|
||||
template<typename Type>
|
||||
struct is_iterator<Type, std::enable_if_t<!std::is_same_v<std::remove_const_t<std::remove_pointer_t<Type>>, void>>>
|
||||
: internal::has_iterator_category<Type> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Potential empty type.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr auto is_empty_v = is_empty<Type>::value;
|
||||
inline constexpr bool is_iterator_v = is_iterator<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is of the
|
||||
* required iterator type, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
* @tparam It Required iterator type.
|
||||
*/
|
||||
template<typename Type, typename It, typename = void>
|
||||
struct is_iterator_type: std::false_type {};
|
||||
|
||||
/*! @copydoc is_iterator_type */
|
||||
template<typename Type, typename It>
|
||||
struct is_iterator_type<Type, It, std::enable_if_t<is_iterator_v<Type> && std::is_same_v<Type, It>>>
|
||||
: std::true_type {};
|
||||
|
||||
/*! @copydoc is_iterator_type */
|
||||
template<typename Type, typename It>
|
||||
struct is_iterator_type<Type, It, std::enable_if_t<!std::is_same_v<Type, It>, std::void_t<typename It::iterator_type>>>
|
||||
: is_iterator_type<Type, typename It::iterator_type> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
* @tparam It Required iterator type.
|
||||
*/
|
||||
template<typename Type, typename It>
|
||||
inline constexpr bool is_iterator_type_v = is_iterator_type<Type, It>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is both
|
||||
* an empty and non-final class, false otherwise.
|
||||
* @tparam Type The type to test
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_ebco_eligible
|
||||
: std::conjunction<std::is_empty<Type>, std::negation<std::is_final<Type>>> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_ebco_eligible_v = is_ebco_eligible<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if `Type::is_transparent`
|
||||
* is valid and denotes a type, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_transparent: std::false_type {};
|
||||
|
||||
/*! @copydoc is_transparent */
|
||||
template<typename Type>
|
||||
struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_transparent_v = is_transparent<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is
|
||||
* equality comparable, false otherwise.
|
||||
* @tparam Type 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.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_tuple_size_value: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct has_tuple_size_value<Type, std::void_t<decltype(std::tuple_size<const Type>::value)>>: std::true_type {};
|
||||
|
||||
template<typename Type, std::size_t... Index>
|
||||
[[nodiscard]] constexpr bool unpack_maybe_equality_comparable(std::index_sequence<Index...>) {
|
||||
return (is_equality_comparable<std::tuple_element_t<Index, Type>>::value && ...);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
[[nodiscard]] constexpr bool maybe_equality_comparable(choice_t<0>) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto maybe_equality_comparable(choice_t<1>) -> decltype(std::declval<typename Type::value_type>(), bool{}) {
|
||||
if constexpr(is_iterator_v<Type>) {
|
||||
return true;
|
||||
} else if constexpr(std::is_same_v<typename Type::value_type, Type>) {
|
||||
return maybe_equality_comparable<Type>(choice<0>);
|
||||
} else {
|
||||
return is_equality_comparable<typename Type::value_type>::value;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<is_complete_v<std::tuple_size<std::remove_const_t<Type>>>, bool> maybe_equality_comparable(choice_t<2>) {
|
||||
if constexpr(has_tuple_size_value<Type>::value) {
|
||||
return unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
|
||||
} else {
|
||||
return maybe_equality_comparable<Type>(choice<1>);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/*! @copydoc is_equality_comparable */
|
||||
template<typename Type>
|
||||
struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>>
|
||||
: std::bool_constant<internal::maybe_equality_comparable<Type>(choice<2>)> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_equality_comparable_v = is_equality_comparable<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Transcribes the constness of a type to another type.
|
||||
@@ -590,7 +629,6 @@ struct constness_as {
|
||||
using type = std::remove_const_t<To>;
|
||||
};
|
||||
|
||||
|
||||
/*! @copydoc constness_as */
|
||||
template<typename To, typename From>
|
||||
struct constness_as<To, const From> {
|
||||
@@ -598,7 +636,6 @@ struct constness_as<To, const From> {
|
||||
using type = std::add_const_t<To>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias template to facilitate the transcription of the constness.
|
||||
* @tparam To The type to which to transcribe the constness.
|
||||
@@ -607,7 +644,6 @@ struct constness_as<To, const From> {
|
||||
template<typename To, typename From>
|
||||
using constness_as_t = typename constness_as<To, From>::type;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Extracts the class of a non-static member object or function.
|
||||
* @tparam Member A pointer to a non-static member object or function.
|
||||
@@ -617,20 +653,19 @@ class member_class {
|
||||
static_assert(std::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function");
|
||||
|
||||
template<typename Class, typename Ret, typename... Args>
|
||||
static Class * clazz(Ret(Class:: *)(Args...));
|
||||
static Class *clazz(Ret (Class::*)(Args...));
|
||||
|
||||
template<typename Class, typename Ret, typename... Args>
|
||||
static Class * clazz(Ret(Class:: *)(Args...) const);
|
||||
static Class *clazz(Ret (Class::*)(Args...) const);
|
||||
|
||||
template<typename Class, typename Type>
|
||||
static Class * clazz(Type Class:: *);
|
||||
static Class *clazz(Type Class::*);
|
||||
|
||||
public:
|
||||
/*! @brief The class of the given non-static member object or function. */
|
||||
using type = std::remove_pointer_t<decltype(clazz(std::declval<Member>()))>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Member A pointer to a non-static member object or function.
|
||||
@@ -638,8 +673,6 @@ public:
|
||||
template<typename Member>
|
||||
using member_class_t = typename member_class<Member>::type;
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#ifndef ENTT_CORE_UTILITY_HPP
|
||||
#define ENTT_CORE_UTILITY_HPP
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/*! @brief Identity function object (waiting for C++20). */
|
||||
struct identity {
|
||||
/*! @brief Indicates that this is a transparent function object. */
|
||||
using is_transparent = void;
|
||||
|
||||
/**
|
||||
* @brief Returns its argument unchanged.
|
||||
* @tparam Type Type of the argument.
|
||||
@@ -18,12 +18,11 @@ struct identity {
|
||||
* @return The submitted value as-is.
|
||||
*/
|
||||
template<class Type>
|
||||
[[nodiscard]] constexpr Type && operator()(Type &&value) const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] constexpr Type &&operator()(Type &&value) const ENTT_NOEXCEPT {
|
||||
return std::forward<Type>(value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constant utility to disambiguate overloaded members of a class.
|
||||
* @tparam Type Type of the desired overload.
|
||||
@@ -32,8 +31,9 @@ struct identity {
|
||||
* @return Pointer to the member.
|
||||
*/
|
||||
template<typename Type, typename Class>
|
||||
[[nodiscard]] constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; }
|
||||
|
||||
[[nodiscard]] constexpr auto overload(Type Class::*member) ENTT_NOEXCEPT {
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constant utility to disambiguate overloaded functions.
|
||||
@@ -42,8 +42,9 @@ template<typename Type, typename Class>
|
||||
* @return Pointer to the function.
|
||||
*/
|
||||
template<typename Func>
|
||||
[[nodiscard]] constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; }
|
||||
|
||||
[[nodiscard]] constexpr auto overload(Func *func) ENTT_NOEXCEPT {
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper type for visitors.
|
||||
@@ -54,15 +55,12 @@ struct overloaded: Func... {
|
||||
using Func::operator()...;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Func Types of function objects.
|
||||
*/
|
||||
template<class... Func>
|
||||
overloaded(Func...)
|
||||
-> overloaded<Func...>;
|
||||
|
||||
overloaded(Func...) -> overloaded<Func...>;
|
||||
|
||||
/**
|
||||
* @brief Basic implementation of a y-combinator.
|
||||
@@ -74,9 +72,8 @@ struct y_combinator {
|
||||
* @brief Constructs a y-combinator from a given function.
|
||||
* @param recursive A potentially recursive function.
|
||||
*/
|
||||
y_combinator(Func recursive):
|
||||
func{std::move(recursive)}
|
||||
{}
|
||||
y_combinator(Func recursive)
|
||||
: func{std::move(recursive)} {}
|
||||
|
||||
/**
|
||||
* @brief Invokes a y-combinator and therefore its underlying function.
|
||||
@@ -84,14 +81,14 @@ struct y_combinator {
|
||||
* @param args Parameters to use to invoke the underlying function.
|
||||
* @return Return value of the underlying function, if any.
|
||||
*/
|
||||
template <class... Args>
|
||||
decltype(auto) operator()(Args &&... args) const {
|
||||
template<class... Args>
|
||||
decltype(auto) operator()(Args &&...args) const {
|
||||
return func(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! @copydoc operator()() */
|
||||
template <class... Args>
|
||||
decltype(auto) operator()(Args &&... args) {
|
||||
template<class... Args>
|
||||
decltype(auto) operator()(Args &&...args) {
|
||||
return func(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -99,8 +96,6 @@ private:
|
||||
Func func;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
37
src/entt/entity/component.hpp
Normal file
37
src/entt/entity/component.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef ENTT_ENTITY_COMPONENT_HPP
|
||||
#define ENTT_ENTITY_COMPONENT_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @brief Commonly used default traits for all types. */
|
||||
struct basic_component_traits {
|
||||
/*! @brief Pointer stability, default is `false`. */
|
||||
static constexpr auto in_place_delete = false;
|
||||
/*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */
|
||||
static constexpr auto ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
|
||||
/*! @brief Page size, default is `ENTT_PACKED_PAGE`. */
|
||||
static constexpr auto page_size = ENTT_PACKED_PAGE;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Common way to access various properties of components.
|
||||
* @tparam Type Type of component.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct component_traits: basic_component_traits {
|
||||
static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Type of component.
|
||||
*/
|
||||
template<class Type>
|
||||
inline constexpr bool ignore_as_empty_v = component_traits<Type>::ignore_if_empty &&std::is_empty_v<Type>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,195 +1,339 @@
|
||||
#ifndef ENTT_ENTITY_ENTITY_HPP
|
||||
#define ENTT_ENTITY_ENTITY_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entity traits.
|
||||
*
|
||||
* Primary template isn't defined on purpose. All the specializations give a
|
||||
* compile-time error unless the template parameter is an accepted entity type.
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct entt_traits;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entity traits for enumeration types.
|
||||
* @tparam Type The type to check.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>>
|
||||
: entt_traits<std::underlying_type_t<Type>>
|
||||
{};
|
||||
: entt_traits<std::underlying_type_t<Type>> {};
|
||||
|
||||
template<typename Type>
|
||||
struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>>
|
||||
: entt_traits<typename Type::entity_type> {};
|
||||
|
||||
/**
|
||||
* @brief Entity traits for a 32 bits entity identifier.
|
||||
*
|
||||
* A 32 bits entity identifier guarantees:
|
||||
*
|
||||
* * 20 bits for the entity number (suitable for almost all the games).
|
||||
* * 12 bit for the version (resets in [0-4095]).
|
||||
*/
|
||||
template<>
|
||||
struct entt_traits<std::uint32_t> {
|
||||
/*! @brief Underlying entity type. */
|
||||
using entity_type = std::uint32_t;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = std::uint16_t;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::int64_t;
|
||||
|
||||
/*! @brief Mask to use to get the entity number out of an identifier. */
|
||||
static constexpr entity_type entity_mask = 0xFFFFF;
|
||||
/*! @brief Mask to use to get the version out of an identifier. */
|
||||
static constexpr entity_type version_mask = 0xFFF;
|
||||
/*! @brief Extent of the entity number within an identifier. */
|
||||
static constexpr std::size_t entity_shift = 20u;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Entity traits for a 64 bits entity identifier.
|
||||
*
|
||||
* A 64 bits entity identifier guarantees:
|
||||
*
|
||||
* * 32 bits for the entity number (an indecently large number).
|
||||
* * 32 bit for the version (an indecently large number).
|
||||
*/
|
||||
template<>
|
||||
struct entt_traits<std::uint64_t> {
|
||||
/*! @brief Underlying entity type. */
|
||||
using entity_type = std::uint64_t;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = std::uint32_t;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::int64_t;
|
||||
|
||||
/*! @brief Mask to use to get the entity number out of an identifier. */
|
||||
static constexpr entity_type entity_mask = 0xFFFFFFFF;
|
||||
/*! @brief Mask to use to get the version out of an identifier. */
|
||||
static constexpr entity_type version_mask = 0xFFFFFFFF;
|
||||
/*! @brief Extent of the entity number within an identifier. */
|
||||
static constexpr std::size_t entity_shift = 32u;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Converts an entity type to its underlying type.
|
||||
* @tparam Entity The value type.
|
||||
* @param entity The value to convert.
|
||||
* @return The integral representation of the given value.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr auto to_integral(const Entity entity) ENTT_NOEXCEPT {
|
||||
return static_cast<typename entt_traits<Entity>::entity_type>(entity);
|
||||
}
|
||||
|
||||
|
||||
/*! @brief Null object for all entity identifiers. */
|
||||
struct null_t {
|
||||
/**
|
||||
* @brief Converts the null object to identifiers of any type.
|
||||
* @tparam Entity Type of entity identifier.
|
||||
* @return The null representation for the given identifier.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT {
|
||||
return Entity{entt_traits<Entity>::entity_mask};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two null objects.
|
||||
* @return True in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==(const null_t &) const ENTT_NOEXCEPT {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two null objects.
|
||||
* @return False in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator!=(const null_t &) const ENTT_NOEXCEPT {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an entity identifier of any type.
|
||||
* @tparam Entity Type of entity identifier.
|
||||
* @param entity Entity identifier with which to compare.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity &entity) const ENTT_NOEXCEPT {
|
||||
return (to_integral(entity) & entt_traits<Entity>::entity_mask) == to_integral(static_cast<Entity>(*this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an entity identifier of any type.
|
||||
* @tparam Entity Type of entity identifier.
|
||||
* @param entity Entity identifier with which to compare.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity &entity) const ENTT_NOEXCEPT {
|
||||
return !(entity == *this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an entity identifier of any type.
|
||||
* @tparam Entity Type of entity identifier.
|
||||
* @param entity Entity identifier with which to compare.
|
||||
* @param other A null object yet to be converted.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity &entity, const null_t &other) ENTT_NOEXCEPT {
|
||||
return other.operator==(entity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an entity identifier of any type.
|
||||
* @tparam Entity Type of entity identifier.
|
||||
* @param entity Entity identifier with which to compare.
|
||||
* @param other A null object yet to be converted.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity &entity, const null_t &other) ENTT_NOEXCEPT {
|
||||
return !(other == entity);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Entity traits.
|
||||
* @tparam Type Type of identifier.
|
||||
*/
|
||||
template<typename Type>
|
||||
class entt_traits: internal::entt_traits<Type> {
|
||||
using base_type = internal::entt_traits<Type>;
|
||||
|
||||
public:
|
||||
/*! @brief Value type. */
|
||||
using value_type = Type;
|
||||
/*! @brief Underlying entity type. */
|
||||
using entity_type = typename base_type::entity_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename base_type::version_type;
|
||||
/*! @brief Reserved identifier. */
|
||||
static constexpr entity_type reserved = base_type::entity_mask | (base_type::version_mask << base_type::entity_shift);
|
||||
/*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */
|
||||
static constexpr auto page_size = ENTT_SPARSE_PAGE;
|
||||
|
||||
/**
|
||||
* @brief Converts an entity to its underlying type.
|
||||
* @param value The value to convert.
|
||||
* @return The integral representation of the given value.
|
||||
*/
|
||||
[[nodiscard]] static constexpr entity_type to_integral(const value_type value) ENTT_NOEXCEPT {
|
||||
return static_cast<entity_type>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the entity part once converted to the underlying type.
|
||||
* @param value The value to convert.
|
||||
* @return The integral representation of the entity part.
|
||||
*/
|
||||
[[nodiscard]] static constexpr entity_type to_entity(const value_type value) ENTT_NOEXCEPT {
|
||||
return (to_integral(value) & base_type::entity_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the version part once converted to the underlying type.
|
||||
* @param value The value to convert.
|
||||
* @return The integral representation of the version part.
|
||||
*/
|
||||
[[nodiscard]] static constexpr version_type to_version(const value_type value) ENTT_NOEXCEPT {
|
||||
return (to_integral(value) >> base_type::entity_shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an identifier from its parts.
|
||||
*
|
||||
* If the version part is not provided, a tombstone is returned.<br/>
|
||||
* If the entity part is not provided, a null identifier is returned.
|
||||
*
|
||||
* @param entity The entity part of the identifier.
|
||||
* @param version The version part of the identifier.
|
||||
* @return A properly constructed identifier.
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) ENTT_NOEXCEPT {
|
||||
return value_type{(entity & base_type::entity_mask) | (static_cast<entity_type>(version) << base_type::entity_shift)};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Combines two identifiers in a single one.
|
||||
*
|
||||
* The returned identifier is a copy of the first element except for its
|
||||
* version, which is taken from the second element.
|
||||
*
|
||||
* @param lhs The identifier from which to take the entity part.
|
||||
* @param rhs The identifier from which to take the version part.
|
||||
* @return A properly constructed identifier.
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) ENTT_NOEXCEPT {
|
||||
constexpr auto mask = (base_type::version_mask << base_type::entity_shift);
|
||||
return value_type{(lhs & base_type::entity_mask) | (rhs & mask)};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_integral
|
||||
* @tparam Entity The value type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_integral(const Entity value) ENTT_NOEXCEPT {
|
||||
return entt_traits<Entity>::to_integral(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_entity
|
||||
* @tparam Entity The value type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_entity(const Entity value) ENTT_NOEXCEPT {
|
||||
return entt_traits<Entity>::to_entity(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_version
|
||||
* @tparam Entity The value type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::version_type to_version(const Entity value) ENTT_NOEXCEPT {
|
||||
return entt_traits<Entity>::to_version(value);
|
||||
}
|
||||
|
||||
/*! @brief Null object for all identifiers. */
|
||||
struct null_t {
|
||||
/**
|
||||
* @brief Converts the null object to identifiers of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @return The null representation for the given type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT {
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
return entity_traits::combine(entity_traits::reserved, entity_traits::reserved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two null objects.
|
||||
* @param other A null object.
|
||||
* @return True in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const ENTT_NOEXCEPT {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two null objects.
|
||||
* @param other A null object.
|
||||
* @return False in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) const ENTT_NOEXCEPT {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
return entity_traits::to_entity(entity) == entity_traits::to_entity(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT {
|
||||
return !(entity == *this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A null object yet to be converted.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity, const null_t other) ENTT_NOEXCEPT {
|
||||
return other.operator==(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A null object yet to be converted.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity, const null_t other) ENTT_NOEXCEPT {
|
||||
return !(other == entity);
|
||||
}
|
||||
|
||||
/*! @brief Tombstone object for all identifiers. */
|
||||
struct tombstone_t {
|
||||
/**
|
||||
* @brief Converts the tombstone object to identifiers of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @return The tombstone representation for the given type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT {
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
return entity_traits::combine(entity_traits::reserved, entity_traits::reserved);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two tombstone objects.
|
||||
* @param other A tombstone object.
|
||||
* @return True in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two tombstone objects.
|
||||
* @param other A tombstone object.
|
||||
* @return False in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
return entity_traits::to_version(entity) == entity_traits::to_version(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT {
|
||||
return !(entity == *this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A tombstone object yet to be converted.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT {
|
||||
return other.operator==(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A tombstone object yet to be converted.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT {
|
||||
return !(other == entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compile-time constant for null entities.
|
||||
*
|
||||
* There exist implicit conversions from this variable to entity identifiers of
|
||||
* any allowed type. Similarly, there exist comparision operators between the
|
||||
* null entity and any other entity identifier.
|
||||
* There exist implicit conversions from this variable to identifiers of any
|
||||
* allowed type. Similarly, there exist comparision operators between the null
|
||||
* entity and any other identifier.
|
||||
*/
|
||||
inline constexpr null_t null{};
|
||||
|
||||
/**
|
||||
* @brief Compile-time constant for tombstone entities.
|
||||
*
|
||||
* There exist implicit conversions from this variable to identifiers of any
|
||||
* allowed type. Similarly, there exist comparision operators between the
|
||||
* tombstone entity and any other identifier.
|
||||
*/
|
||||
inline constexpr tombstone_t tombstone{};
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,69 +1,54 @@
|
||||
#ifndef ENTT_ENTITY_FWD_HPP
|
||||
#define ENTT_ENTITY_FWD_HPP
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include "../core/fwd.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
template<typename>
|
||||
template<typename Entity, typename = std::allocator<Entity>>
|
||||
class basic_sparse_set;
|
||||
|
||||
|
||||
template<typename, typename, typename>
|
||||
template<typename, typename Type, typename = std::allocator<Type>, typename = void>
|
||||
class basic_storage;
|
||||
|
||||
|
||||
template<typename>
|
||||
class basic_registry;
|
||||
|
||||
|
||||
template<typename...>
|
||||
template<typename, typename, typename, typename = void>
|
||||
class basic_view;
|
||||
|
||||
|
||||
template<typename>
|
||||
class basic_runtime_view;
|
||||
|
||||
|
||||
template<typename...>
|
||||
template<typename, typename, typename, typename>
|
||||
class basic_group;
|
||||
|
||||
|
||||
template<typename>
|
||||
class basic_observer;
|
||||
|
||||
|
||||
template<typename>
|
||||
class basic_organizer;
|
||||
|
||||
|
||||
template<typename, typename...>
|
||||
struct basic_handle;
|
||||
|
||||
|
||||
template<typename>
|
||||
class basic_snapshot;
|
||||
|
||||
|
||||
template<typename>
|
||||
class basic_snapshot_loader;
|
||||
|
||||
|
||||
template<typename>
|
||||
class basic_continuous_loader;
|
||||
|
||||
|
||||
/*! @brief Default entity identifier. */
|
||||
enum class entity: id_type {};
|
||||
|
||||
enum class entity : id_type {};
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using sparse_set = basic_sparse_set<entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
@@ -71,27 +56,21 @@ using sparse_set = basic_sparse_set<entity>;
|
||||
template<typename... Args>
|
||||
using storage = basic_storage<entity, Args...>;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using registry = basic_registry<entity>;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using observer = basic_observer<entity>;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using organizer = basic_organizer<entity>;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using handle = basic_handle<entity>;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using const_handle = basic_handle<const entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
@@ -99,7 +78,6 @@ using const_handle = basic_handle<const entity>;
|
||||
template<typename... Args>
|
||||
using handle_view = basic_handle<entity, Args...>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
@@ -107,31 +85,26 @@ using handle_view = basic_handle<entity, Args...>;
|
||||
template<typename... Args>
|
||||
using const_handle_view = basic_handle<const entity, Args...>;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot = basic_snapshot<entity>;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot_loader = basic_snapshot_loader<entity>;
|
||||
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using continuous_loader = basic_continuous_loader<entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
* @tparam Get Types of components iterated by the view.
|
||||
* @tparam Exclude Types of components used to filter the view.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using view = basic_view<entity, Args...>;
|
||||
|
||||
template<typename Get, typename Exclude = exclude_t<>>
|
||||
using view = basic_view<entity, Get, Exclude>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using runtime_view = basic_runtime_view<entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
@@ -139,8 +112,6 @@ using runtime_view = basic_runtime_view<entity>;
|
||||
template<typename... Args>
|
||||
using group = basic_group<entity, Args...>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,32 +1,30 @@
|
||||
#ifndef ENTT_ENTITY_GROUP_HPP
|
||||
#define ENTT_ENTITY_GROUP_HPP
|
||||
|
||||
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "component.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "sparse_set.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Group.
|
||||
*
|
||||
* Primary template isn't defined on purpose. All the specializations give a
|
||||
* compile-time error, but for a few reasonable cases.
|
||||
*/
|
||||
template<typename...>
|
||||
template<typename, typename, typename, typename>
|
||||
class basic_group;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Non-owning group.
|
||||
*
|
||||
@@ -60,113 +58,112 @@ class basic_group;
|
||||
* In any other case, attempting to use a group results in undefined behavior.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Exclude Types of components used to filter the group.
|
||||
* @tparam Get Type of components observed by the group.
|
||||
* @tparam Exclude Types of components used to filter the group.
|
||||
*/
|
||||
template<typename Entity, typename... Exclude, typename... Get>
|
||||
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>> final {
|
||||
template<typename Entity, typename... Get, typename... Exclude>
|
||||
class basic_group<Entity, owned_t<>, get_t<Get...>, exclude_t<Exclude...>> final {
|
||||
/*! @brief A registry is allowed to create groups. */
|
||||
friend class basic_registry<Entity>;
|
||||
|
||||
template<typename Component>
|
||||
using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Component>>::storage_type, Component>;
|
||||
template<typename Comp>
|
||||
using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Comp>>::storage_type, Comp>;
|
||||
|
||||
class iterable_group final {
|
||||
friend class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>>;
|
||||
using basic_common_type = std::common_type_t<typename storage_type<Get>::base_type...>;
|
||||
|
||||
template<typename It>
|
||||
class iterable_group_iterator final {
|
||||
friend class iterable_group;
|
||||
struct extended_group_iterator final {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
template<typename... Args>
|
||||
iterable_group_iterator(It from, const std::tuple<storage_type<Get> *...> &args) ENTT_NOEXCEPT
|
||||
: it{from},
|
||||
pools{args}
|
||||
{}
|
||||
extended_group_iterator() = default;
|
||||
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
|
||||
using pointer = void;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
extended_group_iterator(typename basic_common_type::iterator from, const std::tuple<storage_type<Get> *...> &args) ENTT_NOEXCEPT
|
||||
: it{from},
|
||||
pools{args} {}
|
||||
|
||||
iterable_group_iterator & operator++() ENTT_NOEXCEPT {
|
||||
return ++it, *this;
|
||||
}
|
||||
|
||||
iterable_group_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
iterable_group_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
||||
const auto entt = *it;
|
||||
return std::tuple_cat(std::make_tuple(entt), get_as_tuple(*std::get<storage_type<Get> *>(pools), entt)...);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const iterable_group_iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.it == it;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const iterable_group_iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
std::tuple<storage_type<Get> *...> pools;
|
||||
};
|
||||
|
||||
iterable_group(basic_sparse_set<Entity> * const ref, const std::tuple<storage_type<Get> *...> &cpools)
|
||||
: handler{ref},
|
||||
pools{cpools}
|
||||
{}
|
||||
|
||||
public:
|
||||
using iterator = iterable_group_iterator<typename basic_sparse_set<Entity>::iterator>;
|
||||
using reverse_iterator = iterable_group_iterator<typename basic_sparse_set<Entity>::reverse_iterator>;
|
||||
|
||||
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
|
||||
return handler ? iterator{handler->begin(), pools} : iterator{{}, pools};
|
||||
extended_group_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return ++it, *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
|
||||
return handler ? iterator{handler->end(), pools} : iterator{{}, pools};
|
||||
extended_group_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
extended_group_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
|
||||
return handler ? reverse_iterator{handler->rbegin(), pools} : reverse_iterator{{}, pools};
|
||||
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
||||
const auto entt = *it;
|
||||
return std::tuple_cat(std::make_tuple(entt), std::get<storage_type<Get> *>(pools)->get_as_tuple(entt)...);
|
||||
}
|
||||
|
||||
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
|
||||
return handler ? reverse_iterator{handler->rend(), pools} : reverse_iterator{{}, pools};
|
||||
[[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const extended_group_iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.it == it;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const extended_group_iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
basic_sparse_set<Entity> * const handler;
|
||||
const std::tuple<storage_type<Get> *...> pools;
|
||||
typename basic_common_type::iterator it;
|
||||
std::tuple<storage_type<Get> *...> pools;
|
||||
};
|
||||
|
||||
basic_group(basic_sparse_set<Entity> &ref, storage_type<Get> &... gpool) ENTT_NOEXCEPT
|
||||
basic_group(basic_common_type &ref, storage_type<Get> &...gpool) ENTT_NOEXCEPT
|
||||
: handler{&ref},
|
||||
pools{&gpool...}
|
||||
{}
|
||||
pools{&gpool...} {}
|
||||
|
||||
public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Common type among all storage types. */
|
||||
using base_type = basic_common_type;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename basic_sparse_set<Entity>::iterator;
|
||||
using iterator = typename base_type::iterator;
|
||||
/*! @brief Reversed iterator type. */
|
||||
using reverse_iterator = typename basic_sparse_set<Entity>::reverse_iterator;
|
||||
using reverse_iterator = typename base_type::reverse_iterator;
|
||||
/*! @brief Iterable group type. */
|
||||
using iterable = iterable_adaptor<extended_group_iterator>;
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid groups. */
|
||||
basic_group() ENTT_NOEXCEPT
|
||||
: handler{}
|
||||
{}
|
||||
: handler{} {}
|
||||
|
||||
/**
|
||||
* @brief Returns a const reference to the underlying handler.
|
||||
* @return A const reference to the underlying handler.
|
||||
*/
|
||||
const base_type &handle() const ENTT_NOEXCEPT {
|
||||
return *handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the storage for a given component type.
|
||||
* @tparam Comp Type of component of which to return the storage.
|
||||
* @return The storage for the given component type.
|
||||
*/
|
||||
template<typename Comp>
|
||||
[[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
|
||||
return *std::get<storage_type<Comp> *>(pools);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the storage for a given component type.
|
||||
* @tparam Comp Index of component of which to return the storage.
|
||||
* @return The storage for the given component type.
|
||||
*/
|
||||
template<std::size_t Comp>
|
||||
[[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
|
||||
return *std::get<Comp>(pools);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of entities that have the given components.
|
||||
@@ -200,18 +197,6 @@ public:
|
||||
return !*this || handler->empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Direct access to the list of entities.
|
||||
*
|
||||
* The returned pointer is such that range `[data(), data() + size())` is
|
||||
* always a valid range, even if the container is empty.
|
||||
*
|
||||
* @return A pointer to the array of entities.
|
||||
*/
|
||||
[[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT {
|
||||
return *this ? handler->data() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first entity of the group.
|
||||
*
|
||||
@@ -287,7 +272,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Finds an entity.
|
||||
* @param entt A valid entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return An iterator to the given entity if it's found, past the end
|
||||
* iterator otherwise.
|
||||
*/
|
||||
@@ -315,7 +300,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Checks if a group contains an entity.
|
||||
* @param entt A valid entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return True if the group contains the given entity, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const entity_type entt) const {
|
||||
@@ -333,20 +318,20 @@ public:
|
||||
* error. Attempting to use an entity that doesn't belong to the group
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @tparam Component Types of components to get.
|
||||
* @param entt A valid entity identifier.
|
||||
* @tparam Comp Types of components to get.
|
||||
* @param entt A valid identifier.
|
||||
* @return The components assigned to the entity.
|
||||
*/
|
||||
template<typename... Component>
|
||||
template<typename... Comp>
|
||||
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
|
||||
ENTT_ASSERT(contains(entt));
|
||||
ENTT_ASSERT(contains(entt), "Group does not contain entity");
|
||||
|
||||
if constexpr(sizeof...(Component) == 0) {
|
||||
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Get> *>(pools), entt)...);
|
||||
} else if constexpr(sizeof...(Component) == 1) {
|
||||
return (std::get<storage_type<Component> *>(pools)->get(entt), ...);
|
||||
if constexpr(sizeof...(Comp) == 0) {
|
||||
return std::tuple_cat(std::get<storage_type<Get> *>(pools)->get_as_tuple(entt)...);
|
||||
} else if constexpr(sizeof...(Comp) == 1) {
|
||||
return (std::get<storage_type<Comp> *>(pools)->get(entt), ...);
|
||||
} else {
|
||||
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Component> *>(pools), entt)...);
|
||||
return std::tuple_cat(std::get<storage_type<Comp> *>(pools)->get_as_tuple(entt)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +369,7 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to use to _visit_ the group.
|
||||
* @brief Returns an iterable object to use to _visit_ a group.
|
||||
*
|
||||
* The iterable object returns tuples that contain the current entity and a
|
||||
* set of references to its non-empty components. The _constness_ of the
|
||||
@@ -396,8 +381,9 @@ public:
|
||||
*
|
||||
* @return An iterable object to use to _visit_ the group.
|
||||
*/
|
||||
[[nodiscard]] iterable_group each() const ENTT_NOEXCEPT {
|
||||
return iterable_group{handler, pools};
|
||||
[[nodiscard]] iterable each() const ENTT_NOEXCEPT {
|
||||
return handler ? iterable{extended_group_iterator{handler->begin(), pools}, extended_group_iterator{handler->end(), pools}}
|
||||
: iterable{extended_group_iterator{{}, pools}, extended_group_iterator{{}, pools}};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -421,14 +407,14 @@ public:
|
||||
* Moreover, the comparison function object shall induce a
|
||||
* _strict weak ordering_ on the values.
|
||||
*
|
||||
* The sort function oject must offer a member function template
|
||||
* The sort function object must offer a member function template
|
||||
* `operator()` that accepts three arguments:
|
||||
*
|
||||
* * An iterator to the first element of the range to sort.
|
||||
* * An iterator past the last element of the range to sort.
|
||||
* * A comparison function to use to compare the elements.
|
||||
*
|
||||
* @tparam Component Optional types of components to compare.
|
||||
* @tparam Comp Optional types of components to compare.
|
||||
* @tparam Compare Type of comparison function object.
|
||||
* @tparam Sort Type of sort function object.
|
||||
* @tparam Args Types of arguments to forward to the sort function object.
|
||||
@@ -436,20 +422,22 @@ public:
|
||||
* @param algo A valid sort function object.
|
||||
* @param args Arguments to forward to the sort function object, if any.
|
||||
*/
|
||||
template<typename... Component, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
|
||||
template<typename... Comp, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
|
||||
if(*this) {
|
||||
if constexpr(sizeof...(Component) == 0) {
|
||||
if constexpr(sizeof...(Comp) == 0) {
|
||||
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
|
||||
handler->sort(std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
} else if constexpr(sizeof...(Component) == 1) {
|
||||
handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
|
||||
return compare((std::get<storage_type<Component> *>(pools)->get(lhs), ...), (std::get<storage_type<Component> *>(pools)->get(rhs), ...));
|
||||
}, std::move(algo), std::forward<Args>(args)...);
|
||||
} else {
|
||||
handler->sort([this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
|
||||
return compare(std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(rhs)...));
|
||||
}, std::move(algo), std::forward<Args>(args)...);
|
||||
auto comp = [this, &compare](const entity_type lhs, const entity_type rhs) {
|
||||
if constexpr(sizeof...(Comp) == 1) {
|
||||
return compare((std::get<storage_type<Comp> *>(pools)->get(lhs), ...), (std::get<storage_type<Comp> *>(pools)->get(rhs), ...));
|
||||
} else {
|
||||
return compare(std::forward_as_tuple(std::get<storage_type<Comp> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Comp> *>(pools)->get(rhs)...));
|
||||
}
|
||||
};
|
||||
|
||||
handler->sort(std::move(comp), std::move(algo), std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -468,21 +456,20 @@ public:
|
||||
* can quickly ruin the order imposed to the pool of entities shared between
|
||||
* the non-owning groups.
|
||||
*
|
||||
* @tparam Component Type of component to use to impose the order.
|
||||
* @tparam Comp Type of component to use to impose the order.
|
||||
*/
|
||||
template<typename Component>
|
||||
template<typename Comp>
|
||||
void sort() const {
|
||||
if(*this) {
|
||||
handler->respect(*std::get<storage_type<Component> *>(pools));
|
||||
handler->respect(*std::get<storage_type<Comp> *>(pools));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
basic_sparse_set<entity_type> * const handler;
|
||||
base_type *const handler;
|
||||
const std::tuple<storage_type<Get> *...> pools;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Owning group.
|
||||
*
|
||||
@@ -525,144 +512,114 @@ private:
|
||||
* In any other case, attempting to use a group results in undefined behavior.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Exclude Types of components used to filter the group.
|
||||
* @tparam Get Types of components observed by the group.
|
||||
* @tparam Owned Types of components owned by the group.
|
||||
* @tparam Get Types of components observed by the group.
|
||||
* @tparam Exclude Types of components used to filter the group.
|
||||
*/
|
||||
template<typename Entity, typename... Exclude, typename... Get, typename... Owned>
|
||||
class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...> final {
|
||||
template<typename Entity, typename... Owned, typename... Get, typename... Exclude>
|
||||
class basic_group<Entity, owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> final {
|
||||
/*! @brief A registry is allowed to create groups. */
|
||||
friend class basic_registry<Entity>;
|
||||
|
||||
template<typename Component>
|
||||
using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Component>>::storage_type, Component>;
|
||||
template<typename Comp>
|
||||
using storage_type = constness_as_t<typename storage_traits<Entity, std::remove_const_t<Comp>>::storage_type, Comp>;
|
||||
|
||||
class iterable_group final {
|
||||
friend class basic_group<Entity, exclude_t<Exclude...>, get_t<Get...>, Owned...>;
|
||||
using basic_common_type = std::common_type_t<typename storage_type<Owned>::base_type..., typename storage_type<Get>::base_type...>;
|
||||
|
||||
template<typename, typename>
|
||||
class iterable_group_iterator;
|
||||
template<typename>
|
||||
struct extended_group_iterator;
|
||||
|
||||
template<typename It, typename... OIt>
|
||||
class iterable_group_iterator<It, type_list<OIt...>> final {
|
||||
friend class iterable_group;
|
||||
template<typename... OIt>
|
||||
struct extended_group_iterator<type_list<OIt...>> final {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
template<typename... Other>
|
||||
iterable_group_iterator(It from, const std::tuple<Other...> &other, const std::tuple<storage_type<Get> *...> &cpools) ENTT_NOEXCEPT
|
||||
: it{from},
|
||||
owned{std::get<OIt>(other)...},
|
||||
get{cpools}
|
||||
{}
|
||||
extended_group_iterator() = default;
|
||||
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = decltype(std::tuple_cat(std::tuple<Entity>{}, std::declval<basic_group>().get({})));
|
||||
using pointer = void;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
template<typename... Other>
|
||||
extended_group_iterator(typename basic_common_type::iterator from, const std::tuple<Other...> &other, const std::tuple<storage_type<Get> *...> &cpools) ENTT_NOEXCEPT
|
||||
: it{from},
|
||||
owned{std::get<OIt>(other)...},
|
||||
get{cpools} {}
|
||||
|
||||
iterable_group_iterator & operator++() ENTT_NOEXCEPT {
|
||||
return ++it, (++std::get<OIt>(owned), ...), *this;
|
||||
}
|
||||
|
||||
iterable_group_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
iterable_group_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
||||
return std::tuple_cat(
|
||||
std::make_tuple(*it),
|
||||
std::forward_as_tuple(*std::get<OIt>(owned)...),
|
||||
get_as_tuple(*std::get<storage_type<Get> *>(get), *it)...
|
||||
);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const iterable_group_iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.it == it;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const iterable_group_iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
std::tuple<OIt...> owned;
|
||||
std::tuple<storage_type<Get> *...> get;
|
||||
};
|
||||
|
||||
iterable_group(std::tuple<storage_type<Owned> *..., storage_type<Get> *...> cpools, const std::size_t * const extent)
|
||||
: pools{cpools},
|
||||
length{extent}
|
||||
{}
|
||||
|
||||
public:
|
||||
using iterator = iterable_group_iterator<
|
||||
typename basic_sparse_set<Entity>::iterator,
|
||||
type_list_cat_t<std::conditional_t<std::is_void_v<decltype(std::declval<storage_type<Owned>>().get({}))>, type_list<>, type_list<decltype(std::declval<storage_type<Owned>>().end())>>...>
|
||||
>;
|
||||
using reverse_iterator = iterable_group_iterator<
|
||||
typename basic_sparse_set<Entity>::reverse_iterator,
|
||||
type_list_cat_t<std::conditional_t<std::is_void_v<decltype(std::declval<storage_type<Owned>>().get({}))>, type_list<>, type_list<decltype(std::declval<storage_type<Owned>>().rbegin())>>...>
|
||||
>;
|
||||
|
||||
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
|
||||
return length ? iterator{
|
||||
std::get<0>(pools)->basic_sparse_set<Entity>::end() - *length,
|
||||
std::make_tuple((std::get<storage_type<Owned> *>(pools)->end() - *length)...),
|
||||
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
|
||||
} : iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->end()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
|
||||
extended_group_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return ++it, (++std::get<OIt>(owned), ...), *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
|
||||
return length ? iterator{
|
||||
std::get<0>(pools)->basic_sparse_set<Entity>::end(),
|
||||
std::make_tuple((std::get<storage_type<Owned> *>(pools)->end())...),
|
||||
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
|
||||
} : iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->end()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
|
||||
extended_group_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
extended_group_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
|
||||
return length ? reverse_iterator{
|
||||
std::get<0>(pools)->basic_sparse_set<Entity>::rbegin(),
|
||||
std::make_tuple((std::get<storage_type<Owned> *>(pools)->rbegin())...),
|
||||
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
|
||||
} : reverse_iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->rbegin()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
|
||||
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
||||
return std::tuple_cat(
|
||||
std::make_tuple(*it),
|
||||
std::forward_as_tuple(*std::get<OIt>(owned)...),
|
||||
std::get<storage_type<Get> *>(get)->get_as_tuple(*it)...);
|
||||
}
|
||||
|
||||
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
|
||||
return length ? reverse_iterator{
|
||||
std::get<0>(pools)->basic_sparse_set<Entity>::rbegin() + *length,
|
||||
std::make_tuple((std::get<storage_type<Owned> *>(pools)->rbegin() + *length)...),
|
||||
std::make_tuple(std::get<storage_type<Get> *>(pools)...)
|
||||
} : reverse_iterator{{}, std::make_tuple(decltype(std::get<storage_type<Owned> *>(pools)->rbegin()){}...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
|
||||
[[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const extended_group_iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.it == it;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const extended_group_iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::tuple<storage_type<Owned> *..., storage_type<Get> *...> pools;
|
||||
const std::size_t * const length;
|
||||
typename basic_common_type::iterator it;
|
||||
std::tuple<OIt...> owned;
|
||||
std::tuple<storage_type<Get> *...> get;
|
||||
};
|
||||
|
||||
basic_group(const std::size_t &extent, storage_type<Owned> &... opool, storage_type<Get> &... gpool) ENTT_NOEXCEPT
|
||||
basic_group(const std::size_t &extent, storage_type<Owned> &...opool, storage_type<Get> &...gpool) ENTT_NOEXCEPT
|
||||
: pools{&opool..., &gpool...},
|
||||
length{&extent}
|
||||
{}
|
||||
length{&extent} {}
|
||||
|
||||
public:
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = Entity;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Common type among all storage types. */
|
||||
using base_type = basic_common_type;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename basic_sparse_set<Entity>::iterator;
|
||||
using iterator = typename base_type::iterator;
|
||||
/*! @brief Reversed iterator type. */
|
||||
using reverse_iterator = typename basic_sparse_set<Entity>::reverse_iterator;
|
||||
using reverse_iterator = typename base_type::reverse_iterator;
|
||||
/*! @brief Iterable group type. */
|
||||
using iterable = iterable_adaptor<extended_group_iterator<type_list_cat_t<std::conditional_t<ignore_as_empty_v<std::remove_const_t<Owned>>, type_list<>, type_list<decltype(std::declval<storage_type<Owned>>().end())>>...>>>;
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid groups. */
|
||||
basic_group() ENTT_NOEXCEPT
|
||||
: length{}
|
||||
{}
|
||||
: length{} {}
|
||||
|
||||
/**
|
||||
* @brief Returns the storage for a given component type.
|
||||
* @tparam Comp Type of component of which to return the storage.
|
||||
* @return The storage for the given component type.
|
||||
*/
|
||||
template<typename Comp>
|
||||
[[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
|
||||
return *std::get<storage_type<Comp> *>(pools);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the storage for a given component type.
|
||||
* @tparam Comp Index of component of which to return the storage.
|
||||
* @return The storage for the given component type.
|
||||
*/
|
||||
template<std::size_t Comp>
|
||||
[[nodiscard]] decltype(auto) storage() const ENTT_NOEXCEPT {
|
||||
return *std::get<Comp>(pools);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of entities that have the given components.
|
||||
@@ -680,38 +637,6 @@ public:
|
||||
return !*this || !*length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Direct access to the list of components of a given pool.
|
||||
*
|
||||
* The returned pointer is such that range
|
||||
* `[raw<Component>(), raw<Component>() + size())` is always a valid range,
|
||||
* even if the container is empty.<br/>
|
||||
*
|
||||
* @warning
|
||||
* This function is only available for owned types.
|
||||
*
|
||||
* @tparam Component Type of component in which one is interested.
|
||||
* @return A pointer to the array of components.
|
||||
*/
|
||||
template<typename Component>
|
||||
[[nodiscard]] Component * raw() const ENTT_NOEXCEPT {
|
||||
static_assert((std::is_same_v<Component, Owned> || ...), "Non-owned type");
|
||||
auto *cpool = std::get<storage_type<Component> *>(pools);
|
||||
return cpool ? cpool->raw() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Direct access to the list of entities.
|
||||
*
|
||||
* The returned pointer is such that range `[data(), data() + size())` is
|
||||
* always a valid range, even if the container is empty.
|
||||
*
|
||||
* @return A pointer to the array of entities.
|
||||
*/
|
||||
[[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT {
|
||||
return *this ? std::get<0>(pools)->data() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first entity of the group.
|
||||
*
|
||||
@@ -721,7 +646,7 @@ public:
|
||||
* @return An iterator to the first entity of the group.
|
||||
*/
|
||||
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
|
||||
return *this ? (std::get<0>(pools)->basic_sparse_set<entity_type>::end() - *length) : iterator{};
|
||||
return *this ? (std::get<0>(pools)->base_type::end() - *length) : iterator{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -735,7 +660,7 @@ public:
|
||||
* group.
|
||||
*/
|
||||
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
|
||||
return *this ? std::get<0>(pools)->basic_sparse_set<entity_type>::end() : iterator{};
|
||||
return *this ? std::get<0>(pools)->base_type::end() : iterator{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -747,7 +672,7 @@ public:
|
||||
* @return An iterator to the first entity of the reversed group.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
|
||||
return *this ? std::get<0>(pools)->basic_sparse_set<entity_type>::rbegin() : reverse_iterator{};
|
||||
return *this ? std::get<0>(pools)->base_type::rbegin() : reverse_iterator{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -762,7 +687,7 @@ public:
|
||||
* reversed group.
|
||||
*/
|
||||
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
|
||||
return *this ? (std::get<0>(pools)->basic_sparse_set<entity_type>::rbegin() + *length) : reverse_iterator{};
|
||||
return *this ? (std::get<0>(pools)->base_type::rbegin() + *length) : reverse_iterator{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -787,7 +712,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Finds an entity.
|
||||
* @param entt A valid entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return An iterator to the given entity if it's found, past the end
|
||||
* iterator otherwise.
|
||||
*/
|
||||
@@ -815,7 +740,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Checks if a group contains an entity.
|
||||
* @param entt A valid entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return True if the group contains the given entity, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const entity_type entt) const {
|
||||
@@ -833,20 +758,20 @@ public:
|
||||
* error. Attempting to use an entity that doesn't belong to the group
|
||||
* results in undefined behavior.
|
||||
*
|
||||
* @tparam Component Types of components to get.
|
||||
* @param entt A valid entity identifier.
|
||||
* @tparam Comp Types of components to get.
|
||||
* @param entt A valid identifier.
|
||||
* @return The components assigned to the entity.
|
||||
*/
|
||||
template<typename... Component>
|
||||
template<typename... Comp>
|
||||
[[nodiscard]] decltype(auto) get(const entity_type entt) const {
|
||||
ENTT_ASSERT(contains(entt));
|
||||
ENTT_ASSERT(contains(entt), "Group does not contain entity");
|
||||
|
||||
if constexpr(sizeof...(Component) == 0) {
|
||||
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Owned> *>(pools), entt)..., get_as_tuple(*std::get<storage_type<Get> *>(pools), entt)...);
|
||||
} else if constexpr(sizeof...(Component) == 1) {
|
||||
return (std::get<storage_type<Component> *>(pools)->get(entt), ...);
|
||||
if constexpr(sizeof...(Comp) == 0) {
|
||||
return std::tuple_cat(std::get<storage_type<Owned> *>(pools)->get_as_tuple(entt)..., std::get<storage_type<Get> *>(pools)->get_as_tuple(entt)...);
|
||||
} else if constexpr(sizeof...(Comp) == 1) {
|
||||
return (std::get<storage_type<Comp> *>(pools)->get(entt), ...);
|
||||
} else {
|
||||
return std::tuple_cat(get_as_tuple(*std::get<storage_type<Component> *>(pools), entt)...);
|
||||
return std::tuple_cat(std::get<storage_type<Comp> *>(pools)->get_as_tuple(entt)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -878,13 +803,13 @@ public:
|
||||
if constexpr(is_applicable_v<Func, decltype(std::tuple_cat(std::tuple<entity_type>{}, std::declval<basic_group>().get({})))>) {
|
||||
std::apply(func, args);
|
||||
} else {
|
||||
std::apply([&func](auto, auto &&... less) { func(std::forward<decltype(less)>(less)...); }, args);
|
||||
std::apply([&func](auto, auto &&...less) { func(std::forward<decltype(less)>(less)...); }, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to use to _visit_ the group.
|
||||
* @brief Returns an iterable object to use to _visit_ a group.
|
||||
*
|
||||
* The iterable object returns tuples that contain the current entity and a
|
||||
* set of references to its non-empty components. The _constness_ of the
|
||||
@@ -896,8 +821,12 @@ public:
|
||||
*
|
||||
* @return An iterable object to use to _visit_ the group.
|
||||
*/
|
||||
[[nodiscard]] iterable_group each() const ENTT_NOEXCEPT {
|
||||
return iterable_group{pools, length};
|
||||
[[nodiscard]] iterable each() const ENTT_NOEXCEPT {
|
||||
using extended_iterator_type = typename iterable::iterator;
|
||||
iterator last = length ? std::get<0>(pools)->basic_common_type::end() : iterator{};
|
||||
auto from = extended_iterator_type{last - *length, std::make_tuple((std::get<storage_type<Owned> *>(pools)->end() - *length)...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
|
||||
auto to = extended_iterator_type{last, std::make_tuple((std::get<storage_type<Owned> *>(pools)->end())...), std::make_tuple(std::get<storage_type<Get> *>(pools)...)};
|
||||
return {std::move(from), std::move(to)};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -922,14 +851,14 @@ public:
|
||||
* Moreover, the comparison function object shall induce a
|
||||
* _strict weak ordering_ on the values.
|
||||
*
|
||||
* The sort function oject must offer a member function template
|
||||
* The sort function object must offer a member function template
|
||||
* `operator()` that accepts three arguments:
|
||||
*
|
||||
* * An iterator to the first element of the range to sort.
|
||||
* * An iterator past the last element of the range to sort.
|
||||
* * A comparison function to use to compare the elements.
|
||||
*
|
||||
* @tparam Component Optional types of components to compare.
|
||||
* @tparam Comp Optional types of components to compare.
|
||||
* @tparam Compare Type of comparison function object.
|
||||
* @tparam Sort Type of sort function object.
|
||||
* @tparam Args Types of arguments to forward to the sort function object.
|
||||
@@ -937,39 +866,39 @@ public:
|
||||
* @param algo A valid sort function object.
|
||||
* @param args Arguments to forward to the sort function object, if any.
|
||||
*/
|
||||
template<typename... Component, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) const {
|
||||
template<typename... Comp, typename Compare, typename Sort = std_sort, typename... Args>
|
||||
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const {
|
||||
auto *cpool = std::get<0>(pools);
|
||||
|
||||
if constexpr(sizeof...(Component) == 0) {
|
||||
|
||||
if constexpr(sizeof...(Comp) == 0) {
|
||||
static_assert(std::is_invocable_v<Compare, const entity_type, const entity_type>, "Invalid comparison function");
|
||||
cpool->sort_n(*length, std::move(compare), std::move(algo), std::forward<Args>(args)...);
|
||||
} else if constexpr(sizeof...(Component) == 1) {
|
||||
cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
|
||||
return compare((std::get<storage_type<Component> *>(pools)->get(lhs), ...), (std::get<storage_type<Component> *>(pools)->get(rhs), ...));
|
||||
}, std::move(algo), std::forward<Args>(args)...);
|
||||
} else {
|
||||
cpool->sort_n(*length, [this, compare = std::move(compare)](const entity_type lhs, const entity_type rhs) {
|
||||
return compare(std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Component> *>(pools)->get(rhs)...));
|
||||
}, std::move(algo), std::forward<Args>(args)...);
|
||||
auto comp = [this, &compare](const entity_type lhs, const entity_type rhs) {
|
||||
if constexpr(sizeof...(Comp) == 1) {
|
||||
return compare((std::get<storage_type<Comp> *>(pools)->get(lhs), ...), (std::get<storage_type<Comp> *>(pools)->get(rhs), ...));
|
||||
} else {
|
||||
return compare(std::forward_as_tuple(std::get<storage_type<Comp> *>(pools)->get(lhs)...), std::forward_as_tuple(std::get<storage_type<Comp> *>(pools)->get(rhs)...));
|
||||
}
|
||||
};
|
||||
|
||||
cpool->sort_n(*length, std::move(comp), std::move(algo), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
[this](auto *head, auto *... other) {
|
||||
|
||||
[this](auto *head, auto *...other) {
|
||||
for(auto next = *length; next; --next) {
|
||||
const auto pos = next - 1;
|
||||
[[maybe_unused]] const auto entt = head->data()[pos];
|
||||
(other->swap(other->data()[pos], entt), ...);
|
||||
(other->swap_elements(other->data()[pos], entt), ...);
|
||||
}
|
||||
}(std::get<storage_type<Owned> *>(pools)...);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::tuple<storage_type<Owned> *..., storage_type<Get> *...> pools;
|
||||
const size_type * const length;
|
||||
const size_type *const length;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef ENTT_ENTITY_HANDLE_HPP
|
||||
#define ENTT_ENTITY_HANDLE_HPP
|
||||
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -10,10 +9,8 @@
|
||||
#include "fwd.hpp"
|
||||
#include "registry.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Non-owning handle to an entity.
|
||||
*
|
||||
@@ -24,36 +21,28 @@ namespace entt {
|
||||
*/
|
||||
template<typename Entity, typename... Type>
|
||||
struct basic_handle {
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = std::remove_const_t<Entity>;
|
||||
/*! @brief Type of registry accepted by the handle. */
|
||||
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
|
||||
using registry_type = constness_as_t<basic_registry<std::remove_const_t<Entity>>, Entity>;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename registry_type::version_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename registry_type::size_type;
|
||||
|
||||
/*! @brief Constructs an invalid handle. */
|
||||
basic_handle() ENTT_NOEXCEPT
|
||||
: reg{}, entt{null}
|
||||
{}
|
||||
: reg{},
|
||||
entt{null} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a handle from a given registry and entity.
|
||||
* @param ref An instance of the registry class.
|
||||
* @param value An entity identifier.
|
||||
* @param value A valid identifier.
|
||||
*/
|
||||
basic_handle(registry_type &ref, entity_type value) ENTT_NOEXCEPT
|
||||
: reg{&ref}, entt{value}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Compares two handles.
|
||||
* @tparam Args Template parameters of the handle with which to compare.
|
||||
* @param other Handle with which to compare.
|
||||
* @return True if both handles refer to the same registry and the same
|
||||
* entity, false otherwise.
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] bool operator==(const basic_handle<Args...> &other) const ENTT_NOEXCEPT {
|
||||
return reg == other.registry() && entt == other.entity();
|
||||
}
|
||||
: reg{&ref},
|
||||
entt{value} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a const handle from a non-const one.
|
||||
@@ -64,18 +53,15 @@ struct basic_handle {
|
||||
*/
|
||||
template<typename Other, typename... Args>
|
||||
operator basic_handle<Other, Args...>() const ENTT_NOEXCEPT {
|
||||
static_assert(
|
||||
(std::is_same_v<Other, Entity> || std::is_same_v<std::remove_const_t<Other>, Entity>)
|
||||
&& (sizeof...(Type) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Type)) && ... && (type_list_contains_v<type_list<Type...>, Args>))),
|
||||
"Invalid conversion between different handles"
|
||||
);
|
||||
static_assert(std::is_same_v<Other, Entity> || std::is_same_v<std::remove_const_t<Other>, Entity>, "Invalid conversion between different handles");
|
||||
static_assert((sizeof...(Type) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Type)) && ... && (type_list_contains_v<type_list<Type...>, Args>))), "Invalid conversion between different handles");
|
||||
|
||||
return reg ? basic_handle<Other, Args...>{*reg, entt} : basic_handle<Other, Args...>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a handle to its underlying entity.
|
||||
* @return An entity identifier.
|
||||
* @return The contained identifier.
|
||||
*/
|
||||
[[nodiscard]] operator entity_type() const ENTT_NOEXCEPT {
|
||||
return entity();
|
||||
@@ -101,7 +87,7 @@ struct basic_handle {
|
||||
* @brief Returns a pointer to the underlying registry, if any.
|
||||
* @return A pointer to the underlying registry, if any.
|
||||
*/
|
||||
[[nodiscard]] registry_type * registry() const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] registry_type *registry() const ENTT_NOEXCEPT {
|
||||
return reg;
|
||||
}
|
||||
|
||||
@@ -126,7 +112,7 @@ struct basic_handle {
|
||||
* @sa basic_registry::destroy
|
||||
* @param version A desired version upon destruction.
|
||||
*/
|
||||
void destroy(const typename registry_type::version_type version) {
|
||||
void destroy(const version_type version) {
|
||||
reg->destroy(entt, version);
|
||||
}
|
||||
|
||||
@@ -139,7 +125,7 @@ struct basic_handle {
|
||||
* @return A reference to the newly created component.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) emplace(Args &&... args) const {
|
||||
decltype(auto) emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
|
||||
return reg->template emplace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
@@ -153,7 +139,7 @@ struct basic_handle {
|
||||
* @return A reference to the newly created component.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) emplace_or_replace(Args &&... args) const {
|
||||
decltype(auto) emplace_or_replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
|
||||
return reg->template emplace_or_replace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
@@ -167,7 +153,7 @@ struct basic_handle {
|
||||
* @return A reference to the patched component.
|
||||
*/
|
||||
template<typename Component, typename... Func>
|
||||
decltype(auto) patch(Func &&... func) const {
|
||||
decltype(auto) patch(Func &&...func) const {
|
||||
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
|
||||
return reg->template patch<Component>(entt, std::forward<Func>(func)...);
|
||||
}
|
||||
@@ -181,7 +167,7 @@ struct basic_handle {
|
||||
* @return A reference to the component being replaced.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) replace(Args &&... args) const {
|
||||
decltype(auto) replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
|
||||
return reg->template replace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
@@ -190,32 +176,23 @@ struct basic_handle {
|
||||
* @brief Removes the given components from a handle.
|
||||
* @sa basic_registry::remove
|
||||
* @tparam Component Types of components to remove.
|
||||
*/
|
||||
template<typename... Component>
|
||||
void remove() const {
|
||||
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
|
||||
reg->template remove<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the given components from a handle.
|
||||
* @sa basic_registry::remove_if_exists
|
||||
* @tparam Component Types of components to remove.
|
||||
* @return The number of components actually removed.
|
||||
*/
|
||||
template<typename... Component>
|
||||
decltype(auto) remove_if_exists() const {
|
||||
size_type remove() const {
|
||||
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
|
||||
return reg->template remove_if_exists<Component...>(entt);
|
||||
return reg->template remove<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes all the components from a handle and makes it orphaned.
|
||||
* @sa basic_registry::remove_all
|
||||
* @brief Erases the given components from a handle.
|
||||
* @sa basic_registry::erase
|
||||
* @tparam Component Types of components to erase.
|
||||
*/
|
||||
void remove_all() const {
|
||||
static_assert(sizeof...(Type) == 0, "Invalid operation");
|
||||
reg->remove_all(entt);
|
||||
template<typename... Component>
|
||||
void erase() const {
|
||||
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
|
||||
reg->template erase<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,7 +239,7 @@ struct basic_handle {
|
||||
* @return Reference to the component owned by the handle.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
[[nodiscard]] decltype(auto) get_or_emplace(Args &&... args) const {
|
||||
[[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
|
||||
return reg->template get_or_emplace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
@@ -288,14 +265,27 @@ struct basic_handle {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Visits a handle and returns the types for its components.
|
||||
* @sa basic_registry::visit
|
||||
* @brief Visits a handle and returns the pools for its components.
|
||||
*
|
||||
* The signature of the function should be equivalent to the following:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(id_type, const basic_sparse_set<entity_type> &);
|
||||
* @endcode
|
||||
*
|
||||
* Returned pools are those that contain the entity associated with the
|
||||
* handle.
|
||||
*
|
||||
* @tparam Func Type of the function object to invoke.
|
||||
* @param func A valid function object.
|
||||
*/
|
||||
template<typename Func>
|
||||
void visit(Func &&func) const {
|
||||
reg->visit(entt, std::forward<Func>(func));
|
||||
for(auto [id, storage]: reg->storage()) {
|
||||
if(storage.contains(entt)) {
|
||||
func(id, storage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -303,41 +293,48 @@ private:
|
||||
entity_type entt;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares two handles.
|
||||
* @tparam Args Scope of the first handle.
|
||||
* @tparam Other Scope of the second handle.
|
||||
* @param lhs A valid handle.
|
||||
* @param rhs A valid handle.
|
||||
* @return True if both handles refer to the same registry and the same
|
||||
* entity, false otherwise.
|
||||
*/
|
||||
template<typename... Args, typename... Other>
|
||||
[[nodiscard]] bool operator==(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) ENTT_NOEXCEPT {
|
||||
return lhs.registry() == rhs.registry() && lhs.entity() == rhs.entity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two handles.
|
||||
* @tparam Type A valid entity type (see entt_traits for more details).
|
||||
* @tparam Other A valid entity type (see entt_traits for more details).
|
||||
* @tparam Args Scope of the first handle.
|
||||
* @tparam Other Scope of the second handle.
|
||||
* @param lhs A valid handle.
|
||||
* @param rhs A valid handle.
|
||||
* @return False if both handles refer to the same registry and the same
|
||||
* entity, true otherwise.
|
||||
*/
|
||||
template<typename Type, typename Other>
|
||||
bool operator!=(const basic_handle<Type> &lhs, const basic_handle<Other> &rhs) ENTT_NOEXCEPT {
|
||||
template<typename... Args, typename... Other>
|
||||
[[nodiscard]] bool operator!=(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) ENTT_NOEXCEPT {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
basic_handle(basic_registry<Entity> &, Entity) -> basic_handle<Entity>;
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
basic_handle(basic_registry<Entity> &, Entity)
|
||||
-> basic_handle<Entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
basic_handle(const basic_registry<Entity> &, Entity)
|
||||
-> basic_handle<const Entity>;
|
||||
|
||||
|
||||
}
|
||||
basic_handle(const basic_registry<Entity> &, Entity) -> basic_handle<const Entity>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
#ifndef ENTT_ENTITY_HELPER_HPP
|
||||
#define ENTT_ENTITY_HELPER_HPP
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../signal/delegate.hpp"
|
||||
#include "registry.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include "registry.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Converts a registry to a view.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
@@ -37,7 +35,7 @@ struct as_view {
|
||||
* @return A newly created view.
|
||||
*/
|
||||
template<typename Exclude, typename... Component>
|
||||
operator basic_view<entity_type, Exclude, Component...>() const {
|
||||
operator basic_view<entity_type, get_t<Component...>, Exclude>() const {
|
||||
return reg.template view<Component...>(Exclude{});
|
||||
}
|
||||
|
||||
@@ -45,7 +43,6 @@ private:
|
||||
registry_type ®
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
@@ -53,7 +50,6 @@ private:
|
||||
template<typename Entity>
|
||||
as_view(basic_registry<Entity> &) -> as_view<Entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
@@ -61,7 +57,6 @@ as_view(basic_registry<Entity> &) -> as_view<Entity>;
|
||||
template<typename Entity>
|
||||
as_view(const basic_registry<Entity> &) -> as_view<const Entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Converts a registry to a group.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
@@ -81,13 +76,13 @@ struct as_group {
|
||||
|
||||
/**
|
||||
* @brief Conversion function from a registry to a group.
|
||||
* @tparam Exclude Types of components used to filter the group.
|
||||
* @tparam Get Types of components observed by the group.
|
||||
* @tparam Exclude Types of components used to filter the group.
|
||||
* @tparam Owned Types of components owned by the group.
|
||||
* @return A newly created group.
|
||||
*/
|
||||
template<typename Exclude, typename Get, typename... Owned>
|
||||
operator basic_group<entity_type, Exclude, Get, Owned...>() const {
|
||||
template<typename Get, typename Exclude, typename... Owned>
|
||||
operator basic_group<entity_type, owned_t<Owned...>, Get, Exclude>() const {
|
||||
if constexpr(std::is_const_v<registry_type>) {
|
||||
return reg.template group_if_exists<Owned...>(Get{}, Exclude{});
|
||||
} else {
|
||||
@@ -99,7 +94,6 @@ private:
|
||||
registry_type ®
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
@@ -107,7 +101,6 @@ private:
|
||||
template<typename Entity>
|
||||
as_group(basic_registry<Entity> &) -> as_group<Entity>;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
@@ -115,8 +108,6 @@ as_group(basic_registry<Entity> &) -> as_group<Entity>;
|
||||
template<typename Entity>
|
||||
as_group(const basic_registry<Entity> &) -> as_group<const Entity>;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper to create a listener that directly invokes a member function.
|
||||
* @tparam Member Member function to invoke on a component of the given type.
|
||||
@@ -132,23 +123,34 @@ void invoke(basic_registry<Entity> ®, const Entity entt) {
|
||||
func(reg, entt);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the entity associated with a given component.
|
||||
*
|
||||
* @warning
|
||||
* Currently, this function only works correctly with the default pool as it
|
||||
* makes assumptions about how the components are laid out.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Component Type of component.
|
||||
* @param reg A registry that contains the given entity and its components.
|
||||
* @param component A valid component instance.
|
||||
* @param instance A valid component instance.
|
||||
* @return The entity associated with the given component.
|
||||
*/
|
||||
template<typename Entity, typename Component>
|
||||
Entity to_entity(const basic_registry<Entity> ®, const Component &component) {
|
||||
const auto view = reg.template view<const Component>();
|
||||
return *(view.data() + (&component - view.raw()));
|
||||
}
|
||||
|
||||
|
||||
Entity to_entity(const basic_registry<Entity> ®, const Component &instance) {
|
||||
const auto &storage = reg.template storage<Component>();
|
||||
const typename basic_registry<Entity>::base_type &base = storage;
|
||||
const auto *addr = std::addressof(instance);
|
||||
|
||||
for(auto it = base.rbegin(), last = base.rend(); it < last; it += ENTT_PACKED_PAGE) {
|
||||
if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < ENTT_PACKED_PAGE) {
|
||||
return *(it + dist);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
#ifndef ENTT_ENTITY_OBSERVER_HPP
|
||||
#define ENTT_ENTITY_OBSERVER_HPP
|
||||
|
||||
|
||||
#include <limits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../signal/delegate.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "registry.hpp"
|
||||
#include "storage.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/*! @brief Grouping matcher. */
|
||||
template<typename...>
|
||||
struct matcher {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Collector.
|
||||
*
|
||||
@@ -34,7 +30,6 @@ struct matcher {};
|
||||
template<typename...>
|
||||
struct basic_collector;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Collector.
|
||||
*
|
||||
@@ -114,11 +109,9 @@ struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*! @brief Variable template used to ease the definition of collectors. */
|
||||
inline constexpr basic_collector<> collector{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Observer.
|
||||
*
|
||||
@@ -191,7 +184,7 @@ class basic_observer {
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
|
||||
if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) {
|
||||
obs.storage.remove(entt);
|
||||
obs.storage.erase(entt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,14 +208,15 @@ class basic_observer {
|
||||
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> {
|
||||
template<std::size_t Index, typename... Ignore>
|
||||
static void maybe_valid_if(basic_observer &obs, basic_registry<Entity> ®, const Entity entt) {
|
||||
if([®, entt]() {
|
||||
auto condition = [®, entt]() {
|
||||
if constexpr(sizeof...(Ignore) == 0) {
|
||||
return reg.template all_of<AllOf..., Require...>(entt) && !reg.template any_of<NoneOf..., Reject...>(entt);
|
||||
} else {
|
||||
return reg.template all_of<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !reg.template any_of<NoneOf>(entt)) && ...) && !reg.template any_of<Reject...>(entt);
|
||||
}
|
||||
}())
|
||||
{
|
||||
};
|
||||
|
||||
if(condition()) {
|
||||
if(!obs.storage.contains(entt)) {
|
||||
obs.storage.emplace(entt);
|
||||
}
|
||||
@@ -234,7 +228,7 @@ class basic_observer {
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
|
||||
if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) {
|
||||
obs.storage.remove(entt);
|
||||
obs.storage.erase(entt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,8 +275,7 @@ public:
|
||||
/*! @brief Default constructor. */
|
||||
basic_observer()
|
||||
: release{},
|
||||
storage{}
|
||||
{}
|
||||
storage{} {}
|
||||
|
||||
/*! @brief Default copy constructor, deleted on purpose. */
|
||||
basic_observer(const basic_observer &) = delete;
|
||||
@@ -296,8 +289,7 @@ public:
|
||||
*/
|
||||
template<typename... Matcher>
|
||||
basic_observer(basic_registry<entity_type> ®, basic_collector<Matcher...>)
|
||||
: basic_observer{}
|
||||
{
|
||||
: basic_observer{} {
|
||||
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
|
||||
}
|
||||
|
||||
@@ -308,13 +300,13 @@ public:
|
||||
* @brief Default copy assignment operator, deleted on purpose.
|
||||
* @return This observer.
|
||||
*/
|
||||
basic_observer & operator=(const basic_observer &) = delete;
|
||||
basic_observer &operator=(const basic_observer &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator, deleted on purpose.
|
||||
* @return This observer.
|
||||
*/
|
||||
basic_observer & operator=(basic_observer &&) = delete;
|
||||
basic_observer &operator=(basic_observer &&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Connects an observer to a given registry.
|
||||
@@ -364,7 +356,7 @@ public:
|
||||
*
|
||||
* @return A pointer to the array of entities.
|
||||
*/
|
||||
[[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] const entity_type *data() const ENTT_NOEXCEPT {
|
||||
return storage.data();
|
||||
}
|
||||
|
||||
@@ -439,8 +431,6 @@ private:
|
||||
basic_storage<entity_type, payload_type> storage;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,54 +1,47 @@
|
||||
#ifndef ENTT_ENTITY_ORGANIZER_HPP
|
||||
#define ENTT_ENTITY_ORGANIZER_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../container/dense_hash_map.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "helper.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename>
|
||||
struct is_view: std::false_type {};
|
||||
|
||||
template<typename Entity, typename... Exclude, typename... Component>
|
||||
struct is_view<basic_view<Entity, exclude_t<Exclude...>, Component...>>: std::true_type {};
|
||||
template<typename Entity, typename... Component, typename... Exclude>
|
||||
struct is_view<basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>>>: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool is_view_v = is_view<Type>::value;
|
||||
|
||||
|
||||
template<typename Type, typename Override>
|
||||
struct unpack_type {
|
||||
using ro = std::conditional_t<
|
||||
type_list_contains_v<Override, std::add_const_t<Type>> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
|
||||
type_list<std::remove_const_t<Type>>,
|
||||
type_list<>
|
||||
>;
|
||||
type_list<>>;
|
||||
|
||||
using rw = std::conditional_t<
|
||||
type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, std::add_const_t<Type>>),
|
||||
type_list<Type>,
|
||||
type_list<>
|
||||
>;
|
||||
type_list<>>;
|
||||
};
|
||||
|
||||
template<typename Entity, typename... Override>
|
||||
@@ -59,20 +52,17 @@ struct unpack_type<basic_registry<Entity>, type_list<Override...>> {
|
||||
|
||||
template<typename Entity, typename... Override>
|
||||
struct unpack_type<const basic_registry<Entity>, type_list<Override...>>
|
||||
: unpack_type<basic_registry<Entity>, type_list<Override...>>
|
||||
{};
|
||||
: unpack_type<basic_registry<Entity>, type_list<Override...>> {};
|
||||
|
||||
template<typename Entity, typename... Exclude, typename... Component, typename... Override>
|
||||
struct unpack_type<basic_view<Entity, exclude_t<Exclude...>, Component...>, type_list<Override...>> {
|
||||
template<typename Entity, typename... Component, typename... Exclude, typename... Override>
|
||||
struct unpack_type<basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>>, type_list<Override...>> {
|
||||
using ro = type_list_cat_t<type_list<Exclude...>, typename unpack_type<Component, type_list<Override...>>::ro...>;
|
||||
using rw = type_list_cat_t<typename unpack_type<Component, type_list<Override...>>::rw...>;
|
||||
};
|
||||
|
||||
template<typename Entity, typename... Exclude, typename... Component, typename... Override>
|
||||
struct unpack_type<const basic_view<Entity, exclude_t<Exclude...>, Component...>, type_list<Override...>>
|
||||
: unpack_type<basic_view<Entity, exclude_t<Exclude...>, Component...>, type_list<Override...>>
|
||||
{};
|
||||
|
||||
template<typename Entity, typename... Component, typename... Exclude, typename... Override>
|
||||
struct unpack_type<const basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>>, type_list<Override...>>
|
||||
: unpack_type<basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>>, type_list<Override...>> {};
|
||||
|
||||
template<typename, typename>
|
||||
struct resource;
|
||||
@@ -84,32 +74,28 @@ struct resource<type_list<Args...>, type_list<Req...>> {
|
||||
using rw = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::rw..., typename unpack_type<Req, type_list<>>::rw...>;
|
||||
};
|
||||
|
||||
|
||||
template<typename... Req, typename Ret, typename... Args>
|
||||
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource(Ret(*)(Args...));
|
||||
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource(Ret (*)(Args...));
|
||||
|
||||
template<typename... Req, typename Ret, typename Type, typename... Args>
|
||||
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource(Ret(*)(Type &, Args...));
|
||||
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource(Ret (*)(Type &, Args...));
|
||||
|
||||
template<typename... Req, typename Ret, typename Class, typename... Args>
|
||||
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource(Ret(Class:: *)(Args...));
|
||||
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource(Ret (Class::*)(Args...));
|
||||
|
||||
template<typename... Req, typename Ret, typename Class, typename... Args>
|
||||
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource(Ret(Class:: *)(Args...) const);
|
||||
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource(Ret (Class::*)(Args...) const);
|
||||
|
||||
template<typename... Req>
|
||||
resource<type_list<>, type_list<Req...>> to_resource();
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class for creating a static task graph.
|
||||
*
|
||||
@@ -123,9 +109,9 @@ resource<type_list<>, type_list<Req...>> to_resource();
|
||||
*/
|
||||
template<typename Entity>
|
||||
class basic_organizer final {
|
||||
using callback_type = void(const void *, entt::basic_registry<Entity> &);
|
||||
using prepare_type = void(entt::basic_registry<Entity> &);
|
||||
using dependency_type = std::size_t(const bool, type_info *, const std::size_t);
|
||||
using callback_type = void(const void *, basic_registry<Entity> &);
|
||||
using prepare_type = void(basic_registry<Entity> &);
|
||||
using dependency_type = std::size_t(const bool, const type_info **, const std::size_t);
|
||||
|
||||
struct vertex_data final {
|
||||
std::size_t ro_count{};
|
||||
@@ -135,7 +121,7 @@ class basic_organizer final {
|
||||
callback_type *callback{};
|
||||
dependency_type *dependency;
|
||||
prepare_type *prepare{};
|
||||
type_info info{};
|
||||
const type_info *info{};
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
@@ -155,12 +141,12 @@ class basic_organizer final {
|
||||
}
|
||||
|
||||
template<typename... Type>
|
||||
static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] type_info *buffer, [[maybe_unused]] const std::size_t count) {
|
||||
static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const std::size_t count) {
|
||||
if constexpr(sizeof...(Type) == 0u) {
|
||||
return {};
|
||||
} else {
|
||||
type_info info[sizeof...(Type)]{type_id<Type>()...};
|
||||
const auto length = std::min(count, sizeof...(Type));
|
||||
const type_info *info[sizeof...(Type)]{&type_id<Type>()...};
|
||||
const auto length = (std::min)(count, sizeof...(Type));
|
||||
std::copy_n(info, length, buffer);
|
||||
return length;
|
||||
}
|
||||
@@ -262,8 +248,7 @@ public:
|
||||
vertex(const bool vtype, vertex_data data, std::vector<std::size_t> edges)
|
||||
: is_top_level{vtype},
|
||||
node{std::move(data)},
|
||||
reachable{std::move(edges)}
|
||||
{}
|
||||
reachable{std::move(edges)} {}
|
||||
|
||||
/**
|
||||
* @brief Fills a buffer with the type info objects for the writable
|
||||
@@ -272,7 +257,7 @@ public:
|
||||
* @param length The length of the user-supplied buffer.
|
||||
* @return The number of type info objects written to the buffer.
|
||||
*/
|
||||
size_type ro_dependency(type_info *buffer, const std::size_t length) const ENTT_NOEXCEPT {
|
||||
size_type ro_dependency(const type_info **buffer, const std::size_t length) const ENTT_NOEXCEPT {
|
||||
return node.dependency(false, buffer, length);
|
||||
}
|
||||
|
||||
@@ -283,7 +268,7 @@ public:
|
||||
* @param length The length of the user-supplied buffer.
|
||||
* @return The number of type info objects written to the buffer.
|
||||
*/
|
||||
size_type rw_dependency(type_info *buffer, const std::size_t length) const ENTT_NOEXCEPT {
|
||||
size_type rw_dependency(const type_info **buffer, const std::size_t length) const ENTT_NOEXCEPT {
|
||||
return node.dependency(true, buffer, length);
|
||||
}
|
||||
|
||||
@@ -315,15 +300,15 @@ public:
|
||||
* @brief Returns a type info object associated with a vertex.
|
||||
* @return A properly initialized type info object.
|
||||
*/
|
||||
type_info info() const ENTT_NOEXCEPT {
|
||||
return node.info;
|
||||
const type_info &info() const ENTT_NOEXCEPT {
|
||||
return *node.info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a user defined name associated with a vertex, if any.
|
||||
* @return The user defined name associated with the vertex, if any.
|
||||
*/
|
||||
const char * name() const ENTT_NOEXCEPT {
|
||||
const char *name() const ENTT_NOEXCEPT {
|
||||
return node.name;
|
||||
}
|
||||
|
||||
@@ -331,7 +316,7 @@ public:
|
||||
* @brief Returns the function associated with a vertex.
|
||||
* @return The function associated with the vertex.
|
||||
*/
|
||||
function_type * callback() const ENTT_NOEXCEPT {
|
||||
function_type *callback() const ENTT_NOEXCEPT {
|
||||
return node.callback;
|
||||
}
|
||||
|
||||
@@ -339,7 +324,7 @@ public:
|
||||
* @brief Returns the payload associated with a vertex, if any.
|
||||
* @return The payload associated with the vertex, if any.
|
||||
*/
|
||||
const void * data() const ENTT_NOEXCEPT {
|
||||
const void *data() const ENTT_NOEXCEPT {
|
||||
return node.payload;
|
||||
}
|
||||
|
||||
@@ -347,7 +332,7 @@ public:
|
||||
* @brief Returns the list of nodes reachable from a given vertex.
|
||||
* @return The list of nodes reachable from the vertex.
|
||||
*/
|
||||
const std::vector<std::size_t> & children() const ENTT_NOEXCEPT {
|
||||
const std::vector<std::size_t> &children() const ENTT_NOEXCEPT {
|
||||
return reachable;
|
||||
}
|
||||
|
||||
@@ -381,18 +366,18 @@ public:
|
||||
std::apply(Candidate, to_args(reg, typename resource_type::args{}));
|
||||
};
|
||||
|
||||
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
|
||||
vertices.push_back({
|
||||
vertex_data vdata{
|
||||
resource_type::ro::size,
|
||||
resource_type::rw::size,
|
||||
name,
|
||||
nullptr,
|
||||
callback,
|
||||
+[](const bool rw, type_info *buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
+[](basic_registry<entity_type> ®) { void(to_args(reg, typename resource_type::args{})); },
|
||||
type_id<std::integral_constant<decltype(Candidate), Candidate>>()
|
||||
});
|
||||
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
|
||||
|
||||
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
vertices.push_back(std::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -414,22 +399,18 @@ public:
|
||||
std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
|
||||
};
|
||||
|
||||
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
|
||||
vertices.push_back({
|
||||
vertex_data vdata{
|
||||
resource_type::ro::size,
|
||||
resource_type::rw::size,
|
||||
name,
|
||||
&value_or_instance,
|
||||
callback,
|
||||
+[](const bool rw, type_info *buffer, const std::size_t length) {
|
||||
return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length);
|
||||
},
|
||||
+[](basic_registry<entity_type> ®) {
|
||||
void(to_args(reg, typename resource_type::args{}));
|
||||
},
|
||||
type_id<std::integral_constant<decltype(Candidate), Candidate>>()
|
||||
});
|
||||
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
+[](basic_registry<entity_type> ®) { void(to_args(reg, typename resource_type::args{})); },
|
||||
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
|
||||
|
||||
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
vertices.push_back(std::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -445,18 +426,17 @@ public:
|
||||
using resource_type = internal::resource<type_list<>, type_list<Req...>>;
|
||||
track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
|
||||
vertices.push_back({
|
||||
vertex_data vdata{
|
||||
resource_type::ro::size,
|
||||
resource_type::rw::size,
|
||||
name,
|
||||
payload,
|
||||
func,
|
||||
+[](const bool rw, type_info *buffer, const std::size_t length) {
|
||||
return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length);
|
||||
},
|
||||
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
nullptr,
|
||||
type_info{}
|
||||
});
|
||||
&type_id<void>()};
|
||||
|
||||
vertices.push_back(std::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -498,12 +478,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<entt::id_type, std::vector<std::pair<std::size_t, bool>>> dependencies;
|
||||
dense_hash_map<id_type, std::vector<std::pair<std::size_t, bool>>, identity> dependencies;
|
||||
std::vector<vertex_data> vertices;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
#ifndef ENTT_ENTITY_POLY_STORAGE_HPP
|
||||
#define ENTT_ENTITY_POLY_STORAGE_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../poly/poly.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic poly storage implementation.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity>
|
||||
struct Storage: type_list<type_info() const ENTT_NOEXCEPT> {
|
||||
/**
|
||||
* @brief Concept definition.
|
||||
* @tparam Base Opaque base class from which to inherit.
|
||||
*/
|
||||
template<typename Base>
|
||||
struct type: Base {
|
||||
/**
|
||||
* @brief Returns a type info for the contained objects.
|
||||
* @return The type info for the contained objects.
|
||||
*/
|
||||
type_info value_type() const ENTT_NOEXCEPT {
|
||||
return poly_call<0>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concept implementation.
|
||||
* @tparam Type Type for which to generate an implementation.
|
||||
*/
|
||||
template<typename Type>
|
||||
using impl = value_list<&type_id<typename Type::value_type>>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Defines the poly storage type associate with a given entity type.
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
*/
|
||||
template<typename Entity, typename = void>
|
||||
struct poly_storage_traits {
|
||||
/*! @brief Poly storage type for the given entity type. */
|
||||
using storage_type = poly<Storage<Entity>>;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,99 @@
|
||||
#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
|
||||
#define ENTT_ENTITY_RUNTIME_VIEW_HPP
|
||||
|
||||
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "sparse_set.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
#include "sparse_set.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type>
|
||||
class runtime_view_iterator final {
|
||||
[[nodiscard]] bool valid() const {
|
||||
return std::all_of(pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
|
||||
&& std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
|
||||
}
|
||||
|
||||
public:
|
||||
using iterator_type = typename Type::iterator;
|
||||
using difference_type = typename iterator_type::difference_type;
|
||||
using value_type = typename iterator_type::value_type;
|
||||
using pointer = typename iterator_type::pointer;
|
||||
using reference = typename iterator_type::reference;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
|
||||
runtime_view_iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
runtime_view_iterator(const std::vector<const Type *> &cpools, const std::vector<const Type *> &ignore, iterator_type curr) ENTT_NOEXCEPT
|
||||
: pools{&cpools},
|
||||
filter{&ignore},
|
||||
it{curr} {
|
||||
if(it != (*pools)[0]->end() && !valid()) {
|
||||
++(*this);
|
||||
}
|
||||
}
|
||||
|
||||
runtime_view_iterator &operator++() {
|
||||
while(++it != (*pools)[0]->end() && !valid()) {}
|
||||
return *this;
|
||||
}
|
||||
|
||||
runtime_view_iterator operator++(int) {
|
||||
runtime_view_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
runtime_view_iterator &operator--() ENTT_NOEXCEPT {
|
||||
while(--it != (*pools)[0]->begin() && !valid()) {}
|
||||
return *this;
|
||||
}
|
||||
|
||||
runtime_view_iterator operator--(int) ENTT_NOEXCEPT {
|
||||
runtime_view_iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const {
|
||||
return it.operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const runtime_view_iterator &other) const ENTT_NOEXCEPT {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const runtime_view_iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<const Type *> *pools;
|
||||
const std::vector<const Type *> *filter;
|
||||
iterator_type it;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Runtime view.
|
||||
@@ -55,76 +135,7 @@ namespace entt {
|
||||
*/
|
||||
template<typename Entity>
|
||||
class basic_runtime_view final {
|
||||
using underlying_iterator = typename basic_sparse_set<Entity>::iterator;
|
||||
|
||||
class view_iterator final {
|
||||
friend class basic_runtime_view<Entity>;
|
||||
|
||||
view_iterator(const std::vector<const basic_sparse_set<Entity> *> &cpools, const std::vector<const basic_sparse_set<Entity> *> &ignore, underlying_iterator curr) ENTT_NOEXCEPT
|
||||
: pools{&cpools},
|
||||
filter{&ignore},
|
||||
it{curr}
|
||||
{
|
||||
if(it != (*pools)[0]->end() && !valid()) {
|
||||
++(*this);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool valid() const {
|
||||
return std::all_of(pools->begin()++, pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
|
||||
&& std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
|
||||
}
|
||||
|
||||
public:
|
||||
using difference_type = typename underlying_iterator::difference_type;
|
||||
using value_type = typename underlying_iterator::value_type;
|
||||
using pointer = typename underlying_iterator::pointer;
|
||||
using reference = typename underlying_iterator::reference;
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
|
||||
view_iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
view_iterator & operator++() {
|
||||
while(++it != (*pools)[0]->end() && !valid());
|
||||
return *this;
|
||||
}
|
||||
|
||||
view_iterator operator++(int) {
|
||||
view_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
view_iterator & operator--() ENTT_NOEXCEPT {
|
||||
while(--it != (*pools)[0]->begin() && !valid());
|
||||
return *this;
|
||||
}
|
||||
|
||||
view_iterator operator--(int) ENTT_NOEXCEPT {
|
||||
view_iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.it == it;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const {
|
||||
return it.operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
const std::vector<const basic_sparse_set<Entity> *> *pools;
|
||||
const std::vector<const basic_sparse_set<Entity> *> *filter;
|
||||
underlying_iterator it;
|
||||
};
|
||||
using basic_common_type = basic_sparse_set<Entity>;
|
||||
|
||||
[[nodiscard]] bool valid() const {
|
||||
return !pools.empty() && pools.front();
|
||||
@@ -136,29 +147,27 @@ public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Bidirectional iterator type. */
|
||||
using iterator = view_iterator;
|
||||
using iterator = internal::runtime_view_iterator<basic_common_type>;
|
||||
|
||||
/*! @brief Default constructor to use to create empty, invalid views. */
|
||||
basic_runtime_view() ENTT_NOEXCEPT
|
||||
: pools{},
|
||||
filter{}
|
||||
{}
|
||||
filter{} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a runtime view from a set of storage classes.
|
||||
* @param cpools The storage for the types to iterate.
|
||||
* @param epools The storage for the types used to filter the view.
|
||||
*/
|
||||
basic_runtime_view(std::vector<const basic_sparse_set<Entity> *> cpools, std::vector<const basic_sparse_set<Entity> *> epools) ENTT_NOEXCEPT
|
||||
basic_runtime_view(std::vector<const basic_common_type *> cpools, std::vector<const basic_common_type *> epools) ENTT_NOEXCEPT
|
||||
: pools{std::move(cpools)},
|
||||
filter{std::move(epools)}
|
||||
{
|
||||
const auto it = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
|
||||
filter{std::move(epools)} {
|
||||
auto candidate = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
|
||||
return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
|
||||
});
|
||||
|
||||
// brings the best candidate (if any) on front of the vector
|
||||
std::rotate(pools.begin(), it, pools.end());
|
||||
std::rotate(pools.begin(), candidate, pools.end());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -200,12 +209,12 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Checks if a view contains an entity.
|
||||
* @param entt A valid entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return True if the view contains the given entity, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const entity_type entt) const {
|
||||
return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
|
||||
&& std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
|
||||
&& std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,12 +240,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<const basic_sparse_set<Entity> *> pools;
|
||||
std::vector<const basic_sparse_set<Entity> *> filter;
|
||||
std::vector<const basic_common_type *> pools;
|
||||
std::vector<const basic_common_type *> filter;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
#ifndef ENTT_ENTITY_SNAPSHOT_HPP
|
||||
#define ENTT_ENTITY_SNAPSHOT_HPP
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../container/dense_hash_map.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "component.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "registry.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class to create snapshots from a registry.
|
||||
*
|
||||
@@ -32,12 +30,12 @@ namespace entt {
|
||||
*/
|
||||
template<typename Entity>
|
||||
class basic_snapshot {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
|
||||
template<typename Component, typename Archive, typename It>
|
||||
void get(Archive &archive, std::size_t sz, It first, It last) const {
|
||||
const auto view = reg->template view<std::add_const_t<Component>>();
|
||||
archive(typename traits_type::entity_type(sz));
|
||||
archive(typename entity_traits::entity_type(sz));
|
||||
|
||||
while(first != last) {
|
||||
const auto entt = *(first++);
|
||||
@@ -55,7 +53,7 @@ class basic_snapshot {
|
||||
|
||||
while(begin != last) {
|
||||
const auto entt = *(begin++);
|
||||
((reg->template all_of<Component>(entt) ? ++size[Index] : size[Index]), ...);
|
||||
((reg->template all_of<Component>(entt) ? ++size[Index] : 0u), ...);
|
||||
}
|
||||
|
||||
(get<Component>(archive, size[Index], first, last), ...);
|
||||
@@ -70,14 +68,13 @@ public:
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
basic_snapshot(const basic_registry<entity_type> &source) ENTT_NOEXCEPT
|
||||
: reg{&source}
|
||||
{}
|
||||
: reg{&source} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_snapshot(basic_snapshot &&) = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This snapshot. */
|
||||
basic_snapshot & operator=(basic_snapshot &&) = default;
|
||||
basic_snapshot &operator=(basic_snapshot &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Puts aside all the entities from the underlying registry.
|
||||
@@ -90,17 +87,16 @@ public:
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot & entities(Archive &archive) const {
|
||||
const basic_snapshot &entities(Archive &archive) const {
|
||||
const auto sz = reg->size();
|
||||
|
||||
archive(typename traits_type::entity_type(sz));
|
||||
archive(typename entity_traits::entity_type(sz + 1u));
|
||||
archive(reg->released());
|
||||
|
||||
for(auto first = reg->data(), last = first + sz; first != last; ++first) {
|
||||
archive(*first);
|
||||
}
|
||||
|
||||
archive(reg->destroyed());
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -116,10 +112,10 @@ public:
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename... Component, typename Archive>
|
||||
const basic_snapshot & component(Archive &archive) const {
|
||||
const basic_snapshot &component(Archive &archive) const {
|
||||
if constexpr(sizeof...(Component) == 1u) {
|
||||
const auto view = reg->template view<const Component...>();
|
||||
(component<Component>(archive, view.data(), view.data() + view.size()), ...);
|
||||
(component<Component>(archive, view.rbegin(), view.rend()), ...);
|
||||
return *this;
|
||||
} else {
|
||||
(component<Component>(archive), ...);
|
||||
@@ -142,7 +138,7 @@ public:
|
||||
* @return An object of this type to continue creating the snapshot.
|
||||
*/
|
||||
template<typename... Component, typename Archive, typename It>
|
||||
const basic_snapshot & component(Archive &archive, It first, It last) const {
|
||||
const basic_snapshot &component(Archive &archive, It first, It last) const {
|
||||
component<Component...>(archive, first, last, std::index_sequence_for<Component...>{});
|
||||
return *this;
|
||||
}
|
||||
@@ -151,7 +147,6 @@ private:
|
||||
const basic_registry<entity_type> *reg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class to restore a snapshot as a whole.
|
||||
*
|
||||
@@ -164,20 +159,20 @@ private:
|
||||
*/
|
||||
template<typename Entity>
|
||||
class basic_snapshot_loader {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
|
||||
template<typename Type, typename Archive>
|
||||
void assign(Archive &archive) const {
|
||||
typename traits_type::entity_type length{};
|
||||
typename entity_traits::entity_type length{};
|
||||
archive(length);
|
||||
|
||||
entity_type entt{};
|
||||
|
||||
if constexpr(std::tuple_size_v<decltype(reg->template view<Type>().get({}))> == 0) {
|
||||
if constexpr(ignore_as_empty_v<std::remove_const_t<Type>>) {
|
||||
while(length--) {
|
||||
archive(entt);
|
||||
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
|
||||
ENTT_ASSERT(entity == entt);
|
||||
ENTT_ASSERT(entity == entt, "Entity not available for use");
|
||||
reg->template emplace<Type>(entity);
|
||||
}
|
||||
} else {
|
||||
@@ -186,7 +181,7 @@ class basic_snapshot_loader {
|
||||
while(length--) {
|
||||
archive(entt, instance);
|
||||
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
|
||||
ENTT_ASSERT(entity == entt);
|
||||
ENTT_ASSERT(entity == entt, "Entity not available for use");
|
||||
reg->template emplace<Type>(entity, std::move(instance));
|
||||
}
|
||||
}
|
||||
@@ -201,17 +196,16 @@ public:
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
basic_snapshot_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
|
||||
: reg{&source}
|
||||
{
|
||||
: reg{&source} {
|
||||
// restoring a snapshot as a whole requires a clean registry
|
||||
ENTT_ASSERT(reg->empty());
|
||||
ENTT_ASSERT(reg->empty(), "Registry must be empty");
|
||||
}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_snapshot_loader(basic_snapshot_loader &&) = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This loader. */
|
||||
basic_snapshot_loader & operator=(basic_snapshot_loader &&) = default;
|
||||
basic_snapshot_loader &operator=(basic_snapshot_loader &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Restores entities that were in use during serialization.
|
||||
@@ -224,20 +218,17 @@ public:
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename Archive>
|
||||
const basic_snapshot_loader & entities(Archive &archive) const {
|
||||
typename traits_type::entity_type length{};
|
||||
const basic_snapshot_loader &entities(Archive &archive) const {
|
||||
typename entity_traits::entity_type length{};
|
||||
|
||||
archive(length);
|
||||
std::vector<entity_type> all(length);
|
||||
|
||||
for(decltype(length) pos{}; pos < length; ++pos) {
|
||||
for(std::size_t pos{}; pos < length; ++pos) {
|
||||
archive(all[pos]);
|
||||
}
|
||||
|
||||
entity_type destroyed;
|
||||
archive(destroyed);
|
||||
|
||||
reg->assign(all.cbegin(), all.cend(), destroyed);
|
||||
reg->assign(++all.cbegin(), all.cend(), all[0u]);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -256,7 +247,7 @@ public:
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
template<typename... Component, typename Archive>
|
||||
const basic_snapshot_loader & component(Archive &archive) const {
|
||||
const basic_snapshot_loader &component(Archive &archive) const {
|
||||
(assign<Component>(archive), ...);
|
||||
return *this;
|
||||
}
|
||||
@@ -271,9 +262,11 @@ public:
|
||||
*
|
||||
* @return A valid loader to continue restoring data.
|
||||
*/
|
||||
const basic_snapshot_loader & orphans() const {
|
||||
reg->orphans([this](const auto entt) {
|
||||
reg->destroy(entt);
|
||||
const basic_snapshot_loader &orphans() const {
|
||||
reg->each([this](const auto entt) {
|
||||
if(reg->orphan(entt)) {
|
||||
reg->release(entt);
|
||||
}
|
||||
});
|
||||
|
||||
return *this;
|
||||
@@ -283,7 +276,6 @@ private:
|
||||
basic_registry<entity_type> *reg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class for _continuous loading_.
|
||||
*
|
||||
@@ -302,7 +294,7 @@ private:
|
||||
*/
|
||||
template<typename Entity>
|
||||
class basic_continuous_loader {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
using entity_traits = entt_traits<Entity>;
|
||||
|
||||
void destroy(Entity entt) {
|
||||
if(const auto it = remloc.find(entt); it == remloc.cend()) {
|
||||
@@ -330,7 +322,7 @@ class basic_continuous_loader {
|
||||
|
||||
template<typename Container>
|
||||
auto update(int, Container &container)
|
||||
-> decltype(typename Container::mapped_type{}, void()) {
|
||||
-> decltype(typename Container::mapped_type{}, void()) {
|
||||
// map like container
|
||||
Container other;
|
||||
|
||||
@@ -353,7 +345,7 @@ class basic_continuous_loader {
|
||||
|
||||
template<typename Container>
|
||||
auto update(char, Container &container)
|
||||
-> decltype(typename Container::value_type{}, void()) {
|
||||
-> decltype(typename Container::value_type{}, void()) {
|
||||
// vector like container
|
||||
static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
|
||||
|
||||
@@ -363,7 +355,7 @@ class basic_continuous_loader {
|
||||
}
|
||||
|
||||
template<typename Other, typename Type, typename Member>
|
||||
void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type:: *member) {
|
||||
void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type::*member) {
|
||||
if constexpr(!std::is_same_v<Other, Type>) {
|
||||
return;
|
||||
} else if constexpr(std::is_same_v<Member, entity_type>) {
|
||||
@@ -380,19 +372,19 @@ class basic_continuous_loader {
|
||||
const auto local = ref.second.first;
|
||||
|
||||
if(reg->valid(local)) {
|
||||
reg->template remove_if_exists<Component>(local);
|
||||
reg->template remove<Component>(local);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Other, typename Archive, typename... Type, typename... Member>
|
||||
void assign(Archive &archive, [[maybe_unused]] Member Type:: *... member) {
|
||||
typename traits_type::entity_type length{};
|
||||
void assign(Archive &archive, [[maybe_unused]] Member Type::*...member) {
|
||||
typename entity_traits::entity_type length{};
|
||||
archive(length);
|
||||
|
||||
entity_type entt{};
|
||||
|
||||
if constexpr(std::tuple_size_v<decltype(reg->template view<Other>().get({}))> == 0) {
|
||||
if constexpr(ignore_as_empty_v<std::remove_const_t<Other>>) {
|
||||
while(length--) {
|
||||
archive(entt);
|
||||
restore(entt);
|
||||
@@ -419,14 +411,13 @@ public:
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
basic_continuous_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
|
||||
: reg{&source}
|
||||
{}
|
||||
: reg{&source} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
basic_continuous_loader(basic_continuous_loader &&) = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This loader. */
|
||||
basic_continuous_loader & operator=(basic_continuous_loader &&) = default;
|
||||
basic_continuous_loader &operator=(basic_continuous_loader &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Restores entities that were in use during serialization.
|
||||
@@ -439,25 +430,24 @@ public:
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
template<typename Archive>
|
||||
basic_continuous_loader & entities(Archive &archive) {
|
||||
typename traits_type::entity_type length{};
|
||||
basic_continuous_loader &entities(Archive &archive) {
|
||||
typename entity_traits::entity_type length{};
|
||||
entity_type entt{};
|
||||
|
||||
archive(length);
|
||||
// discards the head of the list of destroyed entities
|
||||
archive(entt);
|
||||
|
||||
for(decltype(length) pos{}; pos < length; ++pos) {
|
||||
for(std::size_t pos{}, last = length - 1u; pos < last; ++pos) {
|
||||
archive(entt);
|
||||
|
||||
if(const auto entity = (to_integral(entt) & traits_type::entity_mask); entity == pos) {
|
||||
if(const auto entity = entity_traits::to_entity(entt); entity == pos) {
|
||||
restore(entt);
|
||||
} else {
|
||||
destroy(entt);
|
||||
}
|
||||
}
|
||||
|
||||
// discards the head of the list of destroyed entities
|
||||
archive(entt);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -481,7 +471,7 @@ public:
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
template<typename... Component, typename Archive, typename... Type, typename... Member>
|
||||
basic_continuous_loader & component(Archive &archive, Member Type:: *... member) {
|
||||
basic_continuous_loader &component(Archive &archive, Member Type::*...member) {
|
||||
(remove_if_exists<Component>(), ...);
|
||||
(assign<Component>(archive, member...), ...);
|
||||
return *this;
|
||||
@@ -495,7 +485,7 @@ public:
|
||||
*
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
basic_continuous_loader & shrink() {
|
||||
basic_continuous_loader &shrink() {
|
||||
auto it = remloc.begin();
|
||||
|
||||
while(it != remloc.cend()) {
|
||||
@@ -527,9 +517,11 @@ public:
|
||||
*
|
||||
* @return A non-const reference to this loader.
|
||||
*/
|
||||
basic_continuous_loader & orphans() {
|
||||
reg->orphans([this](const auto entt) {
|
||||
reg->destroy(entt);
|
||||
basic_continuous_loader &orphans() {
|
||||
reg->each([this](const auto entt) {
|
||||
if(reg->orphan(entt)) {
|
||||
reg->release(entt);
|
||||
}
|
||||
});
|
||||
|
||||
return *this;
|
||||
@@ -537,7 +529,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Tests if a loader knows about a given entity.
|
||||
* @param entt An entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return True if `entity` is managed by the loader, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(entity_type entt) const ENTT_NOEXCEPT {
|
||||
@@ -546,7 +538,7 @@ public:
|
||||
|
||||
/**
|
||||
* @brief Returns the identifier to which an entity refers.
|
||||
* @param entt An entity identifier.
|
||||
* @param entt A valid identifier.
|
||||
* @return The local identifier if any, the null entity otherwise.
|
||||
*/
|
||||
[[nodiscard]] entity_type map(entity_type entt) const ENTT_NOEXCEPT {
|
||||
@@ -561,12 +553,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<entity_type, std::pair<entity_type, bool>> remloc;
|
||||
dense_hash_map<entity_type, std::pair<entity_type, bool>> remloc;
|
||||
basic_registry<entity_type> *reg;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,10 @@
|
||||
#ifndef ENTT_ENTITY_UTILITY_HPP
|
||||
#define ENTT_ENTITY_UTILITY_HPP
|
||||
|
||||
|
||||
#include "../core/type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
@@ -15,7 +12,6 @@ namespace entt {
|
||||
template<typename... Type>
|
||||
struct exclude_t: type_list<Type...> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Variable template for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
@@ -23,14 +19,12 @@ struct exclude_t: type_list<Type...> {};
|
||||
template<typename... Type>
|
||||
inline constexpr exclude_t<Type...> exclude{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias for lists of observed components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct get_t: type_list<Type...>{};
|
||||
|
||||
struct get_t: type_list<Type...> {};
|
||||
|
||||
/**
|
||||
* @brief Variable template for lists of observed components.
|
||||
@@ -39,8 +33,20 @@ struct get_t: type_list<Type...>{};
|
||||
template<typename... Type>
|
||||
inline constexpr get_t<Type...> get{};
|
||||
|
||||
/**
|
||||
* @brief Alias for lists of owned components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct owned_t: type_list<Type...> {};
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief Variable template for lists of owned components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
inline constexpr owned_t<Type...> owned{};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,21 +1,28 @@
|
||||
#include "config/version.h"
|
||||
#include "container/dense_hash_map.hpp"
|
||||
#include "container/dense_hash_set.hpp"
|
||||
#include "core/algorithm.hpp"
|
||||
#include "core/any.hpp"
|
||||
#include "core/attribute.h"
|
||||
#include "core/compressed_pair.hpp"
|
||||
#include "core/enum.hpp"
|
||||
#include "core/family.hpp"
|
||||
#include "core/hashed_string.hpp"
|
||||
#include "core/ident.hpp"
|
||||
#include "core/iterator.hpp"
|
||||
#include "core/memory.hpp"
|
||||
#include "core/monostate.hpp"
|
||||
#include "core/tuple.hpp"
|
||||
#include "core/type_info.hpp"
|
||||
#include "core/type_traits.hpp"
|
||||
#include "core/utility.hpp"
|
||||
#include "entity/component.hpp"
|
||||
#include "entity/entity.hpp"
|
||||
#include "entity/group.hpp"
|
||||
#include "entity/handle.hpp"
|
||||
#include "entity/helper.hpp"
|
||||
#include "entity/observer.hpp"
|
||||
#include "entity/organizer.hpp"
|
||||
#include "entity/poly_storage.hpp"
|
||||
#include "entity/registry.hpp"
|
||||
#include "entity/runtime_view.hpp"
|
||||
#include "entity/snapshot.hpp"
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "container/fwd.hpp"
|
||||
#include "core/fwd.hpp"
|
||||
#include "entity/fwd.hpp"
|
||||
#include "meta/fwd.hpp"
|
||||
#include "poly/fwd.hpp"
|
||||
#include "resource/fwd.hpp"
|
||||
#include "signal/fwd.hpp"
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#ifndef ENTT_LOCATOR_LOCATOR_HPP
|
||||
#define ENTT_LOCATOR_LOCATOR_HPP
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Service locator, nothing more.
|
||||
*
|
||||
@@ -67,7 +64,7 @@ struct service_locator {
|
||||
*
|
||||
* @return A reference to the service implementation currently set, if any.
|
||||
*/
|
||||
[[nodiscard]] static Service & ref() ENTT_NOEXCEPT {
|
||||
[[nodiscard]] static Service &ref() ENTT_NOEXCEPT {
|
||||
return *service;
|
||||
}
|
||||
|
||||
@@ -78,7 +75,7 @@ struct service_locator {
|
||||
* @param args Parameters to use to construct the service.
|
||||
*/
|
||||
template<typename Impl = Service, typename... Args>
|
||||
static void set(Args &&... args) {
|
||||
static void set(Args &&...args) {
|
||||
service = std::make_shared<Impl>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -87,7 +84,7 @@ struct service_locator {
|
||||
* @param ptr Service to use to replace the current one.
|
||||
*/
|
||||
static void set(std::shared_ptr<Service> ptr) {
|
||||
ENTT_ASSERT(static_cast<bool>(ptr));
|
||||
ENTT_ASSERT(static_cast<bool>(ptr), "Null service not allowed");
|
||||
service = std::move(ptr);
|
||||
}
|
||||
|
||||
@@ -104,8 +101,6 @@ private:
|
||||
inline static std::shared_ptr<Service> service = nullptr;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#ifndef ENTT_META_ADL_POINTER_HPP
|
||||
#define ENTT_META_ADL_POINTER_HPP
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief ADL based lookup function for dereferencing meta pointer-like types.
|
||||
* @tparam Type Element type.
|
||||
@@ -16,7 +14,6 @@ decltype(auto) dereference_meta_pointer_like(const Type &value) {
|
||||
return *value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Fake ADL based lookup function for meta pointer-like types.
|
||||
* @tparam Type Element type.
|
||||
@@ -33,8 +30,6 @@ struct adl_meta_pointer_like {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,295 +1,196 @@
|
||||
#ifndef ENTT_META_CONTAINER_HPP
|
||||
#define ENTT_META_CONTAINER_HPP
|
||||
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../container/dense_hash_map.hpp"
|
||||
#include "../container/dense_hash_set.hpp"
|
||||
#include "meta.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Container traits.
|
||||
* @tparam Container Type of the underlying container.
|
||||
* @tparam Trait Traits associated with the underlying container.
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
template<typename Container, template<typename> class... Trait>
|
||||
struct meta_container_traits: public Trait<Container>... {
|
||||
/*! @brief Type of container. */
|
||||
using type = Container;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
/**
|
||||
* @brief Basic STL-compatible container traits
|
||||
* @tparam Container The type of the container.
|
||||
*/
|
||||
template<typename Container>
|
||||
struct basic_container {
|
||||
/**
|
||||
* @brief Returns the size of the given container.
|
||||
* @param cont The container for which to return the size.
|
||||
* @return The size of the given container.
|
||||
*/
|
||||
[[nodiscard]] static typename Container::size_type size(const Container &cont) ENTT_NOEXCEPT {
|
||||
return cont.size();
|
||||
template<typename, typename = void>
|
||||
struct is_dynamic_sequence_container: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct is_dynamic_sequence_container<Type, std::void_t<decltype(&Type::reserve)>>: std::true_type {};
|
||||
|
||||
template<typename, typename = void>
|
||||
struct is_key_only_meta_associative_container: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct is_key_only_meta_associative_container<Type, std::void_t<typename Type::mapped_type>>: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct basic_meta_sequence_container_traits {
|
||||
using iterator = meta_sequence_container::iterator;
|
||||
using size_type = std::size_t;
|
||||
|
||||
[[nodiscard]] static size_type size(const any &container) ENTT_NOEXCEPT {
|
||||
return any_cast<const Type &>(container).size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first element of the given container.
|
||||
* @param cont The container for which to return the iterator.
|
||||
* @return An iterator to the first element of the given container.
|
||||
*/
|
||||
[[nodiscard]] static typename Container::iterator begin(Container &cont) {
|
||||
return cont.begin();
|
||||
}
|
||||
[[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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first element of the given container.
|
||||
* @param cont The container for which to return the iterator.
|
||||
* @return An iterator to the first element of the given container.
|
||||
*/
|
||||
[[nodiscard]] static typename Container::const_iterator cbegin(const Container &cont) {
|
||||
return cont.begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator past the last element of the given container.
|
||||
* @param cont The container for which to return the iterator.
|
||||
* @return An iterator past the last element of the given container.
|
||||
*/
|
||||
[[nodiscard]] static typename Container::iterator end(Container &cont) {
|
||||
return cont.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator past the last element of the given container.
|
||||
* @param cont The container for which to return the iterator.
|
||||
* @return An iterator past the last element of the given container.
|
||||
*/
|
||||
[[nodiscard]] static typename Container::const_iterator cend(const Container &cont) {
|
||||
return cont.end();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic STL-compatible associative container traits
|
||||
* @tparam Container The type of the container.
|
||||
*/
|
||||
template<typename Container>
|
||||
struct basic_associative_container {
|
||||
/**
|
||||
* @brief Returns an iterator to the element with key equivalent to the
|
||||
* given one, if any.
|
||||
* @param cont The container in which to search for the element.
|
||||
* @param key The key of the element to search.
|
||||
* @return An iterator to the element with the given key, if any.
|
||||
*/
|
||||
[[nodiscard]] static typename Container::iterator find(Container &cont, const typename Container::key_type &key) {
|
||||
return cont.find(key);
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
[[nodiscard]] static typename Container::const_iterator cfind(const Container &cont, const typename Container::key_type &key) {
|
||||
return cont.find(key);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic STL-compatible dynamic container traits
|
||||
* @tparam Container The type of the container.
|
||||
*/
|
||||
template<typename Container>
|
||||
struct basic_dynamic_container {
|
||||
/**
|
||||
* @brief Clears the content of the given container.
|
||||
* @param cont The container for which to clear the content.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] static bool clear([[maybe_unused]] Container &cont) {
|
||||
return cont.clear(), true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic STL-compatible dynamic associative container traits
|
||||
* @tparam Container The type of the container.
|
||||
*/
|
||||
template<typename Container>
|
||||
struct basic_dynamic_associative_container {
|
||||
/**
|
||||
* @brief Removes the specified element from the given container.
|
||||
* @param cont The container from which to remove the element.
|
||||
* @param key The element to remove.
|
||||
* @return A bool denoting whether the removal took place.
|
||||
*/
|
||||
[[nodiscard]] static bool erase([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
|
||||
const auto sz = cont.size();
|
||||
return cont.erase(key) != sz;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic STL-compatible sequence container traits
|
||||
* @tparam Container The type of the container.
|
||||
*/
|
||||
template<typename Container>
|
||||
struct basic_sequence_container {
|
||||
/**
|
||||
* @brief Returns a reference to the element at the specified location of
|
||||
* the given container (no bounds checking is performed).
|
||||
* @param cont The container from which to get the element.
|
||||
* @param pos The position of the element to return.
|
||||
* @return A reference to the requested element.
|
||||
*/
|
||||
[[nodiscard]] static typename Container::reference get(Container &cont, typename Container::size_type pos) {
|
||||
return cont[pos];
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
[[nodiscard]] static typename Container::const_reference cget(const Container &cont, typename Container::size_type pos) {
|
||||
return cont[pos];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief STL-compatible dynamic associative key-only container traits
|
||||
* @tparam Container The type of the container.
|
||||
*/
|
||||
template<typename Container>
|
||||
struct dynamic_associative_key_only_container {
|
||||
/**
|
||||
* @brief Inserts an element into the given container.
|
||||
* @param cont The container in which to insert the element.
|
||||
* @param key The element to insert.
|
||||
* @return A bool denoting whether the insertion took place.
|
||||
*/
|
||||
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
|
||||
return cont.insert(key).second;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief STL-compatible dynamic key-value associative container traits
|
||||
* @tparam Container The type of the container.
|
||||
*/
|
||||
template<typename Container>
|
||||
struct dynamic_associative_key_value_container {
|
||||
/**
|
||||
* @brief Inserts an element (a key/value pair) into the given container.
|
||||
* @param cont The container in which to insert the element.
|
||||
* @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.
|
||||
*/
|
||||
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key, [[maybe_unused]] const typename Container::mapped_type &value) {
|
||||
return cont.insert(std::make_pair(key, value)).second;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief STL-compatible dynamic sequence container traits
|
||||
* @tparam Container The type of the container.
|
||||
*/
|
||||
template<typename Container>
|
||||
struct dynamic_sequence_container {
|
||||
/**
|
||||
* @brief Resizes the given container to contain the given number of
|
||||
* elements.
|
||||
* @param cont The container to resize.
|
||||
* @param sz The new size of the container.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] static bool resize([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::size_type sz) {
|
||||
return cont.resize(sz), true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an element at the specified location of the given
|
||||
* container.
|
||||
* @param cont The container into which to insert the element.
|
||||
* @param it Iterator before which the element will be inserted.
|
||||
* @param value Element value to insert.
|
||||
* @return A pair consisting of an iterator to the inserted element (in case
|
||||
* of success) and a bool denoting whether the insertion took place.
|
||||
*/
|
||||
[[nodiscard]] static std::pair<typename Container::iterator, bool> insert([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it, [[maybe_unused]] const typename Container::value_type &value) {
|
||||
return { cont.insert(it, value), true };
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the element at the specified location from the given
|
||||
* container.
|
||||
* @param cont The container from which to remove the element.
|
||||
* @param it Iterator to the element to remove.
|
||||
* @return A pair consisting of an iterator following the last removed
|
||||
* element (in case of success) and a bool denoting whether the insertion
|
||||
* took place.
|
||||
*/
|
||||
[[nodiscard]] static std::pair<typename Container::iterator, bool> erase([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it) {
|
||||
return { cont.erase(it), true };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief STL-compatible fixed sequence container traits
|
||||
* @tparam Container The type of the container.
|
||||
*/
|
||||
template<typename Container>
|
||||
struct fixed_sequence_container {
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
* @return False to indicate failure in all cases.
|
||||
*/
|
||||
[[nodiscard]] static bool resize(const Container &, typename Container::size_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
* @return False to indicate failure in all cases.
|
||||
*/
|
||||
[[nodiscard]] static bool clear(const Container &) {
|
||||
[[nodiscard]] static bool clear([[maybe_unused]] any &container) {
|
||||
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
cont->clear();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
* @return A pair consisting of an invalid iterator and a false value to
|
||||
* indicate failure in all cases.
|
||||
*/
|
||||
[[nodiscard]] static std::pair<typename Container::iterator, bool> insert(const Container &, typename Container::const_iterator, const typename Container::value_type &) {
|
||||
return { {}, false };
|
||||
[[nodiscard]] static iterator begin(any &container) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{std::begin(*cont)};
|
||||
}
|
||||
|
||||
return iterator{std::begin(any_cast<const Type &>(container))};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Does nothing.
|
||||
* @return A pair consisting of an invalid iterator and a false value to
|
||||
* indicate failure in all cases.
|
||||
*/
|
||||
[[nodiscard]] static std::pair<typename Container::iterator, bool> erase(const Container &, typename Container::const_iterator) {
|
||||
return { {}, false };
|
||||
[[nodiscard]] static iterator end(any &container) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{std::end(*cont)};
|
||||
}
|
||||
|
||||
return iterator{std::end(any_cast<const Type &>(container))};
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator insert([[maybe_unused]] any &container, [[maybe_unused]] iterator it, [[maybe_unused]] meta_any &value) {
|
||||
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
// 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{cont->insert(any_cast<const typename Type::iterator &>(it.base()), element ? *element : value.cast<typename Type::value_type>())};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator erase([[maybe_unused]] any &container, [[maybe_unused]] iterator it) {
|
||||
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{cont->erase(any_cast<const typename Type::iterator &>(it.base()))};
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] static meta_any get(any &container, size_type pos) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return meta_any{std::in_place_type<typename Type::reference>, (*cont)[pos]};
|
||||
}
|
||||
|
||||
return meta_any{std::in_place_type<typename Type::const_reference>, any_cast<const Type &>(container)[pos]};
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct basic_meta_associative_container_traits {
|
||||
using iterator = meta_associative_container::iterator;
|
||||
using size_type = std::size_t;
|
||||
|
||||
static constexpr auto key_only = is_key_only_meta_associative_container<Type>::value;
|
||||
|
||||
[[nodiscard]] static size_type size(const any &container) ENTT_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 begin(any &container) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{std::integral_constant<bool, key_only>{}, cont->begin()};
|
||||
}
|
||||
|
||||
return iterator{std::integral_constant<bool, key_only>{}, std::begin(any_cast<const Type &>(container))};
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator end(any &container) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{std::integral_constant<bool, key_only>{}, cont->end()};
|
||||
}
|
||||
|
||||
return iterator{std::integral_constant<bool, key_only>{}, std::end(any_cast<const Type &>(container))};
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool insert(any &container, meta_any &key, [[maybe_unused]] meta_any &value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
|
||||
if constexpr(is_key_only_meta_associative_container<Type>::value) {
|
||||
return cont->insert(key.cast<const typename Type::key_type &>()).second;
|
||||
} else {
|
||||
if(value.allow_cast<const typename Type::mapped_type &>()) {
|
||||
return cont->emplace(key.cast<const typename Type::key_type &>(), value.cast<const typename Type::mapped_type &>()).second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool erase(any &container, meta_any &key) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
|
||||
return (cont->erase(key.cast<const typename Type::key_type &>()) != cont->size());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator find(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{std::integral_constant<bool, key_only>{}, cont->find(key.cast<const typename Type::key_type &>())};
|
||||
}
|
||||
|
||||
return iterator{std::integral_constant<bool, key_only>{}, any_cast<const Type &>(container).find(key.cast<const typename Type::key_type &>())};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::vector`s of any type.
|
||||
@@ -298,15 +199,7 @@ struct fixed_sequence_container {
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
struct meta_sequence_container_traits<std::vector<Type, Args...>>
|
||||
: meta_container_traits<
|
||||
std::vector<Type, Args...>,
|
||||
basic_container,
|
||||
basic_dynamic_container,
|
||||
basic_sequence_container,
|
||||
dynamic_sequence_container
|
||||
>
|
||||
{};
|
||||
|
||||
: internal::basic_meta_sequence_container_traits<std::vector<Type, Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::array`s of any type.
|
||||
@@ -315,14 +208,7 @@ struct meta_sequence_container_traits<std::vector<Type, Args...>>
|
||||
*/
|
||||
template<typename Type, auto N>
|
||||
struct meta_sequence_container_traits<std::array<Type, N>>
|
||||
: meta_container_traits<
|
||||
std::array<Type, N>,
|
||||
basic_container,
|
||||
basic_sequence_container,
|
||||
fixed_sequence_container
|
||||
>
|
||||
{};
|
||||
|
||||
: internal::basic_meta_sequence_container_traits<std::array<Type, N>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `std::map`s of any type.
|
||||
@@ -332,16 +218,7 @@ struct meta_sequence_container_traits<std::array<Type, N>>
|
||||
*/
|
||||
template<typename Key, typename Value, typename... Args>
|
||||
struct meta_associative_container_traits<std::map<Key, Value, Args...>>
|
||||
: meta_container_traits<
|
||||
std::map<Key, Value, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_value_container
|
||||
>
|
||||
{};
|
||||
|
||||
: internal::basic_meta_associative_container_traits<std::map<Key, Value, Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `std::unordered_map`s of any
|
||||
@@ -352,16 +229,7 @@ struct meta_associative_container_traits<std::map<Key, Value, Args...>>
|
||||
*/
|
||||
template<typename Key, typename Value, typename... Args>
|
||||
struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
|
||||
: meta_container_traits<
|
||||
std::unordered_map<Key, Value, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_value_container
|
||||
>
|
||||
{};
|
||||
|
||||
: internal::basic_meta_associative_container_traits<std::unordered_map<Key, Value, Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `std::set`s of any type.
|
||||
@@ -370,16 +238,7 @@ struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>
|
||||
*/
|
||||
template<typename Key, typename... Args>
|
||||
struct meta_associative_container_traits<std::set<Key, Args...>>
|
||||
: meta_container_traits<
|
||||
std::set<Key, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_only_container
|
||||
>
|
||||
{};
|
||||
|
||||
: internal::basic_meta_associative_container_traits<std::set<Key, Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `std::unordered_set`s of any
|
||||
@@ -389,18 +248,27 @@ struct meta_associative_container_traits<std::set<Key, Args...>>
|
||||
*/
|
||||
template<typename Key, typename... Args>
|
||||
struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
|
||||
: meta_container_traits<
|
||||
std::unordered_set<Key, Args...>,
|
||||
basic_container,
|
||||
basic_associative_container,
|
||||
basic_dynamic_container,
|
||||
basic_dynamic_associative_container,
|
||||
dynamic_associative_key_only_container
|
||||
>
|
||||
{};
|
||||
: internal::basic_meta_associative_container_traits<std::unordered_set<Key, Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `dense_hash_map`s of any type.
|
||||
* @tparam Key The key type of the elements.
|
||||
* @tparam Type The value type of the elements.
|
||||
* @tparam Args Other arguments.
|
||||
*/
|
||||
template<typename Key, typename Type, typename... Args>
|
||||
struct meta_associative_container_traits<dense_hash_map<Key, Type, Args...>>
|
||||
: internal::basic_meta_associative_container_traits<dense_hash_map<Key, Type, Args...>> {};
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief Meta associative container traits for `dense_hash_set`s of any type.
|
||||
* @tparam Type The value type of the elements.
|
||||
* @tparam Args Other arguments.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
struct meta_associative_container_traits<dense_hash_set<Type, Args...>>
|
||||
: internal::basic_meta_associative_container_traits<dense_hash_set<Type, Args...>> {};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,52 +1,43 @@
|
||||
#ifndef ENTT_META_CTX_HPP
|
||||
#define ENTT_META_CTX_HPP
|
||||
|
||||
|
||||
#include "../core/attribute.h"
|
||||
#include "../config/config.h"
|
||||
|
||||
#include "../core/attribute.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
struct meta_type_node;
|
||||
|
||||
|
||||
struct ENTT_API meta_context {
|
||||
// we could use the lines below but VS2017 returns with an ICE if combined with ENTT_API despite the code being valid C++
|
||||
// inline static meta_type_node *local = nullptr;
|
||||
// inline static meta_type_node **global = &local;
|
||||
|
||||
[[nodiscard]] static meta_type_node * & local() ENTT_NOEXCEPT {
|
||||
[[nodiscard]] static meta_type_node *&local() ENTT_NOEXCEPT {
|
||||
static meta_type_node *chain = nullptr;
|
||||
return chain;
|
||||
}
|
||||
|
||||
[[nodiscard]] static meta_type_node ** & global() ENTT_NOEXCEPT {
|
||||
[[nodiscard]] static meta_type_node **&global() ENTT_NOEXCEPT {
|
||||
static meta_type_node **chain = &local();
|
||||
return chain;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
|
||||
/*! @brief Opaque container for a meta context. */
|
||||
struct meta_ctx {
|
||||
/**
|
||||
@@ -61,8 +52,6 @@ private:
|
||||
internal::meta_type_node **ctx{&internal::meta_context::local()};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#ifndef ENTT_META_FACTORY_HPP
|
||||
#define ENTT_META_FACTORY_HPP
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -13,46 +14,11 @@
|
||||
#include "meta.hpp"
|
||||
#include "node.hpp"
|
||||
#include "policy.hpp"
|
||||
#include "range.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename Node>
|
||||
[[nodiscard]] bool find_if(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
|
||||
return node && (node == candidate || find_if(candidate, node->next));
|
||||
}
|
||||
|
||||
|
||||
template<typename Id, typename Node>
|
||||
[[nodiscard]] bool find_if_not(const Id id, Node *node, const Node *owner) ENTT_NOEXCEPT {
|
||||
if constexpr(std::is_pointer_v<Id>) {
|
||||
return node && ((*node->id == *id && node != owner) || find_if_not(id, node->next, owner));
|
||||
} else {
|
||||
return node && ((node->id == id && node != owner) || find_if_not(id, node->next, owner));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @brief Meta factory to be used for reflection purposes.
|
||||
*
|
||||
@@ -62,8 +28,7 @@ template<typename Id, typename Node>
|
||||
* there are no subtle errors at runtime.
|
||||
*/
|
||||
template<typename...>
|
||||
struct meta_factory;
|
||||
|
||||
class meta_factory;
|
||||
|
||||
/**
|
||||
* @brief Extended meta factory to be used for reflection purposes.
|
||||
@@ -71,58 +36,51 @@ struct meta_factory;
|
||||
* @tparam Spec Property specialization pack used to disambiguate overloads.
|
||||
*/
|
||||
template<typename Type, typename... Spec>
|
||||
struct meta_factory<Type, Spec...>: public meta_factory<Type> {
|
||||
private:
|
||||
template<std::size_t Step = 0, std::size_t... Index, typename... Property, typename... Other>
|
||||
void unpack(std::index_sequence<Index...>, std::tuple<Property...> property, Other &&... other) {
|
||||
unroll<Step>(choice<3>, std::move(std::get<Index>(property))..., std::forward<Other>(other)...);
|
||||
class meta_factory<Type, Spec...>: public meta_factory<Type> {
|
||||
void link_prop_if_required(internal::meta_prop_node &node) {
|
||||
if(meta_range<internal::meta_prop_node *, internal::meta_prop_node> range{*ref}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
|
||||
ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [&node](const auto *curr) { return curr->id == node.id; }) == range.cend(), "Duplicate identifier");
|
||||
node.next = *ref;
|
||||
*ref = &node;
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, typename... Property, typename... Other>
|
||||
void unroll(choice_t<3>, std::tuple<Property...> property, Other &&... other) {
|
||||
unpack<Step>(std::index_sequence_for<Property...>{}, std::move(property), std::forward<Other>(other)...);
|
||||
void unroll(choice_t<2>, std::tuple<Property...> property, Other &&...other) {
|
||||
std::apply([this](auto &&...curr) { (this->unroll<Step>(choice<2>, std::forward<Property>(curr)...)); }, property);
|
||||
unroll<Step + sizeof...(Property)>(choice<2>, std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, typename... Property, typename... Other>
|
||||
void unroll(choice_t<2>, std::pair<Property...> property, Other &&... other) {
|
||||
void unroll(choice_t<1>, std::pair<Property...> property, Other &&...other) {
|
||||
assign<Step>(std::move(property.first), std::move(property.second));
|
||||
unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
|
||||
unroll<Step + 1>(choice<2>, std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, typename Property, typename... Other>
|
||||
std::enable_if_t<!std::is_invocable_v<Property>>
|
||||
unroll(choice_t<1>, Property &&property, Other &&... other) {
|
||||
void unroll(choice_t<0>, Property &&property, Other &&...other) {
|
||||
assign<Step>(std::forward<Property>(property));
|
||||
unroll<Step+1>(choice<3>, std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t Step = 0, typename Func, typename... Other>
|
||||
void unroll(choice_t<0>, Func &&invocable, Other &&... other) {
|
||||
unroll<Step>(choice<3>, std::forward<Func>(invocable)(), std::forward<Other>(other)...);
|
||||
unroll<Step + 1>(choice<2>, std::forward<Other>(other)...);
|
||||
}
|
||||
|
||||
template<std::size_t>
|
||||
void unroll(choice_t<0>) {}
|
||||
|
||||
template<std::size_t = 0, typename Key>
|
||||
void assign(Key &&key, meta_any value = {}) {
|
||||
template<std::size_t = 0>
|
||||
void assign(meta_any key, meta_any value = {}) {
|
||||
static meta_any property[2u]{};
|
||||
|
||||
static internal::meta_prop_node node{
|
||||
nullptr,
|
||||
property[0u],
|
||||
property[1u]
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
entt::meta_any instance{std::forward<Key>(key)};
|
||||
ENTT_ASSERT(!internal::find_if_not(&instance, *curr, &node));
|
||||
property[0u] = std::move(instance);
|
||||
property[0u] = std::move(key);
|
||||
property[1u] = std::move(value);
|
||||
|
||||
if(!internal::find_if(&node, *curr)) {
|
||||
node.next = *curr;
|
||||
*curr = &node;
|
||||
}
|
||||
link_prop_if_required(node);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -131,8 +89,7 @@ public:
|
||||
* @param target The underlying node to which to assign the properties.
|
||||
*/
|
||||
meta_factory(internal::meta_prop_node **target) ENTT_NOEXCEPT
|
||||
: curr{target}
|
||||
{}
|
||||
: ref{target} {}
|
||||
|
||||
/**
|
||||
* @brief Assigns a property to the last meta object created.
|
||||
@@ -146,60 +103,127 @@ public:
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename PropertyOrKey, typename... Value>
|
||||
auto prop(PropertyOrKey &&property_or_key, Value &&... value) && {
|
||||
meta_factory<Type> prop(PropertyOrKey &&property_or_key, Value &&...value) {
|
||||
if constexpr(sizeof...(Value) == 0) {
|
||||
unroll(choice<3>, std::forward<PropertyOrKey>(property_or_key));
|
||||
unroll(choice<2>, std::forward<PropertyOrKey>(property_or_key));
|
||||
} else {
|
||||
assign(std::forward<PropertyOrKey>(property_or_key), std::forward<Value>(value)...);
|
||||
}
|
||||
|
||||
return meta_factory<Type, Spec..., PropertyOrKey, Value...>{curr};
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns properties to the last meta object created.
|
||||
*
|
||||
* Both the keys and the values (if any) must be at least copy
|
||||
* constructible.
|
||||
* Both key and value (if any) must be at least copy constructible.
|
||||
*
|
||||
* @tparam Property Types of the properties.
|
||||
* @param property Properties to assign to the last meta object created.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template <typename... Property>
|
||||
auto props(Property... property) && {
|
||||
unroll(choice<3>, std::forward<Property>(property)...);
|
||||
return meta_factory<Type, Spec..., Property...>{curr};
|
||||
template<typename... Property>
|
||||
meta_factory<Type> props(Property... property) {
|
||||
unroll(choice<2>, std::forward<Property>(property)...);
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
internal::meta_prop_node **curr;
|
||||
internal::meta_prop_node **ref;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic meta factory to be used for reflection purposes.
|
||||
* @tparam Type Reflected type for which the factory was created.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct meta_factory<Type> {
|
||||
class meta_factory<Type> {
|
||||
void link_base_if_required(internal::meta_base_node &node) {
|
||||
if(meta_range<internal::meta_base_node *, internal::meta_base_node> range{owner->base}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
|
||||
node.next = owner->base;
|
||||
owner->base = &node;
|
||||
}
|
||||
}
|
||||
|
||||
void link_conv_if_required(internal::meta_conv_node &node) {
|
||||
if(meta_range<internal::meta_conv_node *, internal::meta_conv_node> range{owner->conv}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
|
||||
node.next = owner->conv;
|
||||
owner->conv = &node;
|
||||
}
|
||||
}
|
||||
|
||||
void link_ctor_if_required(internal::meta_ctor_node &node) {
|
||||
if(meta_range<internal::meta_ctor_node *, internal::meta_ctor_node> range{owner->ctor}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
|
||||
node.next = owner->ctor;
|
||||
owner->ctor = &node;
|
||||
}
|
||||
}
|
||||
|
||||
void link_data_if_required(const id_type id, internal::meta_data_node &node) {
|
||||
meta_range<internal::meta_data_node *, internal::meta_data_node> range{owner->data};
|
||||
ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id, &node](const auto *curr) { return curr != &node && curr->id == id; }) == range.cend(), "Duplicate identifier");
|
||||
node.id = id;
|
||||
|
||||
if(std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
|
||||
node.next = owner->data;
|
||||
owner->data = &node;
|
||||
}
|
||||
}
|
||||
|
||||
void link_func_if_required(const id_type id, internal::meta_func_node &node) {
|
||||
node.id = id;
|
||||
|
||||
if(meta_range<internal::meta_func_node *, internal::meta_func_node> range{owner->func}; std::find(range.cbegin(), range.cend(), &node) == range.cend()) {
|
||||
node.next = owner->func;
|
||||
owner->func = &node;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Setter, auto Getter, typename Policy, std::size_t... Index>
|
||||
auto data(const id_type id, std::index_sequence<Index...>) ENTT_NOEXCEPT {
|
||||
using data_type = std::invoke_result_t<decltype(Getter), Type &>;
|
||||
using args_type = type_list<typename meta_function_helper_t<Type, decltype(value_list_element_v<Index, Setter>)>::args_type...>;
|
||||
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
|
||||
|
||||
static internal::meta_data_node node{
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
Setter::size,
|
||||
/* this is never static */
|
||||
(std::is_member_object_pointer_v<decltype(value_list_element_v<Index, Setter>)> && ... && std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
|
||||
internal::meta_node<std::remove_const_t<std::remove_reference_t<data_type>>>::resolve(),
|
||||
&meta_arg<type_list<type_list_element_t<type_list_element_t<Index, args_type>::size != 1u, type_list_element_t<Index, args_type>>...>>,
|
||||
[](meta_handle instance, meta_any value) -> bool { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
|
||||
&meta_getter<Type, Getter, Policy>
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
link_data_if_required(id, node);
|
||||
return meta_factory<Type, Setter, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Default constructor. */
|
||||
meta_factory()
|
||||
: owner{internal::meta_node<Type>::resolve()} {}
|
||||
|
||||
/**
|
||||
* @brief Makes a meta type _searchable_.
|
||||
* @param id Optional unique identifier.
|
||||
* @return An extended meta factory for the given type.
|
||||
*/
|
||||
auto type(const id_type id = type_hash<Type>::value()) {
|
||||
auto * const node = internal::meta_info<Type>::resolve();
|
||||
meta_range<internal::meta_type_node *, internal::meta_type_node> range{*internal::meta_context::global()};
|
||||
ENTT_ASSERT(std::find_if(range.cbegin(), range.cend(), [id, this](const auto *curr) { return curr != owner && curr->id == id; }) == range.cend(), "Duplicate identifier");
|
||||
owner->id = id;
|
||||
|
||||
ENTT_ASSERT(!internal::find_if_not(id, *internal::meta_context::global(), node));
|
||||
node->id = id;
|
||||
|
||||
if(!internal::find_if(node, *internal::meta_context::global())) {
|
||||
node->next = *internal::meta_context::global();
|
||||
*internal::meta_context::global() = node;
|
||||
if(std::find(range.cbegin(), range.cend(), owner) == range.cend()) {
|
||||
owner->next = *internal::meta_context::global();
|
||||
*internal::meta_context::global() = owner;
|
||||
}
|
||||
|
||||
return meta_factory<Type, Type>{&node->prop};
|
||||
return meta_factory<Type, Type>{&owner->prop};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,53 +237,21 @@ struct meta_factory<Type> {
|
||||
template<typename Base>
|
||||
auto base() ENTT_NOEXCEPT {
|
||||
static_assert(std::is_base_of_v<Base, Type>, "Invalid base type");
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
|
||||
static internal::meta_base_node node{
|
||||
type,
|
||||
nullptr,
|
||||
&internal::meta_info<Base>::resolve,
|
||||
[](const void *instance) ENTT_NOEXCEPT -> const void * {
|
||||
return static_cast<const Base *>(static_cast<const Type *>(instance));
|
||||
internal::meta_node<Base>::resolve(),
|
||||
[](meta_any other) ENTT_NOEXCEPT -> meta_any {
|
||||
if(auto *ptr = other.data(); ptr) {
|
||||
return forward_as_meta(*static_cast<Base *>(static_cast<Type *>(ptr)));
|
||||
}
|
||||
|
||||
return forward_as_meta(*static_cast<const Base *>(static_cast<const Type *>(std::as_const(other).data())));
|
||||
}
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
if(!internal::find_if(&node, type->base)) {
|
||||
node.next = type->base;
|
||||
type->base = &node;
|
||||
}
|
||||
|
||||
return meta_factory<Type>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a meta conversion function to a meta type.
|
||||
*
|
||||
* The given type must be such that an instance of the reflected type can be
|
||||
* converted to it.
|
||||
*
|
||||
* @tparam To Type of the conversion function to assign to the meta type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename To>
|
||||
auto conv() ENTT_NOEXCEPT {
|
||||
static_assert(std::is_convertible_v<Type, To>, "Could not convert to the required type");
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
|
||||
static internal::meta_conv_node node{
|
||||
type,
|
||||
nullptr,
|
||||
&internal::meta_info<To>::resolve,
|
||||
[](const void *instance) -> meta_any {
|
||||
return static_cast<To>(*static_cast<const Type *>(instance));
|
||||
}
|
||||
};
|
||||
|
||||
if(!internal::find_if(&node, type->conv)) {
|
||||
node.next = type->conv;
|
||||
type->conv = &node;
|
||||
}
|
||||
|
||||
link_base_if_required(node);
|
||||
return meta_factory<Type>{};
|
||||
}
|
||||
|
||||
@@ -277,23 +269,40 @@ struct meta_factory<Type> {
|
||||
*/
|
||||
template<auto Candidate>
|
||||
auto conv() ENTT_NOEXCEPT {
|
||||
using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
|
||||
static internal::meta_conv_node node{
|
||||
type,
|
||||
nullptr,
|
||||
&internal::meta_info<conv_type>::resolve,
|
||||
[](const void *instance) -> meta_any {
|
||||
return std::invoke(Candidate, *static_cast<const Type *>(instance));
|
||||
internal::meta_node<std::remove_const_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>>::resolve(),
|
||||
[](const meta_any &instance) -> meta_any {
|
||||
return forward_as_meta(std::invoke(Candidate, *static_cast<const Type *>(instance.data())));
|
||||
}
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
if(!internal::find_if(&node, type->conv)) {
|
||||
node.next = type->conv;
|
||||
type->conv = &node;
|
||||
}
|
||||
link_conv_if_required(node);
|
||||
return meta_factory<Type>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a meta conversion function to a meta type.
|
||||
*
|
||||
* The given type must be such that an instance of the reflected type can be
|
||||
* converted to it.
|
||||
*
|
||||
* @tparam To Type of the conversion function to assign to the meta type.
|
||||
* @return A meta factory for the parent type.
|
||||
*/
|
||||
template<typename To>
|
||||
auto conv() ENTT_NOEXCEPT {
|
||||
static_assert(std::is_convertible_v<Type, To>, "Could not convert to the required type");
|
||||
|
||||
static internal::meta_conv_node node{
|
||||
nullptr,
|
||||
internal::meta_node<std::remove_const_t<std::remove_reference_t<To>>>::resolve(),
|
||||
[](const meta_any &instance) -> meta_any { return forward_as_meta(static_cast<To>(*static_cast<const Type *>(instance.data()))); }
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
link_conv_if_required(node);
|
||||
return meta_factory<Type>{};
|
||||
}
|
||||
|
||||
@@ -313,28 +322,19 @@ struct meta_factory<Type> {
|
||||
template<auto Candidate, typename Policy = as_is_t>
|
||||
auto ctor() ENTT_NOEXCEPT {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
|
||||
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
|
||||
static_assert(std::is_same_v<std::decay_t<typename descriptor::return_type>, Type>, "The function doesn't return an object of the required type");
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
|
||||
static internal::meta_ctor_node node{
|
||||
type,
|
||||
nullptr,
|
||||
nullptr,
|
||||
descriptor::args_type::size,
|
||||
[](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
|
||||
return meta_arg(typename descriptor::args_type{}, index);
|
||||
},
|
||||
[](meta_any * const args) {
|
||||
return meta_invoke<Type, Candidate, Policy>({}, args, std::make_index_sequence<descriptor::args_type::size>{});
|
||||
}
|
||||
&meta_arg<typename descriptor::args_type>,
|
||||
&meta_construct<Type, Candidate, Policy>
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
if(!internal::find_if(&node, type->ctor)) {
|
||||
node.next = type->ctor;
|
||||
type->ctor = &node;
|
||||
}
|
||||
|
||||
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
|
||||
link_ctor_if_required(node);
|
||||
return meta_factory<Type>{};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,40 +349,32 @@ struct meta_factory<Type> {
|
||||
*/
|
||||
template<typename... Args>
|
||||
auto ctor() ENTT_NOEXCEPT {
|
||||
using descriptor = meta_function_helper_t<Type, Type(*)(Args...)>;
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
using descriptor = meta_function_helper_t<Type, Type (*)(Args...)>;
|
||||
|
||||
static internal::meta_ctor_node node{
|
||||
type,
|
||||
nullptr,
|
||||
nullptr,
|
||||
descriptor::args_type::size,
|
||||
[](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
|
||||
return meta_arg(typename descriptor::args_type{}, index);
|
||||
},
|
||||
[](meta_any * const args) {
|
||||
return meta_construct<Type, Args...>(args, std::make_index_sequence<descriptor::args_type::size>{});
|
||||
}
|
||||
&meta_arg<typename descriptor::args_type>,
|
||||
&meta_construct<Type, Args...>
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
if(!internal::find_if(&node, type->ctor)) {
|
||||
node.next = type->ctor;
|
||||
type->ctor = &node;
|
||||
}
|
||||
|
||||
return meta_factory<Type, Type(Args...)>{&node.prop};
|
||||
link_ctor_if_required(node);
|
||||
return meta_factory<Type>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a meta destructor to a meta type.
|
||||
*
|
||||
* Free functions can be assigned to meta types in the role of destructors.
|
||||
* The signature of the function should identical to the following:
|
||||
* Both free functions and member functions can be assigned to meta types in
|
||||
* the role of destructors.<br/>
|
||||
* The signature of a free function should be identical to the following:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(Type &);
|
||||
* @endcode
|
||||
*
|
||||
* Member functions should not take arguments instead.<br/>
|
||||
* The purpose is to give users the ability to free up resources that
|
||||
* require special treatment before an object is actually destroyed.
|
||||
*
|
||||
@@ -392,12 +384,7 @@ struct meta_factory<Type> {
|
||||
template<auto Func>
|
||||
auto dtor() ENTT_NOEXCEPT {
|
||||
static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
|
||||
type->dtor = [](void *instance) {
|
||||
std::invoke(Func, *static_cast<Type *>(instance));
|
||||
};
|
||||
|
||||
owner->dtor = [](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
|
||||
return meta_factory<Type>{};
|
||||
}
|
||||
|
||||
@@ -417,31 +404,41 @@ struct meta_factory<Type> {
|
||||
template<auto Data, typename Policy = as_is_t>
|
||||
auto data(const id_type id) ENTT_NOEXCEPT {
|
||||
if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
return data<Data, Data, Policy>(id);
|
||||
} else {
|
||||
using data_type = std::remove_pointer_t<decltype(Data)>;
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
using data_type = std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>;
|
||||
|
||||
static internal::meta_data_node node{
|
||||
{},
|
||||
type,
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::is_same_v<Type, data_type> || std::is_const_v<data_type>,
|
||||
true,
|
||||
&internal::meta_info<data_type>::resolve,
|
||||
1u,
|
||||
/* this is never static */
|
||||
std::is_const_v<data_type> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
|
||||
internal::meta_node<std::remove_const_t<data_type>>::resolve(),
|
||||
&meta_arg<type_list<std::remove_const_t<data_type>>>,
|
||||
&meta_setter<Type, Data>,
|
||||
&meta_getter<Type, Data, Policy>
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!internal::find_if_not(id, type->data, &node));
|
||||
node.id = id;
|
||||
link_data_if_required(id, node);
|
||||
return meta_factory<Type, std::integral_constant<decltype(Data), Data>, std::integral_constant<decltype(Data), Data>>{&node.prop};
|
||||
} else {
|
||||
using data_type = std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>;
|
||||
|
||||
if(!internal::find_if(&node, type->data)) {
|
||||
node.next = type->data;
|
||||
type->data = &node;
|
||||
}
|
||||
static internal::meta_data_node node{
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
1u,
|
||||
((std::is_same_v<Type, std::remove_const_t<data_type>> || std::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
|
||||
internal::meta_node<std::remove_const_t<data_type>>::resolve(),
|
||||
&meta_arg<type_list<std::remove_const_t<data_type>>>,
|
||||
&meta_setter<Type, Data>,
|
||||
&meta_getter<Type, Data, Policy>
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
link_data_if_required(id, node);
|
||||
return meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&node.prop};
|
||||
}
|
||||
}
|
||||
@@ -468,30 +465,68 @@ struct meta_factory<Type> {
|
||||
*/
|
||||
template<auto Setter, auto Getter, typename Policy = as_is_t>
|
||||
auto data(const id_type id) ENTT_NOEXCEPT {
|
||||
using underlying_type = std::remove_reference_t<std::invoke_result_t<decltype(Getter), Type &>>;
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
using data_type = std::invoke_result_t<decltype(Getter), Type &>;
|
||||
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
|
||||
|
||||
static internal::meta_data_node node{
|
||||
{},
|
||||
type,
|
||||
nullptr,
|
||||
nullptr,
|
||||
std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>),
|
||||
false,
|
||||
&internal::meta_info<underlying_type>::resolve,
|
||||
&meta_setter<Type, Setter>,
|
||||
&meta_getter<Type, Getter, Policy>
|
||||
};
|
||||
if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
|
||||
static internal::meta_data_node node{
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
0u,
|
||||
/* this is never static */
|
||||
internal::meta_traits::is_const,
|
||||
internal::meta_node<std::remove_const_t<std::remove_reference_t<data_type>>>::resolve(),
|
||||
&meta_arg<type_list<>>,
|
||||
&meta_setter<Type, Setter>,
|
||||
&meta_getter<Type, Getter, Policy>
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
ENTT_ASSERT(!internal::find_if_not(id, type->data, &node));
|
||||
node.id = id;
|
||||
link_data_if_required(id, node);
|
||||
return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
|
||||
} else {
|
||||
using args_type = typename meta_function_helper_t<Type, decltype(Setter)>::args_type;
|
||||
|
||||
if(!internal::find_if(&node, type->data)) {
|
||||
node.next = type->data;
|
||||
type->data = &node;
|
||||
static internal::meta_data_node node{
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
1u,
|
||||
/* this is never static nor const */
|
||||
internal::meta_traits::is_none,
|
||||
internal::meta_node<std::remove_const_t<std::remove_reference_t<data_type>>>::resolve(),
|
||||
&meta_arg<type_list<type_list_element_t<args_type::size != 1u, args_type>>>,
|
||||
&meta_setter<Type, Setter>,
|
||||
&meta_getter<Type, Getter, Policy>
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
link_data_if_required(id, node);
|
||||
return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
|
||||
}
|
||||
}
|
||||
|
||||
return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
|
||||
/**
|
||||
* @brief Assigns a meta data to a meta type by means of its setters and
|
||||
* getter.
|
||||
*
|
||||
* Multi-setter support for meta data members. All setters are tried in the
|
||||
* order of definition before returning to the caller.<br/>
|
||||
* Setters can be either free functions, member functions or a mix of them
|
||||
* and are provided via a `value_list` type.
|
||||
*
|
||||
* @sa data
|
||||
*
|
||||
* @tparam Setter The actual functions to use as setters.
|
||||
* @tparam Getter The actual getter function.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param id Unique identifier.
|
||||
* @return An extended meta factory for the parent type.
|
||||
*/
|
||||
template<typename Setter, auto Getter, typename Policy = as_is_t>
|
||||
auto data(const id_type id) ENTT_NOEXCEPT {
|
||||
return data<Setter, Getter, Policy>(id, std::make_index_sequence<Setter::size>{});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -510,44 +545,27 @@ struct meta_factory<Type> {
|
||||
template<auto Candidate, typename Policy = as_is_t>
|
||||
auto func(const id_type id) ENTT_NOEXCEPT {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
|
||||
auto * const type = internal::meta_info<Type>::resolve();
|
||||
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
|
||||
|
||||
static internal::meta_func_node node{
|
||||
{},
|
||||
type,
|
||||
nullptr,
|
||||
nullptr,
|
||||
descriptor::args_type::size,
|
||||
descriptor::is_const,
|
||||
descriptor::is_static,
|
||||
&internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename descriptor::return_type>>::resolve,
|
||||
[](const typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
|
||||
return meta_arg(typename descriptor::args_type{}, index);
|
||||
},
|
||||
[](meta_handle instance, meta_any *args) {
|
||||
return meta_invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<descriptor::args_type::size>{});
|
||||
}
|
||||
(descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
|
||||
internal::meta_node<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_const_t<std::remove_reference_t<typename descriptor::return_type>>>>::resolve(),
|
||||
&meta_arg<typename descriptor::args_type>,
|
||||
&meta_invoke<Type, Candidate, Policy>
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
for(auto *it = &type->func; *it; it = &(*it)->next) {
|
||||
if(*it == &node) {
|
||||
*it = node.next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal::meta_func_node **it = &type->func;
|
||||
for(; *it && (*it)->id != id; it = &(*it)->next);
|
||||
for(; *it && (*it)->id == id && (*it)->arity < node.arity; it = &(*it)->next);
|
||||
|
||||
node.id = id;
|
||||
node.next = *it;
|
||||
*it = &node;
|
||||
|
||||
link_func_if_required(id, node);
|
||||
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
internal::meta_type_node *owner;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Utility function to use for reflection.
|
||||
@@ -562,13 +580,73 @@ struct meta_factory<Type> {
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] auto meta() ENTT_NOEXCEPT {
|
||||
auto * const node = internal::meta_info<Type>::resolve();
|
||||
auto *const node = internal::meta_node<Type>::resolve();
|
||||
// extended meta factory to allow assigning properties to opaque meta types
|
||||
return meta_factory<Type, Type>{&node->prop};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets a type and all its parts.
|
||||
*
|
||||
* Resets a type and all its data members, member functions and properties, as
|
||||
* well as its constructors, destructors and conversion functions if any.<br/>
|
||||
* Base classes aren't reset but the link between the two types is removed.
|
||||
*
|
||||
* The type is also removed from the list of searchable types.
|
||||
*
|
||||
* @param id Unique identifier.
|
||||
*/
|
||||
inline void meta_reset(const id_type id) ENTT_NOEXCEPT {
|
||||
auto clear_chain = [](auto **curr, auto... member) {
|
||||
for(; *curr; *curr = std::exchange((*curr)->next, nullptr)) {
|
||||
if constexpr(sizeof...(member) != 0u) {
|
||||
static_assert(sizeof...(member) == 1u, "Assert in defense of the future me");
|
||||
for(auto **sub = (&((*curr)->*member), ...); *sub; *sub = std::exchange((*sub)->next, nullptr)) {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for(auto **it = internal::meta_context::global(); *it; it = &(*it)->next) {
|
||||
if(auto *node = *it; node->id == id) {
|
||||
clear_chain(&node->prop);
|
||||
clear_chain(&node->base);
|
||||
clear_chain(&node->conv);
|
||||
clear_chain(&node->ctor);
|
||||
clear_chain(&node->data, &internal::meta_data_node::prop);
|
||||
clear_chain(&node->func, &internal::meta_func_node::prop);
|
||||
|
||||
node->id = {};
|
||||
node->dtor = nullptr;
|
||||
*it = std::exchange(node->next, nullptr);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets a type and all its parts.
|
||||
*
|
||||
* @sa meta_reset
|
||||
*
|
||||
* @tparam Type Type to reset.
|
||||
*/
|
||||
template<typename Type>
|
||||
void meta_reset() ENTT_NOEXCEPT {
|
||||
meta_reset(internal::meta_node<Type>::resolve()->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets all searchable types.
|
||||
*
|
||||
* @sa meta_reset
|
||||
*/
|
||||
inline void meta_reset() ENTT_NOEXCEPT {
|
||||
while(*internal::meta_context::global()) {
|
||||
meta_reset((*internal::meta_context::global())->id);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
24
src/entt/meta/fwd.hpp
Normal file
24
src/entt/meta/fwd.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef ENTT_META_FWD_HPP
|
||||
#define ENTT_META_FWD_HPP
|
||||
|
||||
namespace entt {
|
||||
|
||||
class meta_sequence_container;
|
||||
|
||||
class meta_associative_container;
|
||||
|
||||
class meta_any;
|
||||
|
||||
struct meta_handle;
|
||||
|
||||
struct meta_prop;
|
||||
|
||||
struct meta_data;
|
||||
|
||||
struct meta_func;
|
||||
|
||||
class meta_type;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,190 +1,160 @@
|
||||
#ifndef ENTT_META_NODE_HPP
|
||||
#define ENTT_META_NODE_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/attribute.h"
|
||||
#include "../core/enum.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
class meta_any;
|
||||
class meta_type;
|
||||
struct meta_handle;
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
enum class meta_traits : std::uint32_t {
|
||||
is_none = 0x0000,
|
||||
is_const = 0x0001,
|
||||
is_static = 0x0002,
|
||||
is_arithmetic = 0x0004,
|
||||
is_array = 0x0008,
|
||||
is_enum = 0x0010,
|
||||
is_class = 0x0020,
|
||||
is_pointer = 0x0040,
|
||||
is_meta_pointer_like = 0x0080,
|
||||
is_meta_sequence_container = 0x0100,
|
||||
is_meta_associative_container = 0x0200,
|
||||
_entt_enum_as_bitmask
|
||||
};
|
||||
|
||||
struct meta_type_node;
|
||||
|
||||
|
||||
struct meta_prop_node {
|
||||
meta_prop_node * next;
|
||||
meta_prop_node *next;
|
||||
const meta_any &id;
|
||||
meta_any &value;
|
||||
};
|
||||
|
||||
|
||||
struct meta_base_node {
|
||||
meta_type_node * const parent;
|
||||
meta_base_node * next;
|
||||
meta_type_node *(* const type)() ENTT_NOEXCEPT;
|
||||
const void *(* const cast)(const void *) ENTT_NOEXCEPT;
|
||||
meta_base_node *next;
|
||||
meta_type_node *const type;
|
||||
meta_any (*const cast)(meta_any) ENTT_NOEXCEPT;
|
||||
};
|
||||
|
||||
|
||||
struct meta_conv_node {
|
||||
meta_type_node * const parent;
|
||||
meta_conv_node * next;
|
||||
meta_type_node *(* const type)() ENTT_NOEXCEPT;
|
||||
meta_any(* const conv)(const void *);
|
||||
meta_conv_node *next;
|
||||
meta_type_node *const type;
|
||||
meta_any (*const conv)(const meta_any &);
|
||||
};
|
||||
|
||||
|
||||
struct meta_ctor_node {
|
||||
using size_type = std::size_t;
|
||||
meta_type_node * const parent;
|
||||
meta_ctor_node * next;
|
||||
meta_prop_node * prop;
|
||||
meta_ctor_node *next;
|
||||
const size_type arity;
|
||||
meta_type(* const arg)(const size_type) ENTT_NOEXCEPT;
|
||||
meta_any(* const invoke)(meta_any * const);
|
||||
meta_type (*const arg)(const size_type) ENTT_NOEXCEPT;
|
||||
meta_any (*const invoke)(meta_any *const);
|
||||
};
|
||||
|
||||
|
||||
struct meta_data_node {
|
||||
using size_type = std::size_t;
|
||||
id_type id;
|
||||
meta_type_node * const parent;
|
||||
meta_data_node * next;
|
||||
meta_prop_node * prop;
|
||||
const bool is_const;
|
||||
const bool is_static;
|
||||
meta_type_node *(* const type)() ENTT_NOEXCEPT;
|
||||
bool(* const set)(meta_handle, meta_any);
|
||||
meta_any(* const get)(meta_handle);
|
||||
meta_data_node *next;
|
||||
meta_prop_node *prop;
|
||||
const size_type arity;
|
||||
const meta_traits traits;
|
||||
meta_type_node *const type;
|
||||
meta_type (*const arg)(const size_type) ENTT_NOEXCEPT;
|
||||
bool (*const set)(meta_handle, meta_any);
|
||||
meta_any (*const get)(meta_handle);
|
||||
};
|
||||
|
||||
|
||||
struct meta_func_node {
|
||||
using size_type = std::size_t;
|
||||
id_type id;
|
||||
meta_type_node * const parent;
|
||||
meta_func_node * next;
|
||||
meta_prop_node * prop;
|
||||
meta_func_node *next;
|
||||
meta_prop_node *prop;
|
||||
const size_type arity;
|
||||
const bool is_const;
|
||||
const bool is_static;
|
||||
meta_type_node *(* const ret)() ENTT_NOEXCEPT;
|
||||
meta_type(* const arg)(const size_type) ENTT_NOEXCEPT;
|
||||
meta_any(* const invoke)(meta_handle, meta_any *);
|
||||
const meta_traits traits;
|
||||
meta_type_node *const ret;
|
||||
meta_type (*const arg)(const size_type) ENTT_NOEXCEPT;
|
||||
meta_any (*const invoke)(meta_handle, meta_any *const);
|
||||
};
|
||||
|
||||
|
||||
struct meta_template_info {
|
||||
struct meta_template_node {
|
||||
using size_type = std::size_t;
|
||||
const bool is_template_specialization;
|
||||
const size_type arity;
|
||||
meta_type_node *(* const type)() ENTT_NOEXCEPT;
|
||||
meta_type_node *(* const arg)(const size_type) ENTT_NOEXCEPT;
|
||||
meta_type_node *const type;
|
||||
meta_type_node *(*const arg)(const size_type)ENTT_NOEXCEPT;
|
||||
};
|
||||
|
||||
|
||||
struct meta_type_node {
|
||||
using size_type = std::size_t;
|
||||
const type_info info;
|
||||
const type_info *info;
|
||||
id_type id;
|
||||
meta_type_node * next;
|
||||
meta_prop_node * prop;
|
||||
meta_type_node *next;
|
||||
meta_prop_node *prop;
|
||||
const size_type size_of;
|
||||
const bool is_void;
|
||||
const bool is_integral;
|
||||
const bool is_floating_point;
|
||||
const bool is_array;
|
||||
const bool is_enum;
|
||||
const bool is_union;
|
||||
const bool is_class;
|
||||
const bool is_pointer;
|
||||
const bool is_function_pointer;
|
||||
const bool is_member_object_pointer;
|
||||
const bool is_member_function_pointer;
|
||||
const bool is_pointer_like;
|
||||
const bool is_sequence_container;
|
||||
const bool is_associative_container;
|
||||
const meta_template_info template_info;
|
||||
const size_type rank;
|
||||
size_type(* const extent)(const size_type) ENTT_NOEXCEPT ;
|
||||
meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT;
|
||||
meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT;
|
||||
meta_ctor_node * const def_ctor;
|
||||
const meta_traits traits;
|
||||
meta_any (*const default_constructor)();
|
||||
double (*const conversion_helper)(void *, const void *);
|
||||
const meta_template_node *const templ;
|
||||
meta_ctor_node *ctor{nullptr};
|
||||
meta_base_node *base{nullptr};
|
||||
meta_conv_node *conv{nullptr};
|
||||
meta_data_node *data{nullptr};
|
||||
meta_func_node *func{nullptr};
|
||||
void(* dtor)(void *){nullptr};
|
||||
void (*dtor)(void *){nullptr};
|
||||
};
|
||||
|
||||
|
||||
template<auto Member, typename Op, typename Node>
|
||||
auto meta_visit(const Op &op, const Node *node)
|
||||
-> std::decay_t<decltype(node->*Member)> {
|
||||
for(auto *curr = node->*Member; curr; curr = curr->next) {
|
||||
if(op(curr)) {
|
||||
return curr;
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr(std::is_same_v<Node, meta_type_node>) {
|
||||
for(auto *curr = node->base; curr; curr = curr->next) {
|
||||
if(auto *ret = meta_visit<Member>(op, curr->type()); ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
template<typename... Args>
|
||||
meta_type_node * meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT;
|
||||
|
||||
meta_type_node *meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT;
|
||||
|
||||
template<typename Type>
|
||||
class ENTT_API meta_node {
|
||||
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Invalid type");
|
||||
|
||||
template<std::size_t... Index>
|
||||
[[nodiscard]] static auto extent(const meta_type_node::size_type dim, std::index_sequence<Index...>) ENTT_NOEXCEPT {
|
||||
meta_type_node::size_type ext{};
|
||||
((ext = (dim == Index ? std::extent_v<Type, Index> : ext)), ...);
|
||||
return ext;
|
||||
[[nodiscard]] static auto *meta_default_constructor() ENTT_NOEXCEPT {
|
||||
if constexpr(std::is_default_constructible_v<Type>) {
|
||||
return +[]() { return meta_any{std::in_place_type<Type>}; };
|
||||
} else {
|
||||
return static_cast<std::decay_t<decltype(meta_type_node::default_constructor)>>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static meta_ctor_node * meta_default_constructor([[maybe_unused]] meta_type_node *type) ENTT_NOEXCEPT {
|
||||
if constexpr(std::is_default_constructible_v<Type>) {
|
||||
static meta_ctor_node node{
|
||||
type,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0u,
|
||||
nullptr,
|
||||
[](meta_any * const) { return meta_any{std::in_place_type<Type>}; }
|
||||
[[nodiscard]] static auto *meta_conversion_helper() ENTT_NOEXCEPT {
|
||||
if constexpr(std::is_arithmetic_v<Type>) {
|
||||
return +[](void *bin, const void *value) {
|
||||
return bin ? static_cast<double>(*static_cast<Type *>(bin) = static_cast<Type>(*static_cast<const double *>(value))) : static_cast<double>(*static_cast<const Type *>(value));
|
||||
};
|
||||
} else if constexpr(std::is_enum_v<Type>) {
|
||||
return +[](void *bin, const void *value) {
|
||||
return bin ? static_cast<double>(*static_cast<Type *>(bin) = static_cast<Type>(static_cast<std::underlying_type_t<Type>>(*static_cast<const double *>(value)))) : static_cast<double>(*static_cast<const Type *>(value));
|
||||
};
|
||||
} else {
|
||||
return static_cast<std::decay_t<decltype(meta_type_node::conversion_helper)>>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static meta_template_node *meta_template_info() ENTT_NOEXCEPT {
|
||||
if constexpr(is_complete_v<meta_template_traits<Type>>) {
|
||||
static meta_template_node node{
|
||||
meta_template_traits<Type>::args_type::size,
|
||||
meta_node<typename meta_template_traits<Type>::class_type>::resolve(),
|
||||
[](const std::size_t index) ENTT_NOEXCEPT { return meta_arg_node(typename meta_template_traits<Type>::args_type{}, index); }
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
return &node;
|
||||
@@ -193,78 +163,73 @@ class ENTT_API meta_node {
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static meta_template_info meta_template_descriptor() ENTT_NOEXCEPT {
|
||||
if constexpr(is_complete_v<meta_template_traits<Type>>) {
|
||||
return {
|
||||
true,
|
||||
meta_template_traits<Type>::args_type::size,
|
||||
&meta_node<typename meta_template_traits<Type>::class_type>::resolve,
|
||||
[](const std::size_t index) ENTT_NOEXCEPT {
|
||||
return meta_arg_node(typename meta_template_traits<Type>::args_type{}, index);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return { false, 0u, nullptr, nullptr };
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
[[nodiscard]] static meta_type_node * resolve() ENTT_NOEXCEPT {
|
||||
[[nodiscard]] static meta_type_node *resolve() ENTT_NOEXCEPT {
|
||||
static meta_type_node node{
|
||||
type_id<Type>(),
|
||||
&type_id<Type>(),
|
||||
{},
|
||||
nullptr,
|
||||
nullptr,
|
||||
size_of_v<Type>,
|
||||
std::is_void_v<Type>,
|
||||
std::is_integral_v<Type>,
|
||||
std::is_floating_point_v<Type>,
|
||||
std::is_array_v<Type>,
|
||||
std::is_enum_v<Type>,
|
||||
std::is_union_v<Type>,
|
||||
std::is_class_v<Type>,
|
||||
std::is_pointer_v<Type>,
|
||||
std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
|
||||
std::is_member_object_pointer_v<Type>,
|
||||
std::is_member_function_pointer_v<Type>,
|
||||
is_meta_pointer_like_v<Type>,
|
||||
is_complete_v<meta_sequence_container_traits<Type>>,
|
||||
is_complete_v<meta_associative_container_traits<Type>>,
|
||||
meta_template_descriptor(),
|
||||
std::rank_v<Type>,
|
||||
[](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence<std::rank_v<Type>>{}); },
|
||||
&meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<Type>>>>::resolve,
|
||||
&meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_extent_t<Type>>>>::resolve,
|
||||
meta_default_constructor(&node),
|
||||
meta_default_constructor(&node)
|
||||
internal::meta_traits::is_none
|
||||
| (std::is_arithmetic_v<Type> ? internal::meta_traits::is_arithmetic : internal::meta_traits::is_none)
|
||||
| (std::is_array_v<Type> ? internal::meta_traits::is_array : internal::meta_traits::is_none)
|
||||
| (std::is_enum_v<Type> ? internal::meta_traits::is_enum : internal::meta_traits::is_none)
|
||||
| (std::is_class_v<Type> ? internal::meta_traits::is_class : internal::meta_traits::is_none)
|
||||
| (std::is_pointer_v<Type> ? internal::meta_traits::is_pointer : internal::meta_traits::is_none)
|
||||
| (is_meta_pointer_like_v<Type> ? internal::meta_traits::is_meta_pointer_like : internal::meta_traits::is_none)
|
||||
| (is_complete_v<meta_sequence_container_traits<Type>> ? internal::meta_traits::is_meta_sequence_container : internal::meta_traits::is_none)
|
||||
| (is_complete_v<meta_associative_container_traits<Type>> ? internal::meta_traits::is_meta_associative_container : internal::meta_traits::is_none),
|
||||
meta_default_constructor(),
|
||||
meta_conversion_helper(),
|
||||
meta_template_info()
|
||||
// tricks clang-format
|
||||
};
|
||||
|
||||
return &node;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Type>
|
||||
struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>> {};
|
||||
|
||||
|
||||
template<typename... Args>
|
||||
meta_type_node * meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
|
||||
meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info<Args>::resolve()...};
|
||||
[[nodiscard]] meta_type_node *meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
|
||||
meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_node<std::remove_const_t<std::remove_reference_t<Args>>>::resolve()...};
|
||||
return args[index + 1u];
|
||||
}
|
||||
|
||||
template<auto Member, typename Type>
|
||||
[[nodiscard]] static std::decay_t<decltype(std::declval<internal::meta_type_node>().*Member)> find_by(const Type &info_or_id, const internal::meta_type_node *node) {
|
||||
for(auto *curr = node->*Member; curr; curr = curr->next) {
|
||||
if constexpr(std::is_same_v<Type, type_info>) {
|
||||
if(*curr->type->info == info_or_id) {
|
||||
return curr;
|
||||
}
|
||||
} else if constexpr(std::is_same_v<decltype(curr), meta_base_node *>) {
|
||||
if(curr->type->id == info_or_id) {
|
||||
return curr;
|
||||
}
|
||||
} else {
|
||||
if(curr->id == info_or_id) {
|
||||
return curr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(auto *curr = node->base; curr; curr = curr->next) {
|
||||
if(auto *ret = find_by<Member>(info_or_id, curr->type); ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
#ifndef ENTT_META_POINTER_HPP
|
||||
#define ENTT_META_POINTER_HPP
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include "type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Makes plain pointers pointer-like types for the meta system.
|
||||
* @tparam Type Element type.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_meta_pointer_like<Type *>
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
: std::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Partial specialization used to reject pointers to arrays.
|
||||
@@ -26,10 +21,8 @@ struct is_meta_pointer_like<Type *>
|
||||
* @tparam N Number of elements of the array.
|
||||
*/
|
||||
template<typename Type, std::size_t N>
|
||||
struct is_meta_pointer_like<Type(*)[N]>
|
||||
: std::false_type
|
||||
{};
|
||||
|
||||
struct is_meta_pointer_like<Type (*)[N]>
|
||||
: std::false_type {};
|
||||
|
||||
/**
|
||||
* @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta
|
||||
@@ -38,9 +31,7 @@ struct is_meta_pointer_like<Type(*)[N]>
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_meta_pointer_like<std::shared_ptr<Type>>
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
: std::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Makes `std::unique_ptr`s of any type pointer-like types for the meta
|
||||
@@ -50,11 +41,8 @@ struct is_meta_pointer_like<std::shared_ptr<Type>>
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
struct is_meta_pointer_like<std::unique_ptr<Type, Args...>>
|
||||
: std::true_type
|
||||
{};
|
||||
|
||||
|
||||
}
|
||||
: std::true_type {};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,27 +1,66 @@
|
||||
#ifndef ENTT_META_POLICY_HPP
|
||||
#define ENTT_META_POLICY_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/*! @brief Empty class type used to request the _as ref_ policy. */
|
||||
struct as_ref_t {};
|
||||
|
||||
struct as_ref_t {
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as cref_ policy. */
|
||||
struct as_cref_t {};
|
||||
|
||||
struct as_cref_t {
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
template<typename Type>
|
||||
static constexpr bool value = std::is_reference_v<Type>;
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as-is_ policy. */
|
||||
struct as_is_t {};
|
||||
|
||||
struct as_is_t {
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
template<typename>
|
||||
static constexpr bool value = true;
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
};
|
||||
|
||||
/*! @brief Empty class type used to request the _as void_ policy. */
|
||||
struct as_void_t {};
|
||||
|
||||
|
||||
}
|
||||
struct as_void_t {
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
template<typename>
|
||||
static constexpr bool value = true;
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,68 @@
|
||||
#ifndef ENTT_META_RANGE_HPP
|
||||
#define ENTT_META_RANGE_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
#include "../core/iterator.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, typename Node>
|
||||
struct meta_range_iterator {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = Type;
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using node_type = Node;
|
||||
|
||||
meta_range_iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
meta_range_iterator(node_type *head) ENTT_NOEXCEPT
|
||||
: it{head} {}
|
||||
|
||||
meta_range_iterator &operator++() ENTT_NOEXCEPT {
|
||||
return (it = it->next), *this;
|
||||
}
|
||||
|
||||
meta_range_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
meta_range_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
||||
return it;
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const meta_range_iterator &other) const ENTT_NOEXCEPT {
|
||||
return it == other.it;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const meta_range_iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
node_type *it{};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Iterable range to use to iterate all types of meta objects.
|
||||
@@ -15,51 +70,13 @@ namespace entt {
|
||||
* @tparam Node Type of meta nodes iterated.
|
||||
*/
|
||||
template<typename Type, typename Node = typename Type::node_type>
|
||||
class meta_range {
|
||||
struct range_iterator {
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = Type;
|
||||
using pointer = void;
|
||||
using reference = value_type;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using node_type = Node;
|
||||
|
||||
range_iterator() ENTT_NOEXCEPT = default;
|
||||
|
||||
range_iterator(node_type *head) ENTT_NOEXCEPT
|
||||
: it{head}
|
||||
{}
|
||||
|
||||
range_iterator & operator++() ENTT_NOEXCEPT {
|
||||
return (it = it->next), *this;
|
||||
}
|
||||
|
||||
range_iterator operator++(int) ENTT_NOEXCEPT {
|
||||
range_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
|
||||
return it;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
|
||||
return other.it == it;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
node_type *it{};
|
||||
};
|
||||
|
||||
public:
|
||||
struct meta_range {
|
||||
/*! @brief Node type. */
|
||||
using node_type = Node;
|
||||
/*! @brief Input iterator type. */
|
||||
using iterator = range_iterator;
|
||||
using iterator = internal::meta_range_iterator<Type, Node>;
|
||||
/*! @brief Constant input iterator type. */
|
||||
using const_iterator = iterator;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
meta_range() ENTT_NOEXCEPT = default;
|
||||
@@ -69,32 +86,39 @@ public:
|
||||
* @param head The underlying node with which to construct the range.
|
||||
*/
|
||||
meta_range(node_type *head)
|
||||
: node{head}
|
||||
{}
|
||||
: node{head} {}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning.
|
||||
* @return An iterator to the first meta object of the range.
|
||||
*/
|
||||
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT {
|
||||
return iterator{node};
|
||||
}
|
||||
|
||||
/*! @copydoc cbegin */
|
||||
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end.
|
||||
* @return An iterator to the element following the last meta object of the
|
||||
* range.
|
||||
*/
|
||||
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT {
|
||||
return iterator{};
|
||||
}
|
||||
|
||||
/*! @copydoc cend */
|
||||
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
|
||||
return cend();
|
||||
}
|
||||
|
||||
private:
|
||||
node_type *node{nullptr};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef ENTT_META_RESOLVE_HPP
|
||||
#define ENTT_META_RESOLVE_HPP
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include "../core/type_info.hpp"
|
||||
#include "ctx.hpp"
|
||||
@@ -9,10 +8,8 @@
|
||||
#include "node.hpp"
|
||||
#include "range.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the meta type associated with a given type.
|
||||
* @tparam Type Type to use to search for a meta type.
|
||||
@@ -20,10 +17,9 @@ namespace entt {
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] meta_type resolve() ENTT_NOEXCEPT {
|
||||
return internal::meta_info<Type>::resolve();
|
||||
return internal::meta_node<std::remove_const_t<std::remove_reference_t<Type>>>::resolve();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns a range to use to visit all meta types.
|
||||
* @return An iterable range to use to visit all meta types.
|
||||
@@ -32,15 +28,14 @@ template<typename Type>
|
||||
return *internal::meta_context::global();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the meta type associated with a given identifier, if any.
|
||||
* @param id Unique identifier.
|
||||
* @return The meta type associated with the given identifier, if any.
|
||||
*/
|
||||
[[nodiscard]] inline meta_type resolve(const id_type id) ENTT_NOEXCEPT {
|
||||
for(auto *curr = *internal::meta_context::global(); curr; curr = curr->next) {
|
||||
if(curr->id == id) {
|
||||
for(auto &&curr: resolve()) {
|
||||
if(curr.id() == id) {
|
||||
return curr;
|
||||
}
|
||||
}
|
||||
@@ -48,16 +43,14 @@ template<typename Type>
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the meta type associated with a given type info object, if
|
||||
* any.
|
||||
* @brief Returns the meta type associated with a given type info object.
|
||||
* @param info The type info object of the requested type.
|
||||
* @return The meta type associated with the given type info object, if any.
|
||||
*/
|
||||
[[nodiscard]] inline meta_type resolve(const type_info info) ENTT_NOEXCEPT {
|
||||
for(auto *curr = *internal::meta_context::global(); curr; curr = curr->next) {
|
||||
if(curr->info == info) {
|
||||
[[nodiscard]] inline meta_type resolve(const type_info &info) ENTT_NOEXCEPT {
|
||||
for(auto &&curr: resolve()) {
|
||||
if(curr.info() == info) {
|
||||
return curr;
|
||||
}
|
||||
}
|
||||
@@ -65,8 +58,6 @@ template<typename Type>
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
#ifndef ENTT_META_TEMPLATE_HPP
|
||||
#define ENTT_META_TEMPLATE_HPP
|
||||
|
||||
|
||||
#include "../core/type_traits.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/*! @brief Utility class to disambiguate class templates. */
|
||||
template<template<typename...> typename>
|
||||
struct meta_class_template_tag {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief General purpose traits class for generating meta template information.
|
||||
* @tparam Clazz Type of class template.
|
||||
@@ -26,8 +22,6 @@ struct meta_template_traits<Clazz<Args...>> {
|
||||
using args_type = type_list<Args...>;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
#ifndef ENTT_META_TYPE_TRAITS_HPP
|
||||
#define ENTT_META_TYPE_TRAITS_HPP
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Traits class template to be specialized to enable support for meta
|
||||
* template information.
|
||||
@@ -15,7 +13,6 @@ namespace entt {
|
||||
template<typename>
|
||||
struct meta_template_traits;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Traits class template to be specialized to enable support for meta
|
||||
* sequence containers.
|
||||
@@ -23,7 +20,6 @@ struct meta_template_traits;
|
||||
template<typename>
|
||||
struct meta_sequence_container_traits;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Traits class template to be specialized to enable support for meta
|
||||
* associative containers.
|
||||
@@ -31,31 +27,6 @@ struct meta_sequence_container_traits;
|
||||
template<typename>
|
||||
struct meta_associative_container_traits;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a meta associative
|
||||
* container claims to wrap a key-only type, false otherwise.
|
||||
* @tparam Type Potentially key-only meta associative container type.
|
||||
*/
|
||||
template<typename, typename = void>
|
||||
struct is_key_only_meta_associative_container: std::true_type {};
|
||||
|
||||
|
||||
/*! @copydoc is_key_only_meta_associative_container */
|
||||
template<typename Type>
|
||||
struct is_key_only_meta_associative_container<Type, std::void_t<typename meta_associative_container_traits<Type>::type::mapped_type>>
|
||||
: std::false_type
|
||||
{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Potentially key-only meta associative container type.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr auto is_key_only_meta_associative_container_v = is_key_only_meta_associative_container<Type>::value;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is a
|
||||
* pointer-like type from the point of view of the meta system, false otherwise.
|
||||
@@ -64,7 +35,6 @@ inline constexpr auto is_key_only_meta_associative_container_v = is_key_only_met
|
||||
template<typename>
|
||||
struct is_meta_pointer_like: std::false_type {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Partial specialization to ensure that const pointer-like types are
|
||||
* also accepted.
|
||||
@@ -73,7 +43,6 @@ struct is_meta_pointer_like: std::false_type {};
|
||||
template<typename Type>
|
||||
struct is_meta_pointer_like<const Type>: is_meta_pointer_like<Type> {};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type Potentially pointer-like type.
|
||||
@@ -81,8 +50,6 @@ struct is_meta_pointer_like<const Type>: is_meta_pointer_like<Type> {};
|
||||
template<typename Type>
|
||||
inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like<Type>::value;
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef ENTT_META_UTILITY_HPP
|
||||
#define ENTT_META_UTILITY_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
@@ -12,15 +11,12 @@
|
||||
#include "node.hpp"
|
||||
#include "policy.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename, typename>
|
||||
struct meta_function_descriptor;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Meta function descriptor.
|
||||
* @tparam Type Reflected type to which the meta function is associated.
|
||||
@@ -29,19 +25,18 @@ struct meta_function_descriptor;
|
||||
* @tparam Args Function arguments.
|
||||
*/
|
||||
template<typename Type, typename Ret, typename Class, typename... Args>
|
||||
struct meta_function_descriptor<Type, Ret(Class:: *)(Args...) const> {
|
||||
struct meta_function_descriptor<Type, Ret (Class::*)(Args...) const> {
|
||||
/*! @brief Meta function return type. */
|
||||
using return_type = Ret;
|
||||
/*! @brief Meta function arguments. */
|
||||
using args_type = std::conditional_t<std::is_same_v<Type, Class>, type_list<Args...>, type_list<const Class &, Args...>>;
|
||||
using args_type = std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<const Class &, Args...>>;
|
||||
|
||||
/*! @brief True if the meta function is const, false otherwise. */
|
||||
static constexpr auto is_const = true;
|
||||
/*! @brief True if the meta function is static, false otherwise. */
|
||||
static constexpr auto is_static = !std::is_same_v<Type, Class>;
|
||||
static constexpr auto is_static = !std::is_base_of_v<Class, Type>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Meta function descriptor.
|
||||
* @tparam Type Reflected type to which the meta function is associated.
|
||||
@@ -50,31 +45,68 @@ struct meta_function_descriptor<Type, Ret(Class:: *)(Args...) const> {
|
||||
* @tparam Args Function arguments.
|
||||
*/
|
||||
template<typename Type, typename Ret, typename Class, typename... Args>
|
||||
struct meta_function_descriptor<Type, Ret(Class:: *)(Args...)> {
|
||||
struct meta_function_descriptor<Type, Ret (Class::*)(Args...)> {
|
||||
/*! @brief Meta function return type. */
|
||||
using return_type = Ret;
|
||||
/*! @brief Meta function arguments. */
|
||||
using args_type = std::conditional_t<std::is_same_v<Type, Class>, type_list<Args...>, type_list<Class &, Args...>>;
|
||||
using args_type = std::conditional_t<std::is_base_of_v<Class, Type>, type_list<Args...>, type_list<Class &, Args...>>;
|
||||
|
||||
/*! @brief True if the meta function is const, false otherwise. */
|
||||
static constexpr auto is_const = false;
|
||||
/*! @brief True if the meta function is static, false otherwise. */
|
||||
static constexpr auto is_static = !std::is_same_v<Type, Class>;
|
||||
static constexpr auto is_static = !std::is_base_of_v<Class, Type>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Meta function descriptor.
|
||||
* @tparam Type Reflected type to which the meta data is associated.
|
||||
* @tparam Class Actual owner of the data member.
|
||||
* @tparam Ret Data member type.
|
||||
*/
|
||||
template<typename Type, typename Ret, typename Class>
|
||||
struct meta_function_descriptor<Type, Ret Class::*> {
|
||||
/*! @brief Meta data return type. */
|
||||
using return_type = Ret &;
|
||||
/*! @brief Meta data arguments. */
|
||||
using args_type = std::conditional_t<std::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>;
|
||||
|
||||
/*! @brief True if the meta data is const, false otherwise. */
|
||||
static constexpr auto is_const = false;
|
||||
/*! @brief True if the meta data is static, false otherwise. */
|
||||
static constexpr auto is_static = !std::is_base_of_v<Class, Type>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Meta function descriptor.
|
||||
* @tparam Type Reflected type to which the meta function is associated.
|
||||
* @tparam Ret Function return type.
|
||||
* @tparam Args Function arguments.
|
||||
* @tparam MaybeType First function argument.
|
||||
* @tparam Args Other function arguments.
|
||||
*/
|
||||
template<typename Type, typename Ret, typename... Args>
|
||||
struct meta_function_descriptor<Type, Ret(*)(Args...)> {
|
||||
template<typename Type, typename Ret, typename MaybeType, typename... Args>
|
||||
struct meta_function_descriptor<Type, Ret (*)(MaybeType, Args...)> {
|
||||
/*! @brief Meta function return type. */
|
||||
using return_type = Ret;
|
||||
/*! @brief Meta function arguments. */
|
||||
using args_type = type_list<Args...>;
|
||||
using args_type = std::conditional_t<std::is_base_of_v<std::remove_const_t<std::remove_reference_t<MaybeType>>, Type>, type_list<Args...>, type_list<MaybeType, Args...>>;
|
||||
|
||||
/*! @brief True if the meta function is const, false otherwise. */
|
||||
static constexpr auto is_const = std::is_base_of_v<std::remove_const_t<std::remove_reference_t<MaybeType>>, Type> && std::is_const_v<std::remove_reference_t<MaybeType>>;
|
||||
/*! @brief True if the meta function is static, false otherwise. */
|
||||
static constexpr auto is_static = !std::is_base_of_v<std::remove_const_t<std::remove_reference_t<MaybeType>>, Type>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Meta function descriptor.
|
||||
* @tparam Type Reflected type to which the meta function is associated.
|
||||
* @tparam Ret Function return type.
|
||||
*/
|
||||
template<typename Type, typename Ret>
|
||||
struct meta_function_descriptor<Type, Ret (*)()> {
|
||||
/*! @brief Meta function return type. */
|
||||
using return_type = Ret;
|
||||
/*! @brief Meta function arguments. */
|
||||
using args_type = type_list<>;
|
||||
|
||||
/*! @brief True if the meta function is const, false otherwise. */
|
||||
static constexpr auto is_const = false;
|
||||
@@ -82,7 +114,6 @@ struct meta_function_descriptor<Type, Ret(*)(Args...)> {
|
||||
static constexpr auto is_static = true;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Meta function helper.
|
||||
*
|
||||
@@ -95,20 +126,25 @@ struct meta_function_descriptor<Type, Ret(*)(Args...)> {
|
||||
template<typename Type, typename Candidate>
|
||||
class meta_function_helper {
|
||||
template<typename Ret, typename... Args, typename Class>
|
||||
static constexpr meta_function_descriptor<Type, Ret(Class:: *)(Args...) const> get_rid_of_noexcept(Ret(Class:: *)(Args...) const);
|
||||
static constexpr meta_function_descriptor<Type, Ret (Class::*)(Args...) const> get_rid_of_noexcept(Ret (Class::*)(Args...) const);
|
||||
|
||||
template<typename Ret, typename... Args, typename Class>
|
||||
static constexpr meta_function_descriptor<Type, Ret(Class:: *)(Args...)> get_rid_of_noexcept(Ret(Class:: *)(Args...));
|
||||
static constexpr meta_function_descriptor<Type, Ret (Class::*)(Args...)> get_rid_of_noexcept(Ret (Class::*)(Args...));
|
||||
|
||||
template<typename Ret, typename Class>
|
||||
static constexpr meta_function_descriptor<Type, Ret Class::*> get_rid_of_noexcept(Ret Class::*);
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
static constexpr meta_function_descriptor<Type, Ret(*)(Args...)> get_rid_of_noexcept(Ret(*)(Args...));
|
||||
static constexpr meta_function_descriptor<Type, Ret (*)(Args...)> get_rid_of_noexcept(Ret (*)(Args...));
|
||||
|
||||
template<typename Class>
|
||||
static constexpr meta_function_descriptor<Class, decltype(&Class::operator())> get_rid_of_noexcept(Class);
|
||||
|
||||
public:
|
||||
/*! @brief The meta function descriptor of the given function. */
|
||||
using type = decltype(get_rid_of_noexcept(std::declval<Candidate>()));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type Reflected type to which the meta function is associated.
|
||||
@@ -117,36 +153,38 @@ public:
|
||||
template<typename Type, typename Candidate>
|
||||
using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::type;
|
||||
|
||||
/**
|
||||
* @brief Wraps a value depending on the given policy.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @tparam Type Type of value to wrap.
|
||||
* @param value Value to wrap.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Policy = as_is_t, typename Type>
|
||||
meta_any meta_dispatch([[maybe_unused]] Type &&value) {
|
||||
if constexpr(std::is_same_v<Policy, as_void_t>) {
|
||||
return meta_any{std::in_place_type<void>};
|
||||
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
|
||||
return meta_any{std::in_place_type<Type>, std::forward<Type>(value)};
|
||||
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
|
||||
static_assert(std::is_lvalue_reference_v<Type>, "Invalid type");
|
||||
return meta_any{std::in_place_type<const std::remove_reference_t<Type> &>, std::as_const(value)};
|
||||
} else {
|
||||
static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
|
||||
return meta_any{std::forward<Type>(value)};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the meta type of the i-th element of a list of arguments.
|
||||
* @tparam Args Actual types of arguments.
|
||||
* @tparam Type Type list of the actual types of arguments.
|
||||
* @return The meta type of the i-th element of the list of arguments.
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] static meta_type meta_arg(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
|
||||
return internal::meta_arg_node(type_list<Args...>{}, index);
|
||||
template<typename Type>
|
||||
[[nodiscard]] static meta_type meta_arg(const std::size_t index) ENTT_NOEXCEPT {
|
||||
return internal::meta_arg_node(Type{}, index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Constructs an instance given a list of erased parameters, if possible.
|
||||
* @tparam Type Actual type of the instance to construct.
|
||||
* @tparam Args Types of arguments expected.
|
||||
* @tparam Index Indexes to use to extract erased arguments from their list.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
* @return A meta any containing the new instance, if any.
|
||||
*/
|
||||
template<typename Type, typename... Args, std::size_t... Index>
|
||||
[[nodiscard]] meta_any meta_construct(meta_any * const args, std::index_sequence<Index...>) {
|
||||
if(((args+Index)->allow_cast<Args>() && ...)) {
|
||||
return Type{(args+Index)->cast<Args>()...};
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Sets the value of a given variable.
|
||||
* @tparam Type Reflected type to which the variable is associated.
|
||||
@@ -158,25 +196,21 @@ template<typename Type, typename... Args, std::size_t... Index>
|
||||
template<typename Type, auto Data>
|
||||
[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
|
||||
if constexpr(!std::is_same_v<decltype(Data), Type> && !std::is_same_v<decltype(Data), std::nullptr_t>) {
|
||||
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
if constexpr(std::is_member_function_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Data)>;
|
||||
using data_type = type_list_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename descriptor::args_type>;
|
||||
using data_type = type_list_element_t<descriptor::is_static, typename descriptor::args_type>;
|
||||
|
||||
if(auto * const clazz = instance->try_cast<Type>(); clazz) {
|
||||
if(value.allow_cast<data_type>()) {
|
||||
std::invoke(Data, *clazz, value.cast<data_type>());
|
||||
return true;
|
||||
}
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
|
||||
std::invoke(Data, *clazz, value.cast<data_type>());
|
||||
return true;
|
||||
}
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
using data_type = std::remove_reference_t<decltype(std::declval<Type>().*Data)>;
|
||||
using data_type = std::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
|
||||
|
||||
if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
|
||||
if(auto * const clazz = instance->try_cast<Type>(); clazz) {
|
||||
if(value.allow_cast<data_type>()) {
|
||||
std::invoke(Data, clazz) = value.cast<data_type>();
|
||||
return true;
|
||||
}
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
|
||||
std::invoke(Data, *clazz) = value.cast<data_type>();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -194,7 +228,6 @@ template<typename Type, auto Data>
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Gets the value of a given variable.
|
||||
* @tparam Type Reflected type to which the variable is associated.
|
||||
@@ -205,92 +238,159 @@ template<typename Type, auto Data>
|
||||
*/
|
||||
template<typename Type, auto Data, typename Policy = as_is_t>
|
||||
[[nodiscard]] meta_any meta_getter([[maybe_unused]] meta_handle instance) {
|
||||
[[maybe_unused]] auto dispatch = [](auto &&value) {
|
||||
if constexpr(std::is_same_v<Policy, as_void_t>) {
|
||||
return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
|
||||
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
|
||||
return meta_any{std::reference_wrapper{std::forward<decltype(value)>(value)}};
|
||||
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
|
||||
return meta_any{std::cref(std::forward<decltype(value)>(value))};
|
||||
} else {
|
||||
static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
|
||||
return meta_any{std::forward<decltype(value)>(value)};
|
||||
}
|
||||
};
|
||||
if constexpr(std::is_member_pointer_v<decltype(Data)> || std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
|
||||
if constexpr(!std::is_array_v<std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Data), Type &>>>>) {
|
||||
if constexpr(std::is_invocable_v<decltype(Data), Type &>) {
|
||||
if(auto *clazz = instance->try_cast<Type>(); clazz) {
|
||||
return meta_dispatch<Policy>(std::invoke(Data, *clazz));
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
|
||||
auto * const clazz = instance->try_cast<std::conditional_t<std::is_invocable_v<decltype(Data), const Type &>, const Type, Type>>();
|
||||
return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
|
||||
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
|
||||
if constexpr(std::is_array_v<std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>>) {
|
||||
return meta_any{};
|
||||
} else {
|
||||
if(auto * clazz = instance->try_cast<Type>(); clazz) {
|
||||
return dispatch(std::invoke(Data, *clazz));
|
||||
} else {
|
||||
auto * fallback = instance->try_cast<const Type>();
|
||||
return fallback ? dispatch(std::invoke(Data, *fallback)) : meta_any{};
|
||||
if constexpr(std::is_invocable_v<decltype(Data), const Type &>) {
|
||||
if(auto *fallback = instance->try_cast<const Type>(); fallback) {
|
||||
return meta_dispatch<Policy>(std::invoke(Data, *fallback));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return meta_any{};
|
||||
} else if constexpr(std::is_pointer_v<decltype(Data)>) {
|
||||
if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
|
||||
return meta_any{};
|
||||
} else {
|
||||
return dispatch(*Data);
|
||||
return meta_dispatch<Policy>(*Data);
|
||||
}
|
||||
} else {
|
||||
return dispatch(Data);
|
||||
return meta_dispatch<Policy>(Data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Invokes a function given a list of erased parameters, if possible.
|
||||
* @tparam Type Reflected type to which the function is associated.
|
||||
* @tparam Candidate The actual function to invoke.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @tparam Index Indexes to use to extract erased arguments from their list.
|
||||
* @param instance An opaque instance of the underlying type, if required.
|
||||
* @param args Parameters to use to invoke the function.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
template<typename Type, auto Candidate, typename Policy = as_is_t, std::size_t... Index>
|
||||
[[nodiscard]] meta_any meta_invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence<Index...>) {
|
||||
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
|
||||
|
||||
auto dispatch = [](auto &&... params) {
|
||||
if constexpr(std::is_void_v<std::remove_cv_t<typename descriptor::return_type>> || std::is_same_v<Policy, as_void_t>) {
|
||||
std::invoke(Candidate, std::forward<decltype(params)>(params)...);
|
||||
return meta_any{std::in_place_type<void>};
|
||||
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
|
||||
return meta_any{std::reference_wrapper{std::invoke(Candidate, std::forward<decltype(params)>(params)...)}};
|
||||
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
|
||||
return meta_any{std::cref(std::invoke(Candidate, std::forward<decltype(params)>(params)...))};
|
||||
} else {
|
||||
static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
|
||||
return meta_any{std::invoke(Candidate, std::forward<decltype(params)>(params)...)};
|
||||
}
|
||||
};
|
||||
namespace internal {
|
||||
|
||||
if constexpr(std::is_invocable_v<decltype(Candidate), const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
|
||||
if(const auto * const clazz = instance->try_cast<const Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
template<typename Type, typename Policy, typename Candidate, typename... Args>
|
||||
[[nodiscard]] meta_any meta_invoke_with_args(Candidate &&candidate, Args &&...args) {
|
||||
if constexpr(std::is_same_v<std::invoke_result_t<decltype(candidate), Args...>, void>) {
|
||||
std::invoke(candidate, args...);
|
||||
return meta_any{std::in_place_type<void>};
|
||||
} else {
|
||||
return meta_dispatch<Policy>(std::invoke(candidate, args...));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type, typename Policy, typename Candidate, std::size_t... Index>
|
||||
[[nodiscard]] meta_any meta_invoke([[maybe_unused]] meta_handle instance, Candidate &&candidate, [[maybe_unused]] meta_any *args, std::index_sequence<Index...>) {
|
||||
using descriptor = meta_function_helper_t<Type, std::remove_reference_t<Candidate>>;
|
||||
|
||||
if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
|
||||
if(const auto *const clazz = instance->try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Type, Policy>(std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
} else if constexpr(std::is_invocable_v<decltype(Candidate), Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
|
||||
if(auto * const clazz = instance->try_cast<Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return dispatch(*clazz, (args+Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
} else if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
|
||||
if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Type, Policy>(std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
} else {
|
||||
if(((args+Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return dispatch((args+Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
|
||||
return meta_invoke_with_args<Type, Policy>(std::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
|
||||
}
|
||||
}
|
||||
|
||||
return meta_any{};
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args, std::size_t... Index>
|
||||
[[nodiscard]] meta_any meta_construct(meta_any *const args, std::index_sequence<Index...>) {
|
||||
if(((args + Index)->allow_cast<Args>() && ...)) {
|
||||
return meta_any{std::in_place_type<Type>, (args + Index)->cast<Args>()...};
|
||||
}
|
||||
|
||||
return meta_any{};
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Tries to _invoke_ an object given a list of erased parameters.
|
||||
* @tparam Type Reflected type to which the object to _invoke_ is associated.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @tparam Candidate The type of the actual object to _invoke_.
|
||||
* @param instance An opaque instance of the underlying type, if required.
|
||||
* @param candidate The actual object to _invoke_.
|
||||
* @param args Parameters to use to _invoke_ the object.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
[[nodiscard]] meta_any meta_invoke([[maybe_unused]] meta_handle instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args) {
|
||||
return internal::meta_invoke<Type, Policy>(std::move(instance), std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to invoke a function given a list of erased parameters.
|
||||
* @tparam Type Reflected type to which the function is associated.
|
||||
* @tparam Candidate The actual function to invoke.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param instance An opaque instance of the underlying type, if required.
|
||||
* @param args Parameters to use to invoke the function.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, auto Candidate, typename Policy = as_is_t>
|
||||
[[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) {
|
||||
return internal::meta_invoke<Type, Policy>(std::move(instance), Candidate, args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to construct an instance given a list of erased parameters.
|
||||
* @tparam Type Actual type of the instance to construct.
|
||||
* @tparam Args Types of arguments expected.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
* @return A meta any containing the new instance, if any.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
[[nodiscard]] meta_any meta_construct(meta_any *const args) {
|
||||
return internal::meta_construct<Type, Args...>(args, std::index_sequence_for<Args...>{});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to construct an instance given a list of erased parameters.
|
||||
* @tparam Type Reflected type to which the object to _invoke_ is associated.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @tparam Candidate The type of the actual object to _invoke_.
|
||||
* @param args Parameters to use to _invoke_ the object.
|
||||
* @param candidate The actual object to _invoke_.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, typename Policy = as_is_t, typename Candidate>
|
||||
[[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) {
|
||||
if constexpr(meta_function_helper_t<Type, Candidate>::is_static) {
|
||||
return internal::meta_invoke<Type, Policy>({}, std::forward<Candidate>(candidate), args, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
|
||||
} else {
|
||||
return internal::meta_invoke<Type, Policy>(*args, std::forward<Candidate>(candidate), args + 1u, std::make_index_sequence<meta_function_helper_t<Type, std::remove_reference_t<Candidate>>::args_type::size>{});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Tries to construct an instance given a list of erased parameters.
|
||||
* @tparam Type Reflected type to which the function is associated.
|
||||
* @tparam Candidate The actual function to invoke.
|
||||
* @tparam Policy Optional policy (no policy set by default).
|
||||
* @param args Parameters to use to invoke the function.
|
||||
* @return A meta any containing the returned value, if any.
|
||||
*/
|
||||
template<typename Type, auto Candidate, typename Policy = as_is_t>
|
||||
[[nodiscard]] meta_any meta_construct(meta_any *const args) {
|
||||
return meta_construct<Type, Policy>(Candidate, args);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,37 +1,29 @@
|
||||
#ifndef ENTT_PLATFORM_ANDROID_NDK_R17_HPP
|
||||
#define ENTT_PLATFORM_ANDROID_NDK_R17_HPP
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/ndk-version.h>
|
||||
#if __NDK_MAJOR__ == 17
|
||||
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
# include <android/ndk-version.h>
|
||||
# if __NDK_MAJOR__ == 17
|
||||
|
||||
# include <functional>
|
||||
# include <type_traits>
|
||||
# include <utility>
|
||||
|
||||
namespace std {
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename Func, typename... Args>
|
||||
constexpr auto is_invocable(int) -> decltype(std::invoke(std::declval<Func>(), std::declval<Args>()...), std::true_type{});
|
||||
|
||||
|
||||
template<typename, typename...>
|
||||
constexpr std::false_type is_invocable(...);
|
||||
|
||||
|
||||
template<typename Ret, typename Func, typename... Args>
|
||||
constexpr auto is_invocable_r(int)
|
||||
-> std::enable_if_t<decltype(std::is_convertible_v<decltype(std::invoke(std::declval<Func>(), std::declval<Args>()...)), Ret>, std::true_type>;
|
||||
@@ -40,47 +32,36 @@ constexpr auto is_invocable_r(int)
|
||||
template<typename, typename, typename...>
|
||||
constexpr std::false_type is_invocable_r(...);
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template<typename Func, typename... Args>
|
||||
struct is_invocable: decltype(internal::is_invocable<Func, Args...>(0)) {};
|
||||
|
||||
|
||||
template<typename Func, typename... Argsv>
|
||||
inline constexpr bool is_invocable_v = std::is_invocable<Func, Args...>::value;
|
||||
|
||||
|
||||
template<typename Ret, typename Func, typename... Args>
|
||||
struct is_invocable_r: decltype(internal::is_invocable_r<Ret, Func, Args...>(0)) {};
|
||||
|
||||
|
||||
template<typename Ret, typename Func, typename... Args>
|
||||
inline constexpr bool is_invocable_r_v = std::is_invocable_r<Ret, Func, Args...>::value;
|
||||
|
||||
|
||||
template<typename Func, typename...Args>
|
||||
template<typename Func, typename... Args>
|
||||
struct invoke_result {
|
||||
using type = decltype(std::invoke(std::declval<Func>(), std::declval<Args>()...));
|
||||
};
|
||||
|
||||
|
||||
template<typename Func, typename... Args>
|
||||
using invoke_result_t = typename std::invoke_result<Func, Args...>::type;
|
||||
|
||||
} // namespace std
|
||||
|
||||
}
|
||||
|
||||
|
||||
# endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
#ifndef ENTT_POLY_FWD_HPP
|
||||
#define ENTT_POLY_FWD_HPP
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
template<typename, std::size_t Len, std::size_t = alignof(typename std::aligned_storage_t<Len + !Len>)>
|
||||
class basic_poly;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Concept Concept descriptor.
|
||||
@@ -19,8 +15,6 @@ class basic_poly;
|
||||
template<typename Concept>
|
||||
using poly = basic_poly<Concept, sizeof(double[2])>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef ENTT_POLY_POLY_HPP
|
||||
#define ENTT_POLY_POLY_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
@@ -13,17 +12,15 @@
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/*! @brief Inspector class used to infer the type of the virtual table. */
|
||||
struct poly_inspector {
|
||||
/**
|
||||
* @brief Generic conversion operator (definition only).
|
||||
* @tparam Type Type to which conversion is requested.
|
||||
*/
|
||||
template <class Type>
|
||||
template<class Type>
|
||||
operator Type &&() const;
|
||||
|
||||
/**
|
||||
@@ -34,14 +31,13 @@ struct poly_inspector {
|
||||
* @return A poly inspector convertible to any type.
|
||||
*/
|
||||
template<auto Member, typename... Args>
|
||||
poly_inspector invoke(Args &&... args) const;
|
||||
poly_inspector invoke(Args &&...args) const;
|
||||
|
||||
/*! @copydoc invoke */
|
||||
template<auto Member, typename... Args>
|
||||
poly_inspector invoke(Args &&... args);
|
||||
poly_inspector invoke(Args &&...args);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Static virtual table factory.
|
||||
* @tparam Concept Concept descriptor.
|
||||
@@ -53,35 +49,35 @@ class poly_vtable {
|
||||
using inspector = typename Concept::template type<poly_inspector>;
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
static auto vtable_entry(Ret(*)(inspector &, Args...)) -> Ret(*)(basic_any<Len, Align> &, Args...);
|
||||
static auto vtable_entry(Ret (*)(inspector &, Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
static auto vtable_entry(Ret(*)(const inspector &, Args...)) -> Ret(*)(const basic_any<Len, Align> &, Args...);
|
||||
static auto vtable_entry(Ret (*)(const inspector &, Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
static auto vtable_entry(Ret(*)(Args...)) -> Ret(*)(const basic_any<Len, Align> &, Args...);
|
||||
static auto vtable_entry(Ret (*)(Args...)) -> Ret (*)(const basic_any<Len, Align> &, Args...);
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
static auto vtable_entry(Ret(inspector:: *)(Args...)) -> Ret(*)(basic_any<Len, Align> &, Args...);
|
||||
static auto vtable_entry(Ret (inspector::*)(Args...)) -> Ret (*)(basic_any<Len, Align> &, Args...);
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
static auto vtable_entry(Ret(inspector:: *)(Args...) const) -> Ret(*)(const basic_any<Len, Align> &, Args...);
|
||||
static auto vtable_entry(Ret (inspector::*)(Args...) const) -> Ret (*)(const basic_any<Len, Align> &, Args...);
|
||||
|
||||
template<auto... Candidate>
|
||||
static auto make_vtable(value_list<Candidate...>)
|
||||
-> decltype(std::make_tuple(vtable_entry(Candidate)...));
|
||||
-> decltype(std::make_tuple(vtable_entry(Candidate)...));
|
||||
|
||||
template<typename... Func>
|
||||
[[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) {
|
||||
if constexpr(sizeof...(Func) == 0) {
|
||||
[[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) {
|
||||
if constexpr(sizeof...(Func) == 0u) {
|
||||
return decltype(make_vtable(typename Concept::template impl<inspector>{})){};
|
||||
} else if constexpr((std::is_function_v<Func> && ...)) {
|
||||
return decltype(std::make_tuple(vtable_entry(std::declval<Func inspector:: *>())...)){};
|
||||
return decltype(std::make_tuple(vtable_entry(std::declval<Func inspector::*>())...)){};
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Type, auto Candidate, typename Ret, typename Any, typename... Args>
|
||||
static void fill_vtable_entry(Ret(* &entry)(Any &, Args...)) {
|
||||
static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) {
|
||||
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
|
||||
entry = +[](Any &, Args... args) -> Ret {
|
||||
return std::invoke(Candidate, std::forward<Args>(args)...);
|
||||
@@ -95,14 +91,17 @@ class poly_vtable {
|
||||
|
||||
template<typename Type, auto... Index>
|
||||
[[nodiscard]] static auto fill_vtable(std::index_sequence<Index...>) {
|
||||
type impl{};
|
||||
vtable_type impl{};
|
||||
(fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(std::get<Index>(impl)), ...);
|
||||
return impl;
|
||||
}
|
||||
|
||||
using vtable_type = decltype(make_vtable(Concept{}));
|
||||
static constexpr bool is_mono_v = std::tuple_size_v<vtable_type> == 1u;
|
||||
|
||||
public:
|
||||
/*! @brief Virtual table type. */
|
||||
using type = decltype(make_vtable(Concept{}));
|
||||
using type = std::conditional_t<is_mono_v, std::tuple_element_t<0u, vtable_type>, const vtable_type *>;
|
||||
|
||||
/**
|
||||
* @brief Returns a static virtual table for a specific concept and type.
|
||||
@@ -110,14 +109,18 @@ public:
|
||||
* @return A static virtual table for the given concept and type.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] static const auto * instance() {
|
||||
[[nodiscard]] static type instance() {
|
||||
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Type differs from its decayed form");
|
||||
static const auto vtable = fill_vtable<Type>(std::make_index_sequence<Concept::template impl<Type>::size>{});
|
||||
return &vtable;
|
||||
static const vtable_type vtable = fill_vtable<Type>(std::make_index_sequence<Concept::template impl<Type>::size>{});
|
||||
|
||||
if constexpr(is_mono_v) {
|
||||
return std::get<0>(vtable);
|
||||
} else {
|
||||
return &vtable;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Poly base class used to inject functionalities into concepts.
|
||||
* @tparam Poly The outermost poly class.
|
||||
@@ -133,20 +136,29 @@ struct poly_base {
|
||||
* @return The return value of the invoked function, if any.
|
||||
*/
|
||||
template<auto Member, typename... Args>
|
||||
[[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&... args) const {
|
||||
[[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&...args) const {
|
||||
const auto &poly = static_cast<const Poly &>(self);
|
||||
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
|
||||
|
||||
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
|
||||
return poly.vtable(poly.storage, std::forward<Args>(args)...);
|
||||
} else {
|
||||
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc invoke */
|
||||
template<auto Member, typename... Args>
|
||||
[[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&... args) {
|
||||
[[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) {
|
||||
auto &poly = static_cast<Poly &>(self);
|
||||
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
|
||||
|
||||
if constexpr(std::is_function_v<std::remove_pointer_t<decltype(poly.vtable)>>) {
|
||||
return poly.vtable(poly.storage, std::forward<Args>(args)...);
|
||||
} else {
|
||||
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Shortcut for calling `poly_base<Type>::invoke`.
|
||||
* @tparam Member Index of the function to invoke.
|
||||
@@ -157,11 +169,10 @@ struct poly_base {
|
||||
* @return The return value of the invoked function, if any.
|
||||
*/
|
||||
template<auto Member, typename Poly, typename... Args>
|
||||
decltype(auto) poly_call(Poly &&self, Args &&... args) {
|
||||
decltype(auto) poly_call(Poly &&self, Args &&...args) {
|
||||
return std::forward<Poly>(self).template invoke<Member>(self, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Static polymorphism made simple and within everyone's reach.
|
||||
*
|
||||
@@ -182,17 +193,16 @@ class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, L
|
||||
/*! @brief A poly base is allowed to snoop into a poly object. */
|
||||
friend struct poly_base<basic_poly>;
|
||||
|
||||
using vtable_type = typename poly_vtable<Concept, Len, Align>::type;
|
||||
|
||||
public:
|
||||
/*! @brief Concept type. */
|
||||
using concept_type = typename Concept::template type<poly_base<basic_poly>>;
|
||||
/*! @brief Virtual table type. */
|
||||
using vtable_type = typename poly_vtable<Concept, Len, Align>::type;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_poly() ENTT_NOEXCEPT
|
||||
: storage{},
|
||||
vtable{}
|
||||
{}
|
||||
vtable{} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a poly by directly initializing the new object.
|
||||
@@ -201,20 +211,9 @@ public:
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
explicit basic_poly(std::in_place_type_t<Type>, Args &&... args)
|
||||
explicit basic_poly(std::in_place_type_t<Type>, Args &&...args)
|
||||
: storage{std::in_place_type<Type>, std::forward<Args>(args)...},
|
||||
vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>()}
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Constructs a poly that holds an unmanaged object.
|
||||
* @tparam Type Type of object to use to initialize the poly.
|
||||
* @param value An instance of an object to use to initialize the poly.
|
||||
*/
|
||||
template<typename Type>
|
||||
basic_poly(std::reference_wrapper<Type> value)
|
||||
: basic_poly{std::in_place_type<Type &>, value.get()}
|
||||
{}
|
||||
vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>()} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a poly from a given value.
|
||||
@@ -223,40 +222,13 @@ public:
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, basic_poly>>>
|
||||
basic_poly(Type &&value) ENTT_NOEXCEPT
|
||||
: basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
|
||||
{}
|
||||
: basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @brief Returns the object type if any, `type_id<void>()` otherwise.
|
||||
* @return The object type if any, `type_id<void>()` otherwise.
|
||||
*/
|
||||
basic_poly(const basic_poly &other) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_poly(basic_poly &&other) ENTT_NOEXCEPT
|
||||
: basic_poly{}
|
||||
{
|
||||
swap(*this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assignment operator.
|
||||
* @param other The instance to assign from.
|
||||
* @return This poly object.
|
||||
*/
|
||||
basic_poly & operator=(basic_poly other) {
|
||||
swap(other, *this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the type of the contained object.
|
||||
* @return The type of the contained object, if any.
|
||||
*/
|
||||
[[nodiscard]] type_info type() const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] const type_info &type() const ENTT_NOEXCEPT {
|
||||
return storage.type();
|
||||
}
|
||||
|
||||
@@ -264,12 +236,12 @@ public:
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] const void * data() const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] const void *data() const ENTT_NOEXCEPT {
|
||||
return storage.data();
|
||||
}
|
||||
|
||||
/*! @copydoc data */
|
||||
[[nodiscard]] void * data() ENTT_NOEXCEPT {
|
||||
[[nodiscard]] void *data() ENTT_NOEXCEPT {
|
||||
return storage.data();
|
||||
}
|
||||
|
||||
@@ -280,13 +252,15 @@ public:
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
void emplace(Args &&... args) {
|
||||
*this = basic_poly{std::in_place_type<Type>, std::forward<Args>(args)...};
|
||||
void emplace(Args &&...args) {
|
||||
storage.template emplace<Type>(std::forward<Args>(args)...);
|
||||
vtable = poly_vtable<Concept, Len, Align>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>();
|
||||
}
|
||||
|
||||
/*! @brief Destroys contained object */
|
||||
void reset() {
|
||||
*this = basic_poly{};
|
||||
storage.reset();
|
||||
vtable = {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,40 +268,30 @@ public:
|
||||
* @return False if the poly is empty, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
|
||||
return !(vtable == nullptr);
|
||||
return static_cast<bool>(storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the underlying concept.
|
||||
* @return A pointer to the underlying concept.
|
||||
*/
|
||||
[[nodiscard]] concept_type * operator->() ENTT_NOEXCEPT {
|
||||
[[nodiscard]] concept_type *operator->() ENTT_NOEXCEPT {
|
||||
return this;
|
||||
}
|
||||
|
||||
/*! @copydoc operator-> */
|
||||
[[nodiscard]] const concept_type * operator->() const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] const concept_type *operator->() const ENTT_NOEXCEPT {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swaps two poly objects.
|
||||
* @param lhs A valid poly object.
|
||||
* @param rhs A valid poly object.
|
||||
*/
|
||||
friend void swap(basic_poly &lhs, basic_poly &rhs) {
|
||||
using std::swap;
|
||||
swap(lhs.storage, rhs.storage);
|
||||
swap(lhs.vtable, rhs.vtable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Aliasing constructor.
|
||||
* @return A poly that shares a reference to an unmanaged object.
|
||||
*/
|
||||
[[nodiscard]] basic_poly as_ref() ENTT_NOEXCEPT {
|
||||
basic_poly ref = std::as_const(*this).as_ref();
|
||||
basic_poly ref{};
|
||||
ref.storage = storage.as_ref();
|
||||
ref.vtable = vtable;
|
||||
return ref;
|
||||
}
|
||||
|
||||
@@ -341,11 +305,9 @@ public:
|
||||
|
||||
private:
|
||||
basic_any<Len, Align> storage;
|
||||
const vtable_type *vtable;
|
||||
vtable_type vtable;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#ifndef ENTT_PROCESS_PROCESS_HPP
|
||||
#define ENTT_PROCESS_PROCESS_HPP
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Base class for processes.
|
||||
*
|
||||
@@ -71,44 +69,44 @@ namespace entt {
|
||||
*/
|
||||
template<typename Derived, typename Delta>
|
||||
class process {
|
||||
enum class state: unsigned int {
|
||||
UNINITIALIZED = 0,
|
||||
RUNNING,
|
||||
PAUSED,
|
||||
SUCCEEDED,
|
||||
FAILED,
|
||||
ABORTED,
|
||||
FINISHED,
|
||||
REJECTED
|
||||
enum class state : std::uint8_t {
|
||||
uninitialized = 0,
|
||||
running,
|
||||
paused,
|
||||
succeeded,
|
||||
failed,
|
||||
aborted,
|
||||
finished,
|
||||
rejected
|
||||
};
|
||||
|
||||
template<typename Target = Derived>
|
||||
auto next(std::integral_constant<state, state::UNINITIALIZED>)
|
||||
-> decltype(std::declval<Target>().init(), void()) {
|
||||
auto next(std::integral_constant<state, state::uninitialized>)
|
||||
-> decltype(std::declval<Target>().init(), void()) {
|
||||
static_cast<Target *>(this)->init();
|
||||
}
|
||||
|
||||
template<typename Target = Derived>
|
||||
auto next(std::integral_constant<state, state::RUNNING>, Delta delta, void *data)
|
||||
-> decltype(std::declval<Target>().update(delta, data), void()) {
|
||||
auto next(std::integral_constant<state, state::running>, Delta delta, void *data)
|
||||
-> decltype(std::declval<Target>().update(delta, data), void()) {
|
||||
static_cast<Target *>(this)->update(delta, data);
|
||||
}
|
||||
|
||||
template<typename Target = Derived>
|
||||
auto next(std::integral_constant<state, state::SUCCEEDED>)
|
||||
-> decltype(std::declval<Target>().succeeded(), void()) {
|
||||
auto next(std::integral_constant<state, state::succeeded>)
|
||||
-> decltype(std::declval<Target>().succeeded(), void()) {
|
||||
static_cast<Target *>(this)->succeeded();
|
||||
}
|
||||
|
||||
template<typename Target = Derived>
|
||||
auto next(std::integral_constant<state, state::FAILED>)
|
||||
-> decltype(std::declval<Target>().failed(), void()) {
|
||||
auto next(std::integral_constant<state, state::failed>)
|
||||
-> decltype(std::declval<Target>().failed(), void()) {
|
||||
static_cast<Target *>(this)->failed();
|
||||
}
|
||||
|
||||
template<typename Target = Derived>
|
||||
auto next(std::integral_constant<state, state::ABORTED>)
|
||||
-> decltype(std::declval<Target>().aborted(), void()) {
|
||||
auto next(std::integral_constant<state, state::aborted>)
|
||||
-> decltype(std::declval<Target>().aborted(), void()) {
|
||||
static_cast<Target *>(this)->aborted();
|
||||
}
|
||||
|
||||
@@ -123,7 +121,7 @@ protected:
|
||||
*/
|
||||
void succeed() ENTT_NOEXCEPT {
|
||||
if(alive()) {
|
||||
current = state::SUCCEEDED;
|
||||
current = state::succeeded;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +133,7 @@ protected:
|
||||
*/
|
||||
void fail() ENTT_NOEXCEPT {
|
||||
if(alive()) {
|
||||
current = state::FAILED;
|
||||
current = state::failed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,8 +144,8 @@ protected:
|
||||
* running.
|
||||
*/
|
||||
void pause() ENTT_NOEXCEPT {
|
||||
if(current == state::RUNNING) {
|
||||
current = state::PAUSED;
|
||||
if(current == state::running) {
|
||||
current = state::paused;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,8 +156,8 @@ protected:
|
||||
* paused.
|
||||
*/
|
||||
void unpause() ENTT_NOEXCEPT {
|
||||
if(current == state::PAUSED) {
|
||||
current = state::RUNNING;
|
||||
if(current == state::paused) {
|
||||
current = state::running;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +180,7 @@ public:
|
||||
*/
|
||||
void abort(const bool immediately = false) {
|
||||
if(alive()) {
|
||||
current = state::ABORTED;
|
||||
current = state::aborted;
|
||||
|
||||
if(immediately) {
|
||||
tick({});
|
||||
@@ -195,15 +193,15 @@ public:
|
||||
* @return True if the process is still alive, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool alive() const ENTT_NOEXCEPT {
|
||||
return current == state::RUNNING || current == state::PAUSED;
|
||||
return current == state::running || current == state::paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a process is already terminated.
|
||||
* @return True if the process is terminated, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool dead() const ENTT_NOEXCEPT {
|
||||
return current == state::FINISHED;
|
||||
[[nodiscard]] bool finished() const ENTT_NOEXCEPT {
|
||||
return current == state::finished;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,7 +209,7 @@ public:
|
||||
* @return True if the process is paused, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool paused() const ENTT_NOEXCEPT {
|
||||
return current == state::PAUSED;
|
||||
return current == state::paused;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,7 +217,7 @@ public:
|
||||
* @return True if the process terminated with errors, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool rejected() const ENTT_NOEXCEPT {
|
||||
return current == state::REJECTED;
|
||||
return current == state::rejected;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -228,13 +226,13 @@ public:
|
||||
* @param data Optional data.
|
||||
*/
|
||||
void tick(const Delta delta, void *data = nullptr) {
|
||||
switch (current) {
|
||||
case state::UNINITIALIZED:
|
||||
next(std::integral_constant<state, state::UNINITIALIZED>{});
|
||||
current = state::RUNNING;
|
||||
switch(current) {
|
||||
case state::uninitialized:
|
||||
next(std::integral_constant<state, state::uninitialized>{});
|
||||
current = state::running;
|
||||
break;
|
||||
case state::RUNNING:
|
||||
next(std::integral_constant<state, state::RUNNING>{}, delta, data);
|
||||
case state::running:
|
||||
next(std::integral_constant<state, state::running>{}, delta, data);
|
||||
break;
|
||||
default:
|
||||
// suppress warnings
|
||||
@@ -243,17 +241,17 @@ public:
|
||||
|
||||
// if it's dead, it must be notified and removed immediately
|
||||
switch(current) {
|
||||
case state::SUCCEEDED:
|
||||
next(std::integral_constant<state, state::SUCCEEDED>{});
|
||||
current = state::FINISHED;
|
||||
case state::succeeded:
|
||||
next(std::integral_constant<state, state::succeeded>{});
|
||||
current = state::finished;
|
||||
break;
|
||||
case state::FAILED:
|
||||
next(std::integral_constant<state, state::FAILED>{});
|
||||
current = state::REJECTED;
|
||||
case state::failed:
|
||||
next(std::integral_constant<state, state::failed>{});
|
||||
current = state::rejected;
|
||||
break;
|
||||
case state::ABORTED:
|
||||
next(std::integral_constant<state, state::ABORTED>{});
|
||||
current = state::REJECTED;
|
||||
case state::aborted:
|
||||
next(std::integral_constant<state, state::aborted>{});
|
||||
current = state::rejected;
|
||||
break;
|
||||
default:
|
||||
// suppress warnings
|
||||
@@ -262,10 +260,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
state current{state::UNINITIALIZED};
|
||||
state current{state::uninitialized};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Adaptor for lambdas and functors to turn them into processes.
|
||||
*
|
||||
@@ -313,9 +310,8 @@ struct process_adaptor: process<process_adaptor<Func, Delta>, Delta>, private Fu
|
||||
* @param args Parameters to use to initialize the actual process.
|
||||
*/
|
||||
template<typename... Args>
|
||||
process_adaptor(Args &&... args)
|
||||
: Func{std::forward<Args>(args)...}
|
||||
{}
|
||||
process_adaptor(Args &&...args)
|
||||
: Func{std::forward<Args>(args)...} {}
|
||||
|
||||
/**
|
||||
* @brief Updates a process and its internal state if required.
|
||||
@@ -323,12 +319,14 @@ struct process_adaptor: process<process_adaptor<Func, Delta>, Delta>, private Fu
|
||||
* @param data Optional data.
|
||||
*/
|
||||
void update(const Delta delta, void *data) {
|
||||
Func::operator()(delta, data, [this]() { this->succeed(); }, [this]() { this->fail(); });
|
||||
Func::operator()(
|
||||
delta,
|
||||
data,
|
||||
[this]() { this->succeed(); },
|
||||
[this]() { this->fail(); });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
#ifndef ENTT_PROCESS_SCHEDULER_HPP
|
||||
#define ENTT_PROCESS_SCHEDULER_HPP
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "process.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Cooperative scheduler for processes.
|
||||
*
|
||||
@@ -43,7 +40,7 @@ namespace entt {
|
||||
template<typename Delta>
|
||||
class scheduler {
|
||||
struct process_handler {
|
||||
using instance_type = std::unique_ptr<void, void(*)(void *)>;
|
||||
using instance_type = std::unique_ptr<void, void (*)(void *)>;
|
||||
using update_fn_type = bool(process_handler &, Delta, void *);
|
||||
using abort_fn_type = void(process_handler &, bool);
|
||||
using next_type = std::unique_ptr<process_handler>;
|
||||
@@ -56,13 +53,10 @@ class scheduler {
|
||||
|
||||
struct continuation {
|
||||
continuation(process_handler *ref)
|
||||
: handler{ref}
|
||||
{
|
||||
ENTT_ASSERT(handler);
|
||||
}
|
||||
: handler{ref} {}
|
||||
|
||||
template<typename Proc, typename... Args>
|
||||
continuation then(Args &&... 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)...}, &scheduler::deleter<Proc>};
|
||||
handler->next.reset(new process_handler{std::move(proc), &scheduler::update<Proc>, &scheduler::abort<Proc>, nullptr});
|
||||
@@ -86,7 +80,7 @@ class scheduler {
|
||||
|
||||
if(process->rejected()) {
|
||||
return true;
|
||||
} else if(process->dead()) {
|
||||
} else if(process->finished()) {
|
||||
if(handler.next) {
|
||||
handler = std::move(*handler.next);
|
||||
// forces the process to exit the uninitialized state
|
||||
@@ -120,7 +114,7 @@ public:
|
||||
scheduler(scheduler &&) = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This scheduler. */
|
||||
scheduler & operator=(scheduler &&) = default;
|
||||
scheduler &operator=(scheduler &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Number of processes currently scheduled.
|
||||
@@ -174,7 +168,7 @@ public:
|
||||
* @return An opaque object to use to concatenate processes.
|
||||
*/
|
||||
template<typename Proc, typename... Args>
|
||||
auto attach(Args &&... args) {
|
||||
auto 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)...}, &scheduler::deleter<Proc>};
|
||||
process_handler handler{std::move(proc), &scheduler::update<Proc>, &scheduler::abort<Proc>, nullptr};
|
||||
@@ -255,7 +249,7 @@ public:
|
||||
auto sz = handlers.size();
|
||||
|
||||
for(auto pos = handlers.size(); pos; --pos) {
|
||||
auto &handler = handlers[pos-1];
|
||||
auto &handler = handlers[pos - 1];
|
||||
|
||||
if(const auto dead = handler.update(handler, delta, data); dead) {
|
||||
std::swap(handler, handlers[--sz]);
|
||||
@@ -291,8 +285,6 @@ private:
|
||||
std::vector<process_handler> handlers{};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
#ifndef ENTT_RESOURCE_CACHE_HPP
|
||||
#define ENTT_RESOURCE_CACHE_HPP
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../container/dense_hash_map.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "handle.hpp"
|
||||
#include "loader.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Simple cache for resources of a given type.
|
||||
*
|
||||
@@ -26,7 +24,10 @@ namespace entt {
|
||||
* @tparam Resource Type of resources managed by a cache.
|
||||
*/
|
||||
template<typename Resource>
|
||||
struct resource_cache {
|
||||
class resource_cache {
|
||||
static_assert(std::is_same_v<Resource, std::remove_const_t<std::remove_reference_t<Resource>>>, "Invalid resource type");
|
||||
|
||||
public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Type of resources managed by a cache. */
|
||||
@@ -39,7 +40,7 @@ struct resource_cache {
|
||||
resource_cache(resource_cache &&) = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This cache. */
|
||||
resource_cache & operator=(resource_cache &&) = default;
|
||||
resource_cache &operator=(resource_cache &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Number of resources managed by a cache.
|
||||
@@ -90,9 +91,7 @@ struct resource_cache {
|
||||
* @return A handle for the given resource.
|
||||
*/
|
||||
template<typename Loader, typename... Args>
|
||||
resource_handle<Resource> load(const id_type id, Args &&... args) {
|
||||
static_assert(std::is_base_of_v<resource_loader<Loader, Resource>, Loader>, "Invalid loader type");
|
||||
|
||||
resource_handle<resource_type> load(const id_type id, Args &&...args) {
|
||||
if(auto it = resources.find(id); it == resources.cend()) {
|
||||
if(auto handle = temp<Loader>(std::forward<Args>(args)...); handle) {
|
||||
return (resources[id] = std::move(handle));
|
||||
@@ -128,7 +127,7 @@ struct resource_cache {
|
||||
* @return A handle for the given resource.
|
||||
*/
|
||||
template<typename Loader, typename... Args>
|
||||
resource_handle<Resource> reload(const id_type id, Args &&... args) {
|
||||
resource_handle<resource_type> reload(const id_type id, Args &&...args) {
|
||||
return (discard(id), load<Loader>(id, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
@@ -145,7 +144,7 @@ struct resource_cache {
|
||||
* @return A handle for the given resource.
|
||||
*/
|
||||
template<typename Loader, typename... Args>
|
||||
[[nodiscard]] resource_handle<Resource> temp(Args &&... args) const {
|
||||
[[nodiscard]] resource_handle<resource_type> temp(Args &&...args) const {
|
||||
return Loader{}.get(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -162,7 +161,7 @@ struct resource_cache {
|
||||
* @param id Unique resource identifier.
|
||||
* @return A handle for the given resource.
|
||||
*/
|
||||
[[nodiscard]] resource_handle<Resource> handle(const id_type id) const {
|
||||
[[nodiscard]] resource_handle<const resource_type> handle(const id_type id) const {
|
||||
if(auto it = resources.find(id); it != resources.cend()) {
|
||||
return it->second;
|
||||
}
|
||||
@@ -170,6 +169,15 @@ struct resource_cache {
|
||||
return {};
|
||||
}
|
||||
|
||||
/*! @copydoc handle */
|
||||
[[nodiscard]] resource_handle<resource_type> handle(const id_type id) {
|
||||
if(auto it = resources.find(id); it != resources.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a cache contains a given identifier.
|
||||
* @param id Unique resource identifier.
|
||||
@@ -203,14 +211,14 @@ struct resource_cache {
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(const entt::id_type);
|
||||
* void(entt::resource_handle<Resource>);
|
||||
* void(const entt::id_type, entt::resource_handle<Resource>);
|
||||
* void(entt::resource_handle<const resource_type>);
|
||||
* void(const entt::id_type, entt::resource_handle<const resource_type>);
|
||||
* @endcode
|
||||
*
|
||||
* @tparam Func Type of the function object to invoke.
|
||||
* @param func A valid function object.
|
||||
*/
|
||||
template <typename Func>
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
auto begin = resources.begin();
|
||||
auto end = resources.end();
|
||||
@@ -220,7 +228,42 @@ struct resource_cache {
|
||||
|
||||
if constexpr(std::is_invocable_v<Func, id_type>) {
|
||||
func(curr->first);
|
||||
} else if constexpr(std::is_invocable_v<Func, resource_handle<Resource>>) {
|
||||
} else if constexpr(std::is_invocable_v<Func, resource_handle<const resource_type>>) {
|
||||
func(resource_handle<const resource_type>{curr->second});
|
||||
} else {
|
||||
func(curr->first, resource_handle<const resource_type>{curr->second});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @copybrief each
|
||||
*
|
||||
* The function object is invoked for each element. It is provided with
|
||||
* either the resource identifier, the resource handle or both of them.<br/>
|
||||
* The signature of the function must be equivalent to one of the following
|
||||
* forms:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(const entt::id_type);
|
||||
* void(entt::resource_handle<resource_type>);
|
||||
* void(const entt::id_type, entt::resource_handle<resource_type>);
|
||||
* @endcode
|
||||
*
|
||||
* @tparam Func Type of the function object to invoke.
|
||||
* @param func A valid function object.
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) {
|
||||
auto begin = resources.begin();
|
||||
auto end = resources.end();
|
||||
|
||||
while(begin != end) {
|
||||
auto curr = begin++;
|
||||
|
||||
if constexpr(std::is_invocable_v<Func, id_type>) {
|
||||
func(curr->first);
|
||||
} else if constexpr(std::is_invocable_v<Func, resource_handle<resource_type>>) {
|
||||
func(curr->second);
|
||||
} else {
|
||||
func(curr->first, curr->second);
|
||||
@@ -229,11 +272,9 @@ struct resource_cache {
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<id_type, resource_handle<Resource>> resources;
|
||||
dense_hash_map<id_type, resource_handle<resource_type>, identity> resources;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,23 +1,17 @@
|
||||
#ifndef ENTT_RESOURCE_FWD_HPP
|
||||
#define ENTT_RESOURCE_FWD_HPP
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<typename>
|
||||
class resource_cache;
|
||||
|
||||
template<typename>
|
||||
struct resource_cache;
|
||||
|
||||
|
||||
template<typename>
|
||||
struct resource_handle;
|
||||
|
||||
class resource_handle;
|
||||
|
||||
template<typename, typename>
|
||||
class resource_loader;
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#ifndef ENTT_RESOURCE_HANDLE_HPP
|
||||
#define ENTT_RESOURCE_HANDLE_HPP
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "fwd.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Shared resource handle.
|
||||
*
|
||||
@@ -24,7 +22,17 @@ namespace entt {
|
||||
* @tparam Resource Type of resource managed by a handle.
|
||||
*/
|
||||
template<typename Resource>
|
||||
struct resource_handle {
|
||||
class resource_handle {
|
||||
/*! @brief Resource handles are friends with each other. */
|
||||
template<typename>
|
||||
friend class resource_handle;
|
||||
|
||||
public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = long;
|
||||
/*! @brief Type of resources managed by a cache. */
|
||||
using resource_type = Resource;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
resource_handle() ENTT_NOEXCEPT = default;
|
||||
|
||||
@@ -32,9 +40,88 @@ struct resource_handle {
|
||||
* @brief Creates a handle from a shared pointer, namely a resource.
|
||||
* @param res A pointer to a properly initialized resource.
|
||||
*/
|
||||
resource_handle(std::shared_ptr<Resource> res) ENTT_NOEXCEPT
|
||||
: resource{std::move(res)}
|
||||
{}
|
||||
resource_handle(std::shared_ptr<resource_type> res) ENTT_NOEXCEPT
|
||||
: resource{std::move(res)} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
resource_handle(const resource_handle &other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
resource_handle(resource_handle &&other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Aliasing constructor.
|
||||
* @tparam Other Type of resource managed by the received handle.
|
||||
* @param other The handle with which to share ownership information.
|
||||
* @param res Unrelated and unmanaged resources.
|
||||
*/
|
||||
template<typename Other>
|
||||
resource_handle(const resource_handle<Other> &other, resource_type &res) noexcept
|
||||
: resource{other.resource, std::addressof(res)} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructs a handle which shares ownership of the resource.
|
||||
* @tparam Other Type of resource managed by the received handle.
|
||||
* @param other The handle to copy from.
|
||||
*/
|
||||
template<typename Other, typename = std::enable_if_t<!std::is_same_v<resource_type, Other> && std::is_base_of_v<resource_type, Other>>>
|
||||
resource_handle(const resource_handle<Other> &other) ENTT_NOEXCEPT
|
||||
: resource{other.resource} {}
|
||||
|
||||
/**
|
||||
* @brief Move constructs a handle which takes ownership of the resource.
|
||||
* @tparam Other Type of resource managed by the received handle.
|
||||
* @param other The handle to move from.
|
||||
*/
|
||||
template<typename Other, typename = std::enable_if_t<!std::is_same_v<resource_type, Other> && std::is_base_of_v<resource_type, Other>>>
|
||||
resource_handle(resource_handle<Other> &&other) ENTT_NOEXCEPT
|
||||
: resource{std::move(other.resource)} {}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This resource handle.
|
||||
*/
|
||||
resource_handle &operator=(const resource_handle &other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This resource handle.
|
||||
*/
|
||||
resource_handle &operator=(resource_handle &&other) ENTT_NOEXCEPT = default;
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator from foreign handle.
|
||||
* @tparam Other Type of resource managed by the received handle.
|
||||
* @param other The handle to copy from.
|
||||
* @return This resource handle.
|
||||
*/
|
||||
template<typename Other>
|
||||
std::enable_if_t<!std::is_same_v<resource_type, Other> && std::is_base_of_v<resource_type, Other>, resource_handle &>
|
||||
operator=(const resource_handle<Other> &other) ENTT_NOEXCEPT {
|
||||
resource = other.resource;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator from foreign handle.
|
||||
* @tparam Other Type of resource managed by the received handle.
|
||||
* @param other The handle to move from.
|
||||
* @return This resource handle.
|
||||
*/
|
||||
template<typename Other>
|
||||
std::enable_if_t<!std::is_same_v<resource_type, Other> && std::is_base_of_v<resource_type, Other>, resource_handle &>
|
||||
operator=(resource_handle<Other> &&other) ENTT_NOEXCEPT {
|
||||
resource = std::move(other.resource);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a reference to the managed resource.
|
||||
@@ -44,33 +131,17 @@ struct resource_handle {
|
||||
*
|
||||
* @return A reference to the managed resource.
|
||||
*/
|
||||
[[nodiscard]] const Resource & get() const ENTT_NOEXCEPT {
|
||||
ENTT_ASSERT(static_cast<bool>(resource));
|
||||
[[nodiscard]] resource_type &get() const ENTT_NOEXCEPT {
|
||||
return *resource;
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
[[nodiscard]] Resource & get() ENTT_NOEXCEPT {
|
||||
return const_cast<Resource &>(std::as_const(*this).get());
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
[[nodiscard]] operator const Resource & () const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] operator resource_type &() const ENTT_NOEXCEPT {
|
||||
return get();
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
[[nodiscard]] operator Resource & () ENTT_NOEXCEPT {
|
||||
return get();
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
[[nodiscard]] const Resource & operator *() const ENTT_NOEXCEPT {
|
||||
return get();
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
[[nodiscard]] Resource & operator *() ENTT_NOEXCEPT {
|
||||
[[nodiscard]] resource_type &operator*() const ENTT_NOEXCEPT {
|
||||
return get();
|
||||
}
|
||||
|
||||
@@ -83,16 +154,10 @@ struct resource_handle {
|
||||
* @return A pointer to the managed resource or `nullptr` if the handle
|
||||
* contains no resource at all.
|
||||
*/
|
||||
[[nodiscard]] const Resource * operator->() const ENTT_NOEXCEPT {
|
||||
ENTT_ASSERT(static_cast<bool>(resource));
|
||||
[[nodiscard]] resource_type *operator->() const ENTT_NOEXCEPT {
|
||||
return resource.get();
|
||||
}
|
||||
|
||||
/*! @copydoc operator-> */
|
||||
[[nodiscard]] Resource * operator->() ENTT_NOEXCEPT {
|
||||
return const_cast<Resource *>(std::as_const(*this).operator->());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a handle contains a resource, false otherwise.
|
||||
* @return True if the handle contains a resource, false otherwise.
|
||||
@@ -101,12 +166,18 @@ struct resource_handle {
|
||||
return static_cast<bool>(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of handles pointing the same resource.
|
||||
* @return The number of handles pointing the same resource.
|
||||
*/
|
||||
[[nodiscard]] size_type use_count() const ENTT_NOEXCEPT {
|
||||
return resource.use_count();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Resource> resource;
|
||||
std::shared_ptr<resource_type> resource;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
#ifndef ENTT_RESOURCE_LOADER_HPP
|
||||
#define ENTT_RESOURCE_LOADER_HPP
|
||||
|
||||
|
||||
#include "fwd.hpp"
|
||||
#include "handle.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Base class for resource loaders.
|
||||
*
|
||||
@@ -44,7 +41,8 @@ namespace entt {
|
||||
template<typename Loader, typename Resource>
|
||||
class resource_loader {
|
||||
/*! @brief Resource loaders are friends of their caches. */
|
||||
friend struct resource_cache<Resource>;
|
||||
template<typename Other>
|
||||
friend class resource_cache;
|
||||
|
||||
/**
|
||||
* @brief Loads the resource and returns it.
|
||||
@@ -53,13 +51,11 @@ class resource_loader {
|
||||
* @return The resource just loaded or an empty pointer in case of errors.
|
||||
*/
|
||||
template<typename... Args>
|
||||
[[nodiscard]] resource_handle<Resource> get(Args &&... args) const {
|
||||
[[nodiscard]] resource_handle<Resource> get(Args &&...args) const {
|
||||
return static_cast<const Loader *>(this)->load(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,77 +1,61 @@
|
||||
#ifndef ENTT_SIGNAL_DELEGATE_HPP
|
||||
#define ENTT_SIGNAL_DELEGATE_HPP
|
||||
|
||||
|
||||
#include <tuple>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include "../core/type_traits.hpp"
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
#include "../core/type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
|
||||
namespace internal {
|
||||
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
|
||||
|
||||
auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...);
|
||||
|
||||
template<typename Ret, typename Type, typename... Args, typename Other>
|
||||
auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);
|
||||
|
||||
auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...);
|
||||
|
||||
template<typename Class, typename Ret, typename... Args, typename... Other>
|
||||
auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);
|
||||
|
||||
auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...);
|
||||
|
||||
template<typename Class, typename Ret, typename... Args, typename... Other>
|
||||
auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...);
|
||||
|
||||
auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...);
|
||||
|
||||
template<typename Class, typename Type, typename... Other>
|
||||
auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();
|
||||
|
||||
auto function_pointer(Type Class::*, Other &&...) -> Type (*)();
|
||||
|
||||
template<typename... Type>
|
||||
using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));
|
||||
|
||||
|
||||
template<typename... Class, typename Ret, typename... Args>
|
||||
[[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) {
|
||||
[[nodiscard]] constexpr auto index_sequence_for(Ret (*)(Args...)) {
|
||||
return std::index_sequence_for<Class..., Args...>{};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
|
||||
/*! @brief Used to wrap a function or a member of a specified type. */
|
||||
template<auto>
|
||||
struct connect_arg_t {};
|
||||
|
||||
|
||||
/*! @brief Constant of type connect_arg_t used to disambiguate calls. */
|
||||
template<auto Func>
|
||||
inline constexpr connect_arg_t<Func> connect_arg{};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic delegate implementation.
|
||||
*
|
||||
@@ -81,7 +65,6 @@ inline constexpr connect_arg_t<Func> connect_arg{};
|
||||
template<typename>
|
||||
class delegate;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Utility class to use to send around functions and members.
|
||||
*
|
||||
@@ -132,8 +115,8 @@ public:
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
delegate() ENTT_NOEXCEPT
|
||||
: fn{nullptr}, data{nullptr}
|
||||
{}
|
||||
: fn{nullptr},
|
||||
data{nullptr} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a delegate and connects a free function or an unbound
|
||||
@@ -271,7 +254,7 @@ public:
|
||||
* @brief Returns the instance or the payload linked to a delegate, if any.
|
||||
* @return An opaque pointer to the underlying data.
|
||||
*/
|
||||
[[nodiscard]] const void * instance() const ENTT_NOEXCEPT {
|
||||
[[nodiscard]] const void *instance() const ENTT_NOEXCEPT {
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -288,7 +271,7 @@ public:
|
||||
* @return The value returned by the underlying function.
|
||||
*/
|
||||
Ret operator()(Args... args) const {
|
||||
ENTT_ASSERT(static_cast<bool>(*this));
|
||||
ENTT_ASSERT(static_cast<bool>(*this), "Uninitialized delegate");
|
||||
return fn(data, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -315,7 +298,6 @@ private:
|
||||
const void *data;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares the contents of two delegates.
|
||||
* @tparam Ret Return type of a function type.
|
||||
@@ -329,15 +311,12 @@ template<typename Ret, typename... Args>
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Candidate Function or member to connect to the delegate.
|
||||
*/
|
||||
template<auto Candidate>
|
||||
delegate(connect_arg_t<Candidate>)
|
||||
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
|
||||
|
||||
delegate(connect_arg_t<Candidate>) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
@@ -345,9 +324,7 @@ delegate(connect_arg_t<Candidate>)
|
||||
* @tparam Type Type of class or type of payload.
|
||||
*/
|
||||
template<auto Candidate, typename Type>
|
||||
delegate(connect_arg_t<Candidate>, Type &&)
|
||||
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
|
||||
|
||||
delegate(connect_arg_t<Candidate>, Type &&) -> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
@@ -355,11 +332,8 @@ delegate(connect_arg_t<Candidate>, Type &&)
|
||||
* @tparam Args Types of arguments of a function type.
|
||||
*/
|
||||
template<typename Ret, typename... Args>
|
||||
delegate(Ret(*)(const void *, Args...), const void * = nullptr)
|
||||
-> delegate<Ret(Args...)>;
|
||||
|
||||
|
||||
}
|
||||
delegate(Ret (*)(const void *, Args...), const void * = nullptr) -> delegate<Ret(Args...)>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
#ifndef ENTT_SIGNAL_DISPATCHER_HPP
|
||||
#define ENTT_SIGNAL_DISPATCHER_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../container/dense_hash_map.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "sigh.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Basic dispatcher implementation.
|
||||
*
|
||||
@@ -50,29 +49,29 @@ class dispatcher {
|
||||
signal.publish(events[pos]);
|
||||
}
|
||||
|
||||
events.erase(events.cbegin(), events.cbegin()+length);
|
||||
events.erase(events.cbegin(), events.cbegin() + length);
|
||||
}
|
||||
|
||||
void disconnect(void *instance) override {
|
||||
sink().disconnect(instance);
|
||||
bucket().disconnect(instance);
|
||||
}
|
||||
|
||||
void clear() ENTT_NOEXCEPT override {
|
||||
events.clear();
|
||||
}
|
||||
|
||||
[[nodiscard]] sink_type sink() ENTT_NOEXCEPT {
|
||||
return entt::sink{signal};
|
||||
[[nodiscard]] sink_type bucket() ENTT_NOEXCEPT {
|
||||
return sink_type{signal};
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void trigger(Args &&... args) {
|
||||
void trigger(Args &&...args) {
|
||||
Event instance{std::forward<Args>(args)...};
|
||||
signal.publish(instance);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void enqueue(Args &&... args) {
|
||||
void enqueue(Args &&...args) {
|
||||
if constexpr(std::is_aggregate_v<Event>) {
|
||||
events.push_back(Event{std::forward<Args>(args)...});
|
||||
} else {
|
||||
@@ -86,18 +85,14 @@ class dispatcher {
|
||||
};
|
||||
|
||||
template<typename Event>
|
||||
[[nodiscard]] pool_handler<Event> & assure() {
|
||||
const auto index = type_seq<Event>::value();
|
||||
|
||||
if(!(index < pools.size())) {
|
||||
pools.resize(std::size_t(index)+1u);
|
||||
[[nodiscard]] pool_handler<Event> &assure() {
|
||||
if(auto &&ptr = pools[type_hash<Event>::value()]; !ptr) {
|
||||
auto *cpool = new pool_handler<Event>{};
|
||||
ptr.reset(cpool);
|
||||
return *cpool;
|
||||
} else {
|
||||
return static_cast<pool_handler<Event> &>(*ptr);
|
||||
}
|
||||
|
||||
if(!pools[index]) {
|
||||
pools[index].reset(new pool_handler<Event>{});
|
||||
}
|
||||
|
||||
return static_cast<pool_handler<Event> &>(*pools[index]);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -108,7 +103,7 @@ public:
|
||||
dispatcher(dispatcher &&) = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This dispatcher. */
|
||||
dispatcher & operator=(dispatcher &&) = default;
|
||||
dispatcher &operator=(dispatcher &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object for the given event.
|
||||
@@ -129,7 +124,7 @@ public:
|
||||
*/
|
||||
template<typename Event>
|
||||
[[nodiscard]] auto sink() {
|
||||
return assure<Event>().sink();
|
||||
return assure<Event>().bucket();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +138,7 @@ public:
|
||||
* @param args Arguments to use to construct the event.
|
||||
*/
|
||||
template<typename Event, typename... Args>
|
||||
void trigger(Args &&... args) {
|
||||
void trigger(Args &&...args) {
|
||||
assure<Event>().trigger(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -172,7 +167,7 @@ public:
|
||||
* @param args Arguments to use to construct the event.
|
||||
*/
|
||||
template<typename Event, typename... Args>
|
||||
void enqueue(Args &&... args) {
|
||||
void enqueue(Args &&...args) {
|
||||
assure<Event>().enqueue(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
@@ -210,9 +205,7 @@ public:
|
||||
template<typename Type>
|
||||
void disconnect(Type *value_or_instance) {
|
||||
for(auto &&cpool: pools) {
|
||||
if(cpool) {
|
||||
cpool->disconnect(value_or_instance);
|
||||
}
|
||||
cpool.second->disconnect(value_or_instance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,9 +221,7 @@ public:
|
||||
void clear() {
|
||||
if constexpr(sizeof...(Event) == 0) {
|
||||
for(auto &&cpool: pools) {
|
||||
if(cpool) {
|
||||
cpool->clear();
|
||||
}
|
||||
cpool.second->clear();
|
||||
}
|
||||
} else {
|
||||
(assure<Event>().clear(), ...);
|
||||
@@ -259,19 +250,15 @@ public:
|
||||
* to reduce at a minimum the time spent in the bodies of the listeners.
|
||||
*/
|
||||
void update() const {
|
||||
for(auto pos = pools.size(); pos; --pos) {
|
||||
if(auto &&cpool = pools[pos-1]; cpool) {
|
||||
cpool->publish();
|
||||
}
|
||||
for(auto &&cpool: pools) {
|
||||
cpool.second->publish();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<basic_pool>> pools;
|
||||
dense_hash_map<id_type, std::unique_ptr<basic_pool>, identity> pools;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef ENTT_SIGNAL_EMITTER_HPP
|
||||
#define ENTT_SIGNAL_EMITTER_HPP
|
||||
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
@@ -9,15 +8,14 @@
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../container/dense_hash_map.hpp"
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_info.hpp"
|
||||
|
||||
#include "../core/utility.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief General purpose event emitter.
|
||||
*
|
||||
@@ -59,8 +57,8 @@ class emitter {
|
||||
[[nodiscard]] bool empty() const ENTT_NOEXCEPT override {
|
||||
auto pred = [](auto &&element) { return element.first; };
|
||||
|
||||
return std::all_of(once_list.cbegin(), once_list.cend(), pred) &&
|
||||
std::all_of(on_list.cbegin(), on_list.cend(), pred);
|
||||
return std::all_of(once_list.cbegin(), once_list.cend(), pred)
|
||||
&& std::all_of(on_list.cbegin(), on_list.cend(), pred);
|
||||
}
|
||||
|
||||
void clear() ENTT_NOEXCEPT override {
|
||||
@@ -122,24 +120,20 @@ class emitter {
|
||||
};
|
||||
|
||||
template<typename Event>
|
||||
[[nodiscard]] pool_handler<Event> * assure() {
|
||||
const auto index = type_seq<Event>::value();
|
||||
|
||||
if(!(index < pools.size())) {
|
||||
pools.resize(std::size_t(index)+1u);
|
||||
[[nodiscard]] pool_handler<Event> *assure() {
|
||||
if(auto &&ptr = pools[type_hash<Event>::value()]; !ptr) {
|
||||
auto *cpool = new pool_handler<Event>{};
|
||||
ptr.reset(cpool);
|
||||
return cpool;
|
||||
} else {
|
||||
return static_cast<pool_handler<Event> *>(ptr.get());
|
||||
}
|
||||
|
||||
if(!pools[index]) {
|
||||
pools[index].reset(new pool_handler<Event>{});
|
||||
}
|
||||
|
||||
return static_cast<pool_handler<Event> *>(pools[index].get());
|
||||
}
|
||||
|
||||
template<typename Event>
|
||||
[[nodiscard]] const pool_handler<Event> * assure() const {
|
||||
const auto index = type_seq<Event>::value();
|
||||
return (!(index < pools.size()) || !pools[index]) ? nullptr : static_cast<const pool_handler<Event> *>(pools[index].get());
|
||||
[[nodiscard]] const pool_handler<Event> *assure() const {
|
||||
const auto it = pools.find(type_hash<Event>::value());
|
||||
return (it == pools.cend()) ? nullptr : static_cast<const pool_handler<Event> *>(it->second.get());
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -169,8 +163,7 @@ public:
|
||||
* @param conn A connection object to wrap.
|
||||
*/
|
||||
connection(typename pool_handler<Event>::connection_type conn)
|
||||
: pool_handler<Event>::connection_type{std::move(conn)}
|
||||
{}
|
||||
: pool_handler<Event>::connection_type{std::move(conn)} {}
|
||||
};
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
@@ -185,7 +178,7 @@ public:
|
||||
emitter(emitter &&) = default;
|
||||
|
||||
/*! @brief Default move assignment operator. @return This emitter. */
|
||||
emitter & operator=(emitter &&) = default;
|
||||
emitter &operator=(emitter &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Emits the given event.
|
||||
@@ -199,7 +192,7 @@ public:
|
||||
* @param args Parameters to use to initialize the event.
|
||||
*/
|
||||
template<typename Event, typename... Args>
|
||||
void publish(Args &&... args) {
|
||||
void publish(Args &&...args) {
|
||||
Event instance{std::forward<Args>(args)...};
|
||||
assure<Event>()->publish(instance, *static_cast<Derived *>(this));
|
||||
}
|
||||
@@ -289,9 +282,7 @@ public:
|
||||
*/
|
||||
void clear() ENTT_NOEXCEPT {
|
||||
for(auto &&cpool: pools) {
|
||||
if(cpool) {
|
||||
cpool->clear();
|
||||
}
|
||||
cpool.second->clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,16 +303,14 @@ public:
|
||||
*/
|
||||
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
|
||||
return std::all_of(pools.cbegin(), pools.cend(), [](auto &&cpool) {
|
||||
return !cpool || cpool->empty();
|
||||
return cpool.second->empty();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<basic_pool>> pools{};
|
||||
dense_hash_map<id_type, std::unique_ptr<basic_pool>, identity> pools{};
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user