Compare commits
4403 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
344e03ac64 | ||
|
|
da56665b03 | ||
|
|
f6f01ef1bc | ||
|
|
0ed514628c | ||
|
|
a41421d867 | ||
|
|
c1f6b11f7d | ||
|
|
b2233064a0 | ||
|
|
cb974bf567 | ||
|
|
7b7d82e6f6 | ||
|
|
05c6898fc2 | ||
|
|
7ffa459a66 | ||
|
|
93e8e94e60 | ||
|
|
c4e2416621 | ||
|
|
9c25419b9a | ||
|
|
1879830df1 | ||
|
|
29298c0eb1 | ||
|
|
247abef1d7 | ||
|
|
6994d98d2a | ||
|
|
9a600ece2d | ||
|
|
f91226ef47 | ||
|
|
e366ffbd30 | ||
|
|
63b300d39d | ||
|
|
afb70d1570 | ||
|
|
49534eec0d | ||
|
|
3f1277f7bd | ||
|
|
26fad4c385 | ||
|
|
25b3afacf6 | ||
|
|
2d25bbb090 | ||
|
|
0eb834582d | ||
|
|
124a440527 | ||
|
|
5c704636ef | ||
|
|
31fd94cc3c | ||
|
|
573e43272a | ||
|
|
1d89434812 | ||
|
|
e0a1ef7c1b | ||
|
|
48ac0e0eb4 | ||
|
|
bcb6234d94 | ||
|
|
f967963264 | ||
|
|
b22c55dd21 | ||
|
|
4ff5a536ca | ||
|
|
fff5f578ac | ||
|
|
0f44c8c923 | ||
|
|
0b6ad03150 | ||
|
|
2450b0bc69 | ||
|
|
fc8eebf367 | ||
|
|
e4f51f2b7f | ||
|
|
2c2216a89e | ||
|
|
cafe851809 | ||
|
|
35e338cc99 | ||
|
|
8feeaaef7c | ||
|
|
e7a3c4e370 | ||
|
|
ea5c558bd4 | ||
|
|
94f0ed179f | ||
|
|
244c359491 | ||
|
|
1f24fea21a | ||
|
|
8deaa09b24 | ||
|
|
85bffb7143 | ||
|
|
325ca310d3 | ||
|
|
d903e268f0 | ||
|
|
f4b26756c5 | ||
|
|
fb3a34ee91 | ||
|
|
6902bb6c41 | ||
|
|
379819b2b0 | ||
|
|
59abfbfb5a | ||
|
|
6e2d871844 | ||
|
|
57ec3c85cb | ||
|
|
4afdf287f1 | ||
|
|
2810ac7cb9 | ||
|
|
e0d27f9bf8 | ||
|
|
de303c9990 | ||
|
|
1619e780f4 | ||
|
|
a1e37eca6b | ||
|
|
c345e7456c | ||
|
|
d166c026f7 | ||
|
|
5e639996d6 | ||
|
|
dac2ef5a9c | ||
|
|
71d7888e81 | ||
|
|
84a4df9c49 | ||
|
|
95bc203196 | ||
|
|
5a9f6d211c | ||
|
|
a29302faae | ||
|
|
75efa72c65 | ||
|
|
58a84665b0 | ||
|
|
a5263384d9 | ||
|
|
c0e6759c69 | ||
|
|
d754f74316 | ||
|
|
1df5399431 | ||
|
|
c284e6feed | ||
|
|
500239758a | ||
|
|
319ecd8084 | ||
|
|
d7891fabc0 | ||
|
|
e287dd0419 | ||
|
|
4dee9dde11 | ||
|
|
9bae6e67bc | ||
|
|
aa7a7ce25a | ||
|
|
a969468c57 | ||
|
|
a1e76fc638 | ||
|
|
d8ed4ca354 | ||
|
|
3248e3f91e | ||
|
|
f00687e6f9 | ||
|
|
5240c6b60a | ||
|
|
67604a88e1 | ||
|
|
4242dfb8b5 | ||
|
|
f96d8ee832 | ||
|
|
c147ec37c9 | ||
|
|
094ddbba36 | ||
|
|
634630ca2d | ||
|
|
d78c26f266 | ||
|
|
fabc6c9bd7 | ||
|
|
b6e8ddd2ad | ||
|
|
cf2bbae6e1 | ||
|
|
08799616d0 | ||
|
|
58bebf78d8 | ||
|
|
d534fad3ee | ||
|
|
871dc7a401 | ||
|
|
1fe7c78f7e | ||
|
|
22a65f80fc | ||
|
|
756ea8a388 | ||
|
|
12186cb401 | ||
|
|
aa9ffb9eef | ||
|
|
dcb5aed901 | ||
|
|
34f6a747a8 | ||
|
|
912cb2ad54 | ||
|
|
885488b3d6 | ||
|
|
3d3d3ef2d9 | ||
|
|
a7120b3400 | ||
|
|
51915205b0 | ||
|
|
4a3ee042ea | ||
|
|
88a1b8d0df | ||
|
|
7e18a0f966 | ||
|
|
c367082ddd | ||
|
|
9f94b5306d | ||
|
|
44ed10c50b | ||
|
|
1b22809412 | ||
|
|
bdabbaa63d | ||
|
|
c79c109b77 | ||
|
|
f1a2133820 | ||
|
|
17dc061490 | ||
|
|
3b8d82330d | ||
|
|
a20829e700 | ||
|
|
5be2fdc158 | ||
|
|
873b107e69 | ||
|
|
356bbbe53e | ||
|
|
e3ce4e1567 | ||
|
|
e02050c515 | ||
|
|
26930633f0 | ||
|
|
b7a485767f | ||
|
|
f54cdccd4f | ||
|
|
41c9a32f31 | ||
|
|
736ef35805 | ||
|
|
0128cbb4f3 | ||
|
|
ff0a407151 | ||
|
|
34f4403864 | ||
|
|
b1c78efb6c | ||
|
|
28f03ff9ce | ||
|
|
a5fe61adbb | ||
|
|
457f5e59ea | ||
|
|
422fd284e7 | ||
|
|
6f32225736 | ||
|
|
366bbceb02 | ||
|
|
7b7f81e08f | ||
|
|
cfe955f970 | ||
|
|
684ddc9de9 | ||
|
|
f5d38a9aed | ||
|
|
447e3693f2 | ||
|
|
909490bf63 | ||
|
|
d90363e4a4 | ||
|
|
ee5de744c3 | ||
|
|
d401c88a04 | ||
|
|
80563b9557 | ||
|
|
c74900057c | ||
|
|
78867d5c9b | ||
|
|
d435fc7792 | ||
|
|
e6f76e0f96 | ||
|
|
1c6b533609 | ||
|
|
5c3d8360c2 | ||
|
|
3882c7d9af | ||
|
|
15726218bd | ||
|
|
869bfc82cf | ||
|
|
0eb3d54b21 | ||
|
|
f83290f762 | ||
|
|
686a3b9d79 | ||
|
|
4d57d5c327 | ||
|
|
36c21cf7fa | ||
|
|
7ab10e1936 | ||
|
|
41467d35a4 | ||
|
|
d351252a12 | ||
|
|
c6cd4f701c | ||
|
|
65889cca44 | ||
|
|
f1914fd946 | ||
|
|
e53af7bef7 | ||
|
|
b910cd2615 | ||
|
|
58d331ca0e | ||
|
|
17f5b0a330 | ||
|
|
de386292bc | ||
|
|
88bf26a2f8 | ||
|
|
3caad4100d | ||
|
|
916203a240 | ||
|
|
62f1971f7b | ||
|
|
4fde96357d | ||
|
|
c3730b65fb | ||
|
|
1ea072cd38 | ||
|
|
bbe4582ee9 | ||
|
|
89ab5c328a | ||
|
|
3a4672793d | ||
|
|
0a0446f35c | ||
|
|
fc58ff74be | ||
|
|
fed6831cdc | ||
|
|
1605c8d9d3 | ||
|
|
d6641c7d8d | ||
|
|
5079f38e99 | ||
|
|
1eab2a4a80 | ||
|
|
c331107651 | ||
|
|
117b0bd675 | ||
|
|
9b4a6f8776 | ||
|
|
f4e6f2b375 | ||
|
|
5971fb7aa4 | ||
|
|
10dfe7e935 | ||
|
|
a9208a9565 | ||
|
|
1cc5b32cab | ||
|
|
f8a972a3c6 | ||
|
|
5b7cc20027 | ||
|
|
bd34e7f2c7 | ||
|
|
46fe29c3f6 | ||
|
|
c50e2815c8 | ||
|
|
fbfee632d5 | ||
|
|
77c59aabfa | ||
|
|
ebb1e8a728 | ||
|
|
1646217f09 | ||
|
|
645edfb2b8 | ||
|
|
61f28298c9 | ||
|
|
d19f97bf21 | ||
|
|
70c611a84f | ||
|
|
286428c19c | ||
|
|
6ec719bcfa | ||
|
|
11f9bb2d74 | ||
|
|
5a1ba5ad7d | ||
|
|
cf094e7ef5 | ||
|
|
31808bd9a2 | ||
|
|
61a5173a75 | ||
|
|
ed6fe9e657 | ||
|
|
e30fa85200 | ||
|
|
ca1069e182 | ||
|
|
70f73a0949 | ||
|
|
710fff0e3f | ||
|
|
660bc5843e | ||
|
|
13295a14ee | ||
|
|
9ce07ff617 | ||
|
|
b272e04bab | ||
|
|
28b11912ab | ||
|
|
b9f096d125 | ||
|
|
8c60faa1d0 | ||
|
|
1f93ea4eee | ||
|
|
7ca77e53f6 | ||
|
|
69397f3658 | ||
|
|
f907bc066a | ||
|
|
bda52701f5 | ||
|
|
d26f7684ce | ||
|
|
63d6c2bff6 | ||
|
|
cc45e73414 | ||
|
|
5d092bcb18 | ||
|
|
295c68841c | ||
|
|
2664b52559 | ||
|
|
dd36328331 | ||
|
|
c8c929e4a2 | ||
|
|
d1ef7bf155 | ||
|
|
1ab23f17d2 | ||
|
|
a72eb4693b | ||
|
|
67579d062b | ||
|
|
766a233f37 | ||
|
|
905671c236 | ||
|
|
27c1383e46 | ||
|
|
029ccc8f75 | ||
|
|
cde40d586d | ||
|
|
6a16a8a20b | ||
|
|
1a12dede6f | ||
|
|
35a78b65ea | ||
|
|
ada19432f6 | ||
|
|
4998e90870 | ||
|
|
471c11c6dc | ||
|
|
3e13e0b59b | ||
|
|
53cd105f2e | ||
|
|
24b31c3798 | ||
|
|
def82b534b | ||
|
|
a424f4ebf6 | ||
|
|
b8f0a8d8ec | ||
|
|
7941226eff | ||
|
|
86bbb2f6bb | ||
|
|
3c176f7258 | ||
|
|
3642c8a784 | ||
|
|
0e80d90a76 | ||
|
|
4fdf2dccd4 | ||
|
|
f8a997e6c5 | ||
|
|
40f676ed14 | ||
|
|
5e346748ea | ||
|
|
3ef61fe014 | ||
|
|
3885d280d3 | ||
|
|
f41b914197 | ||
|
|
e0684f6348 | ||
|
|
fb980a78c0 | ||
|
|
c2430ab48d | ||
|
|
d36d9cb39c | ||
|
|
0017c08bb6 | ||
|
|
e737ff7470 | ||
|
|
945dc40937 | ||
|
|
7ef0085115 | ||
|
|
d2fa68813f | ||
|
|
f22a09a9a2 | ||
|
|
b0aba79a56 | ||
|
|
7c23e4a2f6 | ||
|
|
7fe035ce4b | ||
|
|
3e7160edad | ||
|
|
aaeb686ec7 | ||
|
|
3fdf4884d8 | ||
|
|
1b23ff4b91 | ||
|
|
88dac318e5 | ||
|
|
520c2e660d | ||
|
|
f5d0d451b4 | ||
|
|
8af6fc0cc4 | ||
|
|
c04b97a313 | ||
|
|
1d85414dc2 | ||
|
|
c6533827f0 | ||
|
|
b5803451b4 | ||
|
|
3417d66b2b | ||
|
|
1e61204e80 | ||
|
|
19c4857ef1 | ||
|
|
66ea94898e | ||
|
|
ced6d21c3e | ||
|
|
429c7c45c7 | ||
|
|
c03b1111aa | ||
|
|
ebd7d3acdc | ||
|
|
5aeec60cfe | ||
|
|
620b4f7517 | ||
|
|
6d58004c11 | ||
|
|
df6d926dec | ||
|
|
e63af24cb5 | ||
|
|
068d9f8ae8 | ||
|
|
c19c848c46 | ||
|
|
0bf0a0a8fa | ||
|
|
743e8678ea | ||
|
|
a7ad1c06f4 | ||
|
|
b1af70e70f | ||
|
|
c87c3533ee | ||
|
|
4839a0ee6c | ||
|
|
a0f0c44e6d | ||
|
|
74691dc1d9 | ||
|
|
e4957badb7 | ||
|
|
46791c4c3a | ||
|
|
56c3917841 | ||
|
|
1fb13d3e93 | ||
|
|
535beb4e2d | ||
|
|
2d318b88c9 | ||
|
|
b7f0b76cef | ||
|
|
d30312f516 | ||
|
|
30772848e6 | ||
|
|
eca01a3979 | ||
|
|
35ef0b7ac1 | ||
|
|
19ccba3a6c | ||
|
|
207b7674ae | ||
|
|
631c55ba92 | ||
|
|
e7b30fd36d | ||
|
|
3e959007b9 | ||
|
|
07ec4ca230 | ||
|
|
6e4946b682 | ||
|
|
47ea16f17c | ||
|
|
722857fc07 | ||
|
|
2125b38381 | ||
|
|
289de7d57b | ||
|
|
25ecd8e797 | ||
|
|
319dfdb070 | ||
|
|
9dbbcac01e | ||
|
|
f545c8e058 | ||
|
|
c68fa6a654 | ||
|
|
d288ecd70d | ||
|
|
312d3aba84 | ||
|
|
4d2b2c6de5 | ||
|
|
80d55a226c | ||
|
|
d86a539350 | ||
|
|
0f7098d0e0 | ||
|
|
8c96be1e92 | ||
|
|
37f396bfe3 | ||
|
|
75894dc401 | ||
|
|
cdee000ce8 | ||
|
|
54ca62600b | ||
|
|
6f4280ed59 | ||
|
|
ddf56b78cd | ||
|
|
53a854f54f | ||
|
|
4896acac7d | ||
|
|
e3defeba2a | ||
|
|
62079908ce | ||
|
|
e65a8f2e5f | ||
|
|
9f27fb1e57 | ||
|
|
04d734e76c | ||
|
|
df50fa1b59 | ||
|
|
051872b8c8 | ||
|
|
57ab9e7be0 | ||
|
|
69d95ba759 | ||
|
|
9caf66d7c8 | ||
|
|
74cb0d40c5 | ||
|
|
deac7f34b8 | ||
|
|
a9883f27c6 | ||
|
|
85b1e57d8d | ||
|
|
b7d8e01867 | ||
|
|
390a56176f | ||
|
|
a1b888cce6 | ||
|
|
2107dd6891 | ||
|
|
1fca56afef | ||
|
|
c0762a6a5a | ||
|
|
f48de1bac9 | ||
|
|
c7dfce89e5 | ||
|
|
822fafcd42 | ||
|
|
1476d4ea9b | ||
|
|
c1c63777e8 | ||
|
|
2fab25ae89 | ||
|
|
75d4491522 | ||
|
|
c7866fb21b | ||
|
|
87987bacde | ||
|
|
bde0219fe6 | ||
|
|
ad64c849b8 | ||
|
|
b808bb83b7 | ||
|
|
d0090d35fb | ||
|
|
7a1a06a24b | ||
|
|
000b17881b | ||
|
|
068b6ed49b | ||
|
|
0187fb48aa | ||
|
|
35a2b38441 | ||
|
|
4747c9a4c8 | ||
|
|
7be8d83278 | ||
|
|
a5d6757d6f | ||
|
|
3f09d47c81 | ||
|
|
9c06d6ba0f | ||
|
|
b7c819bf48 | ||
|
|
9f31803ba7 | ||
|
|
1e7deff9c9 | ||
|
|
04ac15d8d9 | ||
|
|
3762189916 | ||
|
|
18d6e466d0 | ||
|
|
095ecf3142 | ||
|
|
433ed863e5 | ||
|
|
0dba68e754 | ||
|
|
1ab2815823 | ||
|
|
2af5a725e4 | ||
|
|
a86bf1332b | ||
|
|
831054bff1 | ||
|
|
f94de1c069 | ||
|
|
a3d9503a17 | ||
|
|
3f2b15f9f7 | ||
|
|
e48817d518 | ||
|
|
d11cebe30b | ||
|
|
77a5efb327 | ||
|
|
851006efee | ||
|
|
6fc6b2fb35 | ||
|
|
ed17a2c48b | ||
|
|
bd00e797a9 | ||
|
|
e645c4928a | ||
|
|
a425878e80 | ||
|
|
f3cd9d374d | ||
|
|
b3e93b084e | ||
|
|
314c189c49 | ||
|
|
2bb2c55662 | ||
|
|
d13c126e99 | ||
|
|
9b54ee37a6 | ||
|
|
e1ead9d3ee | ||
|
|
cf61068dc0 | ||
|
|
82863f8291 | ||
|
|
e4de59827f | ||
|
|
ccea4c920a | ||
|
|
89166f0e47 | ||
|
|
7a05a16c54 | ||
|
|
d0854646c7 | ||
|
|
1e9c9fe5f8 | ||
|
|
80fac8d8e5 | ||
|
|
c774b98389 | ||
|
|
3fd0403cc9 | ||
|
|
6eb3347a3b | ||
|
|
89bceaff75 | ||
|
|
dc25c9c1a2 | ||
|
|
e68ba5870c | ||
|
|
c68cb33751 | ||
|
|
59f807fd02 | ||
|
|
232ffebc1e | ||
|
|
3cea845a0f | ||
|
|
295f3b32e4 | ||
|
|
254da2c3c6 | ||
|
|
ecd3b8d933 | ||
|
|
c673b9b17c | ||
|
|
cd28de0d63 | ||
|
|
672f6a7112 | ||
|
|
3b50672b70 | ||
|
|
f0613b1c6c | ||
|
|
2197e160ef | ||
|
|
2dccd90166 | ||
|
|
2f873f2dd2 | ||
|
|
fde1a524ea | ||
|
|
0558010479 | ||
|
|
79a054a524 | ||
|
|
d94e443a14 | ||
|
|
3862184e88 | ||
|
|
f40fa3c2f6 | ||
|
|
01bc93459b | ||
|
|
151bd07391 | ||
|
|
935393aae0 | ||
|
|
fbfde43477 | ||
|
|
2ffbe115b7 | ||
|
|
645973eb79 | ||
|
|
1332307972 | ||
|
|
b700f5eb5d | ||
|
|
e60dbdc521 | ||
|
|
c66623b330 | ||
|
|
62246d8796 | ||
|
|
b35f131309 | ||
|
|
3dd82633a3 | ||
|
|
00231bf8a7 | ||
|
|
58d392e813 | ||
|
|
1d4d99d090 | ||
|
|
fe3edf2c83 | ||
|
|
0864ba0429 | ||
|
|
3a96980013 | ||
|
|
423f7a555d | ||
|
|
5db8ad53ac | ||
|
|
c2ab357802 | ||
|
|
4fb558f143 | ||
|
|
5762a8a086 | ||
|
|
ed4c675211 | ||
|
|
f157898462 | ||
|
|
6d20709e07 | ||
|
|
a9a9853c01 | ||
|
|
af14aa4c9e | ||
|
|
24d6b98817 | ||
|
|
899f4baa63 | ||
|
|
c1ab7ba025 | ||
|
|
9d38f60207 | ||
|
|
0efa25cf61 | ||
|
|
6316b60451 | ||
|
|
f268fb60a8 | ||
|
|
3520d6915c | ||
|
|
4da7a84518 | ||
|
|
382dfc3bb4 | ||
|
|
b6dcdc816e | ||
|
|
c9d544089a | ||
|
|
3eb5faeed5 | ||
|
|
7a328c7edf | ||
|
|
6567aa1951 | ||
|
|
92319f0111 | ||
|
|
782d86b6e7 | ||
|
|
c2cae37c1d | ||
|
|
1026d26ecb | ||
|
|
7156803dbe | ||
|
|
f54ed54247 | ||
|
|
f30b50195a | ||
|
|
c90ab9affd | ||
|
|
c2f6ca43f1 | ||
|
|
3e5e41d88f | ||
|
|
9eafc0431d | ||
|
|
0a82b777b2 | ||
|
|
32bcc01a46 | ||
|
|
9c3fe3546b | ||
|
|
83f8aed583 | ||
|
|
2fd6602740 | ||
|
|
a554d406e7 | ||
|
|
5f12f872e6 | ||
|
|
be4eb68a30 | ||
|
|
df5284d9e5 | ||
|
|
0e27d33e7e | ||
|
|
fe6e6ae738 | ||
|
|
9d29713eaa | ||
|
|
270d0277db | ||
|
|
0bd06c8d5d | ||
|
|
733f215ccf | ||
|
|
ad01a69fe5 | ||
|
|
dd9c1dade8 | ||
|
|
b8f70519f6 | ||
|
|
9b9d212dde | ||
|
|
3fe15969db | ||
|
|
ec4bf222c6 | ||
|
|
1173908ee4 | ||
|
|
2595b8a925 | ||
|
|
f4e2a8c76c | ||
|
|
66e1a05652 | ||
|
|
87283dc41f | ||
|
|
a802ebffed | ||
|
|
b84b09421e | ||
|
|
940fd09396 | ||
|
|
920338be59 | ||
|
|
bcd1155b77 | ||
|
|
1dc88109e8 | ||
|
|
262c1f53c1 | ||
|
|
4af0a3a0d1 | ||
|
|
be16418289 | ||
|
|
b54a52fbfe | ||
|
|
ae88159952 | ||
|
|
62c764f681 | ||
|
|
2c48cc10ae | ||
|
|
82f2866789 | ||
|
|
d56e5a269c | ||
|
|
1517b29513 | ||
|
|
bea7b43a1a | ||
|
|
2f878f8b5a | ||
|
|
fc68c1b290 | ||
|
|
9081c185da | ||
|
|
7c4493f237 | ||
|
|
da4e73ab85 | ||
|
|
f3e7f98b48 | ||
|
|
3925fc6124 | ||
|
|
c639130c1e | ||
|
|
75c3116008 | ||
|
|
e9e14eb49c | ||
|
|
d1558304f8 | ||
|
|
0531b530b1 | ||
|
|
f9d0178dd7 | ||
|
|
b66b8d37eb | ||
|
|
05ef4c29d8 | ||
|
|
9c3d756692 | ||
|
|
93651e46f5 | ||
|
|
ea901cbfa0 | ||
|
|
d5dc4f43ee | ||
|
|
498e02f154 | ||
|
|
d0ea8f4f96 | ||
|
|
dec3b7bb39 | ||
|
|
10bc8b05ad | ||
|
|
ad77b54dce | ||
|
|
b6724b0283 | ||
|
|
54270b1038 | ||
|
|
31dc732a74 | ||
|
|
f0e02d6d39 | ||
|
|
156d6e4ead | ||
|
|
4375c1c3d6 | ||
|
|
24a9cd67ee | ||
|
|
ba8d522c19 | ||
|
|
3ae46214a4 | ||
|
|
5119fe8d7b | ||
|
|
ed0319cdd8 | ||
|
|
bc50da6a7c | ||
|
|
52b3b4c249 | ||
|
|
74bab529d2 | ||
|
|
b1b143917b | ||
|
|
7beb4c85c4 | ||
|
|
f3beb5670a | ||
|
|
446c67b69a | ||
|
|
c4507bd172 | ||
|
|
61e872bb4e | ||
|
|
9f22a3e23a | ||
|
|
653dd5cd42 | ||
|
|
bc53ed3be9 | ||
|
|
f935bbccee | ||
|
|
c7d5053536 | ||
|
|
ea78f1d970 | ||
|
|
76298bc26a | ||
|
|
7c84ce666e | ||
|
|
a02a7c67cb | ||
|
|
2bb913b898 | ||
|
|
94a8bb57dd | ||
|
|
f06852b5c2 | ||
|
|
fb14d26015 | ||
|
|
6a53c8eaca | ||
|
|
4a98874431 | ||
|
|
baf60502c6 | ||
|
|
2a01b78b32 | ||
|
|
b02e4efe4d | ||
|
|
3c8f6d2831 | ||
|
|
95b443af16 | ||
|
|
b54766d2b4 | ||
|
|
25929d6188 | ||
|
|
4398c962e7 | ||
|
|
fe8919c540 | ||
|
|
bdaeef856d | ||
|
|
57ad7696be | ||
|
|
7c58c83ee0 | ||
|
|
dd7aaa30ca | ||
|
|
76f95945fc | ||
|
|
869836ba79 | ||
|
|
2358552c27 | ||
|
|
e22ea5e189 | ||
|
|
496fefdd01 | ||
|
|
26f85050c1 | ||
|
|
d478b5bc6a | ||
|
|
c8337e529e | ||
|
|
f0995297cf | ||
|
|
b395df0f56 | ||
|
|
69a6cc6656 | ||
|
|
bf73216a76 | ||
|
|
621860718b | ||
|
|
c34c5da277 | ||
|
|
8dcabba31b | ||
|
|
294064f11f | ||
|
|
d125229312 | ||
|
|
11c1e23a91 | ||
|
|
82bc2e1fe4 | ||
|
|
92a00f591d | ||
|
|
04716a7fde | ||
|
|
b6155080b2 | ||
|
|
0a61de4a09 | ||
|
|
7121da100a | ||
|
|
7bee969ebf | ||
|
|
4a0a534796 | ||
|
|
a0041d9062 | ||
|
|
3dd768bb9b | ||
|
|
2a307a681f | ||
|
|
dd1211d021 | ||
|
|
09a600d68a | ||
|
|
7c25b46513 | ||
|
|
dc42486de8 | ||
|
|
36411faf43 | ||
|
|
a9cd565d65 | ||
|
|
0adbb0ad16 | ||
|
|
db31f77d63 | ||
|
|
c275afef28 | ||
|
|
4bad4f3067 | ||
|
|
d2048c037a | ||
|
|
2a39717893 | ||
|
|
49c2ae0e77 | ||
|
|
869c18f150 | ||
|
|
d79cb5ca98 | ||
|
|
acc6390312 | ||
|
|
2e59fbbccc | ||
|
|
bec0037797 | ||
|
|
d08c7ddb58 | ||
|
|
696681fefa | ||
|
|
5f9faf7a32 | ||
|
|
f160503aaf | ||
|
|
b1e9f75a28 | ||
|
|
91da98353d | ||
|
|
bc86ceb707 | ||
|
|
0baf316e5f | ||
|
|
082605f9d3 | ||
|
|
0fdd7d7a3a | ||
|
|
eee59e6af9 | ||
|
|
223a8628e3 | ||
|
|
c0bb603210 | ||
|
|
2981d8746a | ||
|
|
c06280894b | ||
|
|
2f2bdcac4d | ||
|
|
2739964a1f | ||
|
|
c3a2a44830 | ||
|
|
37a2c3b76c | ||
|
|
146a7b2aa3 | ||
|
|
7e093c951f | ||
|
|
4901188409 | ||
|
|
15d78f80a6 | ||
|
|
d61dff45c1 | ||
|
|
34abddfbbd | ||
|
|
238ebe4e8f | ||
|
|
502accabbc | ||
|
|
9d1df1dae4 | ||
|
|
a39cfb9e99 | ||
|
|
27d0e5f55e | ||
|
|
a0e5d2c495 | ||
|
|
d2c89d2a40 | ||
|
|
54f66c9094 | ||
|
|
10be00b352 | ||
|
|
9032051bf7 | ||
|
|
2d2e4c784e | ||
|
|
0d4674d8e2 | ||
|
|
ac06ad35c1 | ||
|
|
27e492d750 | ||
|
|
f8281f2a37 | ||
|
|
9fc717fa6e | ||
|
|
4a0f2f3fe9 | ||
|
|
ebdd4118fd | ||
|
|
54ae48936f | ||
|
|
3c9045a3a8 | ||
|
|
f80f179499 | ||
|
|
69c6ee0675 | ||
|
|
4e28d96bef | ||
|
|
6552cc4599 | ||
|
|
75b10cfa09 | ||
|
|
dc394f62c6 | ||
|
|
ea6d6662b4 | ||
|
|
de3ecbdd28 | ||
|
|
e5c6559836 | ||
|
|
0d422236d6 | ||
|
|
199b065fe3 | ||
|
|
c46e107107 | ||
|
|
a3f66387b2 | ||
|
|
33383bd0c3 | ||
|
|
35b8d95671 | ||
|
|
6e254fb39d | ||
|
|
f50a03dcb4 | ||
|
|
71554b2c19 | ||
|
|
e7762980ec | ||
|
|
c62099969e | ||
|
|
c45ee64800 | ||
|
|
b53c243ef7 | ||
|
|
9ee084fc40 | ||
|
|
9c969fb6ac | ||
|
|
6a8a9c4b31 | ||
|
|
bc0233e34b | ||
|
|
afd91b4e5a | ||
|
|
50349dc2af | ||
|
|
4b10981d75 | ||
|
|
b16cefd534 | ||
|
|
46d6625467 | ||
|
|
a1a8e134d2 | ||
|
|
0b6bbcc6a3 | ||
|
|
5fac237153 | ||
|
|
d2cc1c880c | ||
|
|
ac18ad5823 | ||
|
|
9ac5f6d046 | ||
|
|
08adb29d91 | ||
|
|
1721d07746 | ||
|
|
9401d560b0 | ||
|
|
7eae8523cb | ||
|
|
45b5eeeaa0 | ||
|
|
12b436e5b8 | ||
|
|
534dc7e7b7 | ||
|
|
5dfac37dac | ||
|
|
f17a4e7f8e | ||
|
|
4b586efe66 | ||
|
|
db6dc1e21b | ||
|
|
da11771dab | ||
|
|
475e3a70b0 | ||
|
|
5255afc80d | ||
|
|
7a3f59cc5d | ||
|
|
9470133e33 | ||
|
|
5ab0f9e4c0 | ||
|
|
ef91cd5375 | ||
|
|
cd9553ca10 | ||
|
|
8b27a846a6 | ||
|
|
9d961ad8aa | ||
|
|
0952f3ce03 | ||
|
|
ab33111192 | ||
|
|
9a457c5aca | ||
|
|
4f1c86c52e | ||
|
|
c605e3b5a1 | ||
|
|
5a8c9b8a95 | ||
|
|
2b8e9cab18 | ||
|
|
c3dec4b04e | ||
|
|
699aa5cd96 | ||
|
|
fea0210b6e | ||
|
|
cf12765738 | ||
|
|
17f47fbc92 | ||
|
|
1e36b6c4b6 | ||
|
|
28692fc142 | ||
|
|
6eff5a88f6 | ||
|
|
5742100973 | ||
|
|
c52eea7db7 | ||
|
|
2f59f5a8fa | ||
|
|
e77fe56e8f | ||
|
|
eea1e7b1f8 | ||
|
|
b0fbccdf10 | ||
|
|
4f3faef153 | ||
|
|
3ae3c82fbb | ||
|
|
1063fbccbe | ||
|
|
b9e60c679a | ||
|
|
88fd79069b | ||
|
|
ab859f7fa7 | ||
|
|
cc4d4dfc2b | ||
|
|
bd62e817dc | ||
|
|
de34a109e1 | ||
|
|
e0e45719fa | ||
|
|
b21b254258 | ||
|
|
ca3ef33f46 | ||
|
|
8c4803d906 | ||
|
|
ffb9e4b0eb | ||
|
|
6010dbc368 | ||
|
|
a6343bd152 | ||
|
|
9e4a7f48a4 | ||
|
|
6ad7424d4a | ||
|
|
218fa1ba35 | ||
|
|
b45db747a8 | ||
|
|
eedecc07fd | ||
|
|
dcea36de7a | ||
|
|
ed0e3f4435 | ||
|
|
8595e4bd99 | ||
|
|
e31b81294d | ||
|
|
ac6e9cf2f0 | ||
|
|
dac4ae94c0 | ||
|
|
b31b585805 | ||
|
|
1368c56655 | ||
|
|
6cab12a14f | ||
|
|
924a09a9c5 | ||
|
|
e4f6293f42 | ||
|
|
f197b32b02 | ||
|
|
b80ab36418 | ||
|
|
d5588333f7 | ||
|
|
10755275ea | ||
|
|
a30cecdf36 | ||
|
|
0068afa06c | ||
|
|
38597a6499 | ||
|
|
65ee240e8e | ||
|
|
336bcf4d11 | ||
|
|
ed74a4c213 | ||
|
|
3e29617da8 | ||
|
|
715b3e450f | ||
|
|
1ab10f3b28 | ||
|
|
304d8a80be | ||
|
|
560a3f664e | ||
|
|
41081204f9 | ||
|
|
b895dfc901 | ||
|
|
93a1d65103 | ||
|
|
443d53400d | ||
|
|
9725582089 | ||
|
|
cd2634a5d4 | ||
|
|
798d1a4f9e | ||
|
|
e13996f68a | ||
|
|
1ee077d511 | ||
|
|
ccf301c73d | ||
|
|
461fe715b7 | ||
|
|
9549bb4f4d | ||
|
|
0215722103 | ||
|
|
7c6606f27e | ||
|
|
f0b10965fb | ||
|
|
53f2bb7701 | ||
|
|
945e61d668 | ||
|
|
e74c4bb684 | ||
|
|
a8eebcb0e2 | ||
|
|
1581aa1cf5 | ||
|
|
839a2cc86d | ||
|
|
3062114f0c | ||
|
|
ab3abf23ed | ||
|
|
b5a7812ab4 | ||
|
|
565de36155 | ||
|
|
c76f078834 | ||
|
|
358a9742c5 | ||
|
|
7f9e200cfb | ||
|
|
a12710af70 | ||
|
|
871234ec76 | ||
|
|
0c062cc351 | ||
|
|
67271e4672 | ||
|
|
2489a95dab | ||
|
|
70b8bd27b8 | ||
|
|
ee88cf16d1 | ||
|
|
d83e818517 | ||
|
|
6462ceb1f5 | ||
|
|
e2f8ea110a | ||
|
|
f1acbbedf9 | ||
|
|
8510f535a5 | ||
|
|
9a97a57423 | ||
|
|
a50cc628ec | ||
|
|
dc922c9e4c | ||
|
|
2f2b0cf98a | ||
|
|
798d5eeb86 | ||
|
|
02d8cefcde | ||
|
|
f627593d63 | ||
|
|
9aeddc2cb1 | ||
|
|
6650071d24 | ||
|
|
006822c7fc | ||
|
|
8bed15e469 | ||
|
|
4200bb9ebb | ||
|
|
fdae346aa6 | ||
|
|
01acb15fab | ||
|
|
3a6764a685 | ||
|
|
e2e8a575c6 | ||
|
|
7205fb63fa | ||
|
|
c7b59fdc14 | ||
|
|
e9a59bb014 | ||
|
|
76ba063f29 | ||
|
|
2988a74fe4 | ||
|
|
72bc9e3973 | ||
|
|
31fb2bc2c3 | ||
|
|
768f8cd74c | ||
|
|
751e044ce2 | ||
|
|
3406250cf6 | ||
|
|
e510bdf4f2 | ||
|
|
fccdff05e3 | ||
|
|
e530b3d6f6 | ||
|
|
0f0b70be23 | ||
|
|
e39f235287 | ||
|
|
af5acb8d32 | ||
|
|
a2f70cb5e4 | ||
|
|
25d10f03bb | ||
|
|
85c1ad060f | ||
|
|
d9b1cc0db3 | ||
|
|
34205014e9 | ||
|
|
749106aa47 | ||
|
|
b828e0295a | ||
|
|
2345002c1c | ||
|
|
2ce18a47b4 | ||
|
|
76b380d7c0 | ||
|
|
d3244ab4da | ||
|
|
d06ccfb8e3 | ||
|
|
6f807d6f9e | ||
|
|
2b0045e23e | ||
|
|
57067bc362 | ||
|
|
abe185c003 | ||
|
|
85ca2f3562 | ||
|
|
3d03b01439 | ||
|
|
879e7d775f | ||
|
|
e9dbd10db4 | ||
|
|
acc95bd9b7 | ||
|
|
504c7b5d6d | ||
|
|
b20ab29d82 | ||
|
|
95b16a0b04 | ||
|
|
6ee64d1dc2 | ||
|
|
83ecd2d1d9 | ||
|
|
325a5dd353 | ||
|
|
e0ee35da61 | ||
|
|
b3fde98020 | ||
|
|
3c7c21cea3 | ||
|
|
c73d6c52bf | ||
|
|
c38c1454b4 | ||
|
|
06d1d23273 | ||
|
|
4081b46302 | ||
|
|
914bf49656 | ||
|
|
dc634c61c4 | ||
|
|
566878b29c | ||
|
|
0060479e33 | ||
|
|
1a0d892201 | ||
|
|
0424b63bf1 | ||
|
|
de9d3c04e2 | ||
|
|
b0e4a853cf | ||
|
|
ac8dfe29ae | ||
|
|
9d33a38ec4 | ||
|
|
e3076fa5d1 | ||
|
|
2067b2aea6 | ||
|
|
a14af95f9d | ||
|
|
8fd2ce8d47 | ||
|
|
d6edc64d65 | ||
|
|
f882158387 | ||
|
|
6f852c2dcb | ||
|
|
e47e74fc76 | ||
|
|
e604060369 | ||
|
|
80f8051c57 | ||
|
|
612c499a3d | ||
|
|
cceffe6ac4 | ||
|
|
a74416c730 | ||
|
|
0830704484 | ||
|
|
79f7eaaf9a | ||
|
|
389e038445 | ||
|
|
8f84bd7091 | ||
|
|
2146e3ded9 | ||
|
|
97c0582765 | ||
|
|
c3f230956c | ||
|
|
b914a4a93e | ||
|
|
befa0fe213 | ||
|
|
61ef5a44e0 | ||
|
|
131fd0d778 | ||
|
|
8973757b43 | ||
|
|
14ce88730f | ||
|
|
84cbfb2f91 | ||
|
|
e8f8520251 | ||
|
|
c26558cd6d | ||
|
|
71feb0516d | ||
|
|
382187089c | ||
|
|
4faeb5c44e | ||
|
|
ac8f569280 | ||
|
|
669420d31c | ||
|
|
df48cc9471 | ||
|
|
274a08070f | ||
|
|
c0e20825ac | ||
|
|
15d821f2f8 | ||
|
|
acbd38c1ed | ||
|
|
92f5f97d83 | ||
|
|
1128b9de81 | ||
|
|
fcd60467a7 | ||
|
|
2f51341633 | ||
|
|
5799f407ae | ||
|
|
c7a5e09c0e | ||
|
|
3318ac2699 | ||
|
|
437f1fea54 | ||
|
|
3ab43f894f | ||
|
|
86f98f40a1 | ||
|
|
655f1dd906 | ||
|
|
243a382485 | ||
|
|
4b74163306 | ||
|
|
50e67d7c15 | ||
|
|
c5afd8f589 | ||
|
|
c6ab65d552 | ||
|
|
1a853fe145 | ||
|
|
72abc8e4c4 | ||
|
|
e15ad2e21b | ||
|
|
5afc5529c2 | ||
|
|
7eed368dc2 | ||
|
|
600303bb5b | ||
|
|
bcfd6d1b4f | ||
|
|
e65b3a790d | ||
|
|
a28467d393 | ||
|
|
bf13d9363d | ||
|
|
ff9c472f86 | ||
|
|
46e601db6e | ||
|
|
d4482d0d26 | ||
|
|
281289c46a | ||
|
|
bc85d96938 | ||
|
|
c2475381fd | ||
|
|
6ac14f35ad | ||
|
|
de18834c91 | ||
|
|
fc7d28c723 | ||
|
|
7ac2ce50a0 | ||
|
|
9cf9661484 | ||
|
|
8dbf00ad3a | ||
|
|
e0e623fa36 | ||
|
|
4094669222 | ||
|
|
9e19244659 | ||
|
|
d41ccb6b34 | ||
|
|
72c1da2507 | ||
|
|
2e8c5ea2de | ||
|
|
65561fe431 | ||
|
|
cf401aa0b5 | ||
|
|
9b2c9936c2 | ||
|
|
e4aabc7feb | ||
|
|
610951771e | ||
|
|
f76959af63 | ||
|
|
0eb5b0437b | ||
|
|
c1ac684f9a | ||
|
|
473c36aba5 | ||
|
|
38e6722358 | ||
|
|
d2a0f86908 | ||
|
|
c6707bec97 | ||
|
|
5c6a11cb8f | ||
|
|
600cc5e167 | ||
|
|
c441a9ad97 | ||
|
|
c2d2ba29ea | ||
|
|
25af23d3ff | ||
|
|
cbd6fd8aee | ||
|
|
7a7fc20438 | ||
|
|
ca4b2b68a7 | ||
|
|
f3ae553706 | ||
|
|
fe6696b107 | ||
|
|
3a85d0f179 | ||
|
|
9845d2c87d | ||
|
|
ea8730c2a9 | ||
|
|
c81868f8f7 | ||
|
|
33d1839b75 | ||
|
|
df10a01af9 | ||
|
|
4aa40aba4c | ||
|
|
696c94e2ea | ||
|
|
bc5dfb9371 | ||
|
|
88c63b941d | ||
|
|
b8e12dc42a | ||
|
|
2974e959e5 | ||
|
|
67b2fc085c | ||
|
|
cb202c15a5 | ||
|
|
850abd440b | ||
|
|
01d125f53d | ||
|
|
3f0572c5ce | ||
|
|
cc6c45f591 | ||
|
|
8029777c4e | ||
|
|
a6171551bd | ||
|
|
6bb67ab5da | ||
|
|
a31c492c83 | ||
|
|
c36d5e4a9c | ||
|
|
17b3fc93b0 | ||
|
|
d2f4ffc433 | ||
|
|
1c8a296f49 | ||
|
|
de0e5862dd | ||
|
|
e822b8c99e | ||
|
|
48d767749d | ||
|
|
fa48c76dd1 | ||
|
|
754fe9f4ec | ||
|
|
1ad3adfff0 | ||
|
|
0c0fd4d7f7 | ||
|
|
72f5df82b2 | ||
|
|
c7407f5b6a | ||
|
|
f57975acca | ||
|
|
a8a0c9e571 | ||
|
|
e05277d56a | ||
|
|
0b1985ca7e | ||
|
|
637764ee4e | ||
|
|
c6e613c317 | ||
|
|
aa3e769463 | ||
|
|
630ba195d1 | ||
|
|
13276d2f10 | ||
|
|
d59407a339 | ||
|
|
92c2fd9409 | ||
|
|
063e6160e0 | ||
|
|
6155a10037 | ||
|
|
7428cb353c | ||
|
|
fe3b5b03eb | ||
|
|
497fb90b12 | ||
|
|
48ab892de1 | ||
|
|
a85ad88d5a | ||
|
|
cf2566ff74 | ||
|
|
619f51518a | ||
|
|
b26330adab | ||
|
|
83009bac02 | ||
|
|
8780d536c7 | ||
|
|
99f4134d9d | ||
|
|
ca02ab7d5d | ||
|
|
dc295ca0e1 | ||
|
|
8ee91095c5 | ||
|
|
49c7b2f8f4 | ||
|
|
5d80cf11ef | ||
|
|
bc929bcb90 | ||
|
|
26a3057acf | ||
|
|
96cf0a6d02 | ||
|
|
12e773f3fb | ||
|
|
c321997591 | ||
|
|
b2d98452f1 | ||
|
|
16e48aa10f | ||
|
|
4da85a5f4a | ||
|
|
a5c9d3a809 | ||
|
|
f288ba744d | ||
|
|
ba5b85de00 | ||
|
|
bd2f412225 | ||
|
|
a86cf32f55 | ||
|
|
0c8178c753 | ||
|
|
b59e06ec89 | ||
|
|
10153a371b | ||
|
|
a93c1478c0 | ||
|
|
215b7a19c9 | ||
|
|
14ed666b91 | ||
|
|
ac1d61b2c4 | ||
|
|
acb6e90158 | ||
|
|
d3609737f5 | ||
|
|
95b91cd7dd | ||
|
|
affd2a3b91 | ||
|
|
d392259364 | ||
|
|
e03f4fac64 | ||
|
|
538840351a | ||
|
|
1ddad3577c | ||
|
|
d44d1325fc | ||
|
|
dc07af6ad1 | ||
|
|
c6f1809d60 | ||
|
|
261e73bf3e | ||
|
|
8c7d2a1e96 | ||
|
|
72507977bd | ||
|
|
270829f05b | ||
|
|
b92e4f7e65 | ||
|
|
8e890135fe | ||
|
|
a6601939d5 | ||
|
|
c608e735d2 | ||
|
|
e0a1a338a5 | ||
|
|
7aa276df5a | ||
|
|
d939a72219 | ||
|
|
96fc59eee5 | ||
|
|
989f8568cf | ||
|
|
66f451124f | ||
|
|
e59ff47f6f | ||
|
|
b176be9ef7 | ||
|
|
942879bbba | ||
|
|
2065c4294f | ||
|
|
cb02f0621c | ||
|
|
971f371eab | ||
|
|
f21c56bd98 | ||
|
|
363299a27d | ||
|
|
10e74dad41 | ||
|
|
dc041b7ea0 | ||
|
|
584cfdf64c | ||
|
|
74c498cf15 | ||
|
|
a1e5855f2b | ||
|
|
d8e5a97ef3 | ||
|
|
96804b0b28 | ||
|
|
b0d69c50da | ||
|
|
de6b2e139b | ||
|
|
7204840a8a | ||
|
|
76369a01ad | ||
|
|
3a92a93604 | ||
|
|
f1c968372f | ||
|
|
759d9a642f | ||
|
|
86d86c3044 | ||
|
|
c38708c483 | ||
|
|
1673a5ade9 | ||
|
|
c56a49ddce | ||
|
|
03477ce400 | ||
|
|
14d213d13e | ||
|
|
8d86816d8d | ||
|
|
12cf3fd8e7 | ||
|
|
8c23f2de8b | ||
|
|
837481a854 | ||
|
|
b682e58df7 | ||
|
|
c4f430d0d0 | ||
|
|
c7930ab349 | ||
|
|
045baba7ea | ||
|
|
d17ac421ec | ||
|
|
049e529f66 | ||
|
|
ef6e47f625 | ||
|
|
1330cb9126 | ||
|
|
f0ee8bc89d | ||
|
|
ebc0c18534 | ||
|
|
379a4bdda6 | ||
|
|
2ce106c50f | ||
|
|
0ebdfe59ee | ||
|
|
80c700b1f8 | ||
|
|
103f935d61 | ||
|
|
164476721a | ||
|
|
54dd716d02 | ||
|
|
ab681ce637 | ||
|
|
a355de8e97 | ||
|
|
56921d6449 | ||
|
|
7e900626bc | ||
|
|
dc30c29f4e | ||
|
|
370865bb57 | ||
|
|
80015e83d4 | ||
|
|
c37c35b52b | ||
|
|
069004d4eb | ||
|
|
f11695200e | ||
|
|
ef2f8a1a18 | ||
|
|
54cc687c50 | ||
|
|
51f279160f | ||
|
|
e3113f6976 | ||
|
|
485e29a672 | ||
|
|
00e67c50ca | ||
|
|
3e7b3edb9c | ||
|
|
3c6c9d9462 | ||
|
|
6b06a9ff2b | ||
|
|
803db476bb | ||
|
|
c134ea3098 | ||
|
|
6e64f36b39 | ||
|
|
36af39e2b4 | ||
|
|
88929ab730 | ||
|
|
02f00e5339 | ||
|
|
ee67032af1 | ||
|
|
8aea00f527 | ||
|
|
50faed4a50 | ||
|
|
b982817a56 | ||
|
|
e5172a9240 | ||
|
|
dcac7942fa | ||
|
|
4e13529adb | ||
|
|
c553835228 | ||
|
|
1b87193fc1 | ||
|
|
25fca56319 | ||
|
|
bf4252394c | ||
|
|
22757e064f | ||
|
|
fc9fa37e4e | ||
|
|
2d5e3402fa | ||
|
|
b7dd26121a | ||
|
|
23bdbeef4e | ||
|
|
9ac81c5219 | ||
|
|
6b9d346b8b | ||
|
|
9e68eb4d2c | ||
|
|
f1f47ee44a | ||
|
|
436b2b3140 | ||
|
|
f6cfa8ae49 | ||
|
|
13949a8d1f | ||
|
|
88db623dc1 | ||
|
|
976413173a | ||
|
|
91d3349585 | ||
|
|
6e1a774921 | ||
|
|
6b53b509fa | ||
|
|
b8b6203ecd | ||
|
|
81e1500675 | ||
|
|
d2cd18cb1e | ||
|
|
f5ac73f681 | ||
|
|
413630813a | ||
|
|
73b6ef2293 | ||
|
|
428bfbd810 | ||
|
|
c54409bdfb | ||
|
|
b63aebfdaf | ||
|
|
335f876a46 | ||
|
|
c5e99342a3 | ||
|
|
1710eb9249 | ||
|
|
d03770f91f | ||
|
|
9fe6f7a6ea | ||
|
|
2fc605fc3e | ||
|
|
edcd5c4713 | ||
|
|
bd3df1e06a | ||
|
|
b785d1c82b | ||
|
|
93bf14f84f | ||
|
|
5a84646282 | ||
|
|
2e6cfc08f0 | ||
|
|
4b6d3d47ec | ||
|
|
985abaa12a | ||
|
|
a381a7253a | ||
|
|
b8bb509d5c | ||
|
|
f48dbd0e19 | ||
|
|
31c1278374 | ||
|
|
f6aaafd60f | ||
|
|
ae3dec19fd | ||
|
|
990baa0929 | ||
|
|
7ecb65a141 | ||
|
|
a1e55103be | ||
|
|
1b4fc54405 | ||
|
|
e5dcea1fa0 | ||
|
|
9f25195629 | ||
|
|
6936fa1c1c | ||
|
|
7b25eacfc8 | ||
|
|
33989a61e3 | ||
|
|
08d9e8d076 | ||
|
|
da43ef0982 | ||
|
|
02f12bde81 | ||
|
|
b55d5375ac | ||
|
|
281f40bd56 | ||
|
|
dcb7c0c27e | ||
|
|
d3c44a6fa6 | ||
|
|
f432dc6bdc | ||
|
|
ce21ee6001 | ||
|
|
a431f5a674 | ||
|
|
f6153f17ad | ||
|
|
c17ecbc78c | ||
|
|
0feb9f0c56 | ||
|
|
e69cb3d950 | ||
|
|
e7c03dd512 | ||
|
|
0c1371ffae | ||
|
|
8a350acf39 | ||
|
|
594b3b5531 | ||
|
|
e13d06fe20 | ||
|
|
805bb84c8f | ||
|
|
1a62338349 | ||
|
|
4795ba83ba | ||
|
|
ad5b362bca | ||
|
|
8a735452de | ||
|
|
03d0f3e9ca | ||
|
|
ff0983cc42 | ||
|
|
159a413c7d | ||
|
|
6a753d1316 | ||
|
|
c89bf30e05 | ||
|
|
ba4b5ef9f2 | ||
|
|
5b39ee221f | ||
|
|
65c4432325 | ||
|
|
32bbb27c9f | ||
|
|
ef3c030576 | ||
|
|
554a182229 | ||
|
|
9154d78e58 | ||
|
|
82d933aa3d | ||
|
|
ef0fe9b13c | ||
|
|
f6700b7094 | ||
|
|
21f00cf251 | ||
|
|
900d2bf816 | ||
|
|
3846fa3f28 | ||
|
|
52f77d61ba | ||
|
|
039341de69 | ||
|
|
5adf332a5f | ||
|
|
efbb32a498 | ||
|
|
3156dd1321 | ||
|
|
2fbeeafbb8 | ||
|
|
db680f3bcd | ||
|
|
4a20fa5275 | ||
|
|
3fb2da7174 | ||
|
|
7f8bebbdd5 | ||
|
|
597fc0265f | ||
|
|
d5d5770dac | ||
|
|
772ac64e3b | ||
|
|
92d7337f04 | ||
|
|
200425114c | ||
|
|
b92a73a2a2 | ||
|
|
e83c77b99f | ||
|
|
28aa35160d | ||
|
|
18c9bfa134 | ||
|
|
bdb7763237 | ||
|
|
bc9ee46b8f | ||
|
|
b92b734db2 | ||
|
|
2748a6cd3c | ||
|
|
888876185d | ||
|
|
03fea6358b | ||
|
|
59b0dc6735 | ||
|
|
35a42b2172 | ||
|
|
daa4056f45 | ||
|
|
bb5abe633f | ||
|
|
dc238db355 | ||
|
|
4c692c23bb | ||
|
|
b093e82db3 | ||
|
|
7a1c2108a1 | ||
|
|
4aa2b49649 | ||
|
|
cdaced4df6 | ||
|
|
cdd029853b | ||
|
|
507bafdd9c | ||
|
|
07a36123e5 | ||
|
|
a205e7ada9 | ||
|
|
25e9330bb4 | ||
|
|
b2edfa454c | ||
|
|
07767a09d9 | ||
|
|
e8d85d9269 | ||
|
|
5cf0ba079f | ||
|
|
e08b1f82ce | ||
|
|
c2196149ee | ||
|
|
65b5ce7880 | ||
|
|
9c254ec3e0 | ||
|
|
f4418e0205 | ||
|
|
a314f7b42e | ||
|
|
dc5a72cda5 | ||
|
|
380cb41ca9 | ||
|
|
83f7e633a3 | ||
|
|
ab1c920435 | ||
|
|
7094d658f8 | ||
|
|
11617291e3 | ||
|
|
790aa03834 | ||
|
|
bcd16ea5ea | ||
|
|
81c044760b | ||
|
|
b0e0e80b69 | ||
|
|
280bb1d84f | ||
|
|
bb42dceaca | ||
|
|
d0873ed551 | ||
|
|
0fbddfc47b | ||
|
|
3f1dee2650 | ||
|
|
a4b8b93e7f | ||
|
|
02d1417ef4 | ||
|
|
50812a908c | ||
|
|
1a1ed55485 | ||
|
|
09fa322a0e | ||
|
|
1a9a423c35 | ||
|
|
7b0449213c | ||
|
|
c0251f5c29 | ||
|
|
4509d8a60b | ||
|
|
b1738b0902 | ||
|
|
45259462aa | ||
|
|
772a7427a2 | ||
|
|
afa58b81f6 | ||
|
|
6822c0f0e3 | ||
|
|
0a155ecb68 | ||
|
|
15fff94447 | ||
|
|
ff06df2acb | ||
|
|
df9301d591 | ||
|
|
e51b1bbb25 | ||
|
|
aa275f4b1c | ||
|
|
ed11bda9fd | ||
|
|
ed34a3f5d4 | ||
|
|
a99b8b7984 | ||
|
|
f750254cc2 | ||
|
|
21ece182f5 | ||
|
|
6439dca43a | ||
|
|
ca424a4577 | ||
|
|
87bc2cb1ab | ||
|
|
58f22cc3b5 | ||
|
|
fa8362f000 | ||
|
|
1816206dfc | ||
|
|
fcfa994152 | ||
|
|
e7262660c2 | ||
|
|
a1e14d5740 | ||
|
|
60c11f3f30 | ||
|
|
3fe584d366 | ||
|
|
28e38321ee | ||
|
|
1faeeeeabc | ||
|
|
75a0c672b1 | ||
|
|
db829b21aa | ||
|
|
24bdc29c27 | ||
|
|
692a78984f | ||
|
|
77a399738c | ||
|
|
5d7358899d | ||
|
|
aca25b9999 | ||
|
|
182c6c534b | ||
|
|
0500f155e6 | ||
|
|
125b826f62 | ||
|
|
922bfbf724 | ||
|
|
f1e584fad9 | ||
|
|
0c4dcdea71 | ||
|
|
ec4b383198 | ||
|
|
3328c7e78b | ||
|
|
357fcd44d7 | ||
|
|
5a0a682d35 | ||
|
|
1fcb7e5aba | ||
|
|
eec867bc9e | ||
|
|
5a956d2914 | ||
|
|
e0e29cc363 | ||
|
|
9fc8e03f72 | ||
|
|
b054e93f0e | ||
|
|
653680a356 | ||
|
|
40035f2e52 | ||
|
|
a70b7daec4 | ||
|
|
0f3e7b5dac | ||
|
|
2fbc08b606 | ||
|
|
e4897f709e | ||
|
|
84445aa28b | ||
|
|
0795f9a9f2 | ||
|
|
44ae0d67f6 | ||
|
|
a74f0ca370 | ||
|
|
266c1fcdcb | ||
|
|
977c3407e7 | ||
|
|
99c2299ed4 | ||
|
|
39a08f17da | ||
|
|
57de1187fc | ||
|
|
2bba6d4c0d | ||
|
|
2f03b225f7 | ||
|
|
533bc1ce94 | ||
|
|
add9df6058 | ||
|
|
d3496f3ff5 | ||
|
|
e97f7ee725 | ||
|
|
37497295fb | ||
|
|
2e89b3b5b9 | ||
|
|
518bbc651e | ||
|
|
ffd1d97e03 | ||
|
|
e503d431f1 | ||
|
|
49a066714a | ||
|
|
7eec610d21 | ||
|
|
530507c36b | ||
|
|
4d2584d8fc | ||
|
|
0f5057920e | ||
|
|
a98000cf3b | ||
|
|
0cec8de164 | ||
|
|
1caa8d923d | ||
|
|
4fa51f8c52 | ||
|
|
a8be765aa8 | ||
|
|
d2d35d490a | ||
|
|
26ba137424 | ||
|
|
e6006663ec | ||
|
|
74eb2772b6 | ||
|
|
3878a696af | ||
|
|
49ac34c405 | ||
|
|
a7d4a980ba | ||
|
|
2196db562e | ||
|
|
2ad3e0ed4c | ||
|
|
6e03fe77ae | ||
|
|
af8ec7b5dd | ||
|
|
7fa29e7341 | ||
|
|
9c6950d163 | ||
|
|
5d4cbfe8e7 | ||
|
|
4747422110 | ||
|
|
7d1416ac74 | ||
|
|
2efaa7af7b | ||
|
|
68e259870f | ||
|
|
29c2c94784 | ||
|
|
3f2e1d078f | ||
|
|
0a259da05a | ||
|
|
1b22fe6de2 | ||
|
|
9b700c3bd2 | ||
|
|
3b72e30c36 | ||
|
|
9eba103de9 | ||
|
|
ecadee3876 | ||
|
|
699f9105ae | ||
|
|
8a19e8dafe | ||
|
|
588c056205 | ||
|
|
866a7fb641 | ||
|
|
a5fe42268f | ||
|
|
0bd6816bdd | ||
|
|
1c6670c7a1 | ||
|
|
699a0eb934 | ||
|
|
72440ab937 | ||
|
|
9ad807bd58 | ||
|
|
9fb1970ac0 | ||
|
|
48dfac2588 | ||
|
|
c6d3714e6f | ||
|
|
1345c257c3 | ||
|
|
19112a8f27 | ||
|
|
e0979fcf3f | ||
|
|
d514ecbd5e | ||
|
|
a53dbb6950 | ||
|
|
a03b88e0eb | ||
|
|
4472eb1c40 | ||
|
|
3443987127 | ||
|
|
c73a79fd42 | ||
|
|
dedbe3d431 | ||
|
|
87ef713a17 | ||
|
|
4ba8ac4fa1 | ||
|
|
e74e0531bd | ||
|
|
b67cb4bd1f | ||
|
|
22628c9ac4 | ||
|
|
4dd0862fad | ||
|
|
0ec57fbb8d | ||
|
|
19ab584d32 | ||
|
|
97fe978d14 | ||
|
|
2a74c7d897 | ||
|
|
cdf9c2fc6f | ||
|
|
235f84a0d4 | ||
|
|
ccaa490a2f | ||
|
|
8eaf11b510 | ||
|
|
57a5faa448 | ||
|
|
be87191d0a | ||
|
|
40aabe76c7 | ||
|
|
9d304cb35c | ||
|
|
ee08a4966f | ||
|
|
aeca69903e | ||
|
|
e1b3f2b95a | ||
|
|
25c7436652 | ||
|
|
771c449621 | ||
|
|
61ecaa5756 | ||
|
|
c05dddc56e | ||
|
|
8e0747fd50 | ||
|
|
1bcc87c916 | ||
|
|
45797907d3 | ||
|
|
3498dea486 | ||
|
|
a4aab8458b | ||
|
|
534744d615 | ||
|
|
dc5450b95e | ||
|
|
9e0e276740 | ||
|
|
1c9c02f3ce | ||
|
|
7774f9f402 | ||
|
|
5607219945 | ||
|
|
69ef3efd2d | ||
|
|
36c118922b | ||
|
|
1d014953e3 | ||
|
|
c5cb1d9bcc | ||
|
|
86d12cf317 | ||
|
|
db9e59ede1 | ||
|
|
cc9b1b0a05 | ||
|
|
5c29de2013 | ||
|
|
559db104f8 | ||
|
|
365c57be4c | ||
|
|
6f0c84fc68 | ||
|
|
75782d9e99 | ||
|
|
69ddf4936e | ||
|
|
4b3108283f | ||
|
|
12d177a6c8 | ||
|
|
54717dc7e2 | ||
|
|
631c909abd | ||
|
|
208746f28f | ||
|
|
61c5f8ae22 | ||
|
|
4e0cca3a08 | ||
|
|
b86ffc2370 | ||
|
|
33574c9885 | ||
|
|
672c542f99 | ||
|
|
f741fe48a1 | ||
|
|
4347ebcee2 | ||
|
|
4e3e5a5361 | ||
|
|
8e6439c3d1 | ||
|
|
b54d358feb | ||
|
|
78baa7b12d | ||
|
|
19f1dd22e9 | ||
|
|
73f583f68a | ||
|
|
52de43e329 | ||
|
|
49ddacaac0 | ||
|
|
4533b3a1c0 | ||
|
|
f30ea02794 | ||
|
|
7112dda299 | ||
|
|
02636a7108 | ||
|
|
36a9456e0d | ||
|
|
113893dcea | ||
|
|
1abbe9c7b2 | ||
|
|
7205ac791c | ||
|
|
3335b81ad4 | ||
|
|
d9c9438f3c | ||
|
|
37250843e1 | ||
|
|
072ab88721 | ||
|
|
c208e6b107 | ||
|
|
65f3185b39 | ||
|
|
34f73f8a2b | ||
|
|
cb4142a97d | ||
|
|
80d08d5a34 | ||
|
|
052aecf533 | ||
|
|
7bde714f18 | ||
|
|
5ff429f656 | ||
|
|
92f27299e1 | ||
|
|
f9013375f8 | ||
|
|
f18b0045ba | ||
|
|
18173cc4c0 | ||
|
|
6a1ffdd7a5 | ||
|
|
8db78b2190 | ||
|
|
3fcccae241 | ||
|
|
6ff8add164 | ||
|
|
58a8c3c82a | ||
|
|
92c5c656c7 | ||
|
|
61856cd648 | ||
|
|
687f82b5c2 | ||
|
|
920c864bed | ||
|
|
1360c985b7 | ||
|
|
b6f953e13b | ||
|
|
796b96071b | ||
|
|
ec56ccc690 | ||
|
|
95931b67e1 | ||
|
|
706bbb83c9 | ||
|
|
43099f47d0 | ||
|
|
eca86999c3 | ||
|
|
a00b44a5fd | ||
|
|
5b8dcff2a4 | ||
|
|
e4d36e4982 | ||
|
|
adfdbf138d | ||
|
|
8d1ba26492 | ||
|
|
792625f763 | ||
|
|
5e8eae4ef8 | ||
|
|
148212da96 | ||
|
|
23ddb12529 | ||
|
|
186a5e8f7b | ||
|
|
dfb5fe1e04 | ||
|
|
640f75373e | ||
|
|
46e5d96ced | ||
|
|
ad3fbe2052 | ||
|
|
cd6c60fd46 | ||
|
|
f7be386d5a | ||
|
|
89b2131052 | ||
|
|
e5d1ca2e3c | ||
|
|
32b8224afd | ||
|
|
00e7ab1db8 | ||
|
|
e376a53b09 | ||
|
|
17a9cd5666 | ||
|
|
fc3de662c3 | ||
|
|
8de568c2fc | ||
|
|
55661883d9 | ||
|
|
b59d3ebeaa | ||
|
|
2866dcdd03 | ||
|
|
b147f9d58c | ||
|
|
8e2a6470ac | ||
|
|
19230f7672 | ||
|
|
764dfbe46a | ||
|
|
0ec7631310 | ||
|
|
0b39ece990 | ||
|
|
97500dff57 | ||
|
|
dc6299a029 | ||
|
|
58b1e2fb98 | ||
|
|
0302fdaaba | ||
|
|
09b260e0af | ||
|
|
24b7e998b2 | ||
|
|
19068ea5c7 | ||
|
|
b5cd3eb468 | ||
|
|
91a2b5a5f7 | ||
|
|
0096f6d962 | ||
|
|
87cfe41b15 | ||
|
|
c490086097 | ||
|
|
5b3fd7537e | ||
|
|
2cab2583c0 | ||
|
|
a40a3b594d | ||
|
|
0fa586a3d8 | ||
|
|
25977cc569 | ||
|
|
0be7064493 | ||
|
|
0b13dc254a | ||
|
|
c1e953ab6e | ||
|
|
a069764af1 | ||
|
|
3dbe6c3902 | ||
|
|
9f0b380024 | ||
|
|
193b102013 | ||
|
|
511fde91fa | ||
|
|
16e3cfc589 | ||
|
|
ed2012a36c | ||
|
|
46598fde32 | ||
|
|
94d0c5fa5c | ||
|
|
4e72291588 | ||
|
|
74cdf000b4 | ||
|
|
565dc3327b | ||
|
|
462af21793 | ||
|
|
94af659c86 | ||
|
|
b63c9fc67b | ||
|
|
f519b55a47 | ||
|
|
2fb039b429 | ||
|
|
4bce5aed77 | ||
|
|
eca6032306 | ||
|
|
dd2f515af1 | ||
|
|
df25482643 | ||
|
|
df016b3bf9 | ||
|
|
8699e96609 | ||
|
|
b0dcaaf744 | ||
|
|
7db001995c | ||
|
|
c88adf9314 | ||
|
|
b13713ce98 | ||
|
|
66b89d170f | ||
|
|
4311e2e686 | ||
|
|
fd566eff7a | ||
|
|
efaa3f9e55 | ||
|
|
b625ff0902 | ||
|
|
fee80321ef | ||
|
|
4b9331f086 | ||
|
|
df9316b896 | ||
|
|
dae5f86d4e | ||
|
|
75a0cefcb3 | ||
|
|
2271aa5b89 | ||
|
|
b668e2a967 | ||
|
|
ce44c59547 | ||
|
|
84802d931d | ||
|
|
8183c4383e | ||
|
|
af249098cd | ||
|
|
8fdd063f00 | ||
|
|
fe328f6a75 | ||
|
|
ef7163acd6 | ||
|
|
6e45f0d5b8 | ||
|
|
ff41faa3fe | ||
|
|
acb2d332ea | ||
|
|
0fb86f21e4 | ||
|
|
e4991d367e | ||
|
|
3144cfafd5 | ||
|
|
c538067544 | ||
|
|
f8e137a1dc | ||
|
|
36ea38fd91 | ||
|
|
baae5a7215 | ||
|
|
a4b267227e | ||
|
|
58dd159699 | ||
|
|
80082f9d51 | ||
|
|
7975ffc10b | ||
|
|
012083a4a1 | ||
|
|
3c67723e83 | ||
|
|
7f0598b3cb | ||
|
|
c5b27e0ae0 | ||
|
|
4e7ad31f18 | ||
|
|
c7a3e9d4ac | ||
|
|
a05e7a84c4 | ||
|
|
389cb85410 | ||
|
|
81ae2bed25 | ||
|
|
0ab71bc2e7 | ||
|
|
81e6bbe643 | ||
|
|
c4723f3b24 | ||
|
|
df4d8e0411 | ||
|
|
4f1820bcad | ||
|
|
e375097e43 | ||
|
|
c51bec0034 | ||
|
|
081c3fdb5b | ||
|
|
f1e7602775 | ||
|
|
acd75ffe1c | ||
|
|
fc813cb59b | ||
|
|
044d14f542 | ||
|
|
28b9f07b99 | ||
|
|
6f20dd4e45 | ||
|
|
2fc05e5b90 | ||
|
|
9afde31f97 | ||
|
|
e835ce0697 | ||
|
|
6030f56c76 | ||
|
|
ba89b53c63 | ||
|
|
1bfb877a3b | ||
|
|
72776d6fb6 | ||
|
|
7bb93420c4 | ||
|
|
bb1b0e0581 | ||
|
|
45ddcf0df9 | ||
|
|
9c4d7a286f | ||
|
|
7b290b43b5 | ||
|
|
2e2782b030 | ||
|
|
48f23bd1ba | ||
|
|
3ece33b26a | ||
|
|
efa98379b0 | ||
|
|
324aeba70f | ||
|
|
7b6715c7b5 | ||
|
|
1ea392b6c9 | ||
|
|
8b1a3849e6 | ||
|
|
e1d7e98c92 | ||
|
|
04b2e1152c | ||
|
|
d392eba4a0 | ||
|
|
799dec4f1c | ||
|
|
11df6ec927 | ||
|
|
03e363f5d9 | ||
|
|
39211889b0 | ||
|
|
db44549276 | ||
|
|
49e702c0c7 | ||
|
|
c9c5214b3e | ||
|
|
24a537d154 | ||
|
|
c32ecf171b | ||
|
|
a62ae21628 | ||
|
|
12f05e8f72 | ||
|
|
81fb727d20 | ||
|
|
e7655c761d | ||
|
|
464fcf4300 | ||
|
|
73b67ea9df | ||
|
|
04a9c80c14 | ||
|
|
80b5ed3d22 | ||
|
|
be5ad379b6 | ||
|
|
13d901fbfa | ||
|
|
f7e7273e91 | ||
|
|
4b3bd265a6 | ||
|
|
42dcec961b | ||
|
|
6b2a3b2916 | ||
|
|
930f9ca436 | ||
|
|
a96a767b9b | ||
|
|
36627dbe78 | ||
|
|
f86bc31cbb | ||
|
|
4a08ca4b5e | ||
|
|
e857aa0640 | ||
|
|
d3c98ad334 | ||
|
|
00dadfe14d | ||
|
|
f26fa92d47 | ||
|
|
7458072df2 | ||
|
|
89aa2a1902 | ||
|
|
7ab08779dc | ||
|
|
46b686910b | ||
|
|
940a799207 | ||
|
|
778cee3b27 | ||
|
|
fb3252732b | ||
|
|
608f7b75e2 | ||
|
|
83853c3dee | ||
|
|
8a0343ad6b | ||
|
|
92d43ce620 | ||
|
|
6943822fed | ||
|
|
aa146c4125 | ||
|
|
b8ec6babb5 | ||
|
|
505f4a2b4f | ||
|
|
1bb0d017c3 | ||
|
|
f33ce615d9 | ||
|
|
0edb49d7c6 | ||
|
|
1fa5a03605 | ||
|
|
fc6bda5cd8 | ||
|
|
59589b6a71 | ||
|
|
57b0624a0a | ||
|
|
2f22395eea | ||
|
|
21bc8d4dfb | ||
|
|
2e74fd8196 | ||
|
|
fee48ab04c | ||
|
|
591f885e67 | ||
|
|
ef803016c0 | ||
|
|
bac51045e5 | ||
|
|
cb5e9393a4 | ||
|
|
097509dd2a | ||
|
|
6cd44248c7 | ||
|
|
1fd61fbcef | ||
|
|
cd2245ef03 | ||
|
|
5ddc746915 | ||
|
|
f7d67067ad | ||
|
|
d1a824f76e | ||
|
|
d7b0fc09d7 | ||
|
|
2d07a6ec1f | ||
|
|
014ba5a7aa | ||
|
|
2f12e524dd | ||
|
|
ea6af75e8e | ||
|
|
a595c6ec6f | ||
|
|
98f785d199 | ||
|
|
a0ed0c864f | ||
|
|
d4ac42749e | ||
|
|
86414671d6 | ||
|
|
6cb935982d | ||
|
|
39ad040d8a | ||
|
|
4cc3824653 | ||
|
|
6d3e0600a1 | ||
|
|
b52c9c1676 | ||
|
|
f7506251fe | ||
|
|
5b06f298f1 | ||
|
|
dc5488a198 | ||
|
|
23d162e9e4 | ||
|
|
de6b660b12 | ||
|
|
60c175a51d | ||
|
|
c0a39c8064 | ||
|
|
61f4f93cc6 | ||
|
|
764404a472 | ||
|
|
04da85c88a | ||
|
|
9551b7a597 | ||
|
|
f1d537d035 | ||
|
|
b43e723c84 | ||
|
|
5466039c1a | ||
|
|
74e11117be | ||
|
|
e0abab2dc4 | ||
|
|
08ff3ff55c | ||
|
|
0b79d99cac | ||
|
|
38f655e7b8 | ||
|
|
6f546ffe95 | ||
|
|
ef8211a46e | ||
|
|
52ea5e4074 | ||
|
|
99621cf08a | ||
|
|
a9ae9ce758 | ||
|
|
fc5a529df8 | ||
|
|
bc1081550d | ||
|
|
e311ab1605 | ||
|
|
994ade0638 | ||
|
|
cf9522bd3b | ||
|
|
7fd1858db0 | ||
|
|
c41509151b | ||
|
|
4e12853d4a | ||
|
|
e1fadbc9b9 | ||
|
|
3c4d13d8b9 | ||
|
|
732159db07 | ||
|
|
00894eaccf | ||
|
|
17818178cf | ||
|
|
89c0abfada | ||
|
|
8bbdd92739 | ||
|
|
f724ceb052 | ||
|
|
b7ac85005f | ||
|
|
8ec899a8e7 | ||
|
|
1013c6a50e | ||
|
|
2cd5d3bab3 | ||
|
|
d9494960a2 | ||
|
|
c0eb6590da | ||
|
|
a9cefcb823 | ||
|
|
d1ff491010 | ||
|
|
2aa34f05d3 | ||
|
|
135d6915ee | ||
|
|
6282195b80 | ||
|
|
adec4f08c6 | ||
|
|
b24fe2f122 | ||
|
|
7b35bcb68a | ||
|
|
4b629045c3 | ||
|
|
c6ba1d05d1 | ||
|
|
3adac90573 | ||
|
|
0332188b6b | ||
|
|
790a1e2812 | ||
|
|
3bd1e13321 | ||
|
|
0cd642ca11 | ||
|
|
d5995998b0 | ||
|
|
62babb9c22 | ||
|
|
b98c69521b | ||
|
|
6cd37b3809 | ||
|
|
238170d0e2 | ||
|
|
6fb5b25530 | ||
|
|
d63f9e1eff | ||
|
|
461865bf3b | ||
|
|
e95d9b9cf6 | ||
|
|
c52b2a4fa9 | ||
|
|
d0ec5d2da0 | ||
|
|
6134058abc | ||
|
|
bd4121c260 | ||
|
|
fbab047d7f | ||
|
|
e216144d07 | ||
|
|
94d5b11191 | ||
|
|
d3c89da2eb | ||
|
|
754a8a637e | ||
|
|
ab24a50de7 | ||
|
|
8099dde34b | ||
|
|
99198fb07f | ||
|
|
18d02a0c95 | ||
|
|
e6cac7d5fb | ||
|
|
d8d6f00fee | ||
|
|
ef5c1a1099 | ||
|
|
2d92d8ee67 | ||
|
|
ae60266477 | ||
|
|
88da5261fc | ||
|
|
15efe9f702 | ||
|
|
badbc5c66e | ||
|
|
d6eea41e13 | ||
|
|
6a2c54adf5 | ||
|
|
75d4bc7c18 | ||
|
|
834f7feb27 | ||
|
|
5d2af3f9e1 | ||
|
|
60e8e4a82a | ||
|
|
92e23476ab | ||
|
|
4560fef058 | ||
|
|
c5d6574617 | ||
|
|
de61a0ca45 | ||
|
|
98470caae1 | ||
|
|
53486c067b | ||
|
|
5b805852fa | ||
|
|
94d02eeb4e | ||
|
|
dbfec1b247 | ||
|
|
a9a1a71145 | ||
|
|
91537bf5f3 | ||
|
|
1baad08288 | ||
|
|
1c5b846488 | ||
|
|
6867760cc4 | ||
|
|
516a9209b7 | ||
|
|
e352c953dc | ||
|
|
f455846d18 | ||
|
|
6d45ac942d | ||
|
|
48939abafa | ||
|
|
fbc9595f12 | ||
|
|
ed2c714419 | ||
|
|
ef7731fb8b | ||
|
|
b5ec03f585 | ||
|
|
a8b224a364 | ||
|
|
3f3943a233 | ||
|
|
4171b4ae47 | ||
|
|
baa4c44632 | ||
|
|
ffed8f37de | ||
|
|
8978a0d159 | ||
|
|
4d09be0cd3 | ||
|
|
987be01bd6 | ||
|
|
7f59fc6321 | ||
|
|
feeb122c0d | ||
|
|
0754f108c9 | ||
|
|
ea82f86749 | ||
|
|
7bd217386a | ||
|
|
1f1e02fee1 | ||
|
|
6d1e4fb3da | ||
|
|
9090f84611 | ||
|
|
8e5ddba173 | ||
|
|
86fccb5071 | ||
|
|
414c3baf15 | ||
|
|
bbbddbf617 | ||
|
|
7638b5a95e | ||
|
|
3df6b05c00 | ||
|
|
8566c58f2b | ||
|
|
33ccb71526 | ||
|
|
2b07b92039 | ||
|
|
959bc269e4 | ||
|
|
8609068dbf | ||
|
|
d6cea80768 | ||
|
|
0f2d6fb324 | ||
|
|
f5d303045c | ||
|
|
ad61b0c84e | ||
|
|
18373bb679 | ||
|
|
c30dfe3bfe | ||
|
|
4993961c16 | ||
|
|
89aece7c28 | ||
|
|
ec96946513 | ||
|
|
e49aa0d424 | ||
|
|
b5c929572a | ||
|
|
394822aa50 | ||
|
|
d12ba5e527 | ||
|
|
ab316bcb2e | ||
|
|
93fc08df45 | ||
|
|
266dd02ef5 | ||
|
|
61c1e359e9 | ||
|
|
32c83986e5 | ||
|
|
f64af2e69d | ||
|
|
6e925c7cdd | ||
|
|
5f50f776c6 | ||
|
|
946ccf3db4 | ||
|
|
7a0aea390b | ||
|
|
ff0e6315f9 | ||
|
|
b7fb485349 | ||
|
|
45cbe66d5d | ||
|
|
bc7a6399c1 | ||
|
|
2d5a3f24aa | ||
|
|
1639429edd | ||
|
|
f81abf4883 | ||
|
|
dcddb7d50e | ||
|
|
42a763031c | ||
|
|
0964ca5918 | ||
|
|
4e870b83cd | ||
|
|
0b19c9be0b | ||
|
|
ac655902a0 | ||
|
|
e4fb293b55 | ||
|
|
d3df64ef4b | ||
|
|
93e3d14f34 | ||
|
|
bc687d412d | ||
|
|
71e85b44b0 | ||
|
|
d4b59aff97 | ||
|
|
e3c21e1f3d | ||
|
|
e012250e0a | ||
|
|
c6bf82664c | ||
|
|
c61e98009f | ||
|
|
44bccaaad6 | ||
|
|
aebca14dea | ||
|
|
4576f27f6e | ||
|
|
0c213fca40 | ||
|
|
891f596191 | ||
|
|
eb2b724902 | ||
|
|
1f8c896181 | ||
|
|
12b39e1fbe | ||
|
|
206d31f27a | ||
|
|
6709331182 | ||
|
|
9460e04ea5 | ||
|
|
462bfea733 | ||
|
|
a2d61dfaeb | ||
|
|
538425e35c | ||
|
|
2e86c1f1a2 | ||
|
|
8aa4d46ce0 | ||
|
|
cdf67a1421 | ||
|
|
93d905d93d | ||
|
|
2c35203647 | ||
|
|
216871fe56 | ||
|
|
03511f39b1 | ||
|
|
5ad0832b22 | ||
|
|
d49e7ba4b2 | ||
|
|
a621b36389 | ||
|
|
d093df02ac | ||
|
|
2e1529e78d | ||
|
|
90be1db402 | ||
|
|
29265e4181 | ||
|
|
2689a7ef13 | ||
|
|
88b58cf23d | ||
|
|
e2e433480b | ||
|
|
b8bc3e4e94 | ||
|
|
c28f52b816 | ||
|
|
ca34309f75 | ||
|
|
ea614a0f3f | ||
|
|
3e7dc7af29 | ||
|
|
0b3e3fd19a | ||
|
|
d3372dc05c | ||
|
|
7d141cb183 | ||
|
|
755699c31b | ||
|
|
acf3d4cd74 | ||
|
|
92414c91b5 | ||
|
|
ff67f402bb | ||
|
|
f048a3f1d8 | ||
|
|
9d39cb51cf | ||
|
|
7624a9d34c | ||
|
|
0fe73fb6ed | ||
|
|
ae11652493 | ||
|
|
0ab46870ae | ||
|
|
a5381374b8 | ||
|
|
7fae655651 | ||
|
|
3d9959c8e5 | ||
|
|
bc86576aa8 | ||
|
|
7c2bce8baf | ||
|
|
b062bbf58d | ||
|
|
8e5a048913 | ||
|
|
ff642ffff7 | ||
|
|
656c12cebd | ||
|
|
48f3fcf3bd | ||
|
|
d797af695b | ||
|
|
75e0161c5f | ||
|
|
c0662816f1 | ||
|
|
415a31ce23 | ||
|
|
6e603e2e51 | ||
|
|
9af318a767 | ||
|
|
30827120f6 | ||
|
|
6194e12616 | ||
|
|
59a27fb652 | ||
|
|
f8ec57c2f6 | ||
|
|
844ef5e232 | ||
|
|
5bf3f7b77e | ||
|
|
00c0afd093 | ||
|
|
5228739c87 | ||
|
|
0f6d1268c7 | ||
|
|
b2a4515d2b | ||
|
|
3576c80d33 | ||
|
|
77afd2d36c | ||
|
|
e6ddd5d9c2 | ||
|
|
b9bf1a234e | ||
|
|
0ce9122449 | ||
|
|
dc41657872 | ||
|
|
64d9380031 | ||
|
|
eca7484e30 | ||
|
|
2b5c393a13 | ||
|
|
0817d416a3 | ||
|
|
ccff753305 | ||
|
|
11481a430a | ||
|
|
e252b22735 | ||
|
|
a32ca8eb1d | ||
|
|
1979a2279f | ||
|
|
1434f942dd | ||
|
|
955d325f07 | ||
|
|
3fac3fe2d7 | ||
|
|
6ff217e74e | ||
|
|
cd667fe34b | ||
|
|
3d6202ecfd | ||
|
|
c40f0ef2bb | ||
|
|
c4b169edd1 | ||
|
|
c6bba98828 | ||
|
|
e5d4f1bb58 | ||
|
|
cf522d60ca | ||
|
|
daf72a7c61 | ||
|
|
f116ad0594 | ||
|
|
e59d40834d | ||
|
|
d06328af7f | ||
|
|
baa9d7d836 | ||
|
|
b030df55ee | ||
|
|
64eb8a2d0d | ||
|
|
7d7c36e0c7 | ||
|
|
9ad5768050 | ||
|
|
1cafbcff38 | ||
|
|
4bbf93fd0c | ||
|
|
120918bc37 | ||
|
|
253448cffb | ||
|
|
26f19fb90e | ||
|
|
e8f982e909 | ||
|
|
0fa433187e | ||
|
|
b0069299ea | ||
|
|
375d5d3e9b | ||
|
|
2d9398ae1a | ||
|
|
fc69e91636 | ||
|
|
5c56cbd672 | ||
|
|
a42255158d | ||
|
|
f3d10a97df | ||
|
|
5d15a3d69f | ||
|
|
94292872dc | ||
|
|
5c8a1e7d10 | ||
|
|
e98d8426bb | ||
|
|
77f80cecf9 | ||
|
|
bce26a1499 | ||
|
|
453f1c6edc | ||
|
|
9f8a36f2c9 | ||
|
|
e6a5945463 | ||
|
|
60393fbc5f | ||
|
|
b9a925dbd4 | ||
|
|
5dbdb1bcb5 | ||
|
|
d55cefc086 | ||
|
|
5380e6d98b | ||
|
|
45cc24e0b8 | ||
|
|
76bf1791eb | ||
|
|
7e9a4c4b16 | ||
|
|
75cd5f169f | ||
|
|
10636c82a2 | ||
|
|
04a6729963 | ||
|
|
b5617398ad | ||
|
|
da14641ccb | ||
|
|
3997bd2396 | ||
|
|
c876350e05 | ||
|
|
1e07b981f0 | ||
|
|
756e909f5e | ||
|
|
2404392daf | ||
|
|
bf6576f5af | ||
|
|
158c2ab76e | ||
|
|
56fa50385e | ||
|
|
eb05ab5fab | ||
|
|
7f87b637d5 | ||
|
|
4b213adc75 | ||
|
|
7e7d5bbf17 | ||
|
|
e18c0a0c19 | ||
|
|
02b6ffc771 | ||
|
|
340d66c24c | ||
|
|
2cbf9d3620 | ||
|
|
11e6793544 | ||
|
|
d07e0336a2 | ||
|
|
7dbfb3d9ae | ||
|
|
02ef5db6e3 | ||
|
|
bb43bb5508 | ||
|
|
a771f083a7 | ||
|
|
67f8bce1dd | ||
|
|
3b6dd23598 | ||
|
|
66bbeae7da | ||
|
|
059334a861 | ||
|
|
f874c8309f | ||
|
|
27be812cc3 | ||
|
|
2adc2e97e1 | ||
|
|
dc4279a2d0 | ||
|
|
85bff4525a | ||
|
|
bd648c0745 | ||
|
|
d5e7005edd | ||
|
|
8913c7ea18 | ||
|
|
0e2afe4f98 | ||
|
|
a936f7cdbe | ||
|
|
44fa466618 | ||
|
|
b05d84e8e3 | ||
|
|
7787c1ddd7 | ||
|
|
52bfddd2e7 | ||
|
|
f59adcdc37 | ||
|
|
e996d3398f | ||
|
|
d73892d25a | ||
|
|
1ebf614d79 | ||
|
|
f9c995f03f | ||
|
|
2dcdd561f0 | ||
|
|
90f97aa8d7 | ||
|
|
5a4b067cee | ||
|
|
cabcc761c6 | ||
|
|
a40ac1c46c | ||
|
|
85ddfc4d21 | ||
|
|
037a35df1d | ||
|
|
64c753023e | ||
|
|
9d72ffb9fe | ||
|
|
4162d4fbc6 | ||
|
|
a4d16bffd3 | ||
|
|
bcaf1489c0 | ||
|
|
a85712e8aa | ||
|
|
0f95d02cdc | ||
|
|
c151d55237 | ||
|
|
785cd6bc11 | ||
|
|
8ec7e3cc97 | ||
|
|
e376493970 | ||
|
|
08e2322d79 | ||
|
|
2832767daa | ||
|
|
62e12ee0aa | ||
|
|
80e73c1089 | ||
|
|
4f93995bd7 | ||
|
|
03c7dac92f | ||
|
|
d0b93f565a | ||
|
|
1512fbae55 | ||
|
|
4d91afdf9f | ||
|
|
c239c3fea3 | ||
|
|
a0b431e8c4 | ||
|
|
005e03aeb3 | ||
|
|
6002d373e2 | ||
|
|
a53066424b | ||
|
|
38ab02ff88 | ||
|
|
fee0b29a0b | ||
|
|
2553695029 | ||
|
|
301939983f | ||
|
|
cd9ae1fbad | ||
|
|
54e9bc86cc | ||
|
|
a1dd4c28c3 | ||
|
|
6d3857f337 | ||
|
|
c4be3e731a | ||
|
|
ea4407b847 | ||
|
|
a62a83044f | ||
|
|
e7e7b06744 | ||
|
|
2222e31885 | ||
|
|
c3f7f83c55 | ||
|
|
86e18f68c4 | ||
|
|
cc7d9e03d9 | ||
|
|
c8639ae434 | ||
|
|
85cf32516e | ||
|
|
bc85817b07 | ||
|
|
1016394be5 | ||
|
|
de35cbf4af | ||
|
|
bb1acee36a | ||
|
|
c6a2ed78c3 | ||
|
|
7729958082 | ||
|
|
ccdaec86b3 | ||
|
|
42afeef993 | ||
|
|
3d06911886 | ||
|
|
98f929e41e | ||
|
|
94d4e0231e | ||
|
|
e60cdb2e3b | ||
|
|
550c021097 | ||
|
|
1aec7f71b8 | ||
|
|
07565927f2 | ||
|
|
fda78ede1b | ||
|
|
1249a4f8d3 | ||
|
|
4e631f1536 | ||
|
|
1757dbc225 | ||
|
|
8149e204d2 | ||
|
|
412f2ef63e | ||
|
|
ea33673daa | ||
|
|
169b816613 | ||
|
|
48edf077fc | ||
|
|
91db153710 | ||
|
|
ea1f010b1a | ||
|
|
935a852745 | ||
|
|
0eb6d7de3c | ||
|
|
3118cd4fa5 | ||
|
|
18832fcb37 | ||
|
|
612554f6af | ||
|
|
1c794591b9 | ||
|
|
a8d95b284d | ||
|
|
772c2dba2f | ||
|
|
9d1a210c97 | ||
|
|
b04b966db1 | ||
|
|
e2c61d90e9 | ||
|
|
d50655c4f7 | ||
|
|
5e4c63736b | ||
|
|
b90b71c8c0 | ||
|
|
722033e906 | ||
|
|
b6ec91fcd0 | ||
|
|
e94c0d003a | ||
|
|
5c46ccb37e | ||
|
|
fd989feea3 | ||
|
|
1b53e83dde | ||
|
|
3ebe827b51 | ||
|
|
b8266e1169 | ||
|
|
4efbe24607 | ||
|
|
e96ac1f6ff | ||
|
|
14915368c7 | ||
|
|
0ff5c18743 | ||
|
|
240814cc85 | ||
|
|
1912350cc6 | ||
|
|
146faa6008 | ||
|
|
e5fa67850b | ||
|
|
1377b51341 | ||
|
|
db67fb3539 | ||
|
|
6d216406f3 | ||
|
|
ab225eaec1 | ||
|
|
4d6d9e567d | ||
|
|
0fcf0142ba | ||
|
|
ab907e4fef | ||
|
|
1c1c3eb271 | ||
|
|
a03a569534 | ||
|
|
309fb0fa83 | ||
|
|
14c1431848 | ||
|
|
c3dc32415b | ||
|
|
44d6246278 | ||
|
|
5bbd7e03f9 | ||
|
|
f5f463b411 | ||
|
|
6eaefbe25c | ||
|
|
4b5c2c85a5 | ||
|
|
0f951cd322 | ||
|
|
cf0da32fd0 | ||
|
|
5a3085c42b | ||
|
|
42cc480bf5 | ||
|
|
2822eda858 | ||
|
|
6c804b5ca2 | ||
|
|
5149d1395e | ||
|
|
f75a2dab8d | ||
|
|
a045c88c61 | ||
|
|
a5fdf917df | ||
|
|
80a0e47f1a | ||
|
|
a304313ad4 | ||
|
|
05b1d5a4da | ||
|
|
edeef3541c | ||
|
|
cd929d8e65 | ||
|
|
b005971427 | ||
|
|
c35614fb63 | ||
|
|
18e16b09f2 | ||
|
|
b18b76c1f0 | ||
|
|
c9f65267ba | ||
|
|
cce52c673b | ||
|
|
fdde216f0e | ||
|
|
d1901a97d1 | ||
|
|
eb2077b95b | ||
|
|
fad3bdeed4 | ||
|
|
e1a537e547 | ||
|
|
ba098e1199 | ||
|
|
0ec755fccf | ||
|
|
997dd433b3 | ||
|
|
4aea1567db | ||
|
|
446c8df3b4 | ||
|
|
f4bd868d6a | ||
|
|
8490264af3 | ||
|
|
505cfdd193 | ||
|
|
39ecd1545c | ||
|
|
9b80c0028d | ||
|
|
35276b55af | ||
|
|
eb63dd6227 | ||
|
|
9f24b3c584 | ||
|
|
53e951d96d | ||
|
|
17dd386937 | ||
|
|
3eb00382e7 | ||
|
|
98b5f7a26a | ||
|
|
fb70ec1cb0 | ||
|
|
47ada87ba2 | ||
|
|
7a949dd328 | ||
|
|
3982217b67 | ||
|
|
8cb61da9c2 | ||
|
|
375c780d3b | ||
|
|
f3b6c2ce5d | ||
|
|
a7a2c96382 | ||
|
|
99336ef746 | ||
|
|
72d2adfe1c | ||
|
|
707574e294 | ||
|
|
18ffbd0027 | ||
|
|
68a0e4f39a | ||
|
|
ddb99ced34 | ||
|
|
cb2782bc71 | ||
|
|
52cade9267 | ||
|
|
ec600eb2f4 | ||
|
|
61e96e2dab | ||
|
|
9f5433053d | ||
|
|
d2489a57b7 | ||
|
|
e5841cd467 | ||
|
|
820d52428f | ||
|
|
ae6931b046 | ||
|
|
90a97b90bb | ||
|
|
4b38d81f00 | ||
|
|
8c27ca9e36 | ||
|
|
4b89fc390d | ||
|
|
29c1766714 | ||
|
|
2e5a9f117c | ||
|
|
2abcbcd30f | ||
|
|
ac8bde4ea8 | ||
|
|
78a13efc6c | ||
|
|
c99e859978 | ||
|
|
ed448cb99f | ||
|
|
5d472a1f2e | ||
|
|
92a938db0e | ||
|
|
aa979b2046 | ||
|
|
2daaf899d3 | ||
|
|
fa4c6bccbc | ||
|
|
bedea4b11a | ||
|
|
bc415242f2 | ||
|
|
2eeb7552d6 | ||
|
|
3a6ecb10a7 | ||
|
|
f55004d1e4 | ||
|
|
1a3304a886 | ||
|
|
58bcbe75b7 | ||
|
|
753df6decf | ||
|
|
c32f947c18 | ||
|
|
6123e4ac8a | ||
|
|
c52f16f5b8 | ||
|
|
3dac65a012 | ||
|
|
bc089bc4c1 | ||
|
|
1075ded4dc | ||
|
|
5578ea2f30 | ||
|
|
ade3e58829 | ||
|
|
ee2e88476c | ||
|
|
1726e983ad | ||
|
|
44341f0bcc | ||
|
|
366da3d0fe | ||
|
|
f7fa2f605b | ||
|
|
6854dea47e | ||
|
|
9d7e1cd99d | ||
|
|
330f3dff77 | ||
|
|
073c46e7bf | ||
|
|
9950b2ea34 | ||
|
|
a7c2a5c49b | ||
|
|
c2c39cd0d0 | ||
|
|
b6e7c36b11 | ||
|
|
002f92fe1e | ||
|
|
d6d0cdf9aa | ||
|
|
7d002df94f | ||
|
|
f0d7408f94 | ||
|
|
7154678347 | ||
|
|
68f0743c40 | ||
|
|
3d5905c878 | ||
|
|
a344a1ca59 | ||
|
|
5f539ddfb7 | ||
|
|
a974235d10 | ||
|
|
2d17ef5c7e | ||
|
|
dda8c209df | ||
|
|
be88d5dfb8 | ||
|
|
4a537d82d3 | ||
|
|
6f36723097 | ||
|
|
35bce924f8 | ||
|
|
9356e8ccb5 | ||
|
|
1ffde24ef6 | ||
|
|
2f52bef882 | ||
|
|
b1369582e1 | ||
|
|
cf176719a8 | ||
|
|
d7ed72ac06 | ||
|
|
83322664f1 | ||
|
|
5af7e96f70 | ||
|
|
c95041d7c3 | ||
|
|
62f40dcb21 | ||
|
|
b4f88e303a | ||
|
|
cd0ec69446 | ||
|
|
909415d167 | ||
|
|
337bc6d97a | ||
|
|
6c9fab7da1 | ||
|
|
315b1f5913 | ||
|
|
c2d1859858 | ||
|
|
37ba7316e0 | ||
|
|
fc1292b1d1 | ||
|
|
0507680cc1 | ||
|
|
60475d3354 | ||
|
|
b1cd794b2c | ||
|
|
cd98ecff88 | ||
|
|
f8ec4027ee | ||
|
|
d980a5cf44 | ||
|
|
761604d044 | ||
|
|
0f4161f616 | ||
|
|
4a668c97a3 | ||
|
|
9d687c25b3 | ||
|
|
0b73082aa0 | ||
|
|
085e1ae157 | ||
|
|
7c0db3203b | ||
|
|
bc987ed03f | ||
|
|
57e1bf3afd | ||
|
|
90606bd410 | ||
|
|
9744a3745c | ||
|
|
14e051f970 | ||
|
|
2396c9b6da | ||
|
|
c386a9d140 | ||
|
|
12847593c2 | ||
|
|
6cfa024ea2 | ||
|
|
4b43d99660 | ||
|
|
c1bfc29e7f | ||
|
|
7e91e27f14 | ||
|
|
f8015036a9 | ||
|
|
b7ef1607dc | ||
|
|
b93a31dd5b | ||
|
|
fa09964f10 | ||
|
|
0038728be3 | ||
|
|
ec56651959 | ||
|
|
8259371d6a | ||
|
|
d8623991c0 | ||
|
|
0c205431b0 | ||
|
|
58dbaf4a51 | ||
|
|
3b50ebae83 | ||
|
|
8b895eff7a | ||
|
|
70af0365bf | ||
|
|
bb3e3bfa1f | ||
|
|
54aa98a752 | ||
|
|
3bff0aa1ea | ||
|
|
b012231635 | ||
|
|
6c6f05fc91 | ||
|
|
3338d5e105 | ||
|
|
390ec2f0c1 | ||
|
|
4ebdf7a6e8 | ||
|
|
6f1366dbb5 | ||
|
|
503791d3c0 | ||
|
|
902dc49de2 | ||
|
|
2d299f31e5 | ||
|
|
df298587b8 | ||
|
|
b9c33008d8 | ||
|
|
ca97f1c4a3 | ||
|
|
effed56653 | ||
|
|
7b501aa89b | ||
|
|
6c0d0d465b | ||
|
|
a52bd20912 | ||
|
|
aabcc445ee | ||
|
|
d491e504cc | ||
|
|
3142e430e7 | ||
|
|
b784d80a50 | ||
|
|
7344654308 | ||
|
|
e01b35c39c | ||
|
|
b8b2c4ee73 | ||
|
|
8cd1ce97f7 | ||
|
|
05b514b743 | ||
|
|
22596e0f5b | ||
|
|
e7031794df | ||
|
|
af69a0a1fd | ||
|
|
52fa690764 | ||
|
|
4ad411e320 | ||
|
|
09da190e93 | ||
|
|
797dd56bb7 | ||
|
|
5e1d77fcd5 | ||
|
|
2820f2658b | ||
|
|
f3fc32660b | ||
|
|
2d4b00ec24 | ||
|
|
86808f5035 | ||
|
|
82946e2372 | ||
|
|
22d117a397 | ||
|
|
662cfc9fdc | ||
|
|
a3e73909cf | ||
|
|
95bafc8ced | ||
|
|
05f1906f77 | ||
|
|
dbbb131424 | ||
|
|
fc7ec35242 | ||
|
|
7ac10472dc | ||
|
|
d255889c5c | ||
|
|
7662da22fc | ||
|
|
64cc200df0 | ||
|
|
63c983683c | ||
|
|
92f79c99f7 | ||
|
|
24f937fe4f | ||
|
|
47bb682890 | ||
|
|
9ab674ef9a | ||
|
|
83eb0de916 | ||
|
|
6359a12dbb | ||
|
|
eb8e96f413 | ||
|
|
138bd96167 | ||
|
|
0d5ea4711d | ||
|
|
fa4212f07b | ||
|
|
c7635a7e3d | ||
|
|
3923c4cfd2 | ||
|
|
6ad884080c | ||
|
|
c578a43611 | ||
|
|
aebfa7161f | ||
|
|
682bc502e2 | ||
|
|
cf018ff74c | ||
|
|
5a9cb251ad | ||
|
|
bbbf5a5edf | ||
|
|
7df0449100 | ||
|
|
820add87ea | ||
|
|
9a574aa00c | ||
|
|
10da82a331 | ||
|
|
26c816e78c | ||
|
|
808e238384 | ||
|
|
ff068e032b | ||
|
|
5072e96277 | ||
|
|
c55c1c0615 | ||
|
|
9983faef70 | ||
|
|
70a264e939 | ||
|
|
9ef6008c67 | ||
|
|
5a3e816544 | ||
|
|
3e385fb884 | ||
|
|
fa5cce7477 | ||
|
|
b2de76e8a0 | ||
|
|
edb363b236 | ||
|
|
12dcfdb5e1 | ||
|
|
86c1dd7f32 | ||
|
|
d8ff4285da | ||
|
|
7effde0478 | ||
|
|
559ee931fb | ||
|
|
cb27a7fe3e | ||
|
|
c33a8dc2c8 | ||
|
|
11fcf88b88 | ||
|
|
4f0baa80d7 | ||
|
|
ddea97bc88 | ||
|
|
102c9891a0 | ||
|
|
fb4784b695 | ||
|
|
9a0650c703 | ||
|
|
a62b93acec | ||
|
|
2d11bdc736 | ||
|
|
7d263d36a0 | ||
|
|
4965fd5888 | ||
|
|
36db8b6f59 | ||
|
|
9e69f62a39 | ||
|
|
f307021cf1 | ||
|
|
0709c402f8 | ||
|
|
df5deb8b88 | ||
|
|
111dd40097 | ||
|
|
c83e7d7995 | ||
|
|
718f964de7 | ||
|
|
ce0db9b968 | ||
|
|
3f0d602353 | ||
|
|
5364d778b0 | ||
|
|
0ddec227fa | ||
|
|
a5ea35ee56 | ||
|
|
a3e03fb889 | ||
|
|
b7711f0182 | ||
|
|
aae199ff1c | ||
|
|
8d0611a188 | ||
|
|
958b245c3d | ||
|
|
fbb77092eb | ||
|
|
ebc8328712 | ||
|
|
7967c6dfc8 | ||
|
|
fca08a5162 | ||
|
|
49f65d6762 | ||
|
|
7684e1bad5 | ||
|
|
46e974d201 | ||
|
|
ab55d0abc8 | ||
|
|
ed668d5144 | ||
|
|
dec0f28a2b | ||
|
|
de7d79f1f4 | ||
|
|
d204d580dd | ||
|
|
e4e38edf24 | ||
|
|
3721a1f90b | ||
|
|
897850c3eb | ||
|
|
a22efb25c6 | ||
|
|
f7e80879ae | ||
|
|
bf902e6398 | ||
|
|
aed817f724 | ||
|
|
5ac76d29fc | ||
|
|
81311ddd03 | ||
|
|
3c52070243 | ||
|
|
9070f50658 | ||
|
|
ecc3c56cb1 | ||
|
|
a86191f6e0 | ||
|
|
aa5fdac522 | ||
|
|
3cd32c74a1 | ||
|
|
2e2f6a03d9 | ||
|
|
25a073f20b | ||
|
|
0fb244e381 | ||
|
|
631ba70b72 | ||
|
|
0a1d6b2a6f | ||
|
|
94bfa5ea25 | ||
|
|
118c14bf1e | ||
|
|
cf395f707a | ||
|
|
6e040fa87c | ||
|
|
c0a7f84382 | ||
|
|
826d7b7c26 | ||
|
|
91e63d0f19 | ||
|
|
2d69e5f6ff | ||
|
|
23f0fcd024 | ||
|
|
3fcd82abad | ||
|
|
d766c39791 | ||
|
|
a76c3b3baa | ||
|
|
9290b4eecc | ||
|
|
eccfec4b4f | ||
|
|
80aadd3874 | ||
|
|
9da15826db | ||
|
|
8c403f8795 | ||
|
|
b010824dbd | ||
|
|
3340f8864f | ||
|
|
9fb3cdfc4c | ||
|
|
3a3a2c2702 | ||
|
|
be38919758 | ||
|
|
a816ccf6ee | ||
|
|
5e85068e35 | ||
|
|
77865ab4a1 | ||
|
|
5fc6ee27f6 | ||
|
|
5995adf8b6 | ||
|
|
c9f47ed89a | ||
|
|
d6325ffcfa | ||
|
|
9d72472114 | ||
|
|
102350a125 | ||
|
|
1c650cb136 | ||
|
|
625e74653d | ||
|
|
5bad762293 | ||
|
|
fc1ff11352 | ||
|
|
0595ba384e | ||
|
|
f80f5e9955 | ||
|
|
f689014c3e | ||
|
|
9b24655bbf | ||
|
|
c3201070a1 | ||
|
|
8a146209e4 | ||
|
|
2b719726cd | ||
|
|
27209e4836 | ||
|
|
0497762f94 | ||
|
|
b38f1e744b | ||
|
|
481c49e18e | ||
|
|
69cf9115b5 | ||
|
|
3eedd89efe | ||
|
|
ad262ea624 | ||
|
|
08cd8c95f7 | ||
|
|
c86790c6b8 | ||
|
|
e466d9252f | ||
|
|
02f8a0baa6 | ||
|
|
9f7bbe3f9d | ||
|
|
e81e0e97e0 | ||
|
|
52554c3972 | ||
|
|
48b6c4876a | ||
|
|
99e89c2540 | ||
|
|
0e8453d4ed | ||
|
|
c750b746b3 | ||
|
|
0ac07e2e83 | ||
|
|
ead6cb9ca3 | ||
|
|
c401f9211d | ||
|
|
abb72c0a9a | ||
|
|
bc9172bd43 | ||
|
|
b205a5e49d | ||
|
|
fccf9642d8 | ||
|
|
96dd68f52b | ||
|
|
7f923bb389 | ||
|
|
7ab7ebb3f6 | ||
|
|
4eacb58a3e | ||
|
|
24248832d1 | ||
|
|
a53f0900bd | ||
|
|
6a1a5a0f74 | ||
|
|
65aa4e145e | ||
|
|
cf903aa082 | ||
|
|
75dd86e8ef | ||
|
|
70a3d62c14 | ||
|
|
291e3cd229 | ||
|
|
9b28c1fdd2 | ||
|
|
d1d73da039 | ||
|
|
59f041b9a9 | ||
|
|
fbf3b9ce4d | ||
|
|
9be2e1c4c9 | ||
|
|
a06c9f890c | ||
|
|
fc8e8874a9 | ||
|
|
09e0f68616 | ||
|
|
0e7e36f80d | ||
|
|
8484dcd332 | ||
|
|
8a46296b48 | ||
|
|
b748a910b2 | ||
|
|
932603eea3 | ||
|
|
5056972f79 | ||
|
|
d99ccca291 | ||
|
|
1d9b26d9ec | ||
|
|
3a64707c6e | ||
|
|
6f4071bd75 | ||
|
|
1354fdc613 | ||
|
|
991244655a | ||
|
|
0d07d935bf | ||
|
|
bd56b642a7 | ||
|
|
d989f0edf2 | ||
|
|
f561cf9c8f | ||
|
|
13502e5467 | ||
|
|
045c2a6f05 | ||
|
|
725e9feb68 | ||
|
|
6e45126f53 | ||
|
|
6ebc39e038 | ||
|
|
8b0a7c302b | ||
|
|
0c3e50da2f | ||
|
|
d220cf4acc | ||
|
|
eb1ce7e927 | ||
|
|
46f6f41a6b | ||
|
|
2fa59fc43c | ||
|
|
b7763b3887 | ||
|
|
8c002b67d5 | ||
|
|
7692c4a377 | ||
|
|
1f0acec06c | ||
|
|
1b5295a8fe | ||
|
|
0b699a3f20 | ||
|
|
409d7a499d | ||
|
|
ba7428f3d6 | ||
|
|
c12c32d26e | ||
|
|
0ca5ea0150 | ||
|
|
11ca7c7b3e | ||
|
|
8f6c47527d | ||
|
|
dd28882b27 | ||
|
|
1b93a449b2 | ||
|
|
7cf2ec09b7 | ||
|
|
4d1952a406 | ||
|
|
b8d25e2327 | ||
|
|
89d7c7e572 | ||
|
|
75b19230eb | ||
|
|
7889ca1ca7 | ||
|
|
cec1b932bd | ||
|
|
2c7455ea2b | ||
|
|
edc9cc9278 | ||
|
|
51eafaeb4f | ||
|
|
556373d331 | ||
|
|
804cfb7482 | ||
|
|
143eae0729 | ||
|
|
29d4846de7 | ||
|
|
306178f371 | ||
|
|
371b541fbc | ||
|
|
902658fd21 | ||
|
|
0ca8dff974 | ||
|
|
a212b054e7 | ||
|
|
cccd1baa2f | ||
|
|
5dd25aed4d | ||
|
|
6ddc725b75 | ||
|
|
36ab7444a0 | ||
|
|
a8d004334a | ||
|
|
900398a632 | ||
|
|
f24bb8737d | ||
|
|
cb5e9b197a | ||
|
|
450e20ae78 | ||
|
|
5d42a76fe5 | ||
|
|
c5075a3db0 | ||
|
|
ad5bb5198b | ||
|
|
d306bc4a9a | ||
|
|
5c3b956542 | ||
|
|
ade8533f28 | ||
|
|
ad3413d6ad | ||
|
|
f3d0e3f4dd | ||
|
|
6e2e030ba7 | ||
|
|
613f993638 | ||
|
|
2566e3631b | ||
|
|
4ad6c0a8a9 | ||
|
|
0369ac450e | ||
|
|
ab16680cc8 | ||
|
|
8a344cd9b2 | ||
|
|
4e66fb4589 | ||
|
|
0043e3d623 | ||
|
|
ed168015bf | ||
|
|
1d450ef27e | ||
|
|
932e681d22 | ||
|
|
032bcd9fbe | ||
|
|
e113fa53a4 | ||
|
|
da212dc2a4 | ||
|
|
d1c5a62a9d | ||
|
|
0c777e10e5 | ||
|
|
b919b172b1 | ||
|
|
5dd8d05114 | ||
|
|
3400b32015 | ||
|
|
2e4becad60 | ||
|
|
3d485858d5 | ||
|
|
be93643808 | ||
|
|
f704352bae | ||
|
|
6683b46b07 | ||
|
|
a1fe458338 | ||
|
|
e6328e3207 | ||
|
|
8b1f703397 | ||
|
|
583c8add7e | ||
|
|
0266cc8e99 | ||
|
|
fac4132cb1 | ||
|
|
bf3864b2da | ||
|
|
7c21042858 | ||
|
|
d0fd9e4618 | ||
|
|
9b53230f83 | ||
|
|
d814b7b11e | ||
|
|
9f5421d3d4 | ||
|
|
6b9e5db3bf | ||
|
|
9eac3faf3d | ||
|
|
252de444fc | ||
|
|
c29b9cc937 | ||
|
|
6ac582a771 | ||
|
|
04b0c9f2cf | ||
|
|
6b2468f033 | ||
|
|
2737acb114 | ||
|
|
d03e9c48c5 | ||
|
|
08d9cfe82c | ||
|
|
e8ea8f91c3 | ||
|
|
e7cfa7fda5 | ||
|
|
b0b504d002 | ||
|
|
1da07ba60b | ||
|
|
cedebf8145 | ||
|
|
29832bb2c0 | ||
|
|
320d815d60 | ||
|
|
9f18401581 | ||
|
|
b3a2f0e3a3 | ||
|
|
c00dcd31d6 | ||
|
|
b836be2c84 | ||
|
|
f89c5cc072 | ||
|
|
ab7fa56bb3 | ||
|
|
7e624159ee | ||
|
|
857a791d68 | ||
|
|
171463faf5 | ||
|
|
2cafb49ffe | ||
|
|
ae12fed5fe | ||
|
|
be5547de53 | ||
|
|
cac50ef566 | ||
|
|
57a5736942 | ||
|
|
167eadf699 | ||
|
|
5676e420a6 | ||
|
|
f5edc9e973 | ||
|
|
4a305e1568 | ||
|
|
748ab221dd | ||
|
|
7d786cea8f | ||
|
|
1bf734338d | ||
|
|
98df1d6004 | ||
|
|
290e942f3e | ||
|
|
46d54f7e01 | ||
|
|
16e1715d06 | ||
|
|
52faa1bec5 | ||
|
|
c8a6465688 | ||
|
|
0273b7606e | ||
|
|
51022cb132 | ||
|
|
78f9d87ac3 | ||
|
|
e57135eaab | ||
|
|
5fbb663529 | ||
|
|
7db0f540bd | ||
|
|
c8f0afb775 | ||
|
|
51a5815098 | ||
|
|
18bd2eb729 | ||
|
|
f04fd61879 | ||
|
|
c1527cc4c8 | ||
|
|
cf1c1ed126 | ||
|
|
c4ba8f96e6 | ||
|
|
350884c627 | ||
|
|
aa756f6d68 | ||
|
|
1a77bf49f5 | ||
|
|
1b509c56fe | ||
|
|
038b10c74d | ||
|
|
39baa59625 | ||
|
|
3fc091ebb2 | ||
|
|
a557e133d3 | ||
|
|
7d4f10ccc6 | ||
|
|
39a15bef12 | ||
|
|
92c59f3ea1 | ||
|
|
226bd44e2c | ||
|
|
78d43a49c6 | ||
|
|
471651ac5a | ||
|
|
89515b0e30 | ||
|
|
1d61c0d970 | ||
|
|
35c3acbade | ||
|
|
58a2c6a13a | ||
|
|
bf0160adbd | ||
|
|
dfbc92dd3e | ||
|
|
85b0bbfd55 | ||
|
|
fb2a93dc05 | ||
|
|
4ac46bf19d | ||
|
|
4d73adb540 | ||
|
|
bdfeb1ae22 | ||
|
|
3fc116ab53 | ||
|
|
8db61a38cc | ||
|
|
0a70979934 | ||
|
|
1a2ccdf991 | ||
|
|
0adee56d76 | ||
|
|
fedd50efe4 | ||
|
|
d7de7dbe6b | ||
|
|
9fb8939efd | ||
|
|
fe8f671137 | ||
|
|
1a4de1482b | ||
|
|
090a2595e1 | ||
|
|
89dc7f817f | ||
|
|
fe0f26ce9c | ||
|
|
11349629f4 | ||
|
|
9a67652c0c | ||
|
|
b35521dfcb | ||
|
|
9faf306d1e | ||
|
|
d8393dace6 | ||
|
|
692e5275a3 | ||
|
|
1cfe517db8 | ||
|
|
e99e1dc2ac | ||
|
|
1bf4ebcabb | ||
|
|
ec4b264868 | ||
|
|
efb125b2d5 | ||
|
|
1c0fdbed59 | ||
|
|
37bb10e564 | ||
|
|
1507d5d85f | ||
|
|
2a86acfc50 | ||
|
|
e0ee01b92e | ||
|
|
6006917622 | ||
|
|
4ffcf6bf3b | ||
|
|
49cde59c4e | ||
|
|
ed7382995c | ||
|
|
a7faab53b9 | ||
|
|
a6aad25117 | ||
|
|
5f06084b19 | ||
|
|
8151fbcb2e | ||
|
|
5a8e46a6b8 | ||
|
|
c4997c52e2 | ||
|
|
ff12c22f50 | ||
|
|
ed7f09ab80 | ||
|
|
f68941992a | ||
|
|
afcd9285e6 | ||
|
|
22f78d5b33 | ||
|
|
5259142eb6 | ||
|
|
dc403ce8ab | ||
|
|
a6fddd6a2c | ||
|
|
819cd623f9 | ||
|
|
f185494de3 | ||
|
|
628a17ae72 | ||
|
|
08169b9180 | ||
|
|
1e79f2441c | ||
|
|
8680c0ba39 | ||
|
|
8a78b0dbd6 | ||
|
|
0232035e34 | ||
|
|
74f3df83db | ||
|
|
53fa0d2fe8 | ||
|
|
52aa9ab761 | ||
|
|
92cf6195b2 | ||
|
|
86a392991a | ||
|
|
30d426d667 | ||
|
|
5702c50680 | ||
|
|
e38d2e156d | ||
|
|
dfc18619a2 | ||
|
|
9e8f2c52a0 | ||
|
|
1c8f5b98f1 | ||
|
|
972470ad42 | ||
|
|
f7e3a055fb | ||
|
|
34f05fb8dc | ||
|
|
709fd34264 | ||
|
|
b888757092 | ||
|
|
0f42827047 | ||
|
|
e69d1556e1 | ||
|
|
141fbf7472 | ||
|
|
c9a3ae8149 | ||
|
|
e16a8d29ea | ||
|
|
fff50d0e50 | ||
|
|
360734b447 | ||
|
|
7e5edad32b | ||
|
|
fc47b47850 | ||
|
|
c7de058e1d | ||
|
|
0fff3c905c | ||
|
|
2fcb055c43 | ||
|
|
97e0d63102 | ||
|
|
5e04f0accd | ||
|
|
16835e3928 | ||
|
|
22e0ef1354 | ||
|
|
0141dc519c | ||
|
|
9aadc30b94 | ||
|
|
23a73fcb7c | ||
|
|
9a3b585110 | ||
|
|
09ee46860a | ||
|
|
d8f289182d | ||
|
|
dc8fa2153b | ||
|
|
32fb335832 | ||
|
|
58885854f1 | ||
|
|
3e87788541 | ||
|
|
5746df4d74 | ||
|
|
71d86c44e0 | ||
|
|
c5e50289e1 | ||
|
|
e62f1edada | ||
|
|
50e8db28b8 | ||
|
|
ef7c572018 | ||
|
|
1e962754cc | ||
|
|
0240453b07 | ||
|
|
38a80a95f2 | ||
|
|
b5e411d251 | ||
|
|
71a623276e | ||
|
|
1e76703144 | ||
|
|
6ffaf11226 | ||
|
|
fc0caec1a4 | ||
|
|
043f9a5025 | ||
|
|
822264a65e | ||
|
|
8e9a6a4f06 | ||
|
|
76f3909ec9 | ||
|
|
23e839b40e | ||
|
|
6a560fc7bf | ||
|
|
709d1c93a4 | ||
|
|
8d4b5f4bb7 | ||
|
|
9eb5a85e9e | ||
|
|
e7521445e9 | ||
|
|
bb050e2660 | ||
|
|
bc3b0eb491 | ||
|
|
7cea05d376 | ||
|
|
b8a3bdf6b5 | ||
|
|
638b6dba17 | ||
|
|
50ba8c6c39 | ||
|
|
94d15ebbef | ||
|
|
e150882231 | ||
|
|
80a659c90c | ||
|
|
17d96427ea | ||
|
|
7fdda788af | ||
|
|
182adbd9d9 | ||
|
|
4931c9cd9b | ||
|
|
a112409735 | ||
|
|
7aaa6dd986 | ||
|
|
3c39cfe645 | ||
|
|
6a46325e7e | ||
|
|
15c9688a5a | ||
|
|
d9f93ccc11 | ||
|
|
652e569afc | ||
|
|
c55372459f | ||
|
|
09f36e32f7 | ||
|
|
688d435d8e | ||
|
|
e7403d8551 | ||
|
|
60039441a1 | ||
|
|
97f4414cc4 | ||
|
|
df9595bc0d | ||
|
|
93533b7bc6 | ||
|
|
a99afa2ddf | ||
|
|
1e651a5145 | ||
|
|
79ecfa2573 | ||
|
|
e2b676d54c | ||
|
|
2b73bf35b6 | ||
|
|
2137b3a879 | ||
|
|
e52b3fd5bc | ||
|
|
0dfd2aa714 | ||
|
|
5d63c4c981 | ||
|
|
84d3f9ab9a | ||
|
|
1133dba9d8 | ||
|
|
cd2fdc2ffe | ||
|
|
57d017ed8e | ||
|
|
3ad2c559f1 | ||
|
|
c3facfa925 | ||
|
|
db8d9ebc72 | ||
|
|
3aef00af18 | ||
|
|
a4d576bae8 | ||
|
|
9320365ef6 | ||
|
|
0be7494042 | ||
|
|
df55f338ca | ||
|
|
8210efb548 | ||
|
|
43503e2fc9 | ||
|
|
448c3ae425 | ||
|
|
f7684a8a3e | ||
|
|
4f200ac71e | ||
|
|
4772559e8b | ||
|
|
a984ce5bba | ||
|
|
eee8a338e2 | ||
|
|
8894c0ef48 | ||
|
|
c5b8577d94 | ||
|
|
ce9def4a56 | ||
|
|
894601aad2 | ||
|
|
285c91e81b | ||
|
|
ba8ca93afc | ||
|
|
ad0dab2493 | ||
|
|
8b66316180 | ||
|
|
da4ee38914 | ||
|
|
62fde229e2 | ||
|
|
676115d214 | ||
|
|
f36d838df1 | ||
|
|
f32f3ab895 | ||
|
|
fc0432df8c | ||
|
|
797b5bcb53 | ||
|
|
b816f203cd | ||
|
|
714e2f86a1 | ||
|
|
ff75085f15 | ||
|
|
dbc8b18b80 | ||
|
|
efb2bbe8b2 | ||
|
|
8278c8eedd | ||
|
|
6f696a026b | ||
|
|
f558797246 | ||
|
|
c8671d1c2b | ||
|
|
7fd41e48b9 | ||
|
|
409d5f5966 | ||
|
|
5d1802faf7 | ||
|
|
a580bac385 | ||
|
|
c43214543f | ||
|
|
b3c568fb6f | ||
|
|
b34fe3200c | ||
|
|
dada8dbdeb | ||
|
|
e7d4077065 | ||
|
|
b1e54bfd86 | ||
|
|
85ad4c4766 | ||
|
|
3dce560759 | ||
|
|
969b8f0a7a | ||
|
|
ba8e738f40 | ||
|
|
4bc80fae8d | ||
|
|
ee5156704d | ||
|
|
986cd03732 | ||
|
|
937fdabaa9 | ||
|
|
c0fa97510e | ||
|
|
2fc6fe442d | ||
|
|
7ba14f5a57 | ||
|
|
352e4576fc | ||
|
|
210eebc0dc | ||
|
|
5904941361 | ||
|
|
b352815cf8 | ||
|
|
38a2751cd9 | ||
|
|
6388607d11 | ||
|
|
469276b8be | ||
|
|
2a863ee851 | ||
|
|
b6dae2fe57 | ||
|
|
d202bd3e50 | ||
|
|
dc2e44b2c0 | ||
|
|
32c481c28c | ||
|
|
8519c99706 | ||
|
|
5b1bac4c19 | ||
|
|
0a95a0674b | ||
|
|
2f11f6dc37 | ||
|
|
af66274c72 | ||
|
|
c5679b208f | ||
|
|
020fc179a5 | ||
|
|
dc9c1fc762 | ||
|
|
f0938d70b2 | ||
|
|
072761c5ba | ||
|
|
8aacd4d022 | ||
|
|
b6f9ca0021 | ||
|
|
a43f354511 | ||
|
|
43766406ae | ||
|
|
37dd1ae363 | ||
|
|
5a3effaef5 | ||
|
|
cd4bcce70f | ||
|
|
c1e7549b61 | ||
|
|
036ef25da9 | ||
|
|
9884c37ef4 | ||
|
|
23069d76eb | ||
|
|
b2d0e7fae2 | ||
|
|
30a039a031 | ||
|
|
8d67bb726c | ||
|
|
c4dec4cd4d | ||
|
|
f17b975fb9 | ||
|
|
7a3b7593d0 | ||
|
|
bad342b840 | ||
|
|
e3968a8f9d | ||
|
|
f577183c24 | ||
|
|
be58f2e68a | ||
|
|
99f81e82d5 | ||
|
|
7cfd3957de | ||
|
|
c51c88a17c | ||
|
|
e09af98dc5 | ||
|
|
89635f6583 | ||
|
|
14034642f1 | ||
|
|
4af7d975c1 | ||
|
|
d9884917fb | ||
|
|
95fd4e4c99 | ||
|
|
9457a55910 | ||
|
|
56e7dd0de0 | ||
|
|
f0dc882ae9 | ||
|
|
acb70d4440 | ||
|
|
167721bf8c | ||
|
|
4f438e5228 | ||
|
|
0f0aeb6d47 | ||
|
|
d1a6edad8a | ||
|
|
388feb7edb | ||
|
|
962b068c92 | ||
|
|
a32373bc3a | ||
|
|
94a5a4ac1e | ||
|
|
ed8eea12bd | ||
|
|
83bea8b654 | ||
|
|
d4d2db228e | ||
|
|
f8b8c91fe8 | ||
|
|
8451301a5a | ||
|
|
449b03f6bd | ||
|
|
3853ff725f | ||
|
|
ee66e3ef9e | ||
|
|
2643500957 | ||
|
|
88467a87a4 | ||
|
|
d1cdeb4a2d | ||
|
|
f5ced7fe39 | ||
|
|
023267ecab | ||
|
|
3d515a760c | ||
|
|
026c5987dd | ||
|
|
84fb3694f2 | ||
|
|
169dcbcd74 | ||
|
|
d28b6fbf1e | ||
|
|
9f7a2ef84e | ||
|
|
cc5ea60d2b | ||
|
|
8bc63494bc | ||
|
|
9acdeeed04 | ||
|
|
d2cdb2a209 | ||
|
|
36bad31355 | ||
|
|
427587e591 | ||
|
|
4f028d8201 | ||
|
|
d59c052554 | ||
|
|
93ebe91bc5 | ||
|
|
fadb8f695e | ||
|
|
8bb1518d09 | ||
|
|
e8d9d663a7 | ||
|
|
2d2648cf57 | ||
|
|
231036784d | ||
|
|
882b91b221 | ||
|
|
df346ab380 | ||
|
|
c7b8e82ada | ||
|
|
b8784863f2 | ||
|
|
3f67054f03 | ||
|
|
36d1b0a4bc | ||
|
|
748777b8eb | ||
|
|
acd8e0bce5 | ||
|
|
d2d068edff | ||
|
|
e2a7a7ce20 | ||
|
|
b25b1c45fb | ||
|
|
c3b0fa6c93 | ||
|
|
63a4e67174 | ||
|
|
88e37438fa | ||
|
|
5be1bf7d82 | ||
|
|
eb4689d2f1 | ||
|
|
e81549e5fd | ||
|
|
becaef36ff | ||
|
|
6aefa40ca2 | ||
|
|
250ef50361 | ||
|
|
5a1af60357 | ||
|
|
46db75308c | ||
|
|
33f5e13b29 | ||
|
|
54bb4797db | ||
|
|
7a14fbb221 | ||
|
|
18349f5ee4 | ||
|
|
22b93cdd0a | ||
|
|
63bc0b2ba1 | ||
|
|
c57a7c745d | ||
|
|
f2831b5f5c | ||
|
|
96f793f91b | ||
|
|
4e2a0d6e58 | ||
|
|
442c7f1f09 | ||
|
|
dbff4af7c6 | ||
|
|
93b09836da | ||
|
|
1782dc1565 | ||
|
|
cc16874d58 | ||
|
|
c8925b2ae3 | ||
|
|
fc043b9fcd | ||
|
|
ea86d33bc1 | ||
|
|
82f33b82e3 | ||
|
|
c645cb83a2 | ||
|
|
d6d79a2aa5 | ||
|
|
786568fd2f | ||
|
|
434f77a058 | ||
|
|
02f777a143 | ||
|
|
8025a84aeb | ||
|
|
c37a50d3b8 | ||
|
|
6dbbb265d1 | ||
|
|
02ce2ff74c | ||
|
|
28e5267132 | ||
|
|
f498b8a049 | ||
|
|
b31afe5c8c | ||
|
|
eac944dbea | ||
|
|
965b20c37a | ||
|
|
fba85754d7 | ||
|
|
3c69f98451 | ||
|
|
cad8a90124 | ||
|
|
b8d888b17f | ||
|
|
942d783e4e | ||
|
|
0e352cb466 | ||
|
|
50af38b952 | ||
|
|
1459c59cd0 | ||
|
|
e74f5b2991 | ||
|
|
0dec05fd70 | ||
|
|
3cff21b4d0 | ||
|
|
c380da7214 | ||
|
|
e2bf903c49 | ||
|
|
9cf64ba881 | ||
|
|
74d901b7ae | ||
|
|
b15cb46a6d | ||
|
|
89dc76e3b2 | ||
|
|
000b7d2651 | ||
|
|
9ffa372ba2 | ||
|
|
510cfcf1fc | ||
|
|
e7f6d93a1e | ||
|
|
a17c449075 | ||
|
|
c4da7a87f9 | ||
|
|
4a8b2f826d | ||
|
|
4901e4fb80 | ||
|
|
ce3a0157cb | ||
|
|
a146b06e4b | ||
|
|
dc78a3e56d | ||
|
|
86c524dade | ||
|
|
6889edcfc4 | ||
|
|
3cd5934bad | ||
|
|
064104f23a | ||
|
|
e80b1c264c | ||
|
|
03c3ee514b | ||
|
|
c93d0f0d59 | ||
|
|
85793d38bc | ||
|
|
49b4a85d55 | ||
|
|
5e8a9340f1 | ||
|
|
2b97c01bd6 | ||
|
|
39e3a5a708 | ||
|
|
df13d993f7 | ||
|
|
36c62763e5 | ||
|
|
ad5651ffb2 | ||
|
|
717b091b49 | ||
|
|
4376bbe40b | ||
|
|
2382d2e21c | ||
|
|
520ccfcd06 | ||
|
|
0bdc5dfe95 | ||
|
|
6a656a1b0a | ||
|
|
5ad4079dbf | ||
|
|
bfa46b795f | ||
|
|
ecaa9c275c | ||
|
|
93fd1757f8 | ||
|
|
71d0958398 | ||
|
|
ed89d94d7a | ||
|
|
135132e5f0 | ||
|
|
1ad75f5c1b | ||
|
|
21c6f9e394 | ||
|
|
5a7e954aee | ||
|
|
c1117e260c | ||
|
|
b0ea150e94 | ||
|
|
0e3bdc02ea | ||
|
|
e5a075a329 | ||
|
|
30c7a64619 | ||
|
|
ab12f29ebf | ||
|
|
a0c3a82c76 | ||
|
|
085a281f8a | ||
|
|
1f871c24b9 | ||
|
|
9f46b51985 | ||
|
|
fc572b8717 | ||
|
|
4404601fa3 | ||
|
|
faf7e28119 | ||
|
|
0303facfd9 | ||
|
|
86e056a736 | ||
|
|
75105dc1fc | ||
|
|
14b4979c98 | ||
|
|
f956c64765 | ||
|
|
8b3f954ad8 | ||
|
|
a013cfcd1e | ||
|
|
65553e6c43 | ||
|
|
401c881c00 | ||
|
|
cf0e4d24a1 | ||
|
|
21810f3b39 | ||
|
|
0b211ab0ba | ||
|
|
30c7cf3512 | ||
|
|
bf8839a560 | ||
|
|
818998c532 | ||
|
|
98f54029d0 | ||
|
|
d41f2c138b | ||
|
|
50f07a6a0d | ||
|
|
b10116febb | ||
|
|
17b5d732e4 | ||
|
|
5b16b1d827 | ||
|
|
e5fe962130 | ||
|
|
00f03d9bb7 | ||
|
|
f7c285af20 | ||
|
|
f6e3121c76 | ||
|
|
a95aa81850 | ||
|
|
ffa5825658 | ||
|
|
df5b90cc7c | ||
|
|
9dde644fd0 | ||
|
|
d525a1536c | ||
|
|
54f18f3f0d | ||
|
|
ce4f26a5d5 | ||
|
|
177a7429f1 | ||
|
|
f672d734f9 | ||
|
|
faf5a38f1c | ||
|
|
03c4267b84 | ||
|
|
ab08621808 | ||
|
|
d06c0e5c5d | ||
|
|
32e76298e4 | ||
|
|
752163a5c0 | ||
|
|
6568fa23f8 | ||
|
|
9c69288304 | ||
|
|
3a3346e750 | ||
|
|
47ab73d9a4 | ||
|
|
9555385325 | ||
|
|
f80a03afc7 | ||
|
|
c1b64770d1 | ||
|
|
400f106d62 | ||
|
|
1cc20716ae | ||
|
|
fc7d123871 | ||
|
|
2a8a014ad0 | ||
|
|
861f452d26 | ||
|
|
64a7d5e4fd | ||
|
|
7c45423969 | ||
|
|
480f70d7e2 | ||
|
|
7f182896ca | ||
|
|
1319fe2eb5 | ||
|
|
f5c231aa80 | ||
|
|
84d468333a | ||
|
|
dfdbb0a061 | ||
|
|
27365abbe3 | ||
|
|
f3aed46c94 | ||
|
|
7e0ea176cf | ||
|
|
791e13e7bf | ||
|
|
9dff3ac749 | ||
|
|
45f207164d | ||
|
|
bea6f3ec14 | ||
|
|
1edc883ca2 | ||
|
|
116825d604 | ||
|
|
26bc5ef091 | ||
|
|
8c228287aa | ||
|
|
5c7c682d41 | ||
|
|
bfc2eca041 | ||
|
|
b043b48e6e | ||
|
|
d7c03d7356 | ||
|
|
c41f6aebf4 | ||
|
|
5e6cda7c5e | ||
|
|
9c71b53abc | ||
|
|
3f96e04a7b | ||
|
|
90eeeedf52 | ||
|
|
6649362fec | ||
|
|
39c8889585 | ||
|
|
b5b1a64f0c | ||
|
|
cd108b5f57 | ||
|
|
780f3f8552 | ||
|
|
afea5eb69e | ||
|
|
b72cf5d364 | ||
|
|
c133686dde | ||
|
|
e216fa98ef | ||
|
|
8f9d8e188f | ||
|
|
800751cbe0 | ||
|
|
14bc73cde9 | ||
|
|
41307046be | ||
|
|
c259c79384 | ||
|
|
49f69facaf | ||
|
|
da2b6acf91 | ||
|
|
fbdbe848c5 | ||
|
|
cc41caede9 | ||
|
|
ee373eb6fb | ||
|
|
d4b18b1e27 | ||
|
|
94e2fe2cbb | ||
|
|
c93658ee04 | ||
|
|
ad7ee0b716 | ||
|
|
b2fad7a567 | ||
|
|
e80adc2799 | ||
|
|
ac111224ae | ||
|
|
0813bb1a28 | ||
|
|
4d1ad8f749 | ||
|
|
80b444e531 | ||
|
|
3a6468cd0a | ||
|
|
c9fdb215f3 | ||
|
|
85ff5f2d10 | ||
|
|
be3597524f | ||
|
|
5717dbda4f | ||
|
|
588eec4672 | ||
|
|
cc3d0d8211 | ||
|
|
1550efaf7e | ||
|
|
007300b881 | ||
|
|
454f072f13 | ||
|
|
b3be6c75c3 | ||
|
|
f8774f314b | ||
|
|
3db35ad343 | ||
|
|
0e42a779e2 | ||
|
|
d34e829811 | ||
|
|
ebd988702e | ||
|
|
1232398742 | ||
|
|
6dbcd47143 | ||
|
|
0e07482e26 | ||
|
|
6bb4800ecd | ||
|
|
37e1ac71b0 | ||
|
|
869f96816c | ||
|
|
35a7008444 | ||
|
|
67f80ee111 | ||
|
|
083a58753b | ||
|
|
b652357a5c | ||
|
|
49a52140b0 | ||
|
|
e37f84a227 | ||
|
|
50fc83d478 | ||
|
|
a3da1c54eb | ||
|
|
b8471e3cf1 | ||
|
|
4bd645d5c6 | ||
|
|
83446c0694 | ||
|
|
b4c30fc07b | ||
|
|
8325f5bbae | ||
|
|
9eb1196526 | ||
|
|
5fe5d4b6fc | ||
|
|
34af44b8d3 | ||
|
|
643a20fec3 | ||
|
|
576b931090 | ||
|
|
2cc1f044df | ||
|
|
c651392643 | ||
|
|
9a669176ac | ||
|
|
b902831db8 | ||
|
|
90a1de383a | ||
|
|
83f9d42d31 | ||
|
|
94136531a5 | ||
|
|
b8b1e6ba62 | ||
|
|
d6911337f3 | ||
|
|
d2cbb72490 | ||
|
|
c835b4d363 | ||
|
|
ece4480200 | ||
|
|
57f8d90e38 | ||
|
|
da2b2701fe | ||
|
|
6d7fba3abf | ||
|
|
90798c161b | ||
|
|
65e270ff57 | ||
|
|
4912e19281 | ||
|
|
6402564f44 | ||
|
|
a06d5dd7bb | ||
|
|
15e7486ca3 | ||
|
|
ac462cfce9 | ||
|
|
d921306dd8 | ||
|
|
05417705ed | ||
|
|
1c7d9e3d75 | ||
|
|
97dd928ca4 | ||
|
|
03949f7d60 | ||
|
|
effe477351 | ||
|
|
12ac858242 | ||
|
|
eec1937f52 | ||
|
|
906cd48fb7 | ||
|
|
78beecf6f1 | ||
|
|
06a0646541 | ||
|
|
0499a6c6f9 | ||
|
|
0e62f2ee85 | ||
|
|
2ba4c36af0 | ||
|
|
688e6ad79f | ||
|
|
f8ee0ce185 | ||
|
|
a226e06ae8 | ||
|
|
e0e51b51b7 | ||
|
|
9e9e3d43a8 | ||
|
|
7691a9bdad | ||
|
|
22020cae49 | ||
|
|
6cd910b0f6 | ||
|
|
b5e9811063 | ||
|
|
7668c7dd00 | ||
|
|
d71f743e85 | ||
|
|
73ef0222ac | ||
|
|
6152387096 | ||
|
|
b93ffe3b44 | ||
|
|
478eb7c5b5 | ||
|
|
6c40d8bd8b | ||
|
|
7026fe4d5a | ||
|
|
9a4491dc50 | ||
|
|
0d835e5014 | ||
|
|
29b5ffb58d | ||
|
|
a179ec485b | ||
|
|
f220a577e0 | ||
|
|
b22b1d4794 | ||
|
|
d2d19e3fbc | ||
|
|
19ef290499 | ||
|
|
f6584b45ed | ||
|
|
bad97a8b5b | ||
|
|
7116df15d6 | ||
|
|
ffbb018d12 | ||
|
|
a4dcdfc403 | ||
|
|
87d901b1ae | ||
|
|
9126651cb9 | ||
|
|
3996ce8ce5 | ||
|
|
6340423b32 | ||
|
|
0d921dc1fc | ||
|
|
25afea4f9c | ||
|
|
ba46bf3af5 | ||
|
|
416b4885f9 | ||
|
|
9a10ee0efa | ||
|
|
d63b78f0e7 | ||
|
|
99411241f6 | ||
|
|
941fb1349b | ||
|
|
a470925305 | ||
|
|
e3ac292af1 | ||
|
|
260b9a8d0d | ||
|
|
530407f9b2 | ||
|
|
52e7b50e9b | ||
|
|
23aa097d0a | ||
|
|
0bea153aa0 | ||
|
|
00be58e65d | ||
|
|
a5cc985bc2 | ||
|
|
afba54fb5e | ||
|
|
46150a2da4 | ||
|
|
842988c2ad | ||
|
|
ebad34ae51 | ||
|
|
bceb359438 | ||
|
|
19a32134ab | ||
|
|
e44a71daf2 | ||
|
|
573750a43d | ||
|
|
dd4c73b41f | ||
|
|
094326220f | ||
|
|
729a071284 | ||
|
|
ee7857a560 | ||
|
|
4cba604712 | ||
|
|
18a62797d9 | ||
|
|
5d4ac62c9e | ||
|
|
2ef8c41b48 | ||
|
|
891831a96a | ||
|
|
11d18fa1af | ||
|
|
ad69cbc681 | ||
|
|
10995de7bd | ||
|
|
c4d78c06eb | ||
|
|
eb252321a7 | ||
|
|
04dd1447ee | ||
|
|
b14edbe1f4 | ||
|
|
c697e52c0c | ||
|
|
b6911da8f0 | ||
|
|
038448865b | ||
|
|
9e44fdbc55 | ||
|
|
e088f0f31e | ||
|
|
6101feda10 | ||
|
|
7a3fa68468 | ||
|
|
16a11638a7 | ||
|
|
43932492a7 | ||
|
|
8d08ffc4ae | ||
|
|
a5a4ee4bfe | ||
|
|
e66f3a80e8 | ||
|
|
e69efacb47 | ||
|
|
528b361e34 | ||
|
|
a77bb3d341 | ||
|
|
6b17385ad7 | ||
|
|
33fc01ef4b | ||
|
|
482324c0bd | ||
|
|
0ab13a3a70 | ||
|
|
699fb73726 | ||
|
|
ddba29cc09 | ||
|
|
1cdb9ef47c | ||
|
|
ade3305b4c | ||
|
|
bd2bd37bc4 | ||
|
|
ee6f55193e | ||
|
|
1868df61ea | ||
|
|
dfa1fc7b09 | ||
|
|
a52b0495f1 | ||
|
|
ce00eee29f | ||
|
|
858bfade6a | ||
|
|
4535cf9274 | ||
|
|
84d1fa54ec | ||
|
|
7cf4721efa | ||
|
|
6578838587 | ||
|
|
46b7c4717f | ||
|
|
52bcf63554 | ||
|
|
37ec97550e | ||
|
|
55e20abea8 | ||
|
|
ec7d81dc7a | ||
|
|
e93387b719 | ||
|
|
050b476fc3 | ||
|
|
5b5ffd7eaf | ||
|
|
39bf5fdc05 | ||
|
|
09ff43ef0a | ||
|
|
5a02aeaa89 | ||
|
|
2a3a91af42 | ||
|
|
d4a64e93e0 | ||
|
|
c126b64892 | ||
|
|
526814b9ed | ||
|
|
bc3b790f13 | ||
|
|
1fb0765443 | ||
|
|
c4b85f9bda | ||
|
|
161b5530b9 | ||
|
|
e03979ebdc | ||
|
|
356c0ab594 | ||
|
|
85152bac34 | ||
|
|
c832888d56 | ||
|
|
cac1b87b44 | ||
|
|
30f71b2ed6 | ||
|
|
9f8e9a1916 | ||
|
|
8519fe57ae | ||
|
|
1442a3853c | ||
|
|
2658ddf868 | ||
|
|
f95eecfcc6 | ||
|
|
1e598cca31 | ||
|
|
f3eaeb96f0 | ||
|
|
91fac8049c | ||
|
|
b1325a7514 | ||
|
|
150b83b4f3 | ||
|
|
3a3a5dc071 | ||
|
|
9b76a5bd66 | ||
|
|
850a1f9155 | ||
|
|
ef6c8a38d0 | ||
|
|
e228cb6648 | ||
|
|
3a53cac607 | ||
|
|
df4bd57c82 | ||
|
|
de737fc72d | ||
|
|
ccea7a5783 | ||
|
|
5b84e1528a | ||
|
|
7382addfe4 | ||
|
|
b8dd6822ac | ||
|
|
8c47b85b9b | ||
|
|
4d2666a0e3 | ||
|
|
fc18eaa292 | ||
|
|
22199cdd87 | ||
|
|
76820f25c6 | ||
|
|
bac4984496 | ||
|
|
1414c5feac | ||
|
|
c344f63154 | ||
|
|
77ea28bef2 | ||
|
|
bf63b15e07 | ||
|
|
ce05504278 | ||
|
|
95b90974a2 | ||
|
|
1adbef7352 | ||
|
|
3109928dcd | ||
|
|
24dd63789c | ||
|
|
27225e6b5e | ||
|
|
2994978fdb | ||
|
|
ffd864dc72 | ||
|
|
53a2c88d4b | ||
|
|
444ae73ffb | ||
|
|
9f5f4b9c91 | ||
|
|
ffd2af0257 | ||
|
|
b983845745 | ||
|
|
cfcc6e1029 | ||
|
|
6fea4377b2 | ||
|
|
e01230e425 | ||
|
|
f66db81edd | ||
|
|
a47471d0ae | ||
|
|
06b5a91cd3 | ||
|
|
8aacf3497e | ||
|
|
7fc5e304e3 | ||
|
|
65536febd5 | ||
|
|
60f7910840 | ||
|
|
829c3c612e | ||
|
|
355c7b59aa | ||
|
|
6508cdc823 | ||
|
|
9ef9f603a3 | ||
|
|
e76f881c67 | ||
|
|
4292d2ce86 | ||
|
|
ae927c5600 | ||
|
|
57e2eed771 | ||
|
|
ca807b892f | ||
|
|
9bc015d10e | ||
|
|
59b204c3bc | ||
|
|
4ac2472a62 | ||
|
|
054b9c2402 | ||
|
|
96f267cbfd | ||
|
|
2018163107 | ||
|
|
253b5b1fb7 | ||
|
|
0be2f1b295 | ||
|
|
a8838fc611 | ||
|
|
d02636e370 | ||
|
|
f3c1b09188 | ||
|
|
7bac69f360 | ||
|
|
5a3fdd225e | ||
|
|
4660f58653 | ||
|
|
5fabca3616 | ||
|
|
edb74dae87 | ||
|
|
31b833b46a | ||
|
|
21bc1c51ba | ||
|
|
4f6cab9a45 | ||
|
|
33626fa47c | ||
|
|
9fcc1e17f2 | ||
|
|
a5f48f8af8 | ||
|
|
3dfa526ec6 | ||
|
|
dc28066017 | ||
|
|
2f2edfbde8 | ||
|
|
3beac98499 | ||
|
|
f70ce9dd26 | ||
|
|
e301b9d399 | ||
|
|
42f92ecd7a | ||
|
|
27eb0d04b9 | ||
|
|
112d13c127 | ||
|
|
16afc9d0f8 | ||
|
|
5b4889b46b | ||
|
|
f7eed0e2af | ||
|
|
cce287e8a6 | ||
|
|
9a001ebacc | ||
|
|
79ab4c02bb | ||
|
|
b6de70a3a6 | ||
|
|
15cafe2d78 | ||
|
|
90197abc5c | ||
|
|
2147436a2a | ||
|
|
8ef0c66966 | ||
|
|
2779ad6c6f | ||
|
|
f30fe3c746 | ||
|
|
f71496693f | ||
|
|
e4cd5dbf1f | ||
|
|
ffd5defcb6 | ||
|
|
0b81421124 | ||
|
|
0f73b9e07f | ||
|
|
d3078699d6 | ||
|
|
cc39f9f891 | ||
|
|
70608df843 | ||
|
|
e7f2c6b5ba | ||
|
|
420fc9aa24 | ||
|
|
200012fd41 | ||
|
|
e3c858278b | ||
|
|
1ec7c3afa4 | ||
|
|
6ab0b60f12 | ||
|
|
5ec38b44b0 | ||
|
|
39c2294d43 | ||
|
|
3b92481133 | ||
|
|
6b8d24d2f5 | ||
|
|
62d6ff61ab | ||
|
|
f7c056145a | ||
|
|
451f54b036 | ||
|
|
ef378de883 | ||
|
|
2f2b63da4a | ||
|
|
01d8f2c7e6 | ||
|
|
330d553ffb | ||
|
|
f1d0895eb1 | ||
|
|
4eaf6415b7 | ||
|
|
f0650bf64f | ||
|
|
44856c6207 | ||
|
|
dcbf6e43c7 | ||
|
|
0d22da672d | ||
|
|
a62471b9b8 | ||
|
|
f673f2c5bc | ||
|
|
a7caae5c17 | ||
|
|
d0deefd0d7 | ||
|
|
9810da6982 | ||
|
|
cb93a3bee3 | ||
|
|
aeacc3e39d | ||
|
|
e1c861cc8a | ||
|
|
37ee05a576 | ||
|
|
07a2bd817d | ||
|
|
78c171e0c2 | ||
|
|
1ae436cb08 | ||
|
|
b0d3a84d1e | ||
|
|
1acd9ca981 | ||
|
|
72467b6b9c | ||
|
|
862c85387c | ||
|
|
eeeca3e21c | ||
|
|
4ee4af7fd4 | ||
|
|
d131cc1871 | ||
|
|
bd21ee318d | ||
|
|
02e7fc0bca | ||
|
|
51ba46970e | ||
|
|
9d65b44ab7 | ||
|
|
350d51a92d | ||
|
|
2a8202caa7 | ||
|
|
9e4591554f | ||
|
|
e98ecfd1f9 | ||
|
|
1cbf5c4359 | ||
|
|
0446faeb6f | ||
|
|
0417ea23c3 | ||
|
|
de9886e011 | ||
|
|
770e57c361 | ||
|
|
d80a00701d | ||
|
|
62d3cd8795 | ||
|
|
ad9ec22fd1 | ||
|
|
293985ec10 | ||
|
|
105598ac8e | ||
|
|
ff93f2220a | ||
|
|
33fddcb289 | ||
|
|
6a09bf2c54 | ||
|
|
2913f5bbbe | ||
|
|
671bdb09b8 | ||
|
|
353a0d14a4 | ||
|
|
e0fd83211b | ||
|
|
2c94d9cc37 | ||
|
|
f7dec412ec | ||
|
|
f7c756d215 | ||
|
|
617635a989 | ||
|
|
ea3b2c4713 | ||
|
|
15455a7e68 | ||
|
|
ad5cedc08c | ||
|
|
328f0c6da8 | ||
|
|
8ef818f581 | ||
|
|
48dace64e4 | ||
|
|
ab5837c7c4 | ||
|
|
9fbdbc1844 | ||
|
|
54129cecc2 | ||
|
|
69c514d1a4 | ||
|
|
7047d12eba | ||
|
|
8ab61637f0 | ||
|
|
7e0bd92593 | ||
|
|
99d9a9f44e | ||
|
|
9c55111e14 | ||
|
|
b1d6ba57ad | ||
|
|
47e9330646 | ||
|
|
e16a3d503c | ||
|
|
dc9c93b347 | ||
|
|
faceff620a | ||
|
|
a5a6a58556 | ||
|
|
45fdab27c9 | ||
|
|
8b360479f4 | ||
|
|
b170f2f69a | ||
|
|
7f1abab9ae | ||
|
|
2ec7bc878e | ||
|
|
e97d9bb095 | ||
|
|
2f3b02e870 | ||
|
|
11b7a45c32 | ||
|
|
fb10d2f9c2 | ||
|
|
60bb7f66cf | ||
|
|
ad5143169a | ||
|
|
d68c90a429 | ||
|
|
8a51549395 | ||
|
|
9f997fe1fa | ||
|
|
00f1f6d86b | ||
|
|
be72728000 | ||
|
|
f558126854 | ||
|
|
08ed1500ac | ||
|
|
f0926f1cc7 | ||
|
|
fe3f6aa22b | ||
|
|
1325f75e81 | ||
|
|
4b1d3a7b6f | ||
|
|
404afcdfd6 | ||
|
|
99793180f1 | ||
|
|
c91f9beddb | ||
|
|
c9c5ccaa6d | ||
|
|
da42de7ac8 | ||
|
|
3c9a6ad218 | ||
|
|
f0389d6b47 | ||
|
|
76eab21738 | ||
|
|
3b32c57d94 | ||
|
|
d119032cb9 | ||
|
|
397a04b49c | ||
|
|
d32c8e9457 | ||
|
|
ebb2974ca7 | ||
|
|
cbb1131a5d | ||
|
|
d9de7fe3b0 | ||
|
|
24ba692884 | ||
|
|
960bbbde29 | ||
|
|
eb79b79c35 | ||
|
|
8212ed6d87 | ||
|
|
c639cb5285 | ||
|
|
a88fd1c669 | ||
|
|
b053f23d15 | ||
|
|
9d32a89491 | ||
|
|
cb9a147fff | ||
|
|
c9fddedbf1 | ||
|
|
530bbbe4c5 | ||
|
|
73e5a9f45b | ||
|
|
72d4e947b6 | ||
|
|
41750c3639 | ||
|
|
52b36f38a0 | ||
|
|
58ceb454dd | ||
|
|
9e5a2db4c5 | ||
|
|
781f283c89 | ||
|
|
f1cd085727 | ||
|
|
3aba855bd6 | ||
|
|
7e3abb27a4 | ||
|
|
f0c11daa37 | ||
|
|
167c174f4d | ||
|
|
0173060eaf | ||
|
|
4edd25ff5d | ||
|
|
2a4e098645 | ||
|
|
7c5019c30f | ||
|
|
c13fe3feb6 | ||
|
|
0ced60e712 | ||
|
|
d0764d5854 | ||
|
|
f7905e3bc2 | ||
|
|
3e770792a4 | ||
|
|
8f9934a7f4 | ||
|
|
b921e7d595 | ||
|
|
a9cb2d2efd | ||
|
|
fe519b3acf | ||
|
|
30cc4a1668 | ||
|
|
a71e4d8970 | ||
|
|
66e7141415 | ||
|
|
6f0cdc864f | ||
|
|
4f9deaaf09 | ||
|
|
380745a814 | ||
|
|
ce4e335412 | ||
|
|
274b8181d1 | ||
|
|
767bdcc2ce | ||
|
|
c00cde8bcc | ||
|
|
5859a18b3a | ||
|
|
375124642d | ||
|
|
af9e6dea68 | ||
|
|
78f2267b06 | ||
|
|
0a34f22240 | ||
|
|
b0651fcaed | ||
|
|
d59faa2a08 | ||
|
|
6a3bc37dc1 | ||
|
|
2ea7796b26 | ||
|
|
cf0057bac4 | ||
|
|
fafb325a88 | ||
|
|
6b69b4671f | ||
|
|
eaa95ee840 | ||
|
|
a86ba1fdf6 | ||
|
|
09e0d2d15b | ||
|
|
6d9fa6418d | ||
|
|
6010f5b7a6 | ||
|
|
9c164e1cea | ||
|
|
880fba8dce | ||
|
|
17d57ee49a | ||
|
|
234949a627 | ||
|
|
ff34671526 | ||
|
|
6e22983d98 | ||
|
|
18254c30ec | ||
|
|
922c955239 | ||
|
|
618a325057 | ||
|
|
d81cb7f866 | ||
|
|
f71a4d5381 | ||
|
|
282cb60a66 | ||
|
|
58dbac4422 | ||
|
|
53e228465b | ||
|
|
06426e4fd7 | ||
|
|
c55a97c24d | ||
|
|
0d61289bf3 | ||
|
|
bf10cbc70b | ||
|
|
2d945e426b | ||
|
|
13250887fa | ||
|
|
3507c22968 | ||
|
|
cc3f98ebcd | ||
|
|
4116e2d6ac | ||
|
|
48eab6b4a7 | ||
|
|
25866b5369 | ||
|
|
c4dd06fa45 | ||
|
|
4846d211e0 | ||
|
|
a586ad1237 | ||
|
|
b701c9c464 | ||
|
|
d0f20ed2bf | ||
|
|
0f64a2f3b0 | ||
|
|
bd83fba6cd | ||
|
|
15b9255a25 | ||
|
|
6794d21487 | ||
|
|
118c4432ec | ||
|
|
ccda429bf1 | ||
|
|
590937d2a0 | ||
|
|
241827dd80 | ||
|
|
77b4e0b4bd | ||
|
|
6a53cb32d8 | ||
|
|
f12ff3b15e | ||
|
|
69ad8676b7 | ||
|
|
d0fd756f6b | ||
|
|
7f8ab67e9e | ||
|
|
0e68bb3d2c | ||
|
|
d5b3933752 | ||
|
|
0b7206a92d | ||
|
|
e875f306fd | ||
|
|
8ed5e5ee28 | ||
|
|
948b0d40f6 | ||
|
|
48f4feb7a7 | ||
|
|
ddc0a32bbc | ||
|
|
10a7c54364 | ||
|
|
a66fa9d844 | ||
|
|
a16f2ac15c | ||
|
|
b699797a40 | ||
|
|
a6e9520d06 | ||
|
|
f8310b1296 | ||
|
|
353bf99cd5 | ||
|
|
a478e4acc9 | ||
|
|
d810e0ba7d | ||
|
|
1e51ffdb72 | ||
|
|
7da1d1fc64 | ||
|
|
957697c383 | ||
|
|
107eb72225 | ||
|
|
810b77f9da | ||
|
|
5e3bc2049b | ||
|
|
229500347d | ||
|
|
1f461db0a1 | ||
|
|
6c55aafee3 | ||
|
|
d57e55b719 | ||
|
|
bf772e5fe5 | ||
|
|
413f3356ce | ||
|
|
f147326fe0 | ||
|
|
30c59644b6 | ||
|
|
3fa5acf2e6 | ||
|
|
3e6ded8823 | ||
|
|
612017aaa2 | ||
|
|
ef57d7e7b6 | ||
|
|
a8d0db5036 | ||
|
|
ad6b5f8fc1 | ||
|
|
e3cb6a0aec | ||
|
|
cbf18a7dc4 | ||
|
|
01559410a9 | ||
|
|
f2ab94fa7f | ||
|
|
d7394a8369 | ||
|
|
9feef11d6f | ||
|
|
dc4e5ddc3c | ||
|
|
8600781bb6 | ||
|
|
bdc7bbdc9d | ||
|
|
73badef594 | ||
|
|
9474e6c08c | ||
|
|
653ded0e6f | ||
|
|
e34bec7dee | ||
|
|
610b560fb5 | ||
|
|
0a03ddb8a7 | ||
|
|
f31790631a | ||
|
|
e07128760e | ||
|
|
dd02ae313d | ||
|
|
d14b0b6843 | ||
|
|
f763c8a777 | ||
|
|
4231b040d8 | ||
|
|
67c587e673 | ||
|
|
3978e24fd8 | ||
|
|
c45de0c032 | ||
|
|
ff935efea1 | ||
|
|
808464f47d | ||
|
|
c986a6c4dd | ||
|
|
17c0479343 | ||
|
|
d93238912a | ||
|
|
d6ef0956e6 | ||
|
|
05db0aad29 | ||
|
|
89bbdfa1fe | ||
|
|
871bda6198 | ||
|
|
20732c9206 | ||
|
|
2a34a3ebb6 | ||
|
|
3f04247a53 | ||
|
|
ca0a1f8f8b | ||
|
|
d8a9f0ca12 | ||
|
|
c2116b841e | ||
|
|
700cf69f18 | ||
|
|
ed5dee5218 | ||
|
|
b224dfdfac | ||
|
|
e7da68547f | ||
|
|
9a785ceb2e | ||
|
|
fca1cd5a1c | ||
|
|
24b862e32e | ||
|
|
2ec9043cf2 | ||
|
|
1102d63469 | ||
|
|
b89f39d78c | ||
|
|
7ba479c9c9 | ||
|
|
8ad6a2980c | ||
|
|
d3b6ed78d9 | ||
|
|
8bd5605c2a | ||
|
|
08dc2fcf33 | ||
|
|
caa8d16371 | ||
|
|
bce92b3d85 | ||
|
|
67858bf300 | ||
|
|
7157e7e77d | ||
|
|
cf5074bdc5 | ||
|
|
fda44063ce | ||
|
|
f9becda02c | ||
|
|
fb9fc952c6 | ||
|
|
18451edfe9 | ||
|
|
8c73cac72f | ||
|
|
c54cedf14b | ||
|
|
8ef4cdc9c3 | ||
|
|
c0213e84f6 | ||
|
|
29de6d89d4 | ||
|
|
c9bf38ce36 | ||
|
|
338eb75bab | ||
|
|
31b1b453b0 | ||
|
|
aaf0e145eb | ||
|
|
089b3e13fd | ||
|
|
e9da2ce12a | ||
|
|
92048ac17b | ||
|
|
5e8561a578 | ||
|
|
d2f5e13074 | ||
|
|
820178f006 | ||
|
|
0a36a91e6d | ||
|
|
5013a92795 | ||
|
|
d81ecfec32 | ||
|
|
e99d7e2c3c | ||
|
|
d417984ff3 | ||
|
|
d38b3e641b | ||
|
|
28ce491dd5 | ||
|
|
c260d72125 | ||
|
|
d1d1b3156d | ||
|
|
472064b751 | ||
|
|
95ab9a0b70 | ||
|
|
4b03f6a039 | ||
|
|
c3460727fa | ||
|
|
2cc1850212 | ||
|
|
2d7443acaf | ||
|
|
13d0b0940c | ||
|
|
c101797924 | ||
|
|
83b55f8e3f | ||
|
|
b3b6362cd9 | ||
|
|
fc9af32d5f | ||
|
|
4cd1025011 | ||
|
|
5233fe8abc | ||
|
|
041e31ea78 | ||
|
|
7a3e881099 | ||
|
|
631bf42f84 | ||
|
|
1f704a7019 | ||
|
|
d295c88474 | ||
|
|
1dd9da4dff | ||
|
|
f2eb0c8427 | ||
|
|
c8ba11faf8 | ||
|
|
a2e243d992 | ||
|
|
c588fff5ca | ||
|
|
87f9599fea | ||
|
|
0459599b1d | ||
|
|
9447b1a696 | ||
|
|
0ccb7443c2 | ||
|
|
02cf27091f | ||
|
|
fdfbd04503 | ||
|
|
866c18200a | ||
|
|
c1cada49d4 | ||
|
|
7bf550a75f | ||
|
|
9c540c03aa | ||
|
|
b3df46db19 | ||
|
|
7ca615a1c1 | ||
|
|
c83db557a6 | ||
|
|
d54594f11d | ||
|
|
434e38608f | ||
|
|
871f090ca0 | ||
|
|
d1d235e025 | ||
|
|
e822a5fd53 | ||
|
|
7b82a4ae50 | ||
|
|
c532e9f2eb | ||
|
|
3fd034816e | ||
|
|
bb4b868c79 | ||
|
|
3b3da11a36 | ||
|
|
f2cbb5306b | ||
|
|
94ede1b324 | ||
|
|
0367248338 | ||
|
|
936db30e58 | ||
|
|
4822f0dd11 | ||
|
|
456d220829 | ||
|
|
b459ba6ea7 | ||
|
|
a19ef9bd16 | ||
|
|
59cec88a28 | ||
|
|
3ebc75af80 | ||
|
|
4dce474e03 | ||
|
|
31a18da578 | ||
|
|
8c499850fc | ||
|
|
6b6998a247 | ||
|
|
a6cb0fc856 | ||
|
|
e36b93e87b | ||
|
|
1e3723b8bb | ||
|
|
412372289e | ||
|
|
96f7e66073 | ||
|
|
6040f8f263 | ||
|
|
9761b6e14a | ||
|
|
cb49910ed2 |
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
|
||||
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: skypjack
|
||||
custom: https://www.paypal.me/skypjack
|
||||
61
.github/workflows/analyzer.yml
vendored
Normal file
61
.github/workflows/analyzer.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: analyzer
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- wip
|
||||
|
||||
jobs:
|
||||
|
||||
iwyu:
|
||||
timeout-minutes: 30
|
||||
|
||||
env:
|
||||
IWYU: 0.19
|
||||
LLVM: 15
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
continue-on-error: true
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install llvm/clang
|
||||
# see: https://apt.llvm.org/
|
||||
run: |
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-$LLVM main"
|
||||
sudo apt update
|
||||
sudo apt remove -y "llvm*"
|
||||
sudo apt remove -y "libclang-dev*"
|
||||
sudo apt remove -y "clang*"
|
||||
sudo apt install -y llvm-$LLVM-dev
|
||||
sudo apt install -y libclang-$LLVM-dev
|
||||
sudo apt install -y clang-$LLVM
|
||||
- name: Compile iwyu
|
||||
# see: https://github.com/include-what-you-use/include-what-you-use
|
||||
working-directory: build
|
||||
run: |
|
||||
git clone https://github.com/include-what-you-use/include-what-you-use.git --branch $IWYU --depth 1
|
||||
mkdir include-what-you-use/build
|
||||
cd include-what-you-use/build
|
||||
cmake -DCMAKE_C_COMPILER=clang-$LLVM \
|
||||
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
|
||||
-DCMAKE_INSTALL_PREFIX=./ \
|
||||
..
|
||||
make -j4
|
||||
bin/include-what-you-use --version
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
export PATH=$PATH:${GITHUB_WORKSPACE}/build/include-what-you-use/build/bin
|
||||
cmake -DCMAKE_C_COMPILER=clang-$LLVM \
|
||||
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
|
||||
-DENTT_BUILD_TESTING=ON \
|
||||
-DENTT_BUILD_BENCHMARK=ON \
|
||||
-DENTT_BUILD_EXAMPLE=ON \
|
||||
-DENTT_BUILD_LIB=ON \
|
||||
-DENTT_BUILD_SNAPSHOT=ON \
|
||||
-DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="include-what-you-use;-Xiwyu;--mapping_file=${GITHUB_WORKSPACE}/entt.imp;-Xiwyu;--no_fwd_decls;-Xiwyu;--verbose=1" \
|
||||
..
|
||||
make -j4
|
||||
144
.github/workflows/build.yml
vendored
Normal file
144
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
name: build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
linux:
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, ubuntu-20.04]
|
||||
compiler:
|
||||
- { pkg: g++, exe: 'g++', version: 7 }
|
||||
- { pkg: g++, exe: 'g++', version: 8 }
|
||||
- { pkg: g++, exe: 'g++', version: 9 }
|
||||
- { pkg: g++, exe: 'g++', version: 10 }
|
||||
- { pkg: g++, exe: 'g++', version: 11 }
|
||||
- { pkg: g++, exe: 'g++', version: 12 }
|
||||
- { pkg: clang, exe: 'clang++', version: 8 }
|
||||
- { pkg: clang, exe: 'clang++', version: 9 }
|
||||
- { pkg: clang, exe: 'clang++', version: 10 }
|
||||
- { pkg: clang, exe: 'clang++', version: 11 }
|
||||
- { pkg: clang, exe: 'clang++', version: 12 }
|
||||
- { pkg: clang, exe: 'clang++', version: 13 }
|
||||
- { pkg: clang, exe: 'clang++', version: 14 }
|
||||
exclude:
|
||||
- os: ubuntu-latest
|
||||
compiler: { pkg: g++, exe: 'g++', version: 7 }
|
||||
- os: ubuntu-latest
|
||||
compiler: { pkg: g++, exe: 'g++', version: 8 }
|
||||
- os: ubuntu-latest
|
||||
compiler: { pkg: g++, exe: 'g++', version: 9 }
|
||||
- os: ubuntu-latest
|
||||
compiler: { pkg: clang, exe: 'clang++', version: 8 }
|
||||
- os: ubuntu-latest
|
||||
compiler: { pkg: clang, exe: 'clang++', version: 9 }
|
||||
- os: ubuntu-latest
|
||||
compiler: { pkg: clang, exe: 'clang++', version: 10 }
|
||||
- os: ubuntu-latest
|
||||
compiler: { pkg: clang, exe: 'clang++', version: 11 }
|
||||
- os: ubuntu-20.04
|
||||
compiler: { pkg: g++, exe: 'g++', version: 10 }
|
||||
- os: ubuntu-20.04
|
||||
compiler: { pkg: g++, exe: 'g++', version: 11 }
|
||||
- os: ubuntu-20.04
|
||||
compiler: { pkg: g++, exe: 'g++', version: 12 }
|
||||
- os: ubuntu-20.04
|
||||
compiler: { pkg: clang, exe: 'clang++', version: 12 }
|
||||
- os: ubuntu-20.04
|
||||
compiler: { pkg: clang, exe: 'clang++', version: 13 }
|
||||
- os: ubuntu-20.04
|
||||
compiler: { pkg: clang, exe: 'clang++', version: 14 }
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install compiler
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y ${{ matrix.compiler.pkg }}-${{ matrix.compiler.version }}
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXX: ${{ matrix.compiler.exe }}-${{ matrix.compiler.version }}
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
|
||||
make -j4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
windows:
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
toolset: [default, v141, v142, clang-cl]
|
||||
include:
|
||||
- toolset: v141
|
||||
toolset_option: -T"v141"
|
||||
- toolset: v142
|
||||
toolset_option: -T"v142"
|
||||
- toolset: clang-cl
|
||||
toolset_option: -T"ClangCl"
|
||||
|
||||
runs-on: windows-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.toolset_option }} ..
|
||||
cmake --build . -j 4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
macos:
|
||||
timeout-minutes: 15
|
||||
runs-on: macOS-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
|
||||
make -j4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
|
||||
extra:
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, macOS-latest, ubuntu-latest]
|
||||
id_type: ["std::uint32_t", "std::uint64_t"]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} ..
|
||||
cmake --build . -j 4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
38
.github/workflows/coverage.yml
vendored
Normal file
38
.github/workflows/coverage.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: coverage
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
codecov:
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXXFLAGS: "--coverage -fno-elide-constructors -fno-inline -fno-default-inline"
|
||||
CXX: g++
|
||||
run: |
|
||||
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
|
||||
make -j4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
- name: Collect data
|
||||
working-directory: build
|
||||
run: |
|
||||
sudo apt install lcov
|
||||
lcov -c -d . -o coverage.info
|
||||
lcov -l coverage.info
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: build/coverage.info
|
||||
name: EnTT
|
||||
fail_ci_if_error: true
|
||||
39
.github/workflows/deploy.yml
vendored
Normal file
39
.github/workflows/deploy.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: deploy
|
||||
|
||||
on:
|
||||
release:
|
||||
types: published
|
||||
|
||||
jobs:
|
||||
|
||||
homebrew-entt:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
GH_REPO: homebrew-entt
|
||||
FORMULA: entt.rb
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clone repository
|
||||
working-directory: build
|
||||
env:
|
||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
|
||||
run: git clone https://$GITHUB_ACTOR:$PERSONAL_ACCESS_TOKEN@github.com/$GITHUB_ACTOR/$GH_REPO.git
|
||||
- name: Prepare formula
|
||||
working-directory: build
|
||||
run: |
|
||||
cd $GH_REPO
|
||||
curl "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" --location --fail --silent --show-error --output archive.tar.gz
|
||||
sed -i -e '/url/s/".*"/"'$(echo "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" | sed -e 's/[\/&]/\\&/g')'"/' $FORMULA
|
||||
sed -i -e '/sha256/s/".*"/"'$(openssl sha256 archive.tar.gz | cut -d " " -f 2)'"/' $FORMULA
|
||||
- name: Update remote
|
||||
working-directory: build
|
||||
run: |
|
||||
cd $GH_REPO
|
||||
git config --local user.email "action@github.com"
|
||||
git config --local user.name "$GITHUB_ACTOR"
|
||||
git add $FORMULA
|
||||
git commit -m "Update to ${{ github.ref }}"
|
||||
git push origin master
|
||||
31
.github/workflows/sanitizer.yml
vendored
Normal file
31
.github/workflows/sanitizer.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
name: sanitizer
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
|
||||
clang:
|
||||
timeout-minutes: 15
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [clang++]
|
||||
id_type: ["std::uint32_t", "std::uint64_t"]
|
||||
cxx_std: [cxx_std_17, cxx_std_20]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Compile tests
|
||||
working-directory: build
|
||||
env:
|
||||
CXX: ${{ matrix.compiler }}
|
||||
run: |
|
||||
cmake -DENTT_USE_SANITIZER=ON -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} ..
|
||||
make -j4
|
||||
- name: Run tests
|
||||
working-directory: build
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
run: ctest --timeout 30 -C Debug -j4
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -1,2 +1,13 @@
|
||||
# QtCreator
|
||||
# Conan
|
||||
conan/test_package/build
|
||||
|
||||
# IDEs
|
||||
*.user
|
||||
.idea
|
||||
.vscode
|
||||
.vs
|
||||
CMakeSettings.json
|
||||
cpp.hint
|
||||
|
||||
# Bazel
|
||||
/bazel-*
|
||||
|
||||
73
.travis.yml
73
.travis.yml
@@ -1,73 +0,0 @@
|
||||
language: cpp
|
||||
dist: trusty
|
||||
sudo: false
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-6']
|
||||
env: COMPILER=g++-6
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-7']
|
||||
env: COMPILER=g++-7
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0']
|
||||
packages: ['clang-4.0', 'libstdc++-4.9-dev']
|
||||
env: COMPILER=clang++-4.0
|
||||
- os: linux
|
||||
compiler: clang
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']
|
||||
packages: ['clang-5.0', 'libstdc++-4.9-dev']
|
||||
env: COMPILER=clang++-5.0
|
||||
- os: osx
|
||||
osx_image: xcode8.3
|
||||
compiler: clang
|
||||
env: COMPILER=clang++
|
||||
- os: osx
|
||||
osx_image: xcode9.1
|
||||
compiler: clang
|
||||
env: COMPILER=clang++
|
||||
- os: linux
|
||||
compiler: gcc
|
||||
addons:
|
||||
apt:
|
||||
sources: ['ubuntu-toolchain-r-test']
|
||||
packages: ['g++-7']
|
||||
env:
|
||||
- COMPILER=g++-7
|
||||
- CXXFLAGS="-O0 --coverage -fno-inline -fno-inline-small-functions -fno-default-inline"
|
||||
before_script:
|
||||
- pip install --user cpp-coveralls
|
||||
after_success:
|
||||
- coveralls --gcov gcov-7 --gcov-options '\-lp' --root ${TRAVIS_BUILD_DIR} --build-root ${TRAVIS_BUILD_DIR}/build --extension cpp --extension hpp --exclude deps --include src
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
on_failure: always
|
||||
|
||||
install:
|
||||
- echo ${PATH}
|
||||
- cmake --version
|
||||
- export CXX=${COMPILER}
|
||||
- echo ${CXX}
|
||||
- ${CXX} --version
|
||||
- ${CXX} -v
|
||||
|
||||
script:
|
||||
- mkdir -p build && cd build
|
||||
- cmake .. && make -j4
|
||||
- CTEST_OUTPUT_ON_FAILURE=1 make test
|
||||
53
AUTHORS
53
AUTHORS
@@ -1,7 +1,56 @@
|
||||
# Author
|
||||
|
||||
Michele Caini aka skypjack
|
||||
skypjack
|
||||
|
||||
# Contributors
|
||||
|
||||
Paolo Monteverde aka morbo84
|
||||
alexames
|
||||
BenediktConze
|
||||
bjadamson
|
||||
ceeac
|
||||
ColinH
|
||||
corystegel
|
||||
Croydon
|
||||
cschreib
|
||||
cugone
|
||||
dbacchet
|
||||
dBagrat
|
||||
djarek
|
||||
DNKpp
|
||||
DonKult
|
||||
drglove
|
||||
eliasdaler
|
||||
erez-o
|
||||
eugeneko
|
||||
gale83
|
||||
ghost
|
||||
grdowns
|
||||
Green-Sky
|
||||
Innokentiy-Alaytsev
|
||||
Kerndog73
|
||||
Koward
|
||||
Lawrencemm
|
||||
markand
|
||||
mhammerc
|
||||
Milerius
|
||||
Minimonium
|
||||
morbo84
|
||||
m-waka
|
||||
netpoetica
|
||||
NixAJ
|
||||
Oortonaut
|
||||
Paolo-Oliverio
|
||||
pgruenbacher
|
||||
prowolf
|
||||
Qix-
|
||||
stefanofiorentino
|
||||
suVrik
|
||||
szunhammer
|
||||
The5-1
|
||||
vblanco20-1
|
||||
willtunnels
|
||||
WizardIke
|
||||
WoLfulus
|
||||
w1th0utnam3
|
||||
xissburg
|
||||
zaucy
|
||||
|
||||
14
BUILD.bazel
Normal file
14
BUILD.bazel
Normal file
@@ -0,0 +1,14 @@
|
||||
_msvc_copts = ["/std:c++17"]
|
||||
_gcc_copts = ["-std=c++17"]
|
||||
|
||||
cc_library(
|
||||
name = "entt",
|
||||
visibility = ["//visibility:public"],
|
||||
strip_include_prefix = "src",
|
||||
hdrs = glob(["src/**/*.h", "src/**/*.hpp"]),
|
||||
copts = select({
|
||||
"@bazel_tools//src/conditions:windows": _msvc_copts,
|
||||
"@bazel_tools//src/conditions:windows_msvc": _msvc_copts,
|
||||
"//conditions:default": _gcc_copts,
|
||||
}),
|
||||
)
|
||||
335
CMakeLists.txt
335
CMakeLists.txt
@@ -2,85 +2,310 @@
|
||||
# EnTT
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
cmake_minimum_required(VERSION 3.15.7)
|
||||
|
||||
#
|
||||
# Building in-tree is not allowed (we take care of your craziness).
|
||||
# Read project version
|
||||
#
|
||||
|
||||
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
|
||||
message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the source code and call cmake from there. Thank you.")
|
||||
endif()
|
||||
set(ENTT_VERSION_REGEX "#define ENTT_VERSION_.*[ \t]+(.+)")
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/src/entt/config/version.h" ENTT_VERSION REGEX ${ENTT_VERSION_REGEX})
|
||||
list(TRANSFORM ENTT_VERSION REPLACE ${ENTT_VERSION_REGEX} "\\1")
|
||||
string(JOIN "." ENTT_VERSION ${ENTT_VERSION})
|
||||
|
||||
#
|
||||
# Project configuration
|
||||
#
|
||||
|
||||
project(entt VERSION 2.4.0)
|
||||
project(
|
||||
EnTT
|
||||
VERSION ${ENTT_VERSION}
|
||||
DESCRIPTION "Gaming meets modern C++ - a fast and reliable entity-component system (ECS) and much more"
|
||||
HOMEPAGE_URL "https://github.com/skypjack/entt"
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
endif()
|
||||
|
||||
set(SETTINGS_ORGANIZATION "Michele Caini")
|
||||
set(SETTINGS_APPLICATION ${PROJECT_NAME})
|
||||
set(PROJECT_AUTHOR "Michele Caini")
|
||||
set(PROJECT_AUTHOR_EMAIL "michele.caini@gmail.com")
|
||||
message(VERBOSE "*")
|
||||
message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||
message(VERBOSE "* Copyright (c) 2017-2023 Michele Caini <michele.caini@gmail.com>")
|
||||
message(VERBOSE "*")
|
||||
|
||||
message("*")
|
||||
message("* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
|
||||
message("* Copyright (c) 2017 ${PROJECT_AUTHOR} <${PROJECT_AUTHOR_EMAIL}>")
|
||||
message("*")
|
||||
#
|
||||
# CMake stuff
|
||||
#
|
||||
|
||||
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||
|
||||
#
|
||||
# Compiler stuff
|
||||
#
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." OFF)
|
||||
option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags if available." OFF)
|
||||
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DRELEASE")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0 -g -DDEBUG")
|
||||
if(ENTT_USE_LIBCPP)
|
||||
if(NOT WIN32)
|
||||
include(CheckCXXSourceCompiles)
|
||||
include(CMakePushCheckState)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# it seems that -O3 ruins the performance when using clang ...
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
|
||||
else()
|
||||
# ... on the other side, GCC is incredibly comfortable with it.
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
cmake_push_check_state()
|
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -stdlib=libc++")
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include<type_traits>
|
||||
int main() { return std::is_same_v<int, char>; }
|
||||
" ENTT_HAS_LIBCPP)
|
||||
|
||||
cmake_pop_check_state()
|
||||
endif()
|
||||
|
||||
if(NOT ENTT_HAS_LIBCPP)
|
||||
message(VERBOSE "The option ENTT_USE_LIBCPP is set but libc++ is not available. The flag will not be added to the target.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ENTT_USE_SANITIZER)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||
set(ENTT_HAS_SANITIZER TRUE CACHE BOOL "" FORCE)
|
||||
mark_as_advanced(ENTT_HAS_SANITIZER)
|
||||
endif()
|
||||
|
||||
if(NOT ENTT_HAS_SANITIZER)
|
||||
message(VERBOSE "The option ENTT_USE_SANITIZER is set but sanitizer support is not available. The flags will not be added to the target.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# Include EnTT
|
||||
# Add EnTT target
|
||||
#
|
||||
|
||||
include_directories(${entt_SOURCE_DIR}/src)
|
||||
option(ENTT_INCLUDE_HEADERS "Add all EnTT headers to the EnTT target." OFF)
|
||||
option(ENTT_INCLUDE_NATVIS "Add EnTT natvis files to the EnTT target." OFF)
|
||||
|
||||
if(ENTT_INCLUDE_NATVIS)
|
||||
if(MSVC)
|
||||
set(ENTT_HAS_NATVIS TRUE CACHE BOOL "" FORCE)
|
||||
mark_as_advanced(ENTT_HAS_NATVIS)
|
||||
endif()
|
||||
|
||||
if(NOT ENTT_HAS_NATVIS)
|
||||
message(VERBOSE "The option ENTT_INCLUDE_NATVIS is set but natvis files are not supported. They will not be added to the target.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
add_library(EnTT INTERFACE)
|
||||
add_library(EnTT::EnTT ALIAS EnTT)
|
||||
|
||||
target_include_directories(
|
||||
EnTT
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
target_compile_features(EnTT INTERFACE cxx_std_17)
|
||||
|
||||
if(ENTT_INCLUDE_HEADERS)
|
||||
target_sources(
|
||||
EnTT
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/config.h>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/macro.h>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/version.h>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_map.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_set.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/algorithm.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/any.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/attribute.h>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/compressed_pair.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/enum.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/family.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/hashed_string.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/ident.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/iterator.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/memory.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/monostate.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/tuple.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_info.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/type_traits.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/utility.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/component.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/entity.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/group.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/handle.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/mixin.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/helper.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/observer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/organizer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/registry.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/runtime_view.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/snapshot.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/sparse_set.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/storage.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/view.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/adjacency_matrix.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/dot.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/flow.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/locator/locator.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/adl_pointer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/container.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/context.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/factory.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/meta.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/node.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/pointer.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/policy.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/range.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/resolve.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/template.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/type_traits.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/utility.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/platform/android-ndk-r17.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/poly.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/process.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/scheduler.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/cache.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/loader.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/resource.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/delegate.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/dispatcher.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/emitter.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/fwd.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/sigh.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entt.hpp>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/fwd.hpp>
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENTT_HAS_NATVIS)
|
||||
target_sources(
|
||||
EnTT
|
||||
INTERFACE
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/config.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/container.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/core.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/entity.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/graph.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/locator.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/meta.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/platform.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/poly.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/process.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/resource.natvis>
|
||||
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/signal.natvis>
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ENTT_HAS_SANITIZER)
|
||||
target_compile_options(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
|
||||
target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
|
||||
endif()
|
||||
|
||||
if(ENTT_HAS_LIBCPP)
|
||||
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Install pkg-config file
|
||||
#
|
||||
|
||||
include(JoinPaths)
|
||||
|
||||
set(EnTT_PKGCONFIG ${CMAKE_CURRENT_BINARY_DIR}/entt.pc)
|
||||
|
||||
join_paths(EnTT_PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
|
||||
configure_file(
|
||||
${EnTT_SOURCE_DIR}/cmake/in/entt.pc.in
|
||||
${EnTT_PKGCONFIG}
|
||||
@ONLY
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${EnTT_PKGCONFIG}
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
|
||||
)
|
||||
|
||||
#
|
||||
# Install EnTT
|
||||
#
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
install(
|
||||
TARGETS EnTT
|
||||
EXPORT EnTTTargets
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
write_basic_package_version_file(
|
||||
EnTTConfigVersion.cmake
|
||||
VERSION ${PROJECT_VERSION}
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
|
||||
configure_package_config_file(
|
||||
${EnTT_SOURCE_DIR}/cmake/in/EnTTConfig.cmake.in
|
||||
EnTTConfig.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
|
||||
)
|
||||
|
||||
export(
|
||||
EXPORT EnTTTargets
|
||||
FILE ${CMAKE_CURRENT_BINARY_DIR}/EnTTTargets.cmake
|
||||
NAMESPACE EnTT::
|
||||
)
|
||||
|
||||
install(
|
||||
EXPORT EnTTTargets
|
||||
FILE EnTTTargets.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
|
||||
NAMESPACE EnTT::
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
${PROJECT_BINARY_DIR}/EnTTConfig.cmake
|
||||
${PROJECT_BINARY_DIR}/EnTTConfigVersion.cmake
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
|
||||
)
|
||||
|
||||
install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
export(PACKAGE EnTT)
|
||||
|
||||
#
|
||||
# Tests
|
||||
#
|
||||
|
||||
option(BUILD_TESTING "Enable testing with ctest." ON)
|
||||
option(ENTT_BUILD_TESTING "Enable building tests." OFF)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
if(ENTT_BUILD_TESTING)
|
||||
option(ENTT_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
|
||||
option(ENTT_BUILD_BENCHMARK "Build benchmark." OFF)
|
||||
option(ENTT_BUILD_EXAMPLE "Build examples." OFF)
|
||||
option(ENTT_BUILD_LIB "Build lib tests." OFF)
|
||||
option(ENTT_BUILD_SNAPSHOT "Build snapshot test with Cereal." OFF)
|
||||
|
||||
option(BUILD_BENCHMARK "Build benchmark." OFF)
|
||||
option(BUILD_MOD "Build mod example." OFF)
|
||||
|
||||
# gtest, gtest_main, gmock and gmock_main targets are available from now on
|
||||
set(GOOGLETEST_DEPS_DIR ${entt_SOURCE_DIR}/deps/googletest)
|
||||
configure_file(${entt_SOURCE_DIR}/cmake/in/googletest.in ${GOOGLETEST_DEPS_DIR}/CMakeLists.txt)
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
add_subdirectory(${GOOGLETEST_DEPS_DIR}/src ${GOOGLETEST_DEPS_DIR}/build)
|
||||
set(ENTT_ID_TYPE std::uint32_t CACHE STRING "Type of identifiers to use for the tests")
|
||||
set(ENTT_CXX_STD cxx_std_17 CACHE STRING "C++ standard revision to use for the tests")
|
||||
|
||||
include(CTest)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
@@ -89,22 +314,12 @@ endif()
|
||||
# Documentation
|
||||
#
|
||||
|
||||
find_package(Doxygen 1.8)
|
||||
option(ENTT_BUILD_DOCS "Enable building with documentation." OFF)
|
||||
|
||||
if(DOXYGEN_FOUND)
|
||||
add_subdirectory(docs)
|
||||
if(ENTT_BUILD_DOCS)
|
||||
find_package(Doxygen 1.8)
|
||||
|
||||
if(DOXYGEN_FOUND)
|
||||
add_subdirectory(docs)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# AOB
|
||||
#
|
||||
|
||||
add_custom_target(
|
||||
entt_aob
|
||||
SOURCES
|
||||
appveyor.yml
|
||||
AUTHORS
|
||||
LICENSE
|
||||
README.md
|
||||
.travis.yml
|
||||
)
|
||||
|
||||
43
CONTRIBUTING.md
Normal file
43
CONTRIBUTING.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Contributing
|
||||
|
||||
First of all, thank you very much for taking the time to contribute to the
|
||||
`EnTT` library.<br/>
|
||||
How to do it mostly depends on the type of contribution:
|
||||
|
||||
* If you have a question, **please** ensure there isn't already an answer for
|
||||
you by searching on GitHub under
|
||||
[issues](https://github.com/skypjack/entt/issues). Do not forget to search
|
||||
also through the closed ones. If you are unable to find a proper answer, feel
|
||||
free to [open a new issue](https://github.com/skypjack/entt/issues/new).
|
||||
Usually, questions are marked as such and closed in a few days.
|
||||
|
||||
* If you want to fix a typo in the inline documentation or in the README file,
|
||||
if you want to add some new sections or if you want to help me with the
|
||||
language by reviewing what I wrote so far (I'm not a native speaker after
|
||||
all), **please** open a new
|
||||
[pull request](https://github.com/skypjack/entt/pulls) with your changes.
|
||||
|
||||
* If you found a bug, **please** ensure there isn't already an answer for you by
|
||||
searching on GitHub under [issues](https://github.com/skypjack/entt/issues).
|
||||
If you are unable to find an open issue addressing the problem, feel free to
|
||||
[open a new one](https://github.com/skypjack/entt/issues/new). **Please**, do
|
||||
not forget to carefully describe how to reproduce the problem, then add all
|
||||
the information about the system on which you are experiencing it and point
|
||||
out the version of `EnTT` you are using (tag or commit).
|
||||
|
||||
* If you found a bug and you wrote a patch to fix it, open a new
|
||||
[pull request](https://github.com/skypjack/entt/pulls) with your code.
|
||||
**Please**, add some tests to avoid regressions in future if possible, it
|
||||
would be really appreciated. Note that the `EnTT` library has a
|
||||
[coverage at 100%](https://coveralls.io/github/skypjack/entt?branch=master)
|
||||
(at least it was at 100% at the time I wrote this file) and this is the reason
|
||||
for which you can be confident with using it in a production environment.
|
||||
|
||||
* If you want to propose a new feature and you know how to code it, **please**
|
||||
do not issue directly a pull request. Before to do it,
|
||||
[create a new issue](https://github.com/skypjack/entt/issues/new) to discuss
|
||||
your proposal. Other users could be interested in your idea and the discussion
|
||||
that will follow can refine it and therefore give us a better solution.
|
||||
|
||||
* If you want to request a new feature, I'm available for hiring. Take a look at
|
||||
[my profile](https://github.com/skypjack) and feel free to write me.
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Michele Caini
|
||||
Copyright (c) 2017-2023 Michele Caini, author of EnTT
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
26
TODO
Normal file
26
TODO
Normal file
@@ -0,0 +1,26 @@
|
||||
EXAMPLES
|
||||
* filter on runtime values/variables (not only types)
|
||||
* support to polymorphic types (see #859)
|
||||
|
||||
DOC:
|
||||
* custom storage/view
|
||||
* examples (and credits) from @alanjfs :)
|
||||
* update entity doc when the storage based model is in place
|
||||
* in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
|
||||
|
||||
TODO (high prio):
|
||||
* check natvis files (periodically :)
|
||||
* resource cache: avoid using shared ptr with loader and the others
|
||||
* further optimize exclusion lists in multi type views (no existence check)
|
||||
* further improve the snapshot stuff, ie component functions
|
||||
* use fixture for storage tests to reduce loc number and duplication as much as possible
|
||||
* basic_view<...>::reach(...)
|
||||
* doc: bump entities
|
||||
|
||||
WIP:
|
||||
* get rid of observers, storage based views made them pointless - document alternatives
|
||||
* exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details)
|
||||
* process scheduler: reviews, use free lists internally
|
||||
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
|
||||
* bring nested groups back in place (see bd34e7f)
|
||||
* work stealing job system (see #100) + mt scheduler based on const awareness for types
|
||||
22
appveyor.yml
22
appveyor.yml
@@ -1,22 +0,0 @@
|
||||
# can use variables like {build} and {branch}
|
||||
version: 1.0.{build}
|
||||
|
||||
image: Visual Studio 2017
|
||||
|
||||
environment:
|
||||
BUILD_DIR: "%APPVEYOR_BUILD_FOLDER%\\build"
|
||||
|
||||
platform:
|
||||
- Win32
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
||||
before_build:
|
||||
- cd %BUILD_DIR%
|
||||
- cmake .. -DCMAKE_CXX_FLAGS=/D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING -G"Visual Studio 15 2017"
|
||||
|
||||
build:
|
||||
parallel: true
|
||||
project: build/entt.sln
|
||||
verbosity: minimal
|
||||
5
cmake/in/EnTTConfig.cmake.in
Normal file
5
cmake/in/EnTTConfig.cmake.in
Normal file
@@ -0,0 +1,5 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
set(EnTT_VERSION "@PROJECT_VERSION@")
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/EnTTTargets.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
8
cmake/in/entt.pc.in
Normal file
8
cmake/in/entt.pc.in
Normal file
@@ -0,0 +1,8 @@
|
||||
prefix=@CMAKE_INSTALL_PREFIX@
|
||||
includedir=@EnTT_PKGCONFIG_INCLUDEDIR@
|
||||
|
||||
Name: EnTT
|
||||
Description: Gaming meets modern C++
|
||||
Url: https://github.com/skypjack/entt
|
||||
Version: @ENTT_VERSION@
|
||||
Cflags: -I${includedir}
|
||||
@@ -1,19 +0,0 @@
|
||||
project(googletest-download NONE)
|
||||
cmake_minimum_required(VERSION 3.2)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(
|
||||
googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG release-1.8.0
|
||||
DOWNLOAD_DIR ${GOOGLETEST_DEPS_DIR}
|
||||
TMP_DIR ${GOOGLETEST_DEPS_DIR}/tmp
|
||||
STAMP_DIR ${GOOGLETEST_DEPS_DIR}/stamp
|
||||
SOURCE_DIR ${GOOGLETEST_DEPS_DIR}/src
|
||||
BINARY_DIR ${GOOGLETEST_DEPS_DIR}/build
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
23
cmake/modules/JoinPaths.cmake
Normal file
23
cmake/modules/JoinPaths.cmake
Normal file
@@ -0,0 +1,23 @@
|
||||
# This module provides function for joining paths
|
||||
# known from most languages
|
||||
#
|
||||
# SPDX-License-Identifier: (MIT OR CC0-1.0)
|
||||
# Copyright 2020 Jan Tojnar
|
||||
# https://github.com/jtojnar/cmake-snips
|
||||
#
|
||||
# Modelled after Python’s os.path.join
|
||||
# https://docs.python.org/3.7/library/os.path.html#os.path.join
|
||||
# Windows not supported
|
||||
function(join_paths joined_path first_path_segment)
|
||||
set(temp_path "${first_path_segment}")
|
||||
foreach(current_segment IN LISTS ARGN)
|
||||
if(NOT ("${current_segment}" STREQUAL ""))
|
||||
if(IS_ABSOLUTE "${current_segment}")
|
||||
set(temp_path "${current_segment}")
|
||||
else()
|
||||
set(temp_path "${temp_path}/${current_segment}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
set(${joined_path} "${temp_path}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
37
conan/build.py
Normal file
37
conan/build.py
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from cpt.packager import ConanMultiPackager
|
||||
import os
|
||||
|
||||
if __name__ == "__main__":
|
||||
username = os.getenv("GITHUB_ACTOR")
|
||||
tag_version = os.getenv("GITHUB_REF")
|
||||
tag_package = os.getenv("GITHUB_REPOSITORY")
|
||||
login_username = os.getenv("CONAN_LOGIN_USERNAME")
|
||||
package_version = tag_version.replace("refs/tags/v", "")
|
||||
package_name = tag_package.replace("skypjack/", "")
|
||||
reference = "{}/{}".format(package_name, package_version)
|
||||
channel = os.getenv("CONAN_CHANNEL", "stable")
|
||||
upload = os.getenv("CONAN_UPLOAD")
|
||||
stable_branch_pattern = os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*")
|
||||
test_folder = os.getenv("CPT_TEST_FOLDER", os.path.join("conan", "test_package"))
|
||||
upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True)
|
||||
disable_shared = os.getenv("CONAN_DISABLE_SHARED_BUILD", "False")
|
||||
|
||||
builder = ConanMultiPackager(username=username,
|
||||
reference=reference,
|
||||
channel=channel,
|
||||
login_username=login_username,
|
||||
upload=upload,
|
||||
stable_branch_pattern=stable_branch_pattern,
|
||||
upload_only_when_stable=upload_only_when_stable,
|
||||
test_folder=test_folder)
|
||||
builder.add()
|
||||
|
||||
filtered_builds = []
|
||||
for settings, options, env_vars, build_requires, reference in builder.items:
|
||||
if disable_shared == "False" or not options["{}:shared".format(package_name)]:
|
||||
filtered_builds.append([settings, options, env_vars, build_requires])
|
||||
builder.builds = filtered_builds
|
||||
|
||||
builder.run()
|
||||
7
conan/ci/build.sh
Normal file
7
conan/ci/build.sh
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
conan user
|
||||
python conan/build.py
|
||||
6
conan/ci/install.sh
Normal file
6
conan/ci/install.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
pip install -U conan_package_tools conan
|
||||
13
conan/test_package/CMakeLists.txt
Normal file
13
conan/test_package/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
cmake_minimum_required(VERSION 3.7.2)
|
||||
project(test_package)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE TRUE)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
|
||||
conan_basic_setup()
|
||||
|
||||
add_executable(${PROJECT_NAME} test_package.cpp)
|
||||
target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
|
||||
19
conan/test_package/conanfile.py
Normal file
19
conan/test_package/conanfile.py
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from conans import ConanFile, CMake
|
||||
import os
|
||||
|
||||
|
||||
class TestPackageConan(ConanFile):
|
||||
settings = "os", "compiler", "build_type", "arch"
|
||||
generators = "cmake"
|
||||
|
||||
def build(self):
|
||||
cmake = CMake(self)
|
||||
cmake.configure()
|
||||
cmake.build()
|
||||
|
||||
def test(self):
|
||||
bin_path = os.path.join("bin", "test_package")
|
||||
self.run(bin_path, run_environment=True)
|
||||
56
conan/test_package/test_package.cpp
Normal file
56
conan/test_package/test_package.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <entt/entt.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
struct position {
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
struct velocity {
|
||||
float dx;
|
||||
float dy;
|
||||
};
|
||||
|
||||
void update(entt::registry ®istry) {
|
||||
auto view = registry.view<position, velocity>();
|
||||
|
||||
for(auto entity: view) {
|
||||
// gets only the components that are going to be used ...
|
||||
|
||||
auto &vel = view.get<velocity>(entity);
|
||||
|
||||
vel.dx = 0.;
|
||||
vel.dy = 0.;
|
||||
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
void update(std::uint64_t dt, entt::registry ®istry) {
|
||||
registry.view<position, velocity>().each([dt](auto &pos, auto &vel) {
|
||||
// gets all the components of the view at once ...
|
||||
|
||||
pos.x += vel.dx * dt;
|
||||
pos.y += vel.dy * dt;
|
||||
|
||||
// ...
|
||||
});
|
||||
}
|
||||
|
||||
int main() {
|
||||
entt::registry registry;
|
||||
std::uint64_t dt = 16;
|
||||
|
||||
for(auto i = 0; i < 10; ++i) {
|
||||
auto entity = registry.create();
|
||||
registry.emplace<position>(entity, i * 1.f, i * 1.f);
|
||||
if(i % 2 == 0) { registry.emplace<velocity>(entity, i * .1f, i * .1f); }
|
||||
}
|
||||
|
||||
update(dt, registry);
|
||||
update(registry);
|
||||
|
||||
// ...
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
27
conanfile.py
Normal file
27
conanfile.py
Normal file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from conans import ConanFile
|
||||
|
||||
|
||||
class EnttConan(ConanFile):
|
||||
name = "entt"
|
||||
description = "Gaming meets modern C++ - a fast and reliable entity-component system (ECS) and much more "
|
||||
topics = ("conan," "entt", "gaming", "entity", "ecs")
|
||||
url = "https://github.com/skypjack/entt"
|
||||
homepage = url
|
||||
author = "Michele Caini <michele.caini@gmail.com>"
|
||||
license = "MIT"
|
||||
exports = ["LICENSE"]
|
||||
exports_sources = ["src/*"]
|
||||
no_copy_source = True
|
||||
|
||||
def package(self):
|
||||
self.copy(pattern="LICENSE", dst="licenses")
|
||||
self.copy(pattern="*", dst="include", src="src", keep_path=True)
|
||||
|
||||
def package_info(self):
|
||||
if not self.in_local_cache:
|
||||
self.cpp_info.includedirs = ["src"]
|
||||
|
||||
def package_id(self):
|
||||
self.info.header_only()
|
||||
2
deps/.gitignore
vendored
2
deps/.gitignore
vendored
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -2,20 +2,50 @@
|
||||
# Doxygen configuration (documentation)
|
||||
#
|
||||
|
||||
set(TARGET_DOCS docs)
|
||||
FetchContent_Declare(
|
||||
doxygen-awesome-css
|
||||
GIT_REPOSITORY https://github.com/jothepro/doxygen-awesome-css
|
||||
GIT_TAG main
|
||||
GIT_SHALLOW 1
|
||||
)
|
||||
|
||||
set(DOXY_SOURCE_DIRECTORY ${entt_SOURCE_DIR}/src)
|
||||
FetchContent_GetProperties(doxygen-awesome-css)
|
||||
|
||||
if(NOT doxygen-awesome-css_POPULATED)
|
||||
FetchContent_Populate(doxygen-awesome-css)
|
||||
set(doxygen-awesome-css_INCLUDE_DIR ${doxygen-awesome-css_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src)
|
||||
set(DOXY_CSS_DIRECTORY ${doxygen-awesome-css_INCLUDE_DIR})
|
||||
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
configure_file(doxy.in doxy.cfg @ONLY)
|
||||
|
||||
add_custom_target(
|
||||
${TARGET_DOCS}
|
||||
docs ALL
|
||||
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg
|
||||
WORKING_DIRECTORY ${entt_SOURCE_DIR}
|
||||
WORKING_DIRECTORY ${EnTT_SOURCE_DIR}
|
||||
VERBATIM
|
||||
SOURCES doxy.in
|
||||
SOURCES
|
||||
dox/extra.dox
|
||||
md/config.md
|
||||
md/container.md
|
||||
md/core.md
|
||||
md/entity.md
|
||||
md/faq.md
|
||||
md/lib.md
|
||||
md/links.md
|
||||
md/locator.md
|
||||
md/meta.md
|
||||
md/poly.md
|
||||
md/process.md
|
||||
md/reference.md
|
||||
md/resource.md
|
||||
md/signal.md
|
||||
md/unreal.md
|
||||
doxy.in
|
||||
)
|
||||
|
||||
install(
|
||||
|
||||
395
docs/LICENSE
395
docs/LICENSE
@@ -1,395 +0,0 @@
|
||||
Attribution 4.0 International
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Corporation ("Creative Commons") is not a law firm and
|
||||
does not provide legal services or legal advice. Distribution of
|
||||
Creative Commons public licenses does not create a lawyer-client or
|
||||
other relationship. Creative Commons makes its licenses and related
|
||||
information available on an "as-is" basis. Creative Commons gives no
|
||||
warranties regarding its licenses, any material licensed under their
|
||||
terms and conditions, or any related information. Creative Commons
|
||||
disclaims all liability for damages resulting from their use to the
|
||||
fullest extent possible.
|
||||
|
||||
Using Creative Commons Public Licenses
|
||||
|
||||
Creative Commons public licenses provide a standard set of terms and
|
||||
conditions that creators and other rights holders may use to share
|
||||
original works of authorship and other material subject to copyright
|
||||
and certain other rights specified in the public license below. The
|
||||
following considerations are for informational purposes only, are not
|
||||
exhaustive, and do not form part of our licenses.
|
||||
|
||||
Considerations for licensors: Our public licenses are
|
||||
intended for use by those authorized to give the public
|
||||
permission to use material in ways otherwise restricted by
|
||||
copyright and certain other rights. Our licenses are
|
||||
irrevocable. Licensors should read and understand the terms
|
||||
and conditions of the license they choose before applying it.
|
||||
Licensors should also secure all rights necessary before
|
||||
applying our licenses so that the public can reuse the
|
||||
material as expected. Licensors should clearly mark any
|
||||
material not subject to the license. This includes other CC-
|
||||
licensed material, or material used under an exception or
|
||||
limitation to copyright. More considerations for licensors:
|
||||
wiki.creativecommons.org/Considerations_for_licensors
|
||||
|
||||
Considerations for the public: By using one of our public
|
||||
licenses, a licensor grants the public permission to use the
|
||||
licensed material under specified terms and conditions. If
|
||||
the licensor's permission is not necessary for any reason--for
|
||||
example, because of any applicable exception or limitation to
|
||||
copyright--then that use is not regulated by the license. Our
|
||||
licenses grant only permissions under copyright and certain
|
||||
other rights that a licensor has authority to grant. Use of
|
||||
the licensed material may still be restricted for other
|
||||
reasons, including because others have copyright or other
|
||||
rights in the material. A licensor may make special requests,
|
||||
such as asking that all changes be marked or described.
|
||||
Although not required by our licenses, you are encouraged to
|
||||
respect those requests where reasonable. More_considerations
|
||||
for the public:
|
||||
wiki.creativecommons.org/Considerations_for_licensees
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons Attribution 4.0 International Public License
|
||||
|
||||
By exercising the Licensed Rights (defined below), You accept and agree
|
||||
to be bound by the terms and conditions of this Creative Commons
|
||||
Attribution 4.0 International Public License ("Public License"). To the
|
||||
extent this Public License may be interpreted as a contract, You are
|
||||
granted the Licensed Rights in consideration of Your acceptance of
|
||||
these terms and conditions, and the Licensor grants You such rights in
|
||||
consideration of benefits the Licensor receives from making the
|
||||
Licensed Material available under these terms and conditions.
|
||||
|
||||
|
||||
Section 1 -- Definitions.
|
||||
|
||||
a. Adapted Material means material subject to Copyright and Similar
|
||||
Rights that is derived from or based upon the Licensed Material
|
||||
and in which the Licensed Material is translated, altered,
|
||||
arranged, transformed, or otherwise modified in a manner requiring
|
||||
permission under the Copyright and Similar Rights held by the
|
||||
Licensor. For purposes of this Public License, where the Licensed
|
||||
Material is a musical work, performance, or sound recording,
|
||||
Adapted Material is always produced where the Licensed Material is
|
||||
synched in timed relation with a moving image.
|
||||
|
||||
b. Adapter's License means the license You apply to Your Copyright
|
||||
and Similar Rights in Your contributions to Adapted Material in
|
||||
accordance with the terms and conditions of this Public License.
|
||||
|
||||
c. Copyright and Similar Rights means copyright and/or similar rights
|
||||
closely related to copyright including, without limitation,
|
||||
performance, broadcast, sound recording, and Sui Generis Database
|
||||
Rights, without regard to how the rights are labeled or
|
||||
categorized. For purposes of this Public License, the rights
|
||||
specified in Section 2(b)(1)-(2) are not Copyright and Similar
|
||||
Rights.
|
||||
|
||||
d. Effective Technological Measures means those measures that, in the
|
||||
absence of proper authority, may not be circumvented under laws
|
||||
fulfilling obligations under Article 11 of the WIPO Copyright
|
||||
Treaty adopted on December 20, 1996, and/or similar international
|
||||
agreements.
|
||||
|
||||
e. Exceptions and Limitations means fair use, fair dealing, and/or
|
||||
any other exception or limitation to Copyright and Similar Rights
|
||||
that applies to Your use of the Licensed Material.
|
||||
|
||||
f. Licensed Material means the artistic or literary work, database,
|
||||
or other material to which the Licensor applied this Public
|
||||
License.
|
||||
|
||||
g. Licensed Rights means the rights granted to You subject to the
|
||||
terms and conditions of this Public License, which are limited to
|
||||
all Copyright and Similar Rights that apply to Your use of the
|
||||
Licensed Material and that the Licensor has authority to license.
|
||||
|
||||
h. Licensor means the individual(s) or entity(ies) granting rights
|
||||
under this Public License.
|
||||
|
||||
i. Share means to provide material to the public by any means or
|
||||
process that requires permission under the Licensed Rights, such
|
||||
as reproduction, public display, public performance, distribution,
|
||||
dissemination, communication, or importation, and to make material
|
||||
available to the public including in ways that members of the
|
||||
public may access the material from a place and at a time
|
||||
individually chosen by them.
|
||||
|
||||
j. Sui Generis Database Rights means rights other than copyright
|
||||
resulting from Directive 96/9/EC of the European Parliament and of
|
||||
the Council of 11 March 1996 on the legal protection of databases,
|
||||
as amended and/or succeeded, as well as other essentially
|
||||
equivalent rights anywhere in the world.
|
||||
|
||||
k. You means the individual or entity exercising the Licensed Rights
|
||||
under this Public License. Your has a corresponding meaning.
|
||||
|
||||
|
||||
Section 2 -- Scope.
|
||||
|
||||
a. License grant.
|
||||
|
||||
1. Subject to the terms and conditions of this Public License,
|
||||
the Licensor hereby grants You a worldwide, royalty-free,
|
||||
non-sublicensable, non-exclusive, irrevocable license to
|
||||
exercise the Licensed Rights in the Licensed Material to:
|
||||
|
||||
a. reproduce and Share the Licensed Material, in whole or
|
||||
in part; and
|
||||
|
||||
b. produce, reproduce, and Share Adapted Material.
|
||||
|
||||
2. Exceptions and Limitations. For the avoidance of doubt, where
|
||||
Exceptions and Limitations apply to Your use, this Public
|
||||
License does not apply, and You do not need to comply with
|
||||
its terms and conditions.
|
||||
|
||||
3. Term. The term of this Public License is specified in Section
|
||||
6(a).
|
||||
|
||||
4. Media and formats; technical modifications allowed. The
|
||||
Licensor authorizes You to exercise the Licensed Rights in
|
||||
all media and formats whether now known or hereafter created,
|
||||
and to make technical modifications necessary to do so. The
|
||||
Licensor waives and/or agrees not to assert any right or
|
||||
authority to forbid You from making technical modifications
|
||||
necessary to exercise the Licensed Rights, including
|
||||
technical modifications necessary to circumvent Effective
|
||||
Technological Measures. For purposes of this Public License,
|
||||
simply making modifications authorized by this Section 2(a)
|
||||
(4) never produces Adapted Material.
|
||||
|
||||
5. Downstream recipients.
|
||||
|
||||
a. Offer from the Licensor -- Licensed Material. Every
|
||||
recipient of the Licensed Material automatically
|
||||
receives an offer from the Licensor to exercise the
|
||||
Licensed Rights under the terms and conditions of this
|
||||
Public License.
|
||||
|
||||
b. No downstream restrictions. You may not offer or impose
|
||||
any additional or different terms or conditions on, or
|
||||
apply any Effective Technological Measures to, the
|
||||
Licensed Material if doing so restricts exercise of the
|
||||
Licensed Rights by any recipient of the Licensed
|
||||
Material.
|
||||
|
||||
6. No endorsement. Nothing in this Public License constitutes or
|
||||
may be construed as permission to assert or imply that You
|
||||
are, or that Your use of the Licensed Material is, connected
|
||||
with, or sponsored, endorsed, or granted official status by,
|
||||
the Licensor or others designated to receive attribution as
|
||||
provided in Section 3(a)(1)(A)(i).
|
||||
|
||||
b. Other rights.
|
||||
|
||||
1. Moral rights, such as the right of integrity, are not
|
||||
licensed under this Public License, nor are publicity,
|
||||
privacy, and/or other similar personality rights; however, to
|
||||
the extent possible, the Licensor waives and/or agrees not to
|
||||
assert any such rights held by the Licensor to the limited
|
||||
extent necessary to allow You to exercise the Licensed
|
||||
Rights, but not otherwise.
|
||||
|
||||
2. Patent and trademark rights are not licensed under this
|
||||
Public License.
|
||||
|
||||
3. To the extent possible, the Licensor waives any right to
|
||||
collect royalties from You for the exercise of the Licensed
|
||||
Rights, whether directly or through a collecting society
|
||||
under any voluntary or waivable statutory or compulsory
|
||||
licensing scheme. In all other cases the Licensor expressly
|
||||
reserves any right to collect such royalties.
|
||||
|
||||
|
||||
Section 3 -- License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the
|
||||
following conditions.
|
||||
|
||||
a. Attribution.
|
||||
|
||||
1. If You Share the Licensed Material (including in modified
|
||||
form), You must:
|
||||
|
||||
a. retain the following if it is supplied by the Licensor
|
||||
with the Licensed Material:
|
||||
|
||||
i. identification of the creator(s) of the Licensed
|
||||
Material and any others designated to receive
|
||||
attribution, in any reasonable manner requested by
|
||||
the Licensor (including by pseudonym if
|
||||
designated);
|
||||
|
||||
ii. a copyright notice;
|
||||
|
||||
iii. a notice that refers to this Public License;
|
||||
|
||||
iv. a notice that refers to the disclaimer of
|
||||
warranties;
|
||||
|
||||
v. a URI or hyperlink to the Licensed Material to the
|
||||
extent reasonably practicable;
|
||||
|
||||
b. indicate if You modified the Licensed Material and
|
||||
retain an indication of any previous modifications; and
|
||||
|
||||
c. indicate the Licensed Material is licensed under this
|
||||
Public License, and include the text of, or the URI or
|
||||
hyperlink to, this Public License.
|
||||
|
||||
2. You may satisfy the conditions in Section 3(a)(1) in any
|
||||
reasonable manner based on the medium, means, and context in
|
||||
which You Share the Licensed Material. For example, it may be
|
||||
reasonable to satisfy the conditions by providing a URI or
|
||||
hyperlink to a resource that includes the required
|
||||
information.
|
||||
|
||||
3. If requested by the Licensor, You must remove any of the
|
||||
information required by Section 3(a)(1)(A) to the extent
|
||||
reasonably practicable.
|
||||
|
||||
4. If You Share Adapted Material You produce, the Adapter's
|
||||
License You apply must not prevent recipients of the Adapted
|
||||
Material from complying with this Public License.
|
||||
|
||||
|
||||
Section 4 -- Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that
|
||||
apply to Your use of the Licensed Material:
|
||||
|
||||
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
|
||||
to extract, reuse, reproduce, and Share all or a substantial
|
||||
portion of the contents of the database;
|
||||
|
||||
b. if You include all or a substantial portion of the database
|
||||
contents in a database in which You have Sui Generis Database
|
||||
Rights, then the database in which You have Sui Generis Database
|
||||
Rights (but not its individual contents) is Adapted Material; and
|
||||
|
||||
c. You must comply with the conditions in Section 3(a) if You Share
|
||||
all or a substantial portion of the contents of the database.
|
||||
|
||||
For the avoidance of doubt, this Section 4 supplements and does not
|
||||
replace Your obligations under this Public License where the Licensed
|
||||
Rights include other Copyright and Similar Rights.
|
||||
|
||||
|
||||
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
|
||||
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
|
||||
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
|
||||
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
|
||||
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
|
||||
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
|
||||
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
|
||||
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
|
||||
|
||||
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
|
||||
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
|
||||
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
|
||||
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
|
||||
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
|
||||
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
|
||||
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
|
||||
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
|
||||
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
|
||||
|
||||
c. The disclaimer of warranties and limitation of liability provided
|
||||
above shall be interpreted in a manner that, to the extent
|
||||
possible, most closely approximates an absolute disclaimer and
|
||||
waiver of all liability.
|
||||
|
||||
|
||||
Section 6 -- Term and Termination.
|
||||
|
||||
a. This Public License applies for the term of the Copyright and
|
||||
Similar Rights licensed here. However, if You fail to comply with
|
||||
this Public License, then Your rights under this Public License
|
||||
terminate automatically.
|
||||
|
||||
b. Where Your right to use the Licensed Material has terminated under
|
||||
Section 6(a), it reinstates:
|
||||
|
||||
1. automatically as of the date the violation is cured, provided
|
||||
it is cured within 30 days of Your discovery of the
|
||||
violation; or
|
||||
|
||||
2. upon express reinstatement by the Licensor.
|
||||
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any
|
||||
right the Licensor may have to seek remedies for Your violations
|
||||
of this Public License.
|
||||
|
||||
c. For the avoidance of doubt, the Licensor may also offer the
|
||||
Licensed Material under separate terms or conditions or stop
|
||||
distributing the Licensed Material at any time; however, doing so
|
||||
will not terminate this Public License.
|
||||
|
||||
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
|
||||
License.
|
||||
|
||||
|
||||
Section 7 -- Other Terms and Conditions.
|
||||
|
||||
a. The Licensor shall not be bound by any additional or different
|
||||
terms or conditions communicated by You unless expressly agreed.
|
||||
|
||||
b. Any arrangements, understandings, or agreements regarding the
|
||||
Licensed Material not stated herein are separate from and
|
||||
independent of the terms and conditions of this Public License.
|
||||
|
||||
|
||||
Section 8 -- Interpretation.
|
||||
|
||||
a. For the avoidance of doubt, this Public License does not, and
|
||||
shall not be interpreted to, reduce, limit, restrict, or impose
|
||||
conditions on any use of the Licensed Material that could lawfully
|
||||
be made without permission under this Public License.
|
||||
|
||||
b. To the extent possible, if any provision of this Public License is
|
||||
deemed unenforceable, it shall be automatically reformed to the
|
||||
minimum extent necessary to make it enforceable. If the provision
|
||||
cannot be reformed, it shall be severed from this Public License
|
||||
without affecting the enforceability of the remaining terms and
|
||||
conditions.
|
||||
|
||||
c. No term or condition of this Public License will be waived and no
|
||||
failure to comply consented to unless expressly agreed to by the
|
||||
Licensor.
|
||||
|
||||
d. Nothing in this Public License constitutes or may be interpreted
|
||||
as a limitation upon, or waiver of, any privileges and immunities
|
||||
that apply to the Licensor or You, including from the legal
|
||||
processes of any jurisdiction or authority.
|
||||
|
||||
|
||||
=======================================================================
|
||||
|
||||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
otherwise permitted by the Creative Commons policies published at
|
||||
creativecommons.org/policies, Creative Commons does not authorize the
|
||||
use of the trademark "Creative Commons" or any other trademark or logo
|
||||
of Creative Commons without its prior written consent including,
|
||||
without limitation, in connection with any unauthorized modifications
|
||||
to any of its public licenses or any other arrangements,
|
||||
understandings, or agreements concerning use of licensed material. For
|
||||
the avoidance of doubt, this paragraph does not form part of the
|
||||
public licenses.
|
||||
|
||||
Creative Commons may be contacted at creativecommons.org.
|
||||
820
docs/doxy.in
820
docs/doxy.in
File diff suppressed because it is too large
Load Diff
120
docs/md/config.md
Normal file
120
docs/md/config.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Crash Course: configuration
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Definitions](#definitions)
|
||||
* [ENTT_NOEXCEPTION](#entt_noexception)
|
||||
* [ENTT_USE_ATOMIC](#entt_use_atomic)
|
||||
* [ENTT_ID_TYPE](#entt_id_type)
|
||||
* [ENTT_SPARSE_PAGE](#entt_sparse_page)
|
||||
* [ENTT_PACKED_PAGE](#entt_packed_page)
|
||||
* [ENTT_ASSERT](#entt_assert)
|
||||
* [ENTT_ASSERT_CONSTEXPR](#entt_assert_constexpr)
|
||||
* [ENTT_DISABLE_ASSERT](#entt_disable_assert)
|
||||
* [ENTT_NO_ETO](#entt_no_eto)
|
||||
* [ENTT_STANDARD_CPP](#entt_standard_cpp)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
`EnTT` has become almost completely customizable over time, in many
|
||||
respects. These variables are just one of the many ways to customize how it
|
||||
works.<br/>
|
||||
In the vast majority of cases, users will have no interest in changing the
|
||||
default parameters. For all other cases, the list of possible configurations
|
||||
with which it's possible to adjust the behavior of the library at runtime can be
|
||||
found below.
|
||||
|
||||
# Definitions
|
||||
|
||||
All options are intended as parameters to the compiler (or user-defined macros
|
||||
within the compilation units, if preferred).<br/>
|
||||
Each parameter can result in internal library definitions. It's not recommended
|
||||
to try to also modify these definitions, since there is no guarantee that they
|
||||
will remain stable over time unlike the options below.
|
||||
|
||||
## ENTT_NOEXCEPTION
|
||||
|
||||
Define this variable without assigning any value to it to turn off exception
|
||||
handling in `EnTT`.<br/>
|
||||
This is roughly equivalent to setting the compiler flag `-fno-exceptions` but is
|
||||
also limited to this library only.
|
||||
|
||||
## ENTT_USE_ATOMIC
|
||||
|
||||
In general, `EnTT` doesn't offer primitives to support multi-threading. Many of
|
||||
the features can be split over multiple threads without any explicit control and
|
||||
the user is the one who knows if a synchronization point is required.<br/>
|
||||
However, some features aren't easily accessible to users and are made
|
||||
thread-safe by means of this definition.
|
||||
|
||||
## ENTT_ID_TYPE
|
||||
|
||||
`entt::id_type` is directly controlled by this definition and widely used within
|
||||
the library.<br/>
|
||||
By default, its type is `std::uint32_t`. However, users can define a different
|
||||
default type if necessary.
|
||||
|
||||
## ENTT_SPARSE_PAGE
|
||||
|
||||
It's known that the ECS module of `EnTT` is based on _sparse sets_. What is less
|
||||
known perhaps is that the sparse arrays are paged to reduce memory usage.<br/>
|
||||
Default size of pages (that is, the number of elements they contain) is 4096 but
|
||||
users can adjust it if appropriate. In all case, the chosen value **must** be a
|
||||
power of 2.
|
||||
|
||||
## ENTT_PACKED_PAGE
|
||||
|
||||
As it happens with sparse arrays, packed arrays are also paginated. However, in
|
||||
this case the aim isn't to reduce memory usage but to have pointer stability
|
||||
upon component creation.<br/>
|
||||
Default size of pages (that is, the number of elements they contain) is 1024 but
|
||||
users can adjust it if appropriate. In all case, the chosen value **must** be a
|
||||
power of 2.
|
||||
|
||||
## ENTT_ASSERT
|
||||
|
||||
For performance reasons, `EnTT` doesn't use exceptions or any other control
|
||||
structures. In fact, it offers many features that result in undefined behavior
|
||||
if not used correctly.<br/>
|
||||
To get around this, the library relies on a lot of asserts for the purpose of
|
||||
detecting errors in debug builds. By default, it uses `assert` internally. Users
|
||||
are allowed to overwrite its behavior by setting this variable.
|
||||
|
||||
### ENTT_ASSERT_CONSTEXPR
|
||||
|
||||
Usually, an assert within a `constexpr` function isn't a big deal. However, in
|
||||
case of extreme customizations, it might be useful to differentiate.<br/>
|
||||
For this purpose, `EnTT` introduces an admittedly badly named variable to make
|
||||
the job easier in this regard. By default, this variable forwards its arguments
|
||||
to `ENTT_ASSERT`.
|
||||
|
||||
### ENTT_DISABLE_ASSERT
|
||||
|
||||
Assertions may in turn affect performance to an extent when enabled. Whether
|
||||
`ENTT_ASSERT` and `ENTT_ASSERT_CONSTEXPR` are redefined or not, all asserts can
|
||||
be disabled at once by means of this definition.<br/>
|
||||
Note that `ENTT_DISABLE_ASSERT` takes precedence over the redefinition of the
|
||||
other variables and is therefore meant to disable all controls no matter what.
|
||||
|
||||
## ENTT_NO_ETO
|
||||
|
||||
In order to reduce memory consumption and increase performance, empty types are
|
||||
never instantiated nor stored by the ECS module of `EnTT`.<br/>
|
||||
Use this variable to treat these types like all others and therefore to create a
|
||||
dedicated storage for them.
|
||||
|
||||
## ENTT_STANDARD_CPP
|
||||
|
||||
`EnTT` mixes non-standard language features with others that are perfectly
|
||||
compliant to offer some of its functionalities.<br/>
|
||||
This definition prevents the library from using non-standard techniques, that
|
||||
is, functionalities that aren't fully compliant with the standard C++.<br/>
|
||||
While there are no known portability issues at the time of this writing, this
|
||||
should make the library fully portable anyway if needed.
|
||||
66
docs/md/container.md
Normal file
66
docs/md/container.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Crash Course: containers
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Containers](#containers)
|
||||
* [Dense map](#dense-map)
|
||||
* [Dense set](#dense-set)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
The standard C++ library offers a wide range of containers and it's really
|
||||
difficult to do better (although it's very easy to do worse, as many examples
|
||||
available online demonstrate).<br/>
|
||||
`EnTT` doesn't try in any way to replace what is offered by the standard. Quite
|
||||
the opposite, given the widespread use that is made of standard containers.<br/>
|
||||
However, the library also tries to fill a gap in features and functionalities by
|
||||
making available some containers initially developed for internal use.
|
||||
|
||||
This section of the library is likely to grow larger over time. However, for the
|
||||
moment it's quite small and mainly aimed at satisfying some internal needs.<br/>
|
||||
For all containers made available, full test coverage and stability over time is
|
||||
guaranteed as usual.
|
||||
|
||||
# Containers
|
||||
|
||||
## Dense map
|
||||
|
||||
The dense map made available in `EnTT` is a hash map that aims to return a
|
||||
packed array of elements, so as to reduce the number of jumps in memory during
|
||||
iterations.<br/>
|
||||
The implementation is based on _sparse sets_ and each bucket is identified by an
|
||||
implicit list within the packed array itself.
|
||||
|
||||
The interface is very close to its counterpart in the standard library, that is,
|
||||
the `std::unordered_map` class.<br/>
|
||||
However, both local and non-local iterators returned by a dense map belong to
|
||||
the input iterator category although they respectively model the concepts of a
|
||||
_forward iterator_ type and a _random access iterator_ type.<br/>
|
||||
This is because they return a pair of references rather than a reference to a
|
||||
pair. In other words, dense maps return a so called _proxy iterator_ the value
|
||||
type of which is:
|
||||
|
||||
* `std::pair<const Key &, Type &>` for non-const iterator types.
|
||||
* `std::pair<const Key &, const Type &>` for const iterator types.
|
||||
|
||||
This is quite different from what any standard library map returns and should be
|
||||
taken into account when looking for a drop-in replacement.
|
||||
|
||||
## Dense set
|
||||
|
||||
The dense set made available in `EnTT` is a hash set that aims to return a
|
||||
packed array of elements, so as to reduce the number of jumps in memory during
|
||||
iterations.<br/>
|
||||
The implementation is based on _sparse sets_ and each bucket is identified by an
|
||||
implicit list within the packed array itself.
|
||||
|
||||
The interface is in all respects similar to its counterpart in the standard
|
||||
library, that is, the `std::unordered_set` class.<br/>
|
||||
Therefore, there is no need to go into the API description.
|
||||
986
docs/md/core.md
Normal file
986
docs/md/core.md
Normal file
@@ -0,0 +1,986 @@
|
||||
# Crash Course: core functionalities
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Any as in any type](#any-as-in-any-type)
|
||||
* [Small buffer optimization](#small-buffer-optimization)
|
||||
* [Alignment requirement](#alignment-requirement)
|
||||
* [Compressed pair](#compressed-pair)
|
||||
* [Enum as bitmask](#enum-as-bitmask)
|
||||
* [Hashed strings](#hashed-strings)
|
||||
* [Wide characters](wide-characters)
|
||||
* [Conflicts](#conflicts)
|
||||
* [Iterators](#iterators)
|
||||
* [Input iterator pointer](#input-iterator-pointer)
|
||||
* [Iota iterator](#iota-iterator)
|
||||
* [Iterable adaptor](#iterable-adaptor)
|
||||
* [Memory](#memory)
|
||||
* [Power of two and fast modulus](#power-of-two-and-fast-modulus)
|
||||
* [Allocator aware unique pointers](#allocator-aware-unique-pointers)
|
||||
* [Monostate](#monostate)
|
||||
* [Type support](#type-support)
|
||||
* [Built-in RTTI support](#built-in-rtti-support)
|
||||
* [Type info](#type-info)
|
||||
* [Almost unique identifiers](#almost-unique-identifiers)
|
||||
* [Type traits](#type-traits)
|
||||
* [Size of](#size-of)
|
||||
* [Is applicable](#is-applicable)
|
||||
* [Constness as](#constness-as)
|
||||
* [Member class type](#member-class-type)
|
||||
* [N-th argument](#n-th-argument)
|
||||
* [Integral constant](#integral-constant)
|
||||
* [Tag](#tag)
|
||||
* [Type list and value list](#type-list-and-value-list)
|
||||
* [Unique sequential identifiers](#unique-sequential-identifiers)
|
||||
* [Compile-time generator](#compile-time-generator)
|
||||
* [Runtime generator](#runtime-generator)
|
||||
* [Utilities](#utilities)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
`EnTT` comes with a bunch of core functionalities mostly used by the other parts
|
||||
of the library.<br/>
|
||||
Many of these tools are also useful in everyday work. Therefore, it's worth
|
||||
describing them so as not to reinvent the wheel in case of need.
|
||||
|
||||
# Any as in any type
|
||||
|
||||
`EnTT` offers its own `any` type. It may seem redundant considering that C++17
|
||||
introduced `std::any`, but it is not (hopefully).<br/>
|
||||
First of all, the _type_ returned by an `std::any` is a const reference to an
|
||||
`std::type_info`, an implementation defined class that's not something everyone
|
||||
wants to see in a software. Furthermore, there is no way to bind it to the type
|
||||
system of the library and therefore with its integrated RTTI support.
|
||||
|
||||
The `any` API is very similar to that of its most famous counterpart, mainly
|
||||
because this class serves the same purpose of being an opaque container for any
|
||||
type of value.<br/>
|
||||
Instances also minimize the number of allocations by relying on a well known
|
||||
technique called _small buffer optimization_ and a fake vtable.
|
||||
|
||||
Creating an object of the `any` type, whether empty or not, is trivial:
|
||||
|
||||
```cpp
|
||||
// an empty container
|
||||
entt::any empty{};
|
||||
|
||||
// a container for an int
|
||||
entt::any any{0};
|
||||
|
||||
// in place construction
|
||||
entt::any in_place{std::in_place_type<int>, 42};
|
||||
```
|
||||
|
||||
Alternatively, the `make_any` function serves the same purpose but requires to
|
||||
always be explicit about the type:
|
||||
|
||||
```cpp
|
||||
entt::any any = entt::make_any<int>(42);
|
||||
```
|
||||
|
||||
In both cases, the `any` class takes the burden of destroying the contained
|
||||
element when required, regardless of the storage strategy used for the specific
|
||||
object.<br/>
|
||||
Furthermore, an instance of `any` isn't tied to an actual type. Therefore, the
|
||||
wrapper is reconfigured when it's assigned a new object of a type other than
|
||||
the one it contains.
|
||||
|
||||
There is also a way to directly assign a value to the variable contained by an
|
||||
`entt::any`, without necessarily replacing it. This is especially useful when
|
||||
the object is used in _aliasing mode_, as described below:
|
||||
|
||||
```cpp
|
||||
entt::any any{42};
|
||||
entt::any value{3};
|
||||
|
||||
// assigns by copy
|
||||
any.assign(value);
|
||||
|
||||
// assigns by move
|
||||
any.assign(std::move(value));
|
||||
```
|
||||
|
||||
The `any` class performs a check on the type information and whether or not the
|
||||
original type was copy or move assignable, as appropriate.<br/>
|
||||
In all cases, the `assign` function returns a boolean value that is true in case
|
||||
of success and false otherwise.
|
||||
|
||||
When in doubt about the type of object contained, the `type` member function
|
||||
returns a const reference to the `type_info` associated with its element, or
|
||||
`type_id<void>()` if the container is empty.<br/>
|
||||
The type is also used internally when comparing two `any` objects:
|
||||
|
||||
```cpp
|
||||
if(any == empty) { /* ... */ }
|
||||
```
|
||||
|
||||
In this case, before proceeding with a comparison, it's verified that the _type_
|
||||
of the two objects is actually the same.<br/>
|
||||
Refer to the `EnTT` type system documentation for more details about how
|
||||
`type_info` works and the possible risks of a comparison.
|
||||
|
||||
A particularly interesting feature of this class is that it can also be used as
|
||||
an opaque container for const and non-const references:
|
||||
|
||||
```cpp
|
||||
int value = 42;
|
||||
|
||||
entt::any any{std::in_place_type<int &>(value)};
|
||||
entt::any cany = entt::make_any<const int &>(value);
|
||||
entt::any fwd = entt::forward_as_any(value);
|
||||
|
||||
any.emplace<const int &>(value);
|
||||
```
|
||||
|
||||
In other words, whenever `any` is explicitly told to construct an _alias_, it
|
||||
acts as a pointer to the original instance rather than making a copy of it or
|
||||
moving it internally. The contained object is never destroyed and users must
|
||||
ensure that its lifetime exceeds that of the container.<br/>
|
||||
Similarly, it's possible to create non-owning copies of `any` from an existing
|
||||
object:
|
||||
|
||||
```cpp
|
||||
// aliasing constructor
|
||||
entt::any ref = other.as_ref();
|
||||
```
|
||||
|
||||
In this case, it doesn't matter if the original container actually holds an
|
||||
object or is as a reference for unmanaged elements already. The new instance
|
||||
thus created doesn't create copies and only serves as a reference for the
|
||||
original item.
|
||||
|
||||
It's worth mentioning that, while everything works transparently when it comes
|
||||
to non-const references, there are some exceptions when it comes to const
|
||||
references.<br/>
|
||||
In particular, the `data` member function invoked on a non-const instance of
|
||||
`any` that wraps a const reference returns a null pointer in all cases.
|
||||
|
||||
To cast an instance of `any` to a type, the library offers a set of `any_cast`
|
||||
functions in all respects similar to their most famous counterparts.<br/>
|
||||
The only difference is that, in the case of `EnTT`, they won't raise exceptions
|
||||
but will only trigger an assert in debug mode, otherwise resulting in undefined
|
||||
behavior in case of misuse in release mode.
|
||||
|
||||
## Small buffer optimization
|
||||
|
||||
The `any` class uses a technique called _small buffer optimization_ to reduce
|
||||
the number of allocations where possible.<br/>
|
||||
The default reserved size for an instance of `any` is `sizeof(double[2])`.
|
||||
However, this is also configurable if needed. In fact, `any` is defined as an
|
||||
alias for `basic_any<Len>`, where `Len` is the size above.<br/>
|
||||
Users can easily set a custom size or define their own aliases:
|
||||
|
||||
```cpp
|
||||
using my_any = entt::basic_any<sizeof(double[4])>;
|
||||
```
|
||||
|
||||
This feature, in addition to allowing the choice of a size that best suits the
|
||||
needs of an application, also offers the possibility of forcing dynamic creation
|
||||
of objects during construction.<br/>
|
||||
In other terms, if the size is 0, `any` suppresses the small buffer optimization
|
||||
and always dynamically allocates objects (except for aliasing cases).
|
||||
|
||||
## Alignment requirement
|
||||
|
||||
The alignment requirement is optional and by default the most stringent (the
|
||||
largest) for any object whose size is at most equal to the one provided.<br/>
|
||||
It's provided as an optional second parameter following the desired size for the
|
||||
internal storage:
|
||||
|
||||
```cpp
|
||||
using my_any = entt::basic_any<sizeof(double[4]), alignof(double[4])>;
|
||||
```
|
||||
|
||||
The `basic_any` class template inspects the alignment requirements in each case,
|
||||
even when not provided and may decide not to use the small buffer optimization
|
||||
in order to meet them.
|
||||
|
||||
# Compressed pair
|
||||
|
||||
Primarily designed for internal use and far from being feature complete, the
|
||||
`compressed_pair` class does exactly what it promises: it tries to reduce the
|
||||
size of a pair by exploiting _Empty Base Class Optimization_ (or _EBCO_).<br/>
|
||||
This class **is not** a drop-in replacement for `std::pair`. However, it offers
|
||||
enough functionalities to be a good alternative for when reducing memory usage
|
||||
is more important than having some cool and probably useless feature.
|
||||
|
||||
Although the API is very close to that of `std::pair` (apart from the fact that
|
||||
the template parameters are inferred from the constructor and therefore there is
|
||||
no `entt::make_compressed_pair`), the major difference is that `first` and
|
||||
`second` are functions for implementation requirements:
|
||||
|
||||
```cpp
|
||||
entt::compressed_pair pair{0, 3.};
|
||||
pair.first() = 42;
|
||||
```
|
||||
|
||||
There isn't much to describe then. It's recommended to rely on documentation and
|
||||
intuition. At the end of the day, it's just a pair and nothing more.
|
||||
|
||||
# Enum as bitmask
|
||||
|
||||
Sometimes it's useful to be able to use enums as bitmasks. However, enum classes
|
||||
aren't really suitable for the purpose. Main problem is that they don't convert
|
||||
implicitly to their underlying type.<br/>
|
||||
The choice is then between using old-fashioned enums (with all their problems
|
||||
that I don't want to discuss here) or writing _ugly_ code.
|
||||
|
||||
Fortunately, there is also a third way: adding enough operators in the global
|
||||
scope to treat enum classes as bitmasks transparently.<br/>
|
||||
The ultimate goal is to write code like the following (or maybe something more
|
||||
meaningful, but this should give a grasp and remain simple at the same time):
|
||||
|
||||
```cpp
|
||||
enum class my_flag {
|
||||
unknown = 0x01,
|
||||
enabled = 0x02,
|
||||
disabled = 0x04
|
||||
};
|
||||
|
||||
const my_flag flags = my_flag::enabled;
|
||||
const bool is_enabled = !!(flags & my_flag::enabled);
|
||||
```
|
||||
|
||||
The problem with adding all operators to the global scope is that these come
|
||||
into play even when not required, with the risk of introducing errors that are
|
||||
difficult to deal with.<br/>
|
||||
However, C++ offers enough tools to get around this problem. In particular, the
|
||||
library requires users to register the enum classes for which bitmask support
|
||||
should be enabled:
|
||||
|
||||
```cpp
|
||||
template<>
|
||||
struct entt::enum_as_bitmask<my_flag>
|
||||
: std::true_type
|
||||
{};
|
||||
```
|
||||
|
||||
This is handy when dealing with enum classes defined by third party libraries
|
||||
and over which the user has no control. However, it's also verbose and can be
|
||||
avoided by adding a specific value to the enum class itself:
|
||||
|
||||
```cpp
|
||||
enum class my_flag {
|
||||
unknown = 0x01,
|
||||
enabled = 0x02,
|
||||
disabled = 0x04,
|
||||
_entt_enum_as_bitmask
|
||||
};
|
||||
```
|
||||
|
||||
In this case, there is no need to specialize the `enum_as_bitmask` traits, since
|
||||
`EnTT` automatically detects the flag and enables the bitmask support.<br/>
|
||||
Once the enum class is registered (in one way or the other), the most common
|
||||
operators such as `&`, `|` but also `&=` and `|=` are available for use.
|
||||
|
||||
Refer to the official documentation for the full list of operators.
|
||||
|
||||
# Hashed strings
|
||||
|
||||
Hashed strings are human-readable identifiers in the codebase that turn into
|
||||
numeric values at runtime, thus without affecting performance.<br/>
|
||||
The class has an implicit `constexpr` constructor that chews a bunch of
|
||||
characters. Once created, one can get the original string by means of the `data`
|
||||
member function or convert the instance into a number.<br/>
|
||||
A hashed string is well suited wherever a constant expression is required. No
|
||||
_string-to-number_ conversion will take place at runtime if used carefully.
|
||||
|
||||
Example of use:
|
||||
|
||||
```cpp
|
||||
auto load(entt::hashed_string::hash_type resource) {
|
||||
// uses the numeric representation of the resource to load and return it
|
||||
}
|
||||
|
||||
auto resource = load(entt::hashed_string{"gui/background"});
|
||||
```
|
||||
|
||||
There is also a _user defined literal_ dedicated to hashed strings to make them
|
||||
more _user-friendly_:
|
||||
|
||||
```cpp
|
||||
using namespace entt::literals;
|
||||
constexpr auto str = "text"_hs;
|
||||
```
|
||||
|
||||
User defined literals in `EnTT` are enclosed in the `entt::literals` namespace.
|
||||
Therefore, the entire namespace or selectively the literal of interest must be
|
||||
explicitly included before each use, a bit like `std::literals`.<br/>
|
||||
The class also offers the necessary functionalities to create hashed strings at
|
||||
runtime:
|
||||
|
||||
```cpp
|
||||
std::string orig{"text"};
|
||||
|
||||
// create a full-featured hashed string...
|
||||
entt::hashed_string str{orig.c_str()};
|
||||
|
||||
// ... or compute only the unique identifier
|
||||
const auto hash = entt::hashed_string::value(orig.c_str());
|
||||
```
|
||||
|
||||
This possibility shouldn't be exploited in tight loops, since the computation
|
||||
takes place at runtime and no longer at compile-time. It could therefore affect
|
||||
performance to some degrees.
|
||||
|
||||
## Wide characters
|
||||
|
||||
The `hashed_string` class is an alias for `basic_hashed_string<char>`. To use
|
||||
the C++ type for wide character representations, there exists also the alias
|
||||
`hashed_wstring` for `basic_hashed_string<wchar_t>`.<br/>
|
||||
In this case, the user defined literal to use to create hashed strings on the
|
||||
fly is `_hws`:
|
||||
|
||||
```cpp
|
||||
constexpr auto str = L"text"_hws;
|
||||
```
|
||||
|
||||
The hash type of `hashed_wstring` is the same as its counterpart.
|
||||
|
||||
## Conflicts
|
||||
|
||||
The hashed string class uses FNV-1a internally to hash strings. Because of the
|
||||
_pigeonhole principle_, conflicts are possible. This is a fact.<br/>
|
||||
There is no silver bullet to solve the problem of conflicts when dealing with
|
||||
hashing functions. In this case, the best solution is likely to give up. That's
|
||||
all.<br/>
|
||||
After all, human-readable unique identifiers aren't something strictly defined
|
||||
and over which users have not the control. Choosing a slightly different
|
||||
identifier is probably the best solution to make the conflict disappear in this
|
||||
case.
|
||||
|
||||
# Iterators
|
||||
|
||||
Writing and working with iterators isn't always easy. More often than not it
|
||||
also leads to duplicated code.<br/>
|
||||
`EnTT` tries to overcome this problem by offering some utilities designed to
|
||||
make this hard work easier.
|
||||
|
||||
## Input iterator pointer
|
||||
|
||||
When writing an input iterator that returns in-place constructed values if
|
||||
dereferenced, it's not always straightforward to figure out what `value_type` is
|
||||
and how to make it behave like a full-fledged pointer.<br/>
|
||||
Conversely, it would be very useful to have an `operator->` available on the
|
||||
iterator itself that always works without too much complexity.
|
||||
|
||||
The input iterator pointer is meant for this. It's a small class that wraps the
|
||||
in-place constructed value and adds some functions on top of it to make it
|
||||
suitable for use with input iterators:
|
||||
|
||||
```cpp
|
||||
struct iterator_type {
|
||||
using value_type = std::pair<first_type, second_type>;
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The library makes extensive use of this class internally. In many cases, the
|
||||
`value_type` of the returned iterators is just an input iterator pointer.
|
||||
|
||||
## Iota iterator
|
||||
|
||||
Waiting for C++20, this iterator accepts an integral value and returns all
|
||||
elements in a certain range:
|
||||
|
||||
```cpp
|
||||
entt::iota_iterator first{0};
|
||||
entt::iota_iterator last{100};
|
||||
|
||||
for(; first != last; ++first) {
|
||||
int value = *first;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
In the future, views will replace this class. Meanwhile, the library makes some
|
||||
interesting uses of it when a range of integral values is to be returned to the
|
||||
user.
|
||||
|
||||
## Iterable adaptor
|
||||
|
||||
Typically, a container class provides `begin` and `end` member functions (with
|
||||
their const counterparts) for iteration.<br/>
|
||||
However, it can happen that a class offers multiple iteration methods or allows
|
||||
users to iterate different sets of _elements_.
|
||||
|
||||
The iterable adaptor is a utility class that makes it easier to use and access
|
||||
data in this case.<br/>
|
||||
It accepts a couple of iterators (or an iterator and a sentinel) and offers an
|
||||
_iterable_ object with all the expected methods like `begin`, `end` and whatnot.
|
||||
|
||||
The library uses this class extensively.<br/>
|
||||
Think for example of views, which can be iterated to access entities but also
|
||||
offer a method of obtaining an iterable object that returns tuples of entities
|
||||
and components at once.<br/>
|
||||
Another example is the registry class which allows users to iterate its storage
|
||||
by returning an iterable object for the purpose.
|
||||
|
||||
# Memory
|
||||
|
||||
There are a handful of tools within `EnTT` to interact with memory in one way or
|
||||
another.<br/>
|
||||
Some are geared towards simplifying the implementation of (internal or external)
|
||||
allocator aware containers. Others are designed to help the developer with
|
||||
everyday problems.
|
||||
|
||||
The former are very specific and for niche problems. These are tools designed to
|
||||
unwrap fancy or plain pointers (`to_address`) or to help forget the meaning of
|
||||
acronyms like _POCCA_, _POCMA_ or _POCS_.<br/>
|
||||
I won't describe them here in detail. Instead, I recommend reading the inline
|
||||
documentation to those interested in the subject.
|
||||
|
||||
## Power of two and fast modulus
|
||||
|
||||
Finding out if a number is a power of two (`is_power_of_two`) or what the next
|
||||
power of two is given a random value (`next_power_of_two`) is very useful at
|
||||
times.<br/>
|
||||
For example, it helps to allocate memory in pages having a size suitable for the
|
||||
fast modulus:
|
||||
|
||||
```cpp
|
||||
const std::size_t result = entt::fast_mod(value, modulus);
|
||||
```
|
||||
|
||||
Where `modulus` is necessarily a power of two. Perhaps not everyone knows that
|
||||
this type of operation is far superior in terms of performance to the basic
|
||||
modulus and for this reason preferred in many areas.
|
||||
|
||||
## Allocator aware unique pointers
|
||||
|
||||
A nasty thing in C++ (at least up to C++20) is the fact that shared pointers
|
||||
support allocators while unique pointers don't.<br/>
|
||||
There is a proposal at the moment that also shows (among the other things) how
|
||||
this can be implemented without any compiler support.
|
||||
|
||||
The `allocate_unique` function follows this proposal, making a virtue out of
|
||||
necessity:
|
||||
|
||||
```cpp
|
||||
std::unique_ptr<my_type, entt::allocation_deleter<my_type>> ptr = entt::allocate_unique<my_type>(allocator, arguments);
|
||||
```
|
||||
|
||||
Although the internal implementation is slightly different from what is proposed
|
||||
for the standard, this function offers an API that is a drop-in replacement for
|
||||
the same feature.
|
||||
|
||||
# Monostate
|
||||
|
||||
The monostate pattern is often presented as an alternative to a singleton based
|
||||
configuration system.<br/>
|
||||
This is exactly its purpose in `EnTT`. Moreover, this implementation is thread
|
||||
safe by design (hopefully).
|
||||
|
||||
Keys are integral values (easily obtained by hashed strings), values are basic
|
||||
types like `int`s or `bool`s. Values of different types can be associated with
|
||||
each key, even more than one at a time.<br/>
|
||||
Because of this, one should pay attention to use the same type both during an
|
||||
assignment and when trying to read back the data. Otherwise, there is the risk
|
||||
to incur in unexpected results.
|
||||
|
||||
Example of use:
|
||||
|
||||
```cpp
|
||||
entt::monostate<entt::hashed_string{"mykey"}>{} = true;
|
||||
entt::monostate<"mykey"_hs>{} = 42;
|
||||
|
||||
// ...
|
||||
|
||||
const bool b = entt::monostate<"mykey"_hs>{};
|
||||
const int i = entt::monostate<entt::hashed_string{"mykey"}>{};
|
||||
```
|
||||
|
||||
# Type support
|
||||
|
||||
`EnTT` provides some basic information about types of all kinds.<br/>
|
||||
It also offers additional features that are not yet available in the standard
|
||||
library or that will never be.
|
||||
|
||||
## Built-in RTTI support
|
||||
|
||||
Runtime type identification support (or RTTI) is one of the most frequently
|
||||
disabled features in the C++ world, especially in the gaming sector. Regardless
|
||||
of the reasons for this, it's often a shame not to be able to rely on opaque
|
||||
type information at runtime.<br/>
|
||||
The library tries to fill this gap by offering a built-in system that doesn't
|
||||
serve as a replacement but comes very close to being one and offers similar
|
||||
information to that provided by its counterpart.
|
||||
|
||||
Basically, the whole system relies on a handful of classes. In particular:
|
||||
|
||||
* The unique sequential identifier associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto index = entt::type_index<a_type>::value();
|
||||
```
|
||||
|
||||
The returned value isn't guaranteed to be stable across different runs.<br/>
|
||||
However, it can be very useful as index in associative and unordered
|
||||
associative containers or for positional accesses in a vector or an array.
|
||||
|
||||
An external generator can also be used if needed. In fact, `type_index` can be
|
||||
specialized by type and is also _sfinae-friendly_ in order to allow more
|
||||
refined specializations such as:
|
||||
|
||||
```cpp
|
||||
template<typename Type>
|
||||
struct entt::type_index<Type, std::void_d<decltype(Type::index())>> {
|
||||
static entt::id_type value() noexcept {
|
||||
return Type::index();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Indexes **must** be sequentially generated in this case.<br/>
|
||||
The tool is widely used within `EnTT`. Generating indices not sequentially
|
||||
would break an assumption and would likely lead to undesired behaviors.
|
||||
|
||||
* The hash value associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto hash = entt::type_hash<a_type>::value();
|
||||
```
|
||||
|
||||
In general, the `value` function exposed by `type_hash` is also `constexpr`
|
||||
but this isn't guaranteed for all compilers and platforms (although it's valid
|
||||
with the most well-known and popular ones).
|
||||
|
||||
This function **can** use non-standard features of the language for its own
|
||||
purposes. This makes it possible to provide compile-time identifiers that
|
||||
remain stable across different runs.<br/>
|
||||
Users can prevent the library from using these features by means of the
|
||||
`ENTT_STANDARD_CPP` definition. In this case, there is no guarantee that
|
||||
identifiers remain stable across executions. Moreover, they are generated
|
||||
at runtime and are no longer a compile-time thing.
|
||||
|
||||
As it happens with `type_index`, also `type_hash` is a _sfinae-friendly_ class
|
||||
that can be specialized in order to customize its behavior globally or on a
|
||||
per-type or per-traits basis.
|
||||
|
||||
* The name associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto name = entt::type_name<a_type>::value();
|
||||
```
|
||||
|
||||
This value is extracted from some information generally made available by the
|
||||
compiler in use. Therefore, it may differ depending on the compiler and may be
|
||||
empty in the event that this information isn't available.<br/>
|
||||
For example, given the following class:
|
||||
|
||||
```cpp
|
||||
struct my_type { /* ... */ };
|
||||
```
|
||||
|
||||
The name is `my_type` when compiled with GCC or CLang and `struct my_type`
|
||||
when MSVC is in use.<br/>
|
||||
Most of the time the name is also retrieved at compile-time and is therefore
|
||||
always returned through an `std::string_view`. Users can easily access it and
|
||||
modify it as needed, for example by removing the word `struct` to normalize
|
||||
the result. `EnTT` doesn't do this for obvious reasons, since it would be
|
||||
creating a new string at runtime otherwise.
|
||||
|
||||
This function **can** use non-standard features of the language for its own
|
||||
purposes. Users can prevent the library from using these features by means of
|
||||
the `ENTT_STANDARD_CPP` definition. In this case, the name is just empty.
|
||||
|
||||
As it happens with `type_index`, also `type_name` is a _sfinae-friendly_ class
|
||||
that can be specialized in order to customize its behavior globally or on a
|
||||
per-type or per-traits basis.
|
||||
|
||||
These are then combined into utilities that aim to offer an API that is somewhat
|
||||
similar to that made available by the standard library.
|
||||
|
||||
### Type info
|
||||
|
||||
The `type_info` class isn't a drop-in replacement for `std::type_info` but can
|
||||
provide similar information which are not implementation defined and don't
|
||||
require to enable RTTI.<br/>
|
||||
Therefore, they can sometimes be even more reliable than those obtained
|
||||
otherwise.
|
||||
|
||||
Its type defines an opaque class that is also copyable and movable.<br/>
|
||||
Objects of this type are generally returned by the `type_id` functions:
|
||||
|
||||
```cpp
|
||||
// by type
|
||||
auto info = entt::type_id<a_type>();
|
||||
|
||||
// by value
|
||||
auto other = entt::type_id(42);
|
||||
```
|
||||
|
||||
All elements thus received are nothing more than const references to instances
|
||||
of `type_info` with static storage duration.<br/>
|
||||
This is convenient for saving the entire object aside for the cost of a pointer.
|
||||
However, nothing prevents from constructing `type_info` objects directly:
|
||||
|
||||
```cpp
|
||||
entt::type_info info{std::in_place_type<int>};
|
||||
```
|
||||
|
||||
These are the information made available by `type_info`:
|
||||
|
||||
* The index associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto idx = entt::type_id<a_type>().index();
|
||||
```
|
||||
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto idx = entt::type_index<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
|
||||
```
|
||||
|
||||
* The hash value associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto hash = entt::type_id<a_type>().hash();
|
||||
```
|
||||
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto hash = entt::type_hash<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
|
||||
```
|
||||
|
||||
* The name associated with a given type:
|
||||
|
||||
```cpp
|
||||
auto name = entt::type_id<my_type>().name();
|
||||
```
|
||||
|
||||
This is also an alias for the following:
|
||||
|
||||
```cpp
|
||||
auto name = entt::type_name<std::remove_cv_t<std::remove_reference_t<a_type>>>::value();
|
||||
```
|
||||
|
||||
Where all accessed features are available at compile-time, the `type_info` class
|
||||
is also fully `constexpr`. However, this cannot be guaranteed in advance and
|
||||
depends mainly on the compiler in use and any specializations of the classes
|
||||
described above.
|
||||
|
||||
### Almost unique identifiers
|
||||
|
||||
Since the default non-standard, compile-time implementation of `type_hash` makes
|
||||
use of hashed strings, it may happen that two types are assigned the same hash
|
||||
value.<br/>
|
||||
In fact, although this is quite rare, it's not entirely excluded.
|
||||
|
||||
Another case where two types are assigned the same identifier is when classes
|
||||
from different contexts (for example two or more libraries loaded at runtime)
|
||||
have the same fully qualified name. In this case, `type_name` returns the same
|
||||
value for the two types.<br/>
|
||||
Fortunately, there are several easy ways to deal with this:
|
||||
|
||||
* The most trivial one is to define the `ENTT_STANDARD_CPP` macro. Runtime
|
||||
identifiers don't suffer from the same problem in fact. However, this solution
|
||||
doesn't work well with a plugin system, where the libraries aren't linked.
|
||||
|
||||
* Another possibility is to specialize the `type_name` class for one of the
|
||||
conflicting types, in order to assign it a custom identifier. This is probably
|
||||
the easiest solution that also preserves the feature of the tool.
|
||||
|
||||
* A fully customized identifier generation policy (based for example on enum
|
||||
classes or preprocessing steps) may represent yet another option.
|
||||
|
||||
These are just some examples of possible approaches to the problem but there are
|
||||
many others. As already mentioned above, since users have full control over
|
||||
their types, this problem is in any case easy to solve and should not worry too
|
||||
much.<br/>
|
||||
In all likelihood, it will never happen to run into a conflict anyway.
|
||||
|
||||
## Type traits
|
||||
|
||||
A handful of utilities and traits not present in the standard template library
|
||||
but which can be useful in everyday life.<br/>
|
||||
This list **is not** exhaustive and contains only some of the most useful
|
||||
classes. Refer to the inline documentation for more information on the features
|
||||
offered by this module.
|
||||
|
||||
### Size of
|
||||
|
||||
The standard operator `sizeof` complains if users provide it with functions or
|
||||
incomplete types. On the other hand, it's guaranteed that its result is always
|
||||
non-zero, even if applied to an empty class type.<br/>
|
||||
This small class combines the two and offers an alternative to `sizeof` that
|
||||
works under all circumstances, returning zero if the type isn't supported:
|
||||
|
||||
```cpp
|
||||
const auto size = entt::size_of_v<void>;
|
||||
```
|
||||
|
||||
### Is applicable
|
||||
|
||||
The standard library offers the great `std::is_invocable` trait in several
|
||||
forms. This takes a function type and a series of arguments and returns true if
|
||||
the condition is satisfied.<br/>
|
||||
Moreover, users are also provided with `std::apply`, a tool for combining
|
||||
invocable elements and tuples of arguments.
|
||||
|
||||
It would therefore be a good idea to have a variant of `std::is_invocable` that
|
||||
also accepts its arguments in the form of a tuple-like type, so as to complete
|
||||
the offer:
|
||||
|
||||
```cpp
|
||||
constexpr bool result = entt::is_applicable<Func, std::tuple<a_type, another_type>>;
|
||||
```
|
||||
|
||||
This trait is built on top of `std::is_invocable` and does nothing but unpack a
|
||||
tuple-like type and simplify the code at the call site.
|
||||
|
||||
### Constness as
|
||||
|
||||
A utility to easily transfer the constness of a type to another type:
|
||||
|
||||
```cpp
|
||||
// type is const dst_type because of the constness of src_type
|
||||
using type = entt::constness_as_t<dst_type, const src_type>;
|
||||
```
|
||||
|
||||
The trait is subject to the rules of the language. For example, _transferring_
|
||||
constness between references won't give the desired effect.
|
||||
|
||||
### Member class type
|
||||
|
||||
The `auto` template parameter introduced with C++17 made it possible to simplify
|
||||
many class templates and template functions but also made the class type opaque
|
||||
when members are passed as template arguments.<br/>
|
||||
The purpose of this utility is to extract the class type in a few lines of code:
|
||||
|
||||
```cpp
|
||||
template<typename Member>
|
||||
using clazz = entt::member_class_t<Member>;
|
||||
```
|
||||
|
||||
### N-th argument
|
||||
|
||||
A utility to quickly find the n-th argument of a function, member function or
|
||||
data member (for blind operations on opaque types):
|
||||
|
||||
```cpp
|
||||
using type = entt::nth_argument_t<1u, &clazz::member>;
|
||||
```
|
||||
|
||||
Disambiguation of overloaded functions is the responsibility of the user, should
|
||||
it be needed.
|
||||
|
||||
### Integral constant
|
||||
|
||||
Since `std::integral_constant` may be annoying because of its form that requires
|
||||
to specify both a type and a value of that type, there is a more user-friendly
|
||||
shortcut for the creation of integral constants.<br/>
|
||||
This shortcut is the alias template `entt::integral_constant`:
|
||||
|
||||
```cpp
|
||||
constexpr auto constant = entt::integral_constant<42>;
|
||||
```
|
||||
|
||||
Among the other uses, when combined with a hashed string it helps to define tags
|
||||
as human-readable _names_ where actual types would be required otherwise:
|
||||
|
||||
```cpp
|
||||
constexpr auto enemy_tag = entt::integral_constant<"enemy"_hs>;
|
||||
registry.emplace<enemy_tag>(entity);
|
||||
```
|
||||
|
||||
### Tag
|
||||
|
||||
Type `id_type` is very important and widely used in `EnTT`. Therefore, there is
|
||||
a more user-friendly shortcut for the creation of constants based on it.<br/>
|
||||
This shortcut is the alias template `entt::tag`.
|
||||
|
||||
If used in combination with hashed strings, it helps to use human-readable names
|
||||
where types would be required otherwise. As an example:
|
||||
|
||||
```cpp
|
||||
registry.emplace<entt::tag<"enemy"_hs>>(entity);
|
||||
```
|
||||
|
||||
However, this isn't the only permitted use. Literally any value convertible to
|
||||
`id_type` is a good candidate, such as the named constants of an unscoped enum.
|
||||
|
||||
### Type list and value list
|
||||
|
||||
There is no respectable library where the much desired _type list_ can be
|
||||
missing.<br/>
|
||||
`EnTT` is no exception and provides (making extensive use of it internally) the
|
||||
`type_list` type, in addition to its `value_list` counterpart dedicated to
|
||||
non-type template parameters.
|
||||
|
||||
Here is a (possibly incomplete) list of the functionalities that come with a
|
||||
type list:
|
||||
|
||||
* `type_list_element[_t]` to get the N-th element of a type list.
|
||||
* `type_list_index[_v]` to get the index of a given element of a type list.
|
||||
* `type_list_cat[_t]` and a handy `operator+` to concatenate type lists.
|
||||
* `type_list_unique[_t]` to remove duplicate types from a type list.
|
||||
* `type_list_contains[_v]` to know if a type list contains a given type.
|
||||
* `type_list_diff[_t]` to remove types from type lists.
|
||||
* `type_list_transform[_t]` to _transform_ a range and create another type list.
|
||||
|
||||
I'm also pretty sure that more and more utilities will be added over time as
|
||||
needs become apparent.<br/>
|
||||
Many of these functionalities also exist in their version dedicated to value
|
||||
lists. We therefore have `value_list_element[_v]` as well as
|
||||
`value_list_cat[_t]`and so on.
|
||||
|
||||
# Unique sequential identifiers
|
||||
|
||||
Sometimes it's useful to be able to give unique, sequential numeric identifiers
|
||||
to types either at compile-time or runtime.<br/>
|
||||
There are plenty of different solutions for this out there and I could have used
|
||||
one of them. However, I decided to spend my time to define a couple of tools
|
||||
that fully embraces what the modern C++ has to offer.
|
||||
|
||||
## Compile-time generator
|
||||
|
||||
To generate sequential numeric identifiers at compile-time, `EnTT` offers the
|
||||
`ident` class template:
|
||||
|
||||
```cpp
|
||||
// defines the identifiers for the given types
|
||||
using id = entt::ident<a_type, another_type>;
|
||||
|
||||
// ...
|
||||
|
||||
switch(a_type_identifier) {
|
||||
case id::value<a_type>:
|
||||
// ...
|
||||
break;
|
||||
case id::value<another_type>:
|
||||
// ...
|
||||
break;
|
||||
default:
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
This is what this class template has to offer: a `value` inline variable that
|
||||
contains a numeric identifier for the given type. It can be used in any context
|
||||
where constant expressions are required.
|
||||
|
||||
As long as the list remains unchanged, identifiers are also guaranteed to be
|
||||
stable across different runs. In case they have been used in a production
|
||||
environment and a type has to be removed, one can just use a placeholder to
|
||||
leave the other identifiers unchanged:
|
||||
|
||||
```cpp
|
||||
template<typename> struct ignore_type {};
|
||||
|
||||
using id = entt::ident<
|
||||
a_type_still_valid,
|
||||
ignore_type<no_longer_valid_type>,
|
||||
another_type_still_valid
|
||||
>;
|
||||
```
|
||||
|
||||
Perhaps a bit ugly to see in a codebase but it gets the job done at least.
|
||||
|
||||
## Runtime generator
|
||||
|
||||
The `family` class template helps to generate sequential numeric identifiers for
|
||||
types at runtime:
|
||||
|
||||
```cpp
|
||||
// defines a custom generator
|
||||
using id = entt::family<struct my_tag>;
|
||||
|
||||
// ...
|
||||
|
||||
const auto a_type_id = id::value<a_type>;
|
||||
const auto another_type_id = id::value<another_type>;
|
||||
```
|
||||
|
||||
This is what a _family_ has to offer: a `value` inline variable that contains a
|
||||
numeric identifier for the given type.<br/>
|
||||
The generator is customizable, so as to get different _sequences_ for different
|
||||
purposes if needed.
|
||||
|
||||
Identifiers aren't guaranteed to be stable across different runs. Indeed it
|
||||
mostly depends on the flow of execution.
|
||||
|
||||
# Utilities
|
||||
|
||||
It's not possible to escape the temptation to add utilities of some kind to a
|
||||
library. In fact, `EnTT` also provides a handful of tools to simplify the
|
||||
life of developers:
|
||||
|
||||
* `entt::identity`: the identity function object that will be available with
|
||||
C++20. It returns its argument unchanged and nothing more. It's useful as a
|
||||
sort of _do nothing_ function in template programming.
|
||||
|
||||
* `entt::overload`: a tool to disambiguate different overloads from their
|
||||
function type. It works with both free and member functions.<br/>
|
||||
Consider the following definition:
|
||||
|
||||
```cpp
|
||||
struct clazz {
|
||||
void bar(int) {}
|
||||
void bar() {}
|
||||
};
|
||||
```
|
||||
|
||||
This utility can be used to get the _right_ overload as:
|
||||
|
||||
```cpp
|
||||
auto *member = entt::overload<void(int)>(&clazz::bar);
|
||||
```
|
||||
|
||||
The line above is literally equivalent to:
|
||||
|
||||
```cpp
|
||||
auto *member = static_cast<void(clazz:: *)(int)>(&clazz::bar);
|
||||
```
|
||||
|
||||
Just easier to read and shorter to type.
|
||||
|
||||
* `entt::overloaded`: a small class template used to create a new type with an
|
||||
overloaded `operator()` from a bunch of lambdas or functors.<br/>
|
||||
As an example:
|
||||
|
||||
```cpp
|
||||
entt::overloaded func{
|
||||
[](int value) { /* ... */ },
|
||||
[](char value) { /* ... */ }
|
||||
};
|
||||
|
||||
func(42);
|
||||
func('c');
|
||||
```
|
||||
|
||||
Rather useful when doing metaprogramming and having to pass to a function a
|
||||
callable object that supports multiple types at once.
|
||||
|
||||
* `entt::y_combinator`: this is a C++ implementation of **the** _y-combinator_.
|
||||
If it's not clear what it is, there is probably no need for this utility.<br/>
|
||||
Below is a small example to show its use:
|
||||
|
||||
```cpp
|
||||
entt::y_combinator gauss([](const auto &self, auto value) -> unsigned int {
|
||||
return value ? (value + self(value-1u)) : 0;
|
||||
});
|
||||
|
||||
const auto result = gauss(3u);
|
||||
```
|
||||
|
||||
Maybe convoluted at a first glance but certainly effective. Unfortunately,
|
||||
the language doesn't make it possible to do much better.
|
||||
|
||||
This is a rundown of the (actually few) utilities made available by `EnTT`. The
|
||||
list will probably grow over time but the size of each will remain rather small,
|
||||
as has been the case so far.
|
||||
2344
docs/md/entity.md
Normal file
2344
docs/md/entity.md
Normal file
File diff suppressed because it is too large
Load Diff
215
docs/md/faq.md
Normal file
215
docs/md/faq.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# Frequently Asked Questions
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [FAQ](#faq)
|
||||
* [Why is my debug build on Windows so slow?](#why-is-my-debug-build-on-windows-so-slow)
|
||||
* [How can I represent hierarchies with my components?](#how-can-i-represent-hierarchies-with-my-components)
|
||||
* [Custom entity identifiers: yay or nay?](#custom-entity-identifiers-yay-or-nay)
|
||||
* [Warning C4307: integral constant overflow](#warning-C4307-integral-constant-overflow)
|
||||
* [Warning C4003: the min, the max and the macro](#warning-C4003-the-min-the-max-and-the-macro)
|
||||
* [The standard and the non-copyable types](#the-standard-and-the-non-copyable-types)
|
||||
* [Which functions trigger which signals](#which-functions-trigger-which-signals)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
This is a constantly updated section where I'm trying to put the answers to the
|
||||
most frequently asked questions.<br/>
|
||||
If you don't find your answer here, there are two cases: nobody has done it yet
|
||||
or this section needs updating. In both cases, you can
|
||||
[open a new issue](https://github.com/skypjack/entt/issues/new) or enter either
|
||||
the [gitter channel](https://gitter.im/skypjack/entt) or the
|
||||
[discord server](https://discord.gg/5BjPWBd) to ask for help.<br/>
|
||||
Probably someone already has an answer for you and we can then integrate this
|
||||
part of the documentation.
|
||||
|
||||
# FAQ
|
||||
|
||||
## Why is my debug build on Windows so slow?
|
||||
|
||||
`EnTT` is an experimental project that I also use to keep me up-to-date with the
|
||||
latest revision of the language and the standard library. For this reason, it's
|
||||
likely that some classes you're working with are using standard containers under
|
||||
the hood.<br/>
|
||||
Unfortunately, it's known that the standard containers aren't particularly
|
||||
performing in debugging (the reasons for this go beyond this document) and are
|
||||
even less so on Windows apparently. Fortunately this can also be mitigated a
|
||||
lot, achieving good results in many cases.
|
||||
|
||||
First of all, there are two things to do in a Windows project:
|
||||
|
||||
* Disable the [`/JMC`](https://docs.microsoft.com/cpp/build/reference/jmc)
|
||||
option (_Just My Code_ debugging), available starting with Visual Studio 2017
|
||||
version 15.8.
|
||||
|
||||
* Set the [`_ITERATOR_DEBUG_LEVEL`](https://docs.microsoft.com/cpp/standard-library/iterator-debug-level)
|
||||
macro to 0. This will disable checked iterators and iterator debugging.
|
||||
|
||||
Moreover, set the `ENTT_DISABLE_ASSERT` variable or redefine the `ENTT_ASSERT`
|
||||
macro to disable internal debug checks in `EnTT`:
|
||||
|
||||
```cpp
|
||||
#define ENTT_ASSERT(...) ((void)0)
|
||||
```
|
||||
|
||||
These asserts are introduced to help the users but they require to access to the
|
||||
underlying containers and therefore risk ruining the performance in some cases.
|
||||
|
||||
With these changes, debug performance should increase enough in most cases. If
|
||||
you want something more, you can also switch to an optimization level `O0` or
|
||||
preferably `O1`.
|
||||
|
||||
## How can I represent hierarchies with my components?
|
||||
|
||||
This is one of the first questions that anyone makes when starting to work with
|
||||
the entity-component-system architectural pattern.<br/>
|
||||
There are several approaches to the problem and the best one depends mainly on
|
||||
the real problem one is facing. In all cases, how to do it doesn't strictly
|
||||
depend on the library in use, but the latter certainly allows or not different
|
||||
techniques depending on how the data are laid out.
|
||||
|
||||
I tried to describe some of the approaches that fit well with the model of
|
||||
`EnTT`. [This](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) is the
|
||||
first post of a series that tries to _explore_ the problem. More will probably
|
||||
come in future.<br/>
|
||||
In addition, `EnTT` also offers the possibility to create stable storage types
|
||||
and therefore have pointer stability for one, all or some components. This is by
|
||||
far the most convenient solution when it comes to creating hierarchies and
|
||||
whatnot. See the documentation for the ECS part of the library and in particular
|
||||
what concerns the `component_traits` class for further details.
|
||||
|
||||
## Custom entity identifiers: yay or nay?
|
||||
|
||||
Custom entity identifiers are definitely a good idea in two cases at least:
|
||||
|
||||
* If `std::uint32_t` isn't large enough for your purposes, since this is the
|
||||
underlying type of `entt::entity`.
|
||||
|
||||
* If you want to avoid conflicts when using multiple registries.
|
||||
|
||||
Identifiers can be defined through enum classes and class types that define an
|
||||
`entity_type` member of type `std::uint32_t` or `std::uint64_t`.<br/>
|
||||
In fact, this is a definition equivalent to that of `entt::entity`:
|
||||
|
||||
```cpp
|
||||
enum class entity: std::uint32_t {};
|
||||
```
|
||||
|
||||
There is no limit to the number of identifiers that can be defined.
|
||||
|
||||
## Warning C4307: integral constant overflow
|
||||
|
||||
According to [this](https://github.com/skypjack/entt/issues/121) issue, using a
|
||||
hashed string under VS (toolset v141) could generate a warning.<br/>
|
||||
First of all, I want to reassure you: it's expected and harmless. However, it
|
||||
can be annoying.
|
||||
|
||||
To suppress it and if you don't want to suppress all the other warnings as well,
|
||||
here is a workaround in the form of a macro:
|
||||
|
||||
```cpp
|
||||
#if defined(_MSC_VER)
|
||||
#define HS(str) __pragma(warning(suppress:4307)) entt::hashed_string{str}
|
||||
#else
|
||||
#define HS(str) entt::hashed_string{str}
|
||||
#endif
|
||||
```
|
||||
|
||||
With an example of use included:
|
||||
|
||||
```cpp
|
||||
constexpr auto identifier = HS("my/resource/identifier");
|
||||
```
|
||||
|
||||
Thanks to [huwpascoe](https://github.com/huwpascoe) for the courtesy.
|
||||
|
||||
## Warning C4003: the min, the max and the macro
|
||||
|
||||
On Windows, a header file defines two macros `min` and `max` which may result in
|
||||
conflicts with their counterparts in the standard library and therefore in
|
||||
errors during compilation.
|
||||
|
||||
It's a pretty big problem but fortunately it's not a problem of `EnTT` and there
|
||||
is a fairly simple solution to it.<br/>
|
||||
It consists in defining the `NOMINMAX` macro before including any other header
|
||||
so as to get rid of the extra definitions:
|
||||
|
||||
```cpp
|
||||
#define NOMINMAX
|
||||
```
|
||||
|
||||
Please refer to [this](https://github.com/skypjack/entt/issues/96) issue for
|
||||
more details.
|
||||
|
||||
## The standard and the non-copyable types
|
||||
|
||||
`EnTT` uses internally the trait `std::is_copy_constructible_v` to check if a
|
||||
component is actually copyable. However, this trait doesn't really check whether
|
||||
a type is actually copyable. Instead, it just checks that a suitable copy
|
||||
constructor and copy operator exist.<br/>
|
||||
This can lead to surprising results due to some idiosyncrasies of the standard.
|
||||
|
||||
For example, `std::vector` defines a copy constructor that is conditionally
|
||||
enabled depending on whether the value type is copyable or not. As a result,
|
||||
`std::is_copy_constructible_v` returns true for the following specialization:
|
||||
|
||||
```cpp
|
||||
struct type {
|
||||
std::vector<std::unique_ptr<action>> vec;
|
||||
};
|
||||
```
|
||||
|
||||
However, the copy constructor is effectively disabled upon specialization.
|
||||
Therefore, trying to assign an instance of this type to an entity may trigger a
|
||||
compilation error.<br/>
|
||||
As a workaround, users can mark the type explicitly as non-copyable. This also
|
||||
suppresses the implicit generation of the move constructor and operator, which
|
||||
will therefore have to be defaulted accordingly:
|
||||
|
||||
```cpp
|
||||
struct type {
|
||||
type(const type &) = delete;
|
||||
type(type &&) = default;
|
||||
|
||||
type & operator=(const type &) = delete;
|
||||
type & operator=(type &&) = default;
|
||||
|
||||
std::vector<std::unique_ptr<action>> vec;
|
||||
};
|
||||
```
|
||||
|
||||
Note that aggregate initialization is also disabled as a consequence.<br/>
|
||||
Fortunately, this type of trick is quite rare. The bad news is that there is no
|
||||
way to deal with it at the library level, this being due to the design of the
|
||||
language. On the other hand, the fact that the language itself also offers a way
|
||||
to mitigate the problem makes it manageable.
|
||||
|
||||
## Which functions trigger which signals
|
||||
|
||||
Storage classes offer three _signals_ that are emitted following specific
|
||||
operations. Maybe not everyone knows what these operations are, though.<br/>
|
||||
If this isn't clear, below you can find a _vademecum_ for this purpose:
|
||||
|
||||
* `on_created` is invoked when a component is first added (neither modified nor
|
||||
replaced) to an entity.
|
||||
|
||||
* `on_update` is called whenever an existing component is modified or replaced.
|
||||
|
||||
* `on_destroyed` is called when a component is explicitly or implicitly removed
|
||||
from an entity.
|
||||
|
||||
Among the most controversial functions can be found `emplace_or_replace` and
|
||||
`destroy`. However, following the above rules, it's quite simple to know what
|
||||
will happen.<br/>
|
||||
In the first case, `on_created` is invoked if the entity has not the component,
|
||||
otherwise the latter is replaced and therefore `on_update` is triggered. As for
|
||||
the second case, components are removed from their entities and thus freed when
|
||||
they are recycled. It means that `on_destroyed` is triggered for every component
|
||||
owned by the entity that is destroyed.
|
||||
372
docs/md/graph.md
Normal file
372
docs/md/graph.md
Normal file
@@ -0,0 +1,372 @@
|
||||
# Crash Course: graph
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Data structures](#data-structures)
|
||||
* [Adjacency matrix](#adjacency-matrix)
|
||||
* [Graphviz dot language](#graphviz-dot-language)
|
||||
* [Flow builder](#flow-builder)
|
||||
* [Tasks and resources](#tasks-and-resources)
|
||||
* [Fake resources and order of execution](#fake-resources-and-order-of-execution)
|
||||
* [Sync points](#sync-points)
|
||||
* [Execution graph](#execution-graph)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
`EnTT` doesn't aim to offer everything one needs to work with graphs. Therefore,
|
||||
anyone looking for this in the _graph_ submodule will be disappointed.<br/>
|
||||
Quite the opposite is true though. This submodule is minimal and contains only
|
||||
the data structures and algorithms strictly necessary for the development of
|
||||
some tools such as the _flow builder_.
|
||||
|
||||
# Data structures
|
||||
|
||||
As anticipated in the introduction, the aim isn't to offer all possible data
|
||||
structures suitable for representing and working with graphs. Many will likely
|
||||
be added or refined over time. However I want to discourage anyone expecting
|
||||
tight scheduling on the subject.<br/>
|
||||
The data structures presented in this section are mainly useful for the
|
||||
development and support of some tools which are also part of the same submodule.
|
||||
|
||||
## Adjacency matrix
|
||||
|
||||
The adjacency matrix is designed to represent either a directed or an undirected
|
||||
graph:
|
||||
|
||||
```cpp
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{};
|
||||
```
|
||||
|
||||
The `directed_tag` type _creates_ the graph as directed. There is also an
|
||||
`undirected_tag` counterpart which creates it as undirected.<br/>
|
||||
The interface deviates slightly from the typical double indexing of C and offers
|
||||
an API that is perhaps more familiar to a C++ programmer. Therefore, the access
|
||||
and modification of an element takes place via the `contains`, `insert` and
|
||||
`erase` functions rather than a double call to an `operator[]`:
|
||||
|
||||
```cpp
|
||||
if(adjacency_matrix.contains(0u, 1u)) {
|
||||
adjacency_matrix.erase(0u, 1u);
|
||||
} else {
|
||||
adjacency_matrix.insert(0u, 1u);
|
||||
}
|
||||
```
|
||||
|
||||
Both `insert` and` erase` are _idempotent_ functions which have no effect if the
|
||||
element already exists or has already been deleted.<br/>
|
||||
The first one returns an `std::pair` containing the iterator to the element and
|
||||
a boolean value indicating whether the element was newly inserted or not. The
|
||||
second one returns the number of deleted elements (0 or 1).
|
||||
|
||||
An adjacency matrix is initialized with the number of elements (vertices) when
|
||||
constructing it but can also be resized later using the `resize` function:
|
||||
|
||||
```cpp
|
||||
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
|
||||
```
|
||||
|
||||
To visit all vertices, the class offers a function named `vertices` that returns
|
||||
an iterable object suitable for the purpose:
|
||||
|
||||
```cpp
|
||||
for(auto &&vertex: adjacency_matrix.vertices()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The same result is obtained with the following snippet, since the vertices are
|
||||
plain unsigned integral values:
|
||||
|
||||
```cpp
|
||||
for(auto last = adjacency_matrix.size(), pos = {}; pos < last; ++pos) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
As for visiting the edges, a few functions are available.<br/>
|
||||
When the purpose is to visit all the edges of a given adjacency matrix, the
|
||||
`edges` function returns an iterable object that is used to get them as pairs of
|
||||
vertices:
|
||||
|
||||
```cpp
|
||||
for(auto [lhs, rhs]: adjacency_matrix.edges()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
If the goal is to visit all the in- or out-edges of a given vertex instead, the
|
||||
`in_edges` and `out_edges` functions are meant for that:
|
||||
|
||||
```cpp
|
||||
for(auto [lhs, rhs]: adjacency_matrix.out_edges(3u)) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Both the functions expect the vertex to visit (that is, to return the in- or
|
||||
out-edges for) as an argument.<br/>
|
||||
Finally, the adjacency matrix is an allocator-aware container and offers most of
|
||||
the functionalities one would expect from this type of containers, such as
|
||||
`clear` or 'get_allocator` and so on.
|
||||
|
||||
## Graphviz dot language
|
||||
|
||||
As it's one of the most popular formats, the library offers minimal support for
|
||||
converting a graph to a Graphviz dot snippet.<br/>
|
||||
The simplest way is to pass both an output stream and a graph to the `dot`
|
||||
function:
|
||||
|
||||
```cpp
|
||||
std::ostringstream output{};
|
||||
entt::dot(output, adjacency_matrix);
|
||||
```
|
||||
|
||||
It's also possible to provide a callback to which the vertices are passed and
|
||||
which can be used to add (`dot`) properties to the output as needed:
|
||||
|
||||
```cpp
|
||||
std::ostringstream output{};
|
||||
|
||||
entt::dot(output, adjacency_matrix, [](auto &output, auto vertex) {
|
||||
out << "label=\"v\"" << vertex << ",shape=\"box\"";
|
||||
});
|
||||
```
|
||||
|
||||
This second mode is particularly convenient when the user wants to associate
|
||||
externally managed data to the graph being converted.
|
||||
|
||||
# Flow builder
|
||||
|
||||
A flow builder is used to create execution graphs from tasks and resources.<br/>
|
||||
The implementation is as generic as possible and doesn't bind to any other part
|
||||
of the library.
|
||||
|
||||
This class is designed as a sort of _state machine_ to which a specific task is
|
||||
attached for which the resources accessed in read-only or read-write mode are
|
||||
specified.<br/>
|
||||
Most of the functions in the API also return the flow builder itself, according
|
||||
to what is the common sense API when it comes to builder classes.
|
||||
|
||||
Once all tasks are registered and resources assigned to them, an execution graph
|
||||
in the form of an adjacency matrix is returned to the user.<br/>
|
||||
This graph contains all the tasks assigned to the flow builder in the form of
|
||||
_vertices_. The _vertex_ itself is used as an index to get the identifier passed
|
||||
during registration.
|
||||
|
||||
## Tasks and resources
|
||||
|
||||
Although these terms are used extensively in the documentation, the flow builder
|
||||
has no real concept of tasks and resources.<br/>
|
||||
This class works mainly with _identifiers_, that is, values of type `id_type`.
|
||||
In other terms, both tasks and resources are identified by integral values.<br/>
|
||||
This allows not to couple the class itself to the rest of the library or to any
|
||||
particular data structure. On the other hand, it requires the user to keep track
|
||||
of the association between identifiers and operations or actual data.
|
||||
|
||||
Once a flow builder is created (which requires no constructor arguments), the
|
||||
first thing to do is to bind a task. This tells to the builder _who_ intends to
|
||||
consume the resources that are specified immediately after:
|
||||
|
||||
```cpp
|
||||
entt::flow builder{};
|
||||
builder.bind("task_1"_hs);
|
||||
```
|
||||
|
||||
The example uses the `EnTT` hashed string to generate an identifier for the
|
||||
task.<br/>
|
||||
Indeed, the use of `id_type` as an identifier type isn't by accident. In fact,
|
||||
it matches well with the internal hashed string class. Moreover, it's also the
|
||||
same type returned by the hash function of the internal RTTI system, in case the
|
||||
user wants to rely on that.<br/>
|
||||
However, being an integral value, it leaves the user full freedom to rely on his
|
||||
own tools if necessary.
|
||||
|
||||
Once a task is associated with the flow builder, it's also assigned read-only or
|
||||
read-write resources as appropriate:
|
||||
|
||||
```cpp
|
||||
builder
|
||||
.bind("task_1"_hs)
|
||||
.ro("resource_1"_hs)
|
||||
.ro("resource_2"_hs)
|
||||
.bind("task_2"_hs)
|
||||
.rw("resource_2"_hs)
|
||||
```
|
||||
|
||||
As mentioned, many functions return the builder itself and it's therefore easy
|
||||
to concatenate the different calls.<br/>
|
||||
Also in the case of resources, they are identified by numeric values of type
|
||||
`id_type`. As above, the choice is not entirely random. This goes well with the
|
||||
tools offered by the library while leaving room for maximum flexibility.
|
||||
|
||||
Finally, both the `ro` and` rw` functions also offer an overload that accepts a
|
||||
pair of iterators, so that one can pass a range of resources in one go.
|
||||
|
||||
### Rebinding
|
||||
|
||||
The `flow` class is resource based rather than task based. This means that graph
|
||||
generation is driven by resources and not by the order of _appearance_ of tasks
|
||||
during flow definition.<br/>
|
||||
Although this concept is particularly important, it's almost irrelevant for the
|
||||
vast majority of cases. However, it becomes relevant when _rebinding_ resources
|
||||
or tasks.
|
||||
|
||||
In fact, nothing prevents rebinding elements to a flow.<br/>
|
||||
However, the behavior changes slightly from case to case and has some nuances
|
||||
that it's worth knowing about.
|
||||
|
||||
Directly rebinding a resource without the task being replaced trivially results
|
||||
in the task's access mode for that resource being updated:
|
||||
|
||||
```cpp
|
||||
builder.bind("task"_hs).rw("resource"_hs).ro("resource"_hs)
|
||||
```
|
||||
|
||||
In this case, the resource is accessed in read-only mode, regardless of the
|
||||
first call to `rw`.<br/>
|
||||
Behind the scenes, the call doesn't actually _replace_ the previous one but is
|
||||
queued after it instead, overwriting it when generating the graph. Thus, a large
|
||||
number of resource rebindings may even impact processing times (very difficult
|
||||
to observe but theoretically possible).
|
||||
|
||||
Rebinding resources and also combining it with changes to tasks has far more
|
||||
implications instead.<br/>
|
||||
As mentioned, graph generation takes place starting from resources and not from
|
||||
tasks. Therefore, the result may not be as expected:
|
||||
|
||||
```cpp
|
||||
builder
|
||||
.bind("task_1"_hs)
|
||||
.ro("resource"_hs)
|
||||
.bind("task_2"_hs)
|
||||
.ro("resource"_hs)
|
||||
.bind("task_1"_hs)
|
||||
.rw("resource"_hs);
|
||||
```
|
||||
|
||||
What happens here is that the resource first _sees_ a read-only access request
|
||||
from the first task, then a read-write request from the second task and finally
|
||||
a new read-only request from the first task.<br/>
|
||||
Although this definition would probably be counted as an error, the resulting
|
||||
graph may be unexpected. This in fact consists of a single edge outgoing from
|
||||
the second task and directed to the first task.<br/>
|
||||
To intuitively understand what happens, it's enough to think of the fact that a
|
||||
task never has an edge pointing to itself.
|
||||
|
||||
While not obvious, this approach has its pros and cons like any other solution.
|
||||
For example, creating loops is actually simple in the context of resource-based
|
||||
graph generations:
|
||||
|
||||
```cpp
|
||||
builder
|
||||
.bind("task_1"_hs)
|
||||
.rw("resource"_hs)
|
||||
.bind("task_2"_hs)
|
||||
.rw("resource"_hs)
|
||||
.bind("task_1"_hs)
|
||||
.rw("resource"_hs);
|
||||
```
|
||||
|
||||
As expected, this definition leads to the creation of two edges that define a
|
||||
loop between the two tasks.
|
||||
|
||||
As a general rule, rebinding resources and tasks is highly discouraged because
|
||||
it could lead to subtle bugs if users don't know what they're doing.<br/>
|
||||
However, once the mechanisms of resource-based graph generation are understood,
|
||||
it can offer to the expert user a flexibility and a range of possibilities
|
||||
otherwise inaccessible.
|
||||
|
||||
## Fake resources and order of execution
|
||||
|
||||
The flow builder doesn't offer the ability to specify when a task should execute
|
||||
before or after another task.<br/>
|
||||
In fact, the order of _registration_ on the resources also determines the order
|
||||
in which the tasks are processed during the generation of the execution graph.
|
||||
|
||||
However, there is a way to _force_ the execution order of two processes.<br/>
|
||||
Briefly, since accessing a resource in opposite modes requires sequential rather
|
||||
than parallel scheduling, it's possible to make use of fake resources to rule on
|
||||
the execution order:
|
||||
|
||||
```cpp
|
||||
builder
|
||||
.bind("task_1"_hs)
|
||||
.ro("resource_1"_hs)
|
||||
.rw("fake"_hs)
|
||||
.bind("task_2"_hs)
|
||||
.ro("resource_2"_hs)
|
||||
.ro("fake"_hs)
|
||||
.bind("task_3"_hs)
|
||||
.ro("resource_2"_hs)
|
||||
.ro("fake"_hs)
|
||||
```
|
||||
|
||||
This snippet forces the execution of `task_1` **before** `task_2` and `task_3`.
|
||||
This is due to the fact that the former sets a read-write requirement on a fake
|
||||
resource that the other tasks also want to access in read-only mode.<br/>
|
||||
Similarly, it's possible to force a task to run **after** a certain group:
|
||||
|
||||
```cpp
|
||||
builder
|
||||
.bind("task_1"_hs)
|
||||
.ro("resource_1"_hs)
|
||||
.ro("fake"_hs)
|
||||
.bind("task_2"_hs)
|
||||
.ro("resource_1"_hs)
|
||||
.ro("fake"_hs)
|
||||
.bind("task_3"_hs)
|
||||
.ro("resource_2"_hs)
|
||||
.rw("fake"_hs)
|
||||
```
|
||||
|
||||
In this case, since there are a number of processes that want to read a specific
|
||||
resource, they will do so in parallel by forcing `task_3` to run after all the
|
||||
others tasks.
|
||||
|
||||
## Sync points
|
||||
|
||||
Sometimes it's useful to assign the role of _sync point_ to a node.<br/>
|
||||
Whether it accesses new resources or is simply a watershed, the procedure for
|
||||
assigning this role to a vertex is always the same. First it's tied to the flow
|
||||
builder, then the `sync` function is invoked:
|
||||
|
||||
```cpp
|
||||
builder.bind("sync_point"_hs).sync();
|
||||
```
|
||||
|
||||
The choice to assign an _identity_ to this type of nodes lies in the fact that,
|
||||
more often than not, they also perform operations on resources.<br/>
|
||||
If this isn't the case, it will still be possible to create no-op vertices to
|
||||
which empty tasks are assigned.
|
||||
|
||||
## Execution graph
|
||||
|
||||
Once both the resources and their consumers have been properly registered, the
|
||||
purpose of this tool is to generate an execution graph that takes into account
|
||||
all specified constraints to return the best scheduling for the vertices:
|
||||
|
||||
```cpp
|
||||
entt::adjacency_matrix<entt::directed_tag> graph = builder.graph();
|
||||
```
|
||||
|
||||
Searching for the main vertices (that is, those without in-edges) is usually the
|
||||
first thing required:
|
||||
|
||||
```cpp
|
||||
for(auto &&vertex: graph) {
|
||||
if(auto in_edges = graph.in_edges(vertex); in_edges.begin() == in_edges.end()) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then it's possible to instantiate an execution graph by means of other functions
|
||||
such as `out_edges` to retrieve the children of a given task or `edges` to get
|
||||
the identifiers.
|
||||
97
docs/md/lib.md
Normal file
97
docs/md/lib.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Push EnTT across boundaries
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Working across boundaries](#working-across-boundaries)
|
||||
* [Smooth until proven otherwise](#smooth-until-proven-otherwise)
|
||||
* [Meta context](#meta-context)
|
||||
* [Memory management](#memory-management)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Working across boundaries
|
||||
|
||||
`EnTT` has historically had a limit when used across boundaries on Windows in
|
||||
general and on GNU/Linux when default visibility was set to hidden. The
|
||||
limitation was mainly due to a custom utility used to assign unique, sequential
|
||||
identifiers with different types.<br/>
|
||||
Fortunately, nowadays `EnTT` works smoothly across boundaries.
|
||||
|
||||
## Smooth until proven otherwise
|
||||
|
||||
Many classes in `EnTT` make extensive use of type erasure for their purposes.
|
||||
This raises the need to identify objects whose type has been erased.<br/>
|
||||
The `type_hash` class template is how identifiers are generated and thus made
|
||||
available to the rest of the library. In general, this class doesn't arouse much
|
||||
interest. The only exception is when a conflict between identifiers occurs
|
||||
(definitely uncommon though) or when the default solution proposed by `EnTT`
|
||||
isn't suitable for the user's purposes.<br/>
|
||||
The section dedicated to `type_info` contains all the details to get around the
|
||||
issue in a concise and elegant way. Please refer to the specific documentation.
|
||||
|
||||
When working with linked libraries, compile definitions `ENTT_API_EXPORT` and
|
||||
`ENTT_API_IMPORT` are to import or export symbols, so as to make everything work
|
||||
nicely across boundaries.<br/>
|
||||
On the other hand, everything should run smoothly when working with plugins or
|
||||
shared libraries that don't export any symbols.
|
||||
|
||||
For those who need more details, the test suite contains many examples covering
|
||||
the most common cases (see the `lib` directory for all details).<br/>
|
||||
It goes without saying that it's impossible to cover **all** possible cases.
|
||||
However, what is offered should hopefully serve as a basis for all of them.
|
||||
|
||||
## Meta context
|
||||
|
||||
The runtime reflection system deserves a special mention when it comes to using
|
||||
it across boundaries.<br/>
|
||||
Since it's linked already to a static context to which the elements are attached
|
||||
and different contexts don't relate to each other, they must be _shared_ to
|
||||
allow the use of meta types across boundaries.
|
||||
|
||||
Fortunately, sharing a context is also trivial to do. First of all, the local
|
||||
one is acquired in the main space:
|
||||
|
||||
```cpp
|
||||
auto handle = entt::locator<entt::meta_ctx>::handle();
|
||||
```
|
||||
|
||||
Then, it's passed to the receiving space that sets it as its default context,
|
||||
thus discarding or storing aside the local one:
|
||||
|
||||
```cpp
|
||||
entt::locator<entt::meta_ctx>::reset(handle);
|
||||
```
|
||||
|
||||
From now on, both spaces refer to the same context and on it are attached all
|
||||
new meta types, no matter where they are created.<br/>
|
||||
Note that _replacing_ the main context doesn't also propagate changes across
|
||||
boundaries. In other words, replacing a context results in the decoupling of the
|
||||
two sides and therefore a divergence in the contents.
|
||||
|
||||
## Memory Management
|
||||
|
||||
There is another subtle problem due to memory management that can lead to
|
||||
headaches.<br/>
|
||||
It can occur where there are pools of objects (such as components or events)
|
||||
dynamically created on demand. This is usually not a problem when working with
|
||||
linked libraries that rely on the same dynamic runtime. However, it can occur in
|
||||
the case of plugins or statically linked runtimes.
|
||||
|
||||
As an example, imagine creating an instance of `registry` in the main executable
|
||||
and sharing it with a plugin. If the latter starts working with a component that
|
||||
is unknown to the former, a dedicated pool is created within the registry on
|
||||
first use.<br/>
|
||||
As one can guess, this pool is instantiated on a different side of the boundary
|
||||
from the `registry`. Therefore, the instance is now managing memory from
|
||||
different spaces and this can quickly lead to crashes if not properly addressed.
|
||||
|
||||
To overcome the risk, it's recommended to use well-defined interfaces that make
|
||||
fundamental types pass through the boundaries, isolating the instances of the
|
||||
`EnTT` classes from time to time and as appropriate.<br/>
|
||||
Refer to the test suite for some examples, read the documentation available
|
||||
online about this type of issues or consult someone who has already had such
|
||||
experiences to avoid problems.
|
||||
304
docs/md/links.md
Normal file
304
docs/md/links.md
Normal file
@@ -0,0 +1,304 @@
|
||||
# EnTT in Action
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [EnTT in Action](#entt-in-action)
|
||||
* [Games](#games)
|
||||
* [Engines and the like](#engines-and-the-like)
|
||||
* [Articles, videos and blog posts](#articles-videos-and-blog-posts)
|
||||
* [Any Other Business](#any-other-business)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
`EnTT` is widely used in private and commercial applications. I cannot even
|
||||
mention most of them because of some signatures I put on some documents time
|
||||
ago. Fortunately, there are also people who took the time to implement open
|
||||
source projects based on `EnTT` and didn't hold back when it came to documenting
|
||||
them.
|
||||
|
||||
Below an incomplete list of games, applications and articles that can be used as
|
||||
a reference.<br/>
|
||||
Where I put the word _apparently_ means that the use of `EnTT` is documented but
|
||||
the authors didn't make explicit announcements or contacted me directly.
|
||||
|
||||
If you know of other resources out there that are about `EnTT`, feel free to
|
||||
open an issue or a PR and I'll be glad to add them to this page.<br/>
|
||||
I hope the following lists can grow much more in the future.
|
||||
|
||||
# EnTT in Action
|
||||
|
||||
## Games
|
||||
|
||||
* [Minecraft](https://minecraft.net/en-us/attribution/) by
|
||||
[Mojang](https://mojang.com/): of course, **that** Minecraft, see the
|
||||
open source attributions page for more details.
|
||||
* [Minecraft Earth](https://www.minecraft.net/en-us/about-earth) by
|
||||
[Mojang](https://mojang.com/): an augmented reality game for mobile, that
|
||||
lets users bring Minecraft into the real world.
|
||||
* [Ember Sword](https://embersword.com/): a modern Free-to-Play MMORPG with a
|
||||
player-driven economy, a classless combat system, and scarce, tradable
|
||||
cosmetic collectibles.
|
||||
* Apparently [Diablo II: Resurrected](https://diablo2.blizzard.com/) by
|
||||
[Blizzard](https://www.blizzard.com/): monsters, heroes, items, spells, all
|
||||
resurrected. Thanks unknown insider.
|
||||
* [Apparently](https://www.youtube.com/watch?v=P8xvOA3ikrQ&t=1105s)
|
||||
[Call of Duty: Vanguard](https://www.callofduty.com/vanguard) by
|
||||
[Sledgehammer Games](https://www.sledgehammergames.com/): I can neither
|
||||
confirm nor deny but there is a license I know in the credits.
|
||||
* Apparently [D&D Dark Alliance](https://darkalliance.wizards.com) by
|
||||
[Wizards of the Coast](https://company.wizards.com): your party, their
|
||||
funeral.
|
||||
* [TiltedOnline](https://github.com/tiltedphoques/TiltedOnline) by
|
||||
[Tilted Phoques](https://github.com/tiltedphoques): Skyrim and Fallout 4 mod
|
||||
to play online.
|
||||
* [Antkeeper](https://github.com/antkeeper/antkeeper-source): an ant colony
|
||||
simulation [game](https://antkeeper.com/).
|
||||
* [Openblack](https://github.com/openblack/openblack): open source
|
||||
reimplementation of the game _Black & White_ (2001).
|
||||
* [Land of the Rair](https://github.com/LandOfTheRair/core2): the new backend
|
||||
of [a retro-style MUD](https://rair.land/) for the new age.
|
||||
* [Face Smash](https://play.google.com/store/apps/details?id=com.gamee.facesmash):
|
||||
a game to play with your face.
|
||||
* [EnTT Pacman](https://github.com/Kerndog73/EnTT-Pacman): an example of how
|
||||
to make Pacman with `EnTT`.
|
||||
* [Wacman](https://github.com/carlfindahl/wacman): a pacman clone with OpenGL.
|
||||
* [Classic Tower Defence](https://github.com/kerndog73/Classic-Tower-Defence):
|
||||
a tiny little tower defence game featuring a homemade font.
|
||||
[Check it out](https://indi-kernick.itch.io/classic-tower-defence).
|
||||
* [The Machine](https://github.com/Kerndog73/The-Machine): a box pushing
|
||||
puzzler with logic gates and other cool stuff.
|
||||
[Check it out](https://indi-kernick.itch.io/the-machine-web-version).
|
||||
* [EnTTPong](https://github.com/DomRe/EnttPong): a basic game made to showcase
|
||||
different parts of `EnTT` and C++17.
|
||||
* [Randballs](https://github.com/gale93/randballs): simple `SFML` and `EnTT`
|
||||
playground.
|
||||
* [EnTT Tower Defense](https://github.com/Daivuk/tddod): a data oriented tower
|
||||
defense example.
|
||||
* [EnTT Breakout](https://github.com/vblanco20-1/entt-breakout): simple
|
||||
example of a breakout game, using `SDL` and `EnTT`.
|
||||
* [Arcade puzzle game with EnTT](https://github.com/MasonRG/ArcadePuzzleGame):
|
||||
arcade puzzle game made in C++ using the `SDL2` and `EnTT` libraries.
|
||||
* [Snake with EnTT](https://github.com/MasonRG/SnakeGame): simple snake game
|
||||
made in C++ with the `SDL2` and `EnTT` libraries.
|
||||
* [Mirrors lasers and robots](https://github.com/guillaume-haerinck/imac-tower-defense):
|
||||
a small tower defense game based on mirror orientation.
|
||||
* [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead/): 2D, Zombie,
|
||||
RPG game made from scratch in C++.
|
||||
* [Robotligan](https://github.com/Trisslotten/robotligan): multiplayer
|
||||
football game.
|
||||
* [DungeonSlayer](https://github.com/alohaeee/DungeonSlayer): 2D game made
|
||||
from scratch in C++.
|
||||
* [3DGame](https://github.com/kwarkGorny/3DGame): 2.5D top-down space shooter.
|
||||
* [Pulcher](https://github.com/AODQ/pulcher): 2D cross-platform game inspired
|
||||
by Quake.
|
||||
* [Destroid](https://github.com/tyrannicaltoucan/destroid): _one-bazillionth_
|
||||
arcade game about shooting dirty rocks in space, inspired by Asteroids.
|
||||
* [Wanderer](https://github.com/albin-johansson/wanderer): a 2D exploration
|
||||
based indie game.
|
||||
* [Spelunky® Classic remake](https://github.com/dbeef/spelunky-psp): a truly
|
||||
multiplatform experience with a rewrite from scratch.
|
||||
* [CubbyTower](https://github.com/utilForever/CubbyTower): a simple tower
|
||||
defense game using C++ with Entity Component System (ECS).
|
||||
* [Runeterra](https://github.com/utilForever/Runeterra): Legends of Runeterra
|
||||
simulator using C++ with some reinforcement learning.
|
||||
* [Black Sun](https://store.steampowered.com/app/1670930/Black_Sun/): fly your
|
||||
space ship through a large 2D open world.
|
||||
* [PokeMaster](https://github.com/utilForever/PokeMaster): Pokemon Battle
|
||||
simulator using C++ with some reinforcement learning.
|
||||
* [HomeHearth](https://youtu.be/GrEWl8npL9Y): choose your hero, protect the
|
||||
town, before it's too late.
|
||||
* [City Builder Game](https://github.com/PhiGei2000/CityBuilderGame): a simple
|
||||
city-building game using C++ and OpenGL.
|
||||
* [BattleSub](https://github.com/bfeldpw/battlesub): two player 2D submarine
|
||||
game with some fluid dynamics.
|
||||
* [Crimson Rush](https://github.com/WilKam01/LuaCGame): a dungeon-crawler and
|
||||
rougelike inspired game about exploring and surviving as long as possible.
|
||||
* [Space Fight](https://github.com/cholushkin/SpaceFight): one screen
|
||||
multi-player arcade shooter game prototype.
|
||||
* [Confetti Party](https://github.com/hexerei/entt-confetti): C++ sample
|
||||
application as a starting point using `EnTT` and `SDL2`.
|
||||
|
||||
## Engines and the like:
|
||||
|
||||
* [Aether Engine](https://hadean.com/spatial-simulation/)
|
||||
[v1.1+](https://docs.hadean.com/v1.1/Licenses/) by
|
||||
[Hadean](https://hadean.com/): a library designed for spatially partitioning
|
||||
agent-based simulations.
|
||||
* [Fling Engine](https://github.com/flingengine/FlingEngine): a Vulkan game
|
||||
engine with a focus on data oriented design.
|
||||
* [NovusCore](https://github.com/novuscore/NovusCore): a modern take on World
|
||||
of Warcraft emulation.
|
||||
* [Chrysalis](https://github.com/ivanhawkes/Chrysalis): action RPG SDK for
|
||||
CRYENGINE games.
|
||||
* [LM-Engine](https://github.com/Lawrencemm/LM-Engine): the Vim of game
|
||||
engines.
|
||||
* [Edyn](https://github.com/xissburg/edyn): a real-time physics engine
|
||||
organized as an ECS.
|
||||
* [MushMachine](https://github.com/MadeOfJelly/MushMachine): engine...
|
||||
vrooooommm.
|
||||
* [Antara Gaming SDK](https://github.com/KomodoPlatform/antara-gaming-sdk):
|
||||
the Komodo Gaming Software Development Kit.
|
||||
* [XVP](https://ravingbots.com/xvp-expansive-vehicle-physics-for-unreal-engine/):
|
||||
[_eXpansive Vehicle Physics_](https://github.com/raving-bots/xvp/wiki/Plugin-integration-guide)
|
||||
plugin for Unreal Engine.
|
||||
* [Apparently](https://teamwisp.github.io/credits/)
|
||||
[Wisp](https://teamwisp.github.io/product/) by
|
||||
[Team Wisp](https://teamwisp.github.io/): an advanced real-time ray tracing
|
||||
renderer built for the demands of video game artists.
|
||||
* [shiva](https://github.com/Milerius/shiva): modern C++ engine with
|
||||
modularity.
|
||||
* [ImGui/EnTT editor](https://github.com/Green-Sky/imgui_entt_entity_editor):
|
||||
a drop-in, single-file entity editor for `EnTT` that uses `ImGui` as
|
||||
graphical backend (with
|
||||
[demo code](https://github.com/Green-Sky/imgui_entt_entity_editor_demo)).
|
||||
* [SgOgl](https://github.com/stwe/SgOgl): a game engine library for OpenGL
|
||||
developed for educational purposes.
|
||||
* [Lumos](https://github.com/jmorton06/Lumos): game engine written in C++
|
||||
using OpenGL and Vulkan.
|
||||
* [Silvanus](https://github.com/hobbyistmaker/silvanus): Silvanus Fusion 360
|
||||
Box Generator.
|
||||
* [Lina Engine](https://github.com/inanevin/LinaEngine): an open-source,
|
||||
modular, tiny and fast C++ game engine, aimed to develop 3D desktop games.
|
||||
* [Spike](https://github.com/FahimFuad/Spike): a powerful game engine which
|
||||
can run on a toaster.
|
||||
* [Helena Framework](https://github.com/NIKEA-SOFT/HelenaFramework): a modern
|
||||
framework in C++17 for backend development.
|
||||
* [Unity/EnTT](https://github.com/TongTungGiang/unity-entt): tech demo of a
|
||||
native simulation layer using `EnTT` and `Unity` as a rendering engine.
|
||||
* [OverEngine](https://github.com/OverShifted/OverEngine): an over-engineered
|
||||
game engine.
|
||||
* [Electro](https://github.com/Electro-Technologies/Electro): high performance
|
||||
3D game engine with a high emphasis on rendering.
|
||||
* [Kawaii](https://github.com/Mathieu-Lala/Kawaii_Engine): a modern data
|
||||
oriented game engine.
|
||||
* [Becketron](https://github.com/Doctor-Foxling/Becketron): a game engine
|
||||
written mostly in C++.
|
||||
* [Spatial Engine](https://github.com/luizgabriel/Spatial.Engine): a
|
||||
cross-platform engine created on top of google's filament rendering engine.
|
||||
* [Kaguya](https://github.com/KaiH0717/Kaguya): D3D12 Rendering Engine.
|
||||
* [OpenAWE](https://github.com/OpenAWE-Project/OpenAWE): open implementation
|
||||
of the Alan Wake Engine.
|
||||
* [Nazara Engine](https://github.com/DigitalPulseSoftware/NazaraEngine): fast,
|
||||
cross-platform, object-oriented API to help in daily developer life.
|
||||
* [Billy Engine](https://github.com/billy4479/BillyEngine): some kind of a 2D
|
||||
engine based on `SDL2` and `EnTT`.
|
||||
* [Ducktape](https://github.com/DucktapeEngine/Ducktape): an open source C++
|
||||
2D & 3D game engine that focuses on being fast and powerful.
|
||||
* [The Worst Engine](https://github.com/Parasik72/TWE): a game engine based on
|
||||
OpenGL.
|
||||
* [Ecsact](https://ecsact.dev/): a language aimed at describing ECS, with a
|
||||
[runtime implementation](https://github.com/ecsact-dev/ecsact_rt_entt) based
|
||||
on `EnTT`.
|
||||
* [AGE (Arc Game Engine)](https://github.com/MohitSethi99/ArcGameEngine): an
|
||||
open-source engine for building 2D & 3D real-time rendering and interactive
|
||||
contents.
|
||||
* [Kengine](https://github.com/phisko/kengine): the _Koala engine_ is a game
|
||||
engine entirely implemented as an entity-component-ystem.
|
||||
|
||||
## Articles, videos and blog posts:
|
||||
|
||||
* [Some posts](https://skypjack.github.io/tags/#entt) on my personal
|
||||
[blog](https://skypjack.github.io/) are about `EnTT`, for those who want to
|
||||
know **more** on this project.
|
||||
* [Game Engine series](https://www.youtube.com/c/TheChernoProject/videos) by
|
||||
[The Cherno](https://github.com/TheCherno) (not only about `EnTT` but also
|
||||
on the use of an ECS in general):
|
||||
- [Intro to EnTT](https://www.youtube.com/watch?v=D4hz0wEB978).
|
||||
- [Entities and Components](https://www.youtube.com/watch?v=-B1iu4QJTUc).
|
||||
- [The ENTITY Class](https://www.youtube.com/watch?v=GfSzeAcsBb0).
|
||||
- [Camera Systems](https://www.youtube.com/watch?v=ubZn7BlrnTU).
|
||||
- [Scene Camera](https://www.youtube.com/watch?v=UKVFRRufKzo).
|
||||
- [Native Scripting](https://www.youtube.com/watch?v=iIUhg88MK5M).
|
||||
- [Native Scripting (now with virtual functions!)](https://www.youtube.com/watch?v=1cHEcrIn8IQ).
|
||||
- [Scene Hierarchy Panel](https://www.youtube.com/watch?v=wziDnE8guvI).
|
||||
- [Properties Panel](https://www.youtube.com/watch?v=NBpB0qscF3E).
|
||||
- [Camera Component UI](https://www.youtube.com/watch?v=RIMt_6agUiU).
|
||||
- [Drawing Component UI](https://www.youtube.com/watch?v=u3yq8s3KuSE).
|
||||
- [Transform Component UI](https://www.youtube.com/watch?v=8JqcXYbzPJc).
|
||||
- [Adding/Removing Entities and Components UI](https://www.youtube.com/watch?v=PsyGmsIgp9M).
|
||||
- [Saving and Loading Scenes](https://www.youtube.com/watch?v=IEiOP7Y-Mbc).
|
||||
- ... And so on.
|
||||
[Check out](https://www.youtube.com/channel/UCQ-W1KE9EYfdxhL6S4twUNw) the
|
||||
_Game Engine Series_ by The Cherno for more videos.
|
||||
* [Warmonger Dynasty devlog series](https://david-delassus.medium.com/list/warmonger-dynasty-devlogs-f64b71f556de)
|
||||
by [linkdd](https://github.com/linkdd): an interesting walkthrough of
|
||||
developing a game (also) with EnTT.
|
||||
* [Use EnTT When You Need An ECS](https://www.codingwiththomas.com/blog/use-entt-when-you-need-an-ecs)
|
||||
by [Thomas](https://www.codingwiththomas.com/): I couldn't have said it
|
||||
better.
|
||||
* [Space Battle: Huge edition](http://victor.madtriangles.com/code%20experiment/2018/06/11/post-ecs-battle-huge.html):
|
||||
huge space battle built entirely from scratch.
|
||||
* [Space Battle](https://github.com/vblanco20-1/ECS_SpaceBattle): huge space
|
||||
battle built on `UE4`.
|
||||
* [Experimenting with ECS in UE4](http://victor.madtriangles.com/code%20experiment/2018/03/25/post-ue4-ecs-battle.html):
|
||||
interesting article about `UE4` and `EnTT`.
|
||||
* [Implementing ECS architecture in UE4](https://forums.unrealengine.com/development-discussion/c-gameplay-programming/1449913-implementing-ecs-architecture-in-ue4-giant-space-battle):
|
||||
giant space battle.
|
||||
* [Conan Adventures (SFML and EnTT in C++)](https://leinnan.github.io/blog/conan-adventuressfml-and-entt-in-c.html):
|
||||
create projects in modern C++ using `SFML`, `EnTT`, `Conan` and `CMake`.
|
||||
* [Adding EnTT ECS to Chrysalis](https://www.tauradius.com/post/adding-an-ecs-to-chrysalis/):
|
||||
a blog entry (and its
|
||||
[follow-up](https://www.tauradius.com/post/chrysalis-update-2020-08-02/))
|
||||
about the integration of `EnTT` into `Chrysalis`, an action RPG SDK for
|
||||
CRYENGINE games.
|
||||
* [Creating Minecraft in One Week with C++ and Vulkan](https://vazgriz.com/189/creating-minecraft-in-one-week-with-c-and-vulkan/):
|
||||
a crack at recreating Minecraft in one week using a custom C++ engine and
|
||||
Vulkan ([code included](https://github.com/vazgriz/VoxelGame)).
|
||||
* [Ability Creator](https://www.erichildebrand.net/blog/ability-creator-project-retrospect):
|
||||
project retrospect by [Eric Hildebrand](https://www.erichildebrand.net/).
|
||||
* [EnTT Entity Component System Gaming Library](https://gamefromscratch.com/entt-entity-component-system-gaming-library/):
|
||||
`EnTT` on GameFromScratch.com.
|
||||
* [Custom C++ server for UE5](https://youtu.be/fbXZVNCOvjM) optimized for
|
||||
MMO(RPG)s and its [follow-up](https://youtu.be/yGlZeopx2hU) episode about
|
||||
player bots and full external ECS: a series definitely worth looking at.
|
||||
|
||||
## Any Other Business:
|
||||
|
||||
* [ArcGIS Runtime SDKs](https://developers.arcgis.com/arcgis-runtime/) by
|
||||
[Esri](https://www.esri.com/): they use `EnTT` for the internal ECS and the
|
||||
cross platform C++ rendering engine. The SDKs are utilized by a lot of
|
||||
enterprise custom apps, as well as by Esri for its own public applications
|
||||
such as
|
||||
[Explorer](https://play.google.com/store/apps/details?id=com.esri.explorer),
|
||||
[Collector](https://play.google.com/store/apps/details?id=com.esri.arcgis.collector)
|
||||
and
|
||||
[Navigator](https://play.google.com/store/apps/details?id=com.esri.navigator).
|
||||
* [FASTSUITE Edition 2](https://www.fastsuite.com/en_EN/fastsuite/fastsuite-edition-2.html)
|
||||
by [Cenit](http://www.cenit.com/en_EN/about-us/overview.html): they use
|
||||
`EnTT` to drive their simulation, that is, the communication between robot
|
||||
controller emulator and renderer.
|
||||
* [Ragdoll](https://ragdolldynamics.com/): real-time physics for Autodesk Maya
|
||||
2020.
|
||||
* [Project Lagrange](https://github.com/adobe/lagrange): a robust geometry
|
||||
processing library by [Adobe](https://github.com/adobe).
|
||||
* [AtomicDEX](https://github.com/KomodoPlatform/atomicDEX-Desktop): a secure
|
||||
wallet and non-custodial decentralized exchange rolled into one application.
|
||||
* [Apparently](https://www.linkedin.com/in/skypjack/)
|
||||
[NIO](https://www.nio.io/): there was a collaboration to make some changes
|
||||
to `EnTT`, at the time used for internal projects.
|
||||
* [Apparently](https://www.linkedin.com/jobs/view/architekt-c%2B%2B-at-tieto-1219512333/)
|
||||
[Tieto](https://www.tieto.com/): they published a job post where `EnTT` was
|
||||
listed on their software stack.
|
||||
* [Sequentity](https://github.com/alanjfs/sequentity): A MIDI-like
|
||||
sequencer/tracker for C++ and `ImGui` (with `Magnum` and `EnTT`).
|
||||
* [EnTT meets Sol2](https://github.com/skaarj1989/entt-meets-sol2): freely
|
||||
available examples of how to combine `EnTT` and `Sol2`.
|
||||
* [Godot meets EnTT](https://github.com/portaloffreedom/godot_entt_example/):
|
||||
a simple example on how to use `EnTT` within
|
||||
[`Godot`](https://godotengine.org/).
|
||||
* [Godot and GameNetworkingSockets meet EnTT](https://github.com/portaloffreedom/godot_entt_net_example):
|
||||
a simple example on how to use `EnTT` and
|
||||
[`GameNetworkingSockets`](https://github.com/ValveSoftware/GameNetworkingSockets)
|
||||
within [`Godot`](https://godotengine.org/).
|
||||
* [MatchOneEntt](https://github.com/mhaemmerle/MatchOneEntt): port of
|
||||
[Match One](https://github.com/sschmid/Match-One) for `Entitas-CSharp`.
|
||||
* GitHub contains also
|
||||
[many other examples](https://github.com/search?o=desc&q=%22skypjack%2Fentt%22&s=indexed&type=Code)
|
||||
of use of `EnTT` from which to take inspiration if interested.
|
||||
88
docs/md/locator.md
Normal file
88
docs/md/locator.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Crash Course: service locator
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Service locator](#service-locator)
|
||||
* [Opaque handles](#opaque-handles)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
Usually, service locators are tightly bound to the services they expose and it's
|
||||
hard to define a general purpose solution.<br/>
|
||||
This tiny class tries to fill the gap and gets rid of the burden of defining a
|
||||
different specific locator for each application.
|
||||
|
||||
# Service locator
|
||||
|
||||
The service locator API tries to mimic that of `std::optional` and adds some
|
||||
extra functionalities on top of it such as allocator support.<br/>
|
||||
There are a couple of functions to set up a service, namely `emplace` and
|
||||
`allocate_emplace`:
|
||||
|
||||
```cpp
|
||||
entt::locator<interface>::emplace<service>(argument);
|
||||
entt::locator<interface>::allocate_emplace<service>(allocator, argument);
|
||||
```
|
||||
|
||||
The difference is that the latter expects an allocator as the first argument and
|
||||
uses it to allocate the service itself.<br/>
|
||||
Once a service is set up, it's retrieved using the `value` function:
|
||||
|
||||
```cpp
|
||||
interface &service = entt::locator<interface>::value();
|
||||
```
|
||||
|
||||
Since the service may not be set (and therefore this function may result in an
|
||||
undefined behavior), the `has_value` and `value_or` functions are also available
|
||||
to test a service locator and to get a fallback service in case there is none:
|
||||
|
||||
```cpp
|
||||
if(entt::locator<interface>::has_value()) {
|
||||
// ...
|
||||
}
|
||||
|
||||
interface &service = entt::locator<interface>::value_or<fallback_impl>(argument);
|
||||
```
|
||||
|
||||
All arguments are used only if necessary, that is, if a service doesn't already
|
||||
exist and therefore the fallback service is constructed and returned. In all
|
||||
other cases, they are discarded.<br/>
|
||||
Finally, to reset a service, use the `reset` function.
|
||||
|
||||
## Opaque handles
|
||||
|
||||
Sometimes it's useful to _transfer_ a copy of a service to another locator. For
|
||||
example, when working across boundaries it's common to _share_ a service with a
|
||||
dynamically loaded module.<br/>
|
||||
Options aren't much in this case. Among these is the possibility of _exporting_
|
||||
services and assigning them to a different locator.
|
||||
|
||||
This is what the `handle` and `reset` functions are meant for.<br/>
|
||||
The former returns an opaque object useful for _exporting_ (or rather, obtaining
|
||||
a reference to) a service. The latter also accepts an optional argument to a
|
||||
handle which then allows users to reset a service by initializing it with an
|
||||
opaque handle:
|
||||
|
||||
```cpp
|
||||
auto handle = entt::locator<interface>::handle();
|
||||
entt::locator<interface>::reset(handle);
|
||||
```
|
||||
|
||||
It's worth noting that it's possible to get handles for uninitialized services
|
||||
and use them with other locators. Of course, all a user will get is to have an
|
||||
uninitialized service elsewhere as well.
|
||||
|
||||
Note that exporting a service allows users to _share_ the object currently set
|
||||
in a locator. Replacing it won't replace the element even where a service has
|
||||
been configured with a handle to the previous item.<br/>
|
||||
In other words, if an audio service is replaced with a null object to silence an
|
||||
application and the original service was shared, this operation won't propagate
|
||||
to the other locators. Therefore, a module that share the ownership of the
|
||||
original audio service is still able to emit sounds.
|
||||
961
docs/md/meta.md
Normal file
961
docs/md/meta.md
Normal file
@@ -0,0 +1,961 @@
|
||||
# Crash Course: runtime reflection system
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Names and identifiers](#names-and-identifiers)
|
||||
* [Reflection in a nutshell](#reflection-in-a-nutshell)
|
||||
* [Any to the rescue](#any-to-the-rescue)
|
||||
* [Enjoy the runtime](#enjoy-the-runtime)
|
||||
* [Container support](#container-support)
|
||||
* [Pointer-like types](#pointer-like-types)
|
||||
* [Template information](#template-information)
|
||||
* [Automatic conversions](#automatic-conversions)
|
||||
* [Implicitly generated default constructor](#implicitly-generated-default-constructor)
|
||||
* [From void to any](#from-void-to-any)
|
||||
* [Policies: the more, the less](#policies-the-more-the-less)
|
||||
* [Named constants and enums](#named-constants-and-enums)
|
||||
* [Properties and meta objects](#properties-and-meta-objects)
|
||||
* [Unregister types](#unregister-types)
|
||||
* [Meta context](#meta-context)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
Reflection (or rather, its lack) is a trending topic in the C++ world and a tool
|
||||
that can unlock a lot of interesting features in the specific case of `EnTT`. I
|
||||
looked for a third-party library that met my needs on the subject, but I always
|
||||
came across some details that I didn't like: macros, being intrusive, too many
|
||||
allocations, and so on.<br/>
|
||||
I finally decided to write a built-in, non-intrusive and macro-free runtime
|
||||
reflection system for `EnTT`. Maybe I didn't do better than others or maybe yes,
|
||||
time will tell me, but at least I can model this tool around the library to
|
||||
which it belongs and not the opposite.
|
||||
|
||||
# Names and identifiers
|
||||
|
||||
The meta system doesn't force users to rely on the tools provided by the library
|
||||
when it comes to working with names and identifiers. It does this by offering an
|
||||
API that works with opaque identifiers that may or may not be generated by means
|
||||
of a hashed string.<br/>
|
||||
This means that users can assign any type of identifier to the meta objects, as
|
||||
long as they're numeric. It doesn't matter if they're generated at runtime, at
|
||||
compile-time or with custom functions.
|
||||
|
||||
That being said, the examples in the following sections are all based on the
|
||||
`hashed_string` class as provided by this library. Therefore, where an
|
||||
identifier is required, it's likely that a user defined literal is used as
|
||||
follows:
|
||||
|
||||
```cpp
|
||||
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
|
||||
```
|
||||
|
||||
For what it's worth, this is completely equivalent to:
|
||||
|
||||
```cpp
|
||||
auto factory = entt::meta<my_type>().type(42u);
|
||||
```
|
||||
|
||||
Obviously, human-readable identifiers are more convenient to use and highly
|
||||
recommended.
|
||||
|
||||
# Reflection in a nutshell
|
||||
|
||||
Reflection always starts from actual C++ types. Users cannot reflect _imaginary_
|
||||
types.<br/>
|
||||
The `meta` function is where it all starts:
|
||||
|
||||
```cpp
|
||||
auto factory = entt::meta<my_type>();
|
||||
```
|
||||
|
||||
The returned value is a _factory object_ to use to continue building the meta
|
||||
type.
|
||||
|
||||
By default, a meta type is associated with the identifier returned by the
|
||||
runtime type identification system built-in in `EnTT`.<br/>
|
||||
However, it's also possible to assign custom identifiers to meta types:
|
||||
|
||||
```cpp
|
||||
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
|
||||
```
|
||||
|
||||
Identifiers are used to _retrieve_ meta types at runtime by _name_ other than by
|
||||
type.<br/>
|
||||
However, users can be interested in adding features to a reflected type so that
|
||||
the reflection system can use it correctly under the hood, while they don't want
|
||||
to also make the type _searchable_. In this case, it's sufficient not to invoke
|
||||
`type`.
|
||||
|
||||
A factory is such that all its member functions return the factory itself. It's
|
||||
generally used to create the following:
|
||||
|
||||
* _Constructors_. A constructors is assigned to a reflected type by specifying
|
||||
its _list of arguments_. Free functions are also accepted if the return type
|
||||
is the expected one. From a client perspective, nothing changes between a free
|
||||
function or an actual constructor:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().ctor<int, char>().ctor<&factory>();
|
||||
```
|
||||
|
||||
Meta default constructors are implicitly generated, if possible.
|
||||
|
||||
* _Destructors_. Both free functions and member functions are valid destructors:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().dtor<&destroy>();
|
||||
```
|
||||
|
||||
The purpose is to offer the possibility to free up resources that require
|
||||
_special treatment_ before an object is actually destroyed.<br/>
|
||||
A function should neither delete nor explicitly invoke the destructor of a
|
||||
given instance.
|
||||
|
||||
* _Data members_. Meta data members are actual data members of the underlying
|
||||
type but also static and global variables or constants of any kind. From the
|
||||
point of view of the client, all the variables associated with the reflected
|
||||
type appear as if they were part of the type itself:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>()
|
||||
.data<&my_type::static_variable>("static"_hs)
|
||||
.data<&my_type::data_member>("member"_hs)
|
||||
.data<&global_variable>("global"_hs);
|
||||
```
|
||||
|
||||
The `data` function requires the identifier to use for the meta data member.
|
||||
Users can then access it by _name_ at runtime.<br/>
|
||||
Data members are also defined by means of a setter and getter pair. These are
|
||||
either free functions, class members or a mix of them. This approach is also
|
||||
convenient to create read-only properties from a non-const data member:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().data<nullptr, &my_type::data_member>("member"_hs);
|
||||
```
|
||||
|
||||
Multiple setters are also supported by means of a `value_list` object:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().data<entt::value_list<&from_int, &from_string>, &my_type::data_member>("member"_hs);
|
||||
```
|
||||
|
||||
* _Member functions_. Meta member functions are actual member functions of the
|
||||
underlying type but also plain free functions. From the point of view of the
|
||||
client, all the functions associated with the reflected type appear as if they
|
||||
were part of the type itself:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>()
|
||||
.func<&my_type::static_function>("static"_hs)
|
||||
.func<&my_type::member_function>("member"_hs)
|
||||
.func<&free_function>("free"_hs);
|
||||
```
|
||||
|
||||
The `func` function requires the identifier to use for the meta data function.
|
||||
Users can then access it by _name_ at runtime.<br/>
|
||||
Overloading of meta functions is supported. Overloaded functions are resolved
|
||||
at runtime by the reflection system according to the types of the arguments.
|
||||
|
||||
* _Base classes_. A base class is such that the underlying type is actually
|
||||
derived from it:
|
||||
|
||||
```cpp
|
||||
entt::meta<derived_type>().base<base_type>();
|
||||
```
|
||||
|
||||
The reflection system tracks the relationship and allows for implicit casts at
|
||||
runtime when required. In other terms, wherever a `base_type` is required, an
|
||||
instance of `derived_type` is also accepted.
|
||||
|
||||
* _Conversion functions_. Conversion functions allow users to define conversions
|
||||
that are implicitly performed by the reflection system when required:
|
||||
|
||||
```cpp
|
||||
entt::meta<double>().conv<int>();
|
||||
```
|
||||
|
||||
This is everything users need to create meta types. Refer to the inline
|
||||
documentation for further details.
|
||||
|
||||
## Any to the rescue
|
||||
|
||||
The reflection system offers a kind of _extended version_ of the `entt::any`
|
||||
class (see the core module for more details).<br/>
|
||||
The purpose is to add some feature on top of those already present, so as to
|
||||
integrate it with the meta type system without having to duplicate the code.
|
||||
|
||||
The API is very similar to that of the `any` type. The class `meta_any` _wraps_
|
||||
many of the feature to infer a meta node, before forwarding some or all of the
|
||||
arguments to the underlying storage.<br/>
|
||||
Among the few relevant differences, `meta_any` adds support for containers and
|
||||
pointer-like types, while `any` doesn't.<br/>
|
||||
Similar to `any`, this class is also used to create _aliases_ for unmanaged
|
||||
objects either with `forward_as_meta` or using the `std::in_place_type<T &>`
|
||||
disambiguation tag, as well as from an existing object by means of the `as_ref`
|
||||
member function.<br/>
|
||||
Unlike `any` instead, `meta_any` treats an empty instance and one initialized
|
||||
with `void` differently:
|
||||
|
||||
```cpp
|
||||
entt::meta_any empty{};
|
||||
entt::meta_any other{std::in_place_type<void>};
|
||||
```
|
||||
|
||||
While `any` considers both as empty, `meta_any` treats objects initialized with
|
||||
`void` as if they were _valid_ ones. This allows to differentiate between failed
|
||||
function calls and function calls that are successful but return nothing.
|
||||
|
||||
Finally, the member functions `try_cast`, `cast` and `allow_cast` are used to
|
||||
cast the underlying object to a given type (either a reference or a value type)
|
||||
or to _convert_ a `meta_any` in such a way that a cast becomes viable for the
|
||||
resulting object.<br/>
|
||||
There is in fact no `any_cast` equivalent for `meta_any`.
|
||||
|
||||
## Enjoy the runtime
|
||||
|
||||
Once the web of reflected types is constructed, it's a matter of using it at
|
||||
runtime where required.<br/>
|
||||
There are a few options to search for a reflected type:
|
||||
|
||||
```cpp
|
||||
// direct access to a reflected type
|
||||
auto by_type = entt::resolve<my_type>();
|
||||
|
||||
// look up a reflected type by identifier
|
||||
auto by_id = entt::resolve("reflected_type"_hs);
|
||||
|
||||
// look up a reflected type by type info
|
||||
auto by_type_id = entt::resolve(entt::type_id<my_type>());
|
||||
```
|
||||
|
||||
There exists also an overload of the `resolve` function to use to iterate all
|
||||
reflected types at once. It returns an iterable object to be used in a range-for
|
||||
loop:
|
||||
|
||||
```cpp
|
||||
for(auto &&[id, type]: entt::resolve()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
In all cases, the returned value is an instance of `meta_type` (possibly with
|
||||
its id). This kind of objects offer an API to know their _runtime identifiers_,
|
||||
to iterate all the meta objects associated with them and even to build instances
|
||||
of the underlying type.<br/>
|
||||
Meta data members and functions are accessed by name:
|
||||
|
||||
* Meta data members:
|
||||
|
||||
```cpp
|
||||
auto data = entt::resolve<my_type>().data("member"_hs);
|
||||
```
|
||||
|
||||
The returned type is `meta_data` and may be invalid if there is no meta data
|
||||
object associated with the given identifier.<br/>
|
||||
A meta data object offers an API to query the underlying type (for example, to
|
||||
know if it's a const or a static one), to get the meta type of the variable
|
||||
and to set or get the contained value.
|
||||
|
||||
* Meta function members:
|
||||
|
||||
```cpp
|
||||
auto func = entt::resolve<my_type>().func("member"_hs);
|
||||
```
|
||||
|
||||
The returned type is `meta_func` and may be invalid if there is no meta
|
||||
function object associated with the given identifier.<br/>
|
||||
A meta function object offers an API to query the underlying type (for
|
||||
example, to know if it's a const or a static function), to know the number of
|
||||
arguments, the meta return type and the meta types of the parameters. In
|
||||
addition, a meta function object is used to invoke the underlying function and
|
||||
then get the return value in the form of a `meta_any` object.
|
||||
|
||||
All the meta objects thus obtained as well as the meta types explicitly convert
|
||||
to a boolean value to check for validity:
|
||||
|
||||
```cpp
|
||||
if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Furthermore, all them (and a few more, like meta basis) are returned by a bunch
|
||||
of overloads that provide the caller with iterable ranges of top-level elements.
|
||||
As an example:
|
||||
|
||||
```cpp
|
||||
for(auto &&[id, type]: entt::resolve<my_type>().base()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Meta type are also used to `construct` actual instances of the underlying
|
||||
type.<br/>
|
||||
In particular, the `construct` member function accepts a variable number of
|
||||
arguments and searches for a match. It then returns a `meta_any` object that may
|
||||
or may not be initialized, depending on whether a suitable constructor was found
|
||||
or not.
|
||||
|
||||
There is no object that wraps the destructor of a meta type nor a `destroy`
|
||||
member function in its API. Destructors are invoked implicitly by `meta_any`
|
||||
behind the scenes and users have not to deal with them explicitly. Furthermore,
|
||||
they've no name, cannot be searched and wouldn't have member functions to expose
|
||||
anyway.<br/>
|
||||
Similarly, conversion functions aren't directly accessible. They're used
|
||||
internally by `meta_any` and the meta objects when needed.
|
||||
|
||||
Meta types and meta objects in general contain much more than what was said.
|
||||
Refer to the inline documentation for further details.
|
||||
|
||||
## Container support
|
||||
|
||||
The runtime reflection system also supports containers of all types.<br/>
|
||||
Moreover, _containers_ doesn't necessarily mean those offered by the C++
|
||||
standard library. In fact, user defined data structures can also work with the
|
||||
meta system in many cases.
|
||||
|
||||
To make a container be recognized as such by the meta system, users are required
|
||||
to provide specializations for either the `meta_sequence_container_traits` class
|
||||
or the `meta_associative_container_traits` class, according to the actual _type_
|
||||
of the container.<br/>
|
||||
`EnTT` already exports the specializations for some common classes. In
|
||||
particular:
|
||||
|
||||
* `std::vector`, `std::array`, `std::deque` and `std::list` (but not
|
||||
`std::forward_list`) are supported as _sequence containers_.
|
||||
|
||||
* `std::map`, `std::set` and their unordered counterparts are supported as
|
||||
_associative containers_.
|
||||
|
||||
It's important to include the header file `container.hpp` to make these
|
||||
specializations available to the compiler when needed.<br/>
|
||||
The same file also contains many examples for the users that are interested in
|
||||
making their own containers available to the meta system.
|
||||
|
||||
When a specialization of the `meta_sequence_container_traits` class exists, the
|
||||
meta system treats the wrapped type as a sequence container. In a similar way,
|
||||
a type is treated as an associative container if a specialization of the
|
||||
`meta_associative_container_traits` class is found for it.<br/>
|
||||
Proxy objects are returned by dedicated members of the `meta_any` class. The
|
||||
following is a deliberately verbose example of how users can access a proxy
|
||||
object for a sequence container:
|
||||
|
||||
```cpp
|
||||
std::vector<int> vec{1, 2, 3};
|
||||
entt::meta_any any = entt::forward_as_meta(vec);
|
||||
|
||||
if(any.type().is_sequence_container()) {
|
||||
if(auto view = any.as_sequence_container(); view) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The method to use to get a proxy object for associative containers is
|
||||
`as_associative_container` instead.<br/>
|
||||
It's not necessary to perform a double check actually. Instead, it's enough to
|
||||
query the meta type or verify that the proxy object is valid. In fact, proxies
|
||||
are contextually convertible to bool to check for validity. For example, invalid
|
||||
proxies are returned when the wrapped object isn't a container.<br/>
|
||||
In all cases, users aren't expected to _reflect_ containers explicitly. It's
|
||||
sufficient to assign a container for which a specialization of the traits
|
||||
classes exists to a `meta_any` object to be able to get its proxy object.
|
||||
|
||||
The interface of the `meta_sequence_container` proxy object is the same for all
|
||||
types of sequence containers, although the available features differ from case
|
||||
to case. In particular:
|
||||
|
||||
* The `value_type` member function returns the meta type of the elements.
|
||||
|
||||
* The `size` member function returns the number of elements in the container as
|
||||
an unsigned integer value.
|
||||
|
||||
* The `resize` member function allows to resize the wrapped container and
|
||||
returns true in case of success.<br/>
|
||||
For example, it's not possible to resize fixed size containers.
|
||||
|
||||
* The `clear` member function allows to clear the wrapped container and returns
|
||||
true in case of success.<br/>
|
||||
For example, it's not possible to clear fixed size containers.
|
||||
|
||||
* The `begin` and `end` member functions return opaque iterators that is used to
|
||||
iterate the container directly:
|
||||
|
||||
```cpp
|
||||
for(entt::meta_any element: view) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
In all cases, given an underlying container of type `C`, the returned element
|
||||
contains an object of type `C::value_type` which therefore depends on the
|
||||
actual container.<br/>
|
||||
All meta iterators are input iterators and don't offer an indirection operator
|
||||
on purpose.
|
||||
|
||||
* The `insert` member function is used to add elements to the container. It
|
||||
accepts a meta iterator and the element to insert:
|
||||
|
||||
```cpp
|
||||
auto last = view.end();
|
||||
// appends an integer to the container
|
||||
view.insert(last, 42);
|
||||
```
|
||||
|
||||
This function returns a meta iterator pointing to the inserted element and a
|
||||
boolean value to indicate whether the operation was successful or not. A call
|
||||
to `insert` may silently fail in case of fixed size containers or whether the
|
||||
arguments aren't at least convertible to the required types.<br/>
|
||||
Since meta iterators are contextually convertible to bool, users can rely on
|
||||
them to know if the operation failed on the actual container or upstream, for
|
||||
example due to an argument conversion problem.
|
||||
|
||||
* The `erase` member function is used to remove elements from the container. It
|
||||
accepts a meta iterator to the element to remove:
|
||||
|
||||
```cpp
|
||||
auto first = view.begin();
|
||||
// removes the first element from the container
|
||||
view.erase(first);
|
||||
```
|
||||
|
||||
This function returns a meta iterator following the last removed element and a
|
||||
boolean value to indicate whether the operation was successful or not. A call
|
||||
to `erase` may silently fail in case of fixed size containers.
|
||||
|
||||
* The `operator[]` is used to access container elements. It accepts a single
|
||||
argument, the position of the element to return:
|
||||
|
||||
```cpp
|
||||
for(std::size_t pos{}, last = view.size(); pos < last; ++pos) {
|
||||
entt::meta_any value = view[pos];
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
The function returns instances of `meta_any` that directly refer to the actual
|
||||
elements. Modifying the returned object directly modifies the element inside
|
||||
the container.<br/>
|
||||
Depending on the underlying sequence container, this operation may not be as
|
||||
efficient. For example, in the case of an `std::list`, a positional access
|
||||
translates to a linear visit of the list itself (probably not what the user
|
||||
expects).
|
||||
|
||||
Similarly, also the interface of the `meta_associative_container` proxy object
|
||||
is the same for all types of associative containers. However, there are some
|
||||
differences in behavior in the case of key-only containers. In particular:
|
||||
|
||||
* The `key_only` member function returns true if the wrapped container is a
|
||||
key-only one.
|
||||
|
||||
* The `key_type` member function returns the meta type of the keys.
|
||||
|
||||
* The `mapped_type` member function returns an invalid meta type for key-only
|
||||
containers and the meta type of the mapped values for all other types of
|
||||
containers.
|
||||
|
||||
* The `value_type` member function returns the meta type of the elements.<br/>
|
||||
For example, it returns the meta type of `int` for `std::set<int>` while it
|
||||
returns the meta type of `std::pair<const int, char>` for
|
||||
`std::map<int, char>`.
|
||||
|
||||
* The `size` member function returns the number of elements in the container as
|
||||
an unsigned integer value.
|
||||
|
||||
* The `clear` member function allows to clear the wrapped container and returns
|
||||
true in case of success.
|
||||
|
||||
* The `begin` and `end` member functions return opaque iterators that are used
|
||||
to iterate the container directly:
|
||||
|
||||
```cpp
|
||||
for(std::pair<entt::meta_any, entt::meta_any> element: view) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
In all cases, given an underlying container of type `C`, the returned element
|
||||
is a key-value pair where the key has type `C::key_type` and the value has
|
||||
type `C::mapped_type`. Since key-only containers don't have a mapped type,
|
||||
their _value_ is nothing more than an invalid `meta_any` object.<br/>
|
||||
All meta iterators are input iterators and don't offer an indirection operator
|
||||
on purpose.
|
||||
|
||||
While the accessed key is usually constant in the associative containers and
|
||||
is therefore returned by copy, the value (if any) is wrapped by an instance of
|
||||
`meta_any` that directly refers to the actual element. Modifying it directly
|
||||
modifies the element inside the container.
|
||||
|
||||
* The `insert` member function is used to add elements to a container. It gets
|
||||
two arguments, respectively the key and the value to insert:
|
||||
|
||||
```cpp
|
||||
auto last = view.end();
|
||||
// appends an integer to the container
|
||||
view.insert(last.handle(), 42, 'c');
|
||||
```
|
||||
|
||||
This function returns a boolean value to indicate whether the operation was
|
||||
successful or not. A call to `insert` may fail when the arguments aren't at
|
||||
least convertible to the required types.
|
||||
|
||||
* The `erase` member function is used to remove elements from a container. It
|
||||
gets a single argument, the key to remove:
|
||||
|
||||
```cpp
|
||||
view.erase(42);
|
||||
```
|
||||
|
||||
This function returns a boolean value to indicate whether the operation was
|
||||
successful or not. A call to `erase` may fail when the argument isn't at least
|
||||
convertible to the required type.
|
||||
|
||||
* The `operator[]` is used to access elements in a container. It gets a single
|
||||
argument, the key of the element to return:
|
||||
|
||||
```cpp
|
||||
entt::meta_any value = view[42];
|
||||
```
|
||||
|
||||
The function returns instances of `meta_any` that directly refer to the actual
|
||||
elements. Modifying the returned object directly modifies the element inside
|
||||
the container.
|
||||
|
||||
Container support is minimal but likely sufficient to satisfy all needs.
|
||||
|
||||
## Pointer-like types
|
||||
|
||||
As with containers, it's also possible to _tell_ to the meta system which types
|
||||
are _pointers_. This makes it possible to dereference instances of `meta_any`,
|
||||
thus obtaining light _references_ to pointed objects that are also correctly
|
||||
associated with their meta types.<br/>
|
||||
To make the meta system recognize a type as _pointer-like_, users can specialize
|
||||
the `is_meta_pointer_like` class. `EnTT` already exports the specializations for
|
||||
some common classes. In particular:
|
||||
|
||||
* All types of raw pointers.
|
||||
* `std::unique_ptr` and `std::shared_ptr`.
|
||||
|
||||
It's important to include the header file `pointer.hpp` to make these
|
||||
specializations available to the compiler when needed.<br/>
|
||||
The same file also contains many examples for the users that are interested in
|
||||
making their own pointer-like types available to the meta system.
|
||||
|
||||
When a type is recognized as a pointer-like one by the meta system, it's
|
||||
possible to dereference the instances of `meta_any` that contain these objects.
|
||||
The following is a deliberately verbose example to show how to use this feature:
|
||||
|
||||
```cpp
|
||||
int value = 42;
|
||||
// meta type equivalent to that of int *
|
||||
entt::meta_any any{&value};
|
||||
|
||||
if(any.type().is_pointer_like()) {
|
||||
// meta type equivalent to that of int
|
||||
if(entt::meta_any ref = *any; ref) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
It's not necessary to perform a double check. Instead, it's enough to query the
|
||||
meta type or verify that the returned object is valid. For example, invalid
|
||||
instances are returned when the wrapped object isn't a pointer-like type.<br/>
|
||||
Dereferencing a pointer-like object returns an instance of `meta_any` which
|
||||
_refers_ to the pointed object. Modifying it means modifying the pointed object
|
||||
directly (unless the returned element is const).
|
||||
|
||||
In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However,
|
||||
`EnTT` also supports classes that don't offer an `operator*`. In particular:
|
||||
|
||||
* It's possible to exploit a solution based on ADL lookup by offering a function
|
||||
(also a template one) named `dereference_meta_pointer_like`:
|
||||
|
||||
```cpp
|
||||
template<typename Type>
|
||||
Type & dereference_meta_pointer_like(const custom_pointer_type<Type> &ptr) {
|
||||
return ptr.deref();
|
||||
}
|
||||
```
|
||||
|
||||
* When not in control of the type's namespace, it's possible to inject into the
|
||||
`entt` namespace a specialization of the `adl_meta_pointer_like` class
|
||||
template to bypass the adl lookup as a whole:
|
||||
|
||||
```cpp
|
||||
template<typename Type>
|
||||
struct entt::adl_meta_pointer_like<custom_pointer_type<Type>> {
|
||||
static decltype(auto) dereference(const custom_pointer_type<Type> &ptr) {
|
||||
return ptr.deref();
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
In all other cases and when dereferencing a pointer works as expected regardless
|
||||
of the pointed type, no user intervention is required.
|
||||
|
||||
## Template information
|
||||
|
||||
Meta types also provide a minimal set of information about the _nature_ of the
|
||||
original type in case it's a class template.<br/>
|
||||
By default, this works out of the box and requires no user action. However, it's
|
||||
important to include the header file `template.hpp` to make this information
|
||||
available to the compiler when needed.
|
||||
|
||||
Meta template information are easily found:
|
||||
|
||||
```cpp
|
||||
// this method returns true if the type is recognized as a class template specialization
|
||||
if(auto type = entt::resolve<std::shared_ptr<my_type>>(); type.is_template_specialization()) {
|
||||
// meta type of the class template conveniently wrapped by entt::meta_class_template_tag
|
||||
auto class_type = type.template_type();
|
||||
|
||||
// number of template arguments
|
||||
std::size_t arity = type.template_arity();
|
||||
|
||||
// meta type of the i-th argument
|
||||
auto arg_type = type.template_arg(0u);
|
||||
}
|
||||
```
|
||||
|
||||
Typically, when template information for a type are required, what the library
|
||||
provides is sufficient. However, there are some cases where a user may want more
|
||||
details or a different set of information.<br/>
|
||||
Consider the case of a class template that is meant to wrap function types:
|
||||
|
||||
```cpp
|
||||
template<typename>
|
||||
struct function_type;
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
struct function_type<Ret(Args...)> {};
|
||||
```
|
||||
|
||||
In this case, rather than the function type, it might be useful to provide the
|
||||
return type and unpacked arguments as if they were different template parameters
|
||||
for the original class template.<br/>
|
||||
To achieve this, users must enter the library internals and provide their own
|
||||
specialization for the class template `entt::meta_template_traits`, such as:
|
||||
|
||||
```cpp
|
||||
template<typename Ret, typename... Args>
|
||||
struct entt::meta_template_traits<function_type<Ret(Args...)>> {
|
||||
using class_type = meta_class_template_tag<function_type>;
|
||||
using args_type = type_list<Ret, Args...>;
|
||||
};
|
||||
```
|
||||
|
||||
The reflection system doesn't verify the accuracy of the information nor infer a
|
||||
correspondence between real types and meta types.<br/>
|
||||
Therefore, the specialization is used as is and the information it contains is
|
||||
associated with the appropriate type when required.
|
||||
|
||||
## Automatic conversions
|
||||
|
||||
In C++, there are a number of conversions allowed between arithmetic types that
|
||||
make it convenient to work with this kind of data.<br/>
|
||||
If this were to be translated into explicit registrations with the reflection
|
||||
system, it would result in a long series of instructions such as the following:
|
||||
|
||||
```cpp
|
||||
entt::meta<int>()
|
||||
.conv<bool>()
|
||||
.conv<char>()
|
||||
// ...
|
||||
.conv<double>();
|
||||
```
|
||||
|
||||
Repeated for each type eligible to undergo this type of conversions. This is
|
||||
both error-prone and repetitive.<br/>
|
||||
Similarly, the language allows users to silently convert unscoped enums to their
|
||||
underlying types and offers what it takes to do the same for scoped enums. It
|
||||
would result in the following if it were to be done explicitly:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_enum>()
|
||||
.conv<std::underlying_type_t<my_enum>>();
|
||||
```
|
||||
|
||||
Fortunately, all of this can also be avoided. `EnTT` offers implicit support for
|
||||
these types of conversions:
|
||||
|
||||
```cpp
|
||||
entt::meta_any any{42};
|
||||
any.allow_cast<double>();
|
||||
double value = any.cast<double>();
|
||||
```
|
||||
|
||||
With no need for registration, the conversion takes place automatically under
|
||||
the hood. The same goes for a call to `allow_cast` involving a meta type:
|
||||
|
||||
```cpp
|
||||
entt::meta_type type = entt::resolve<int>();
|
||||
entt::meta_any any{my_enum::a_value};
|
||||
any.allow_cast(type);
|
||||
int value = any.cast<int>();
|
||||
```
|
||||
|
||||
This makes working with arithmetic types and scoped or unscoped enums as easy as
|
||||
it is in C++.<br/>
|
||||
It's still possible to set up conversion functions manually and these are always
|
||||
preferred over the automatic ones.
|
||||
|
||||
## Implicitly generated default constructor
|
||||
|
||||
Creating objects of default constructible types through the reflection system
|
||||
while not having to explicitly register the meta type or its default constructor
|
||||
is also possible.<br/>
|
||||
For example, in the case of primitive types like `int` or `char`, but not just
|
||||
them.
|
||||
|
||||
For default constructible types only, default constructors are automatically
|
||||
defined and associated with their meta types, whether they are explicitly or
|
||||
implicitly generated.<br/>
|
||||
Therefore, this is all is needed to construct an integer from its meta type:
|
||||
|
||||
```cpp
|
||||
entt::resolve<int>().construct();
|
||||
```
|
||||
|
||||
Where the meta type is for example the one returned from a meta container,
|
||||
useful for building keys without knowing or having to register the actual types.
|
||||
|
||||
In all cases, when users register default constructors, they are preferred both
|
||||
during searches and when the `construct` member function is invoked.
|
||||
|
||||
## From void to any
|
||||
|
||||
Sometimes all a user has is an opaque pointer to an object of a known meta type.
|
||||
It would be handy in this case to be able to construct a `meta_any` element from
|
||||
it.<br/>
|
||||
For this purpose, the `meta_type` class offers a `from_void` member function
|
||||
designed to convert an opaque pointer into a `meta_any`:
|
||||
|
||||
```cpp
|
||||
entt::meta_any any = entt::resolve(id).from_void(element);
|
||||
```
|
||||
|
||||
Unfortunately, it's not possible to do a check on the actual type. Therefore,
|
||||
this call can be considered as a _static cast_ with all its _problems_.<br/>
|
||||
On the other hand, the ability to construct a `meta_any` from an opaque pointer
|
||||
opens the door to some pretty interesting uses that are worth exploring.
|
||||
|
||||
## Policies: the more, the less
|
||||
|
||||
Policies are a kind of compile-time directives that can be used when registering
|
||||
reflection information.<br/>
|
||||
Their purpose is to require slightly different behavior than the default in some
|
||||
specific cases. For example, when reading a given data member, its value is
|
||||
returned wrapped in a `meta_any` object which, by default, makes a copy of it.
|
||||
For large objects or if the caller wants to access the original instance, this
|
||||
behavior isn't desirable. Policies are there to offer a solution to this and
|
||||
other problems.
|
||||
|
||||
There are a few alternatives available at the moment:
|
||||
|
||||
* The _as-is_ policy, associated with the type `entt::as_is_t`.<br/>
|
||||
This is the default policy. In general, it should never be used explicitly,
|
||||
since it's implicitly selected if no other policy is specified.<br/>
|
||||
In this case, the return values of the functions as well as the properties
|
||||
exposed as data members are always returned by copy in a dedicated wrapper and
|
||||
therefore associated with their original meta types.
|
||||
|
||||
* The _as-void_ policy, associated with the type `entt::as_void_t`.<br/>
|
||||
Its purpose is to discard the return value of a meta object, whatever it is,
|
||||
thus making it appear as if its type were `void`:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
|
||||
```
|
||||
|
||||
If the use with functions is obvious, perhaps less so is use with constructors
|
||||
and data members. In the first case, the returned wrapper is always empty even
|
||||
though the constructor is still invoked. In the second case, the property
|
||||
isn't accessible for reading instead.
|
||||
|
||||
* The _as-ref_ and _as-cref_ policies, associated with the types
|
||||
`entt::as_ref_t` and `entt::as_cref_t`.<br/>
|
||||
They allow to build wrappers that act as references to unmanaged objects.
|
||||
Accessing the object contained in the wrapper for which the _reference_ was
|
||||
requested makes it possible to directly access the instance used to initialize
|
||||
the wrapper itself:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().data<&my_type::data_member, entt::as_ref_t>("member"_hs);
|
||||
```
|
||||
|
||||
These policies work with constructors (for example, when objects are taken
|
||||
from an external container rather than created on demand), data members and
|
||||
functions in general.<br/>
|
||||
If on the one hand `as_cref_t` always forces the return type to be const,
|
||||
`as_ref_t` _adapts_ to the constness of the passed object and to that of the
|
||||
return type if any.
|
||||
|
||||
Some uses are rather trivial, but it's useful to note that there are some less
|
||||
obvious corner cases that can in turn be solved with the use of policies.
|
||||
|
||||
## Named constants and enums
|
||||
|
||||
As mentioned, the `data` member function is used to reflect constants of any
|
||||
type.<br/>
|
||||
This allows users to create meta types for enums that work exactly like any
|
||||
other meta type built from a class. Similarly, arithmetic types are _enriched_
|
||||
with constants of special meaning where required.<br/>
|
||||
All values thus exported appear to users as if they were constant data members
|
||||
of the reflected types. This avoids the need to _export_ what is the difference
|
||||
between enums and classes in C++ directly in the space of the reflected types.
|
||||
|
||||
Exposing constant values or elements from an enum is quite simple:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_enum>()
|
||||
.data<my_enum::a_value>("a_value"_hs)
|
||||
.data<my_enum::another_value>("another_value"_hs);
|
||||
|
||||
entt::meta<int>().data<2048>("max_int"_hs);
|
||||
```
|
||||
|
||||
Accessing them is trivial as well. It's a matter of doing the following, as with
|
||||
any other data member of a meta type:
|
||||
|
||||
```cpp
|
||||
auto value = entt::resolve<my_enum>().data("a_value"_hs).get({}).cast<my_enum>();
|
||||
auto max = entt::resolve<int>().data("max_int"_hs).get({}).cast<int>();
|
||||
```
|
||||
|
||||
All this happens behind the scenes without any allocation because of the small
|
||||
object optimization performed by the `meta_any` class.
|
||||
|
||||
## Properties and meta objects
|
||||
|
||||
Sometimes (for example, when it comes to creating an editor) it might be useful
|
||||
to attach properties to the meta objects created. Fortunately, this is possible
|
||||
for most of them:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().type("reflected_type"_hs).prop("tooltip"_hs, "message");
|
||||
```
|
||||
|
||||
Properties are always in the key/value form. The key is a numeric identifier,
|
||||
mostly similar to the identifier used to register meta objects. There are no
|
||||
restrictions on the type of the value instead, as long as it's movable.<br/>
|
||||
Key only properties are also supported out of the box:
|
||||
|
||||
```cpp
|
||||
entt::meta<my_type>().type("reflected_type"_hs).prop(my_enum::key_only);
|
||||
```
|
||||
|
||||
To attach multiple properties to a meta object, just invoke `prop` more than
|
||||
once.<br/>
|
||||
It's also possible to call `prop` at different times, as long as the factory is
|
||||
reset to the meta object of interest.
|
||||
|
||||
The meta objects for which properties are supported are currently meta types,
|
||||
meta data and meta functions.<br/>
|
||||
These types also offer a couple of member functions named `prop` to iterate all
|
||||
properties at once or to search a specific property by key:
|
||||
|
||||
```cpp
|
||||
// iterate all properties of a meta type
|
||||
for(auto &&[id, prop]: entt::resolve<my_type>().prop()) {
|
||||
// ...
|
||||
}
|
||||
|
||||
// search for a given property by name
|
||||
auto prop = entt::resolve<my_type>().prop("tooltip"_hs);
|
||||
```
|
||||
|
||||
Meta properties are objects having a fairly poor interface, all in all. They
|
||||
only provide the `value` member function to retrieve the contained value in the
|
||||
form of a `meta_any` object.
|
||||
|
||||
## Unregister types
|
||||
|
||||
A type registered with the reflection system can also be _unregistered_. This
|
||||
means unregistering all its data members, member functions, conversion functions
|
||||
and so on. However, base classes aren't unregistered as well, since they don't
|
||||
necessarily depend on it.<br/>
|
||||
Roughly speaking, unregistering a type means disconnecting all associated meta
|
||||
objects from it and making its identifier no longer available:
|
||||
|
||||
```cpp
|
||||
entt::meta_reset<my_type>();
|
||||
```
|
||||
|
||||
It's also possible to reset types by their unique identifiers:
|
||||
|
||||
```cpp
|
||||
entt::meta_reset("my_type"_hs);
|
||||
```
|
||||
|
||||
Finally, there exists a non-template overload of the `meta_reset` function that
|
||||
doesn't accept arguments and resets all meta types at once:
|
||||
|
||||
```cpp
|
||||
entt::meta_reset();
|
||||
```
|
||||
|
||||
A type can be re-registered later with a completely different name and form.
|
||||
|
||||
## Meta context
|
||||
|
||||
All meta types and their parts are created at runtime and stored in a default
|
||||
_context_. This is obtained via a service locator as:
|
||||
|
||||
```cpp
|
||||
auto &&context = entt::locator<entt::meta_context>::value_or();
|
||||
```
|
||||
|
||||
By itself, a context is an opaque object that the user cannot do much with.
|
||||
However, users can replace an existing context with another at any time:
|
||||
|
||||
```cpp
|
||||
entt::meta_context other{};
|
||||
auto &&context = entt::locator<entt::meta_context>::value_or();
|
||||
std::swap(context, other);
|
||||
```
|
||||
|
||||
This is useful for testing purposes or to define multiple context objects with
|
||||
different meta type to use as appropriate.
|
||||
|
||||
If _replacing_ the default context isn't enough, `EnTT` also offers the ability
|
||||
to use multiple and externally managed contexts with the runtime reflection
|
||||
system.<br/>
|
||||
For example, to create new meta types within a context other than the default
|
||||
one, simply pass it as an argument to the `meta` call:
|
||||
|
||||
```cpp
|
||||
entt::meta_ctx context{};
|
||||
auto factory = entt::meta<my_type>(context).type("reflected_type"_hs);
|
||||
```
|
||||
|
||||
By doing so, the new meta type isn't available in the default context but is
|
||||
usable by passing around the new context when needed, such as when creating a
|
||||
new `meta_any` object:
|
||||
|
||||
```cpp
|
||||
entt::meta_any any{context, std::in_place_type<my_type>};
|
||||
```
|
||||
|
||||
Similarly, to search for meta types in a context other than the default one,
|
||||
it's necessary to pass it to the `resolve` function:
|
||||
|
||||
```cpp
|
||||
entt::meta_type type = entt::resolve(context, "reflected_type"_hs)
|
||||
```
|
||||
|
||||
More generally, when using externally managed contexts, it's always required to
|
||||
provide the system with the context to use, at least at the _entry point_.<br/>
|
||||
For example, once the `meta_type` instant is obtained, it's no longer necessary
|
||||
to pass the context around as the meta type takes the information with it and
|
||||
eventually propagates it to all its parts.<br/>
|
||||
On the other hand, it's necessary to instruct the library on where meta types
|
||||
are to be fetched when `meta_any`s and `meta_handle`s are constructed, a factory
|
||||
created or a meta type resolved.
|
||||
357
docs/md/poly.md
Normal file
357
docs/md/poly.md
Normal file
@@ -0,0 +1,357 @@
|
||||
# Crash Course: poly
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Other libraries](#other-libraries)
|
||||
* [Concept and implementation](#concept-and-implementation)
|
||||
* [Deduced interface](#deduced-interface)
|
||||
* [Defined interface](#defined-interface)
|
||||
* [Fulfill a concept](#fulfill-a-concept)
|
||||
* [Inheritance](#inheritance)
|
||||
* [Static polymorphism in the wild](#static-polymorphism-in-the-wild)
|
||||
* [Storage size and alignment requirement](#storage-size-and-alignment-requirement)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
Static polymorphism is a very powerful tool in C++, albeit sometimes cumbersome
|
||||
to obtain.<br/>
|
||||
This module aims to make it simple and easy to use.
|
||||
|
||||
The library allows to define _concepts_ as interfaces to fulfill with concrete
|
||||
classes without having to inherit from a common base.<br/>
|
||||
Among others, this is one of the advantages of static polymorphism in general
|
||||
and of a generic wrapper like that offered by the `poly` class template in
|
||||
particular.<br/>
|
||||
The result is an object to pass around as such and not through a reference or a
|
||||
pointer, as it happens when it comes to working with dynamic polymorphism.
|
||||
|
||||
Since the `poly` class template makes use of `entt::any` internally, it also
|
||||
supports most of its feature. For example, the possibility to create aliases to
|
||||
existing and thus unmanaged objects. This allows users to exploit the static
|
||||
polymorphism while maintaining ownership of objects.<br/>
|
||||
Likewise, the `poly` class template also benefits from the small buffer
|
||||
optimization offered by the `entt::any` class and therefore minimizes the number
|
||||
of allocations, avoiding them altogether where possible.
|
||||
|
||||
## Other libraries
|
||||
|
||||
There are some very interesting libraries regarding static polymorphism.<br/>
|
||||
The ones that I like more are:
|
||||
|
||||
* [`dyno`](https://github.com/ldionne/dyno): runtime polymorphism done right.
|
||||
* [`Poly`](https://github.com/facebook/folly/blob/master/folly/docs/Poly.md):
|
||||
a class template that makes it easy to define a type-erasing polymorphic
|
||||
object wrapper.
|
||||
|
||||
The former is admittedly an experimental library, with many interesting ideas.
|
||||
I've some doubts about the usefulness of some feature in real world projects,
|
||||
but perhaps my lack of experience comes into play here. In my opinion, its only
|
||||
flaw is the API which I find slightly more cumbersome than other solutions.<br/>
|
||||
The latter was undoubtedly a source of inspiration for this module, although I
|
||||
opted for different choices in the implementation of both the final API and some
|
||||
feature.
|
||||
|
||||
Either way, the authors are gurus of the C++ community, people I only have to
|
||||
learn from.
|
||||
|
||||
# Concept and implementation
|
||||
|
||||
The first thing to do to create a _type-erasing polymorphic object wrapper_ (to
|
||||
use the terminology introduced by Eric Niebler) is to define a _concept_ that
|
||||
types will have to adhere to.<br/>
|
||||
For this purpose, the library offers a single class that supports both deduced
|
||||
and fully defined interfaces. Although having interfaces deduced automatically
|
||||
is convenient and allows users to write less code in most cases, it has some
|
||||
limitations and it's therefore useful to be able to get around the deduction by
|
||||
providing a custom definition for the static virtual table.
|
||||
|
||||
Once the interface is defined, a generic implementation is needed to fulfill the
|
||||
concept itself.<br/>
|
||||
Also in this case, the library allows customizations based on types or families
|
||||
of types, so as to be able to go beyond the generic case where necessary.
|
||||
|
||||
## Deduced interface
|
||||
|
||||
This is how a concept with a deduced interface is defined:
|
||||
|
||||
```cpp
|
||||
struct Drawable: entt::type_list<> {
|
||||
template<typename Base>
|
||||
struct type: Base {
|
||||
void draw() { this->template invoke<0>(*this); }
|
||||
};
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
It's recognizable by the fact that it inherits from an empty type list.<br/>
|
||||
Functions can also be const, accept any number of parameters and return a type
|
||||
other than `void`:
|
||||
|
||||
```cpp
|
||||
struct Drawable: entt::type_list<> {
|
||||
template<typename Base>
|
||||
struct type: Base {
|
||||
bool draw(int pt) const { return this->template invoke<0>(*this, pt); }
|
||||
};
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
In this case, all parameters are passed to `invoke` after the reference to
|
||||
`this` and the return value is whatever the internal call returns.<br/>
|
||||
As for `invoke`, this is a name that is injected into the _concept_ through
|
||||
`Base`, from which one must necessarily inherit. Since it's also a dependent
|
||||
name, the `this-> template` form is unfortunately necessary due to the rules of
|
||||
the language. However, there also exists an alternative that goes through an
|
||||
external call:
|
||||
|
||||
```cpp
|
||||
struct Drawable: entt::type_list<> {
|
||||
template<typename Base>
|
||||
struct type: Base {
|
||||
void draw() const { entt::poly_call<0>(*this); }
|
||||
};
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
Once the _concept_ is defined, users must provide a generic implementation of it
|
||||
in order to tell the system how any type can satisfy its requirements. This is
|
||||
done via an alias template within the concept itself.<br/>
|
||||
The index passed as a template parameter to either `invoke` or `poly_call`
|
||||
refers to how this alias is defined.
|
||||
|
||||
## Defined interface
|
||||
|
||||
A fully defined concept is no different to one for which the interface is
|
||||
deduced, with the only difference that the list of types is not empty this time:
|
||||
|
||||
```cpp
|
||||
struct Drawable: entt::type_list<void()> {
|
||||
template<typename Base>
|
||||
struct type: Base {
|
||||
void draw() { entt::poly_call<0>(*this); }
|
||||
};
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
Again, parameters and return values other than `void` are allowed. Also, the
|
||||
function type must be const when the method to bind to it is const:
|
||||
|
||||
```cpp
|
||||
struct Drawable: entt::type_list<bool(int) const> {
|
||||
template<typename Base>
|
||||
struct type: Base {
|
||||
bool draw(int pt) const { return entt::poly_call<0>(*this, pt); }
|
||||
};
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
Why should a user fully define a concept if the function types are the same as
|
||||
the deduced ones?<br>
|
||||
In fact, this is the limitation that can be worked around by manually defining
|
||||
the static virtual table.
|
||||
|
||||
When things are deduced, there is an implicit constraint.<br/>
|
||||
If the concept exposes a member function called `draw` with function type
|
||||
`void()`, a concept is satisfied:
|
||||
|
||||
* Either by a class that exposes a member function with the same name and the
|
||||
same signature.
|
||||
|
||||
* Or through a lambda that makes use of existing member functions from the
|
||||
interface itself.
|
||||
|
||||
In other words, it's not possible to make use of functions not belonging to the
|
||||
interface, even if they're part of the types that fulfill the concept.<br/>
|
||||
Similarly, it's not possible to deduce a function in the static virtual table
|
||||
with a function type different from that of the associated member function in
|
||||
the interface itself.
|
||||
|
||||
Explicitly defining a static virtual table suppresses the deduction step and
|
||||
allows maximum flexibility when providing the implementation for a concept.
|
||||
|
||||
## Fulfill a concept
|
||||
|
||||
The `impl` alias template of a concept is used to define how it's fulfilled:
|
||||
|
||||
```cpp
|
||||
struct Drawable: entt::type_list<> {
|
||||
// ...
|
||||
|
||||
template<typename Type>
|
||||
using impl = entt::value_list<&Type::draw>;
|
||||
};
|
||||
```
|
||||
|
||||
In this case, it's stated that the `draw` method of a generic type is enough to
|
||||
satisfy the requirements of the `Drawable` concept.<br/>
|
||||
Both member functions and free functions are supported to fulfill concepts:
|
||||
|
||||
```cpp
|
||||
template<typename Type>
|
||||
void print(Type &self) { self.print(); }
|
||||
|
||||
struct Drawable: entt::type_list<void()> {
|
||||
// ...
|
||||
|
||||
template<typename Type>
|
||||
using impl = entt::value_list<&print<Type>>;
|
||||
};
|
||||
```
|
||||
|
||||
Likewise, as long as the parameter types and return type support conversions to
|
||||
and from those of the function type referenced in the static virtual table, the
|
||||
actual implementation may differ in its function type since it's erased
|
||||
internally.<br/>
|
||||
Moreover, the `self` parameter isn't strictly required by the system and can be
|
||||
left out for free functions if not required.
|
||||
|
||||
Refer to the inline documentation for more details.
|
||||
|
||||
# Inheritance
|
||||
|
||||
_Concept inheritance_ is straightforward due to how poly looks like in `EnTT`.
|
||||
Therefore, it's quite easy to build hierarchies of concepts if necessary.<br/>
|
||||
The only constraint is that all concepts in a hierarchy must belong to the same
|
||||
_family_, that is, they must be either all deduced or all defined.
|
||||
|
||||
For a deduced concept, inheritance is achieved in a few steps:
|
||||
|
||||
```cpp
|
||||
struct DrawableAndErasable: entt::type_list<> {
|
||||
template<typename Base>
|
||||
struct type: typename Drawable::template type<Base> {
|
||||
static constexpr auto base = std::tuple_size_v<typename entt::poly_vtable<Drawable>::type>;
|
||||
void erase() { entt::poly_call<base + 0>(*this); }
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
using impl = entt::value_list_cat_t<
|
||||
typename Drawable::impl<Type>,
|
||||
entt::value_list<&Type::erase>
|
||||
>;
|
||||
};
|
||||
```
|
||||
|
||||
The static virtual table is empty and must remain so.<br/>
|
||||
On the other hand, `type` no longer inherits from `Base`. Instead, it forwards
|
||||
its template parameter to the type exposed by the _base class_. Internally, the
|
||||
_size_ of the static virtual table of the base class is used as an offset for
|
||||
the local indexes.<br/>
|
||||
Finally, by means of the `value_list_cat_t` utility, the implementation consists
|
||||
in appending the new functions to the previous list.
|
||||
|
||||
As for a defined concept instead, the list of types is _extended_ in a similar
|
||||
way to what is shown for the implementation of the above concept.<br/>
|
||||
To do this, it's useful to declare a function that allows to convert a _concept_
|
||||
into its underlying `type_list` object:
|
||||
|
||||
```cpp
|
||||
template<typename... Type>
|
||||
entt::type_list<Type...> as_type_list(const entt::type_list<Type...> &);
|
||||
```
|
||||
|
||||
The definition isn't strictly required, since the function is only used through
|
||||
a `decltype` as it follows:
|
||||
|
||||
```cpp
|
||||
struct DrawableAndErasable: entt::type_list_cat_t<
|
||||
decltype(as_type_list(std::declval<Drawable>())),
|
||||
entt::type_list<void()>
|
||||
> {
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
Similar to above, `type_list_cat_t` is used to concatenate the underlying static
|
||||
virtual table with the new function types.<br/>
|
||||
Everything else is the same as already shown instead.
|
||||
|
||||
# Static polymorphism in the wild
|
||||
|
||||
Once the _concept_ and implementation are defined, it's possible to use the
|
||||
`poly` class template to _wrap_ instances that meet the requirements:
|
||||
|
||||
```cpp
|
||||
using drawable = entt::poly<Drawable>;
|
||||
|
||||
struct circle {
|
||||
void draw() { /* ... */ }
|
||||
};
|
||||
|
||||
struct square {
|
||||
void draw() { /* ... */ }
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
drawable instance{circle{}};
|
||||
instance->draw();
|
||||
|
||||
instance = square{};
|
||||
instance->draw();
|
||||
```
|
||||
|
||||
This class offers a wide range of constructors, from the default one (which
|
||||
returns an uninitialized `poly` object) to the copy and move constructors, as
|
||||
well as the ability to create objects in-place.<br/>
|
||||
Among others, there is also a constructor that allows users to wrap unmanaged
|
||||
objects in a `poly` instance (either const or non-const ones):
|
||||
|
||||
```cpp
|
||||
circle shape;
|
||||
drawable instance{std::in_place_type<circle &>, shape};
|
||||
```
|
||||
|
||||
Similarly, it's possible to create non-owning copies of `poly` from an existing
|
||||
object:
|
||||
|
||||
```cpp
|
||||
drawable other = instance.as_ref();
|
||||
```
|
||||
|
||||
In both cases, although the interface of the `poly` object doesn't change, it
|
||||
doesn't construct any element or take care of destroying the referenced objects.
|
||||
|
||||
Note also how the underlying concept is accessed via a call to `operator->` and
|
||||
not directly as `instance.draw()`.<br/>
|
||||
This allows users to decouple the API of the wrapper from that of the concept.
|
||||
Therefore, where `instance.data()` invokes the `data` member function of the
|
||||
poly object, `instance->data()` maps directly to the functionality exposed by
|
||||
the underlying concept.
|
||||
|
||||
# Storage size and alignment requirement
|
||||
|
||||
Under the hood, the `poly` class template makes use of `entt::any`. Therefore,
|
||||
it can take advantage of the possibility of defining at compile-time the size of
|
||||
the storage suitable for the small buffer optimization as well as the alignment
|
||||
requirements:
|
||||
|
||||
```cpp
|
||||
entt::basic_poly<Drawable, sizeof(double[4]), alignof(double[4])>
|
||||
```
|
||||
|
||||
The default size is `sizeof(double[2])`, which seems like a good compromise
|
||||
between a buffer that is too large and one unable to hold anything larger than
|
||||
an integer. The alignment requirement is optional and by default such that it's
|
||||
the most stringent (the largest) for any object whose size is at most equal to
|
||||
the one provided.<br/>
|
||||
It's worth noting that providing a size of 0 (which is an accepted value in all
|
||||
respects) will force the system to dynamically allocate the contained objects in
|
||||
all cases.
|
||||
217
docs/md/process.md
Normal file
217
docs/md/process.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# Crash Course: cooperative scheduler
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [The process](#the-process)
|
||||
* [Adaptor](#adaptor)
|
||||
* [The scheduler](#the-scheduler)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
Processes are a useful tool to work around the strict definition of a system and
|
||||
introduce logic in a different way, usually without resorting to other component
|
||||
types.<br/>
|
||||
`EnTT` offers minimal support to this paradigm by introducing a few classes used
|
||||
to define and execute cooperative processes.
|
||||
|
||||
# The process
|
||||
|
||||
A typical task inherits from the `process` class template that stays true to the
|
||||
CRTP idiom. Moreover, derived classes specify what the intended type for elapsed
|
||||
times is.
|
||||
|
||||
A process should expose publicly the following member functions whether needed
|
||||
(note that it isn't required to define a function unless the derived class wants
|
||||
to _override_ the default behavior):
|
||||
|
||||
* `void update(Delta, void *);`
|
||||
|
||||
This is invoked once per tick until a process is explicitly aborted or ends
|
||||
either with or without errors. Even though it's not mandatory to declare this
|
||||
member function, as a rule of thumb each process should at least define it to
|
||||
work _properly_. The `void *` parameter is an opaque pointer to user data (if
|
||||
any) forwarded directly to the process during an update.
|
||||
|
||||
* `void init();`
|
||||
|
||||
This is invoked when the process joins the running queue of a scheduler. It
|
||||
happens usually as soon as the process is attached to the scheduler if it's a
|
||||
top level one, otherwise when it replaces its parent if it's a _continuation_.
|
||||
|
||||
* `void succeeded();`
|
||||
|
||||
This is invoked in case of success, immediately after an update and during the
|
||||
same tick.
|
||||
|
||||
* `void failed();`
|
||||
|
||||
This is invoked in case of errors, immediately after an update and during the
|
||||
same tick.
|
||||
|
||||
* `void aborted();`
|
||||
|
||||
This is invoked only if a process is explicitly aborted. There is no guarantee
|
||||
that it executes in the same tick, it depends solely on whether the process is
|
||||
aborted immediately or not.
|
||||
|
||||
Derived classes can also change the internal state of a process by invoking
|
||||
`succeed` and `fail`, as well as `pause` and `unpause` the process itself.<br/>
|
||||
All these are protected member functions made available to manage the life cycle
|
||||
of a process from a derived class.
|
||||
|
||||
Here is a minimal example for the sake of curiosity:
|
||||
|
||||
```cpp
|
||||
struct my_process: entt::process<my_process, std::uint32_t> {
|
||||
using delta_type = std::uint32_t;
|
||||
|
||||
my_process(delta_type delay)
|
||||
: remaining{delay}
|
||||
{}
|
||||
|
||||
void update(delta_type delta, void *) {
|
||||
remaining -= std::min(remaining, delta);
|
||||
|
||||
// ...
|
||||
|
||||
if(!remaining) {
|
||||
succeed();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
delta_type remaining;
|
||||
};
|
||||
```
|
||||
|
||||
## Adaptor
|
||||
|
||||
Lambdas and functors can't be used directly with a scheduler because they aren't
|
||||
properly defined processes with managed life cycles.<br/>
|
||||
This class helps in filling the gap and turning lambdas and functors into
|
||||
full-featured processes usable by a scheduler.
|
||||
|
||||
The function call operator has a signature similar to the one of the `update`
|
||||
function of a process but for the fact that it receives two extra callbacks to
|
||||
invoke whenever a process terminates with success or with an error:
|
||||
|
||||
```cpp
|
||||
void(Delta delta, void *data, auto succeed, auto fail);
|
||||
```
|
||||
|
||||
Parameters have the following meaning:
|
||||
|
||||
* `delta` is the elapsed time.
|
||||
* `data` is an opaque pointer to user data if any, `nullptr` otherwise.
|
||||
* `succeed` is a function to call when a process terminates with success.
|
||||
* `fail` is a function to call when a process terminates with errors.
|
||||
|
||||
Both `succeed` and `fail` accept no parameters at all.
|
||||
|
||||
Note that usually users shouldn't worry about creating adaptors at all. A
|
||||
scheduler creates them internally each and every time a lambda or a functor is
|
||||
used as a process.
|
||||
|
||||
# The scheduler
|
||||
|
||||
A cooperative scheduler runs different processes and helps managing their life
|
||||
cycles.
|
||||
|
||||
Each process is invoked once per tick. If it terminates, it's removed
|
||||
automatically from the scheduler and it's never invoked again. Otherwise, it's
|
||||
a good candidate to run one more time the next tick.<br/>
|
||||
A process can also have a _child_. In this case, the parent process is replaced
|
||||
with its child when it terminates and only if it returns with success. In case
|
||||
of errors, both the parent process and its child are discarded. This way, it's
|
||||
easy to create chain of processes to run sequentially.
|
||||
|
||||
Using a scheduler is straightforward. To create it, users must provide only the
|
||||
type for the elapsed times and no arguments at all:
|
||||
|
||||
```cpp
|
||||
entt::basic_scheduler<std::uint64_t> scheduler;
|
||||
```
|
||||
|
||||
Otherwise, the `scheduler` alias is also available for the most common cases. It
|
||||
uses `std::uint32_t` as a default type:
|
||||
|
||||
```cpp
|
||||
entt::scheduler scheduler;
|
||||
```
|
||||
|
||||
The class has member functions to query its internal data structures, like
|
||||
`empty` or `size`, as well as a `clear` utility to reset it to a clean state:
|
||||
|
||||
```cpp
|
||||
// checks if there are processes still running
|
||||
const auto empty = scheduler.empty();
|
||||
|
||||
// gets the number of processes still running
|
||||
entt::scheduler::size_type size = scheduler.size();
|
||||
|
||||
// resets the scheduler to its initial state and discards all the processes
|
||||
scheduler.clear();
|
||||
```
|
||||
|
||||
To attach a process to a scheduler there are mainly two ways:
|
||||
|
||||
* If the process inherits from the `process` class template, it's enough to
|
||||
indicate its type and submit all the parameters required to construct it to
|
||||
the `attach` member function:
|
||||
|
||||
```cpp
|
||||
scheduler.attach<my_process>(1000u);
|
||||
```
|
||||
|
||||
* Otherwise, in case of a lambda or a functor, it's enough to provide an
|
||||
instance of the class to the `attach` member function:
|
||||
|
||||
```cpp
|
||||
scheduler.attach([](auto...){ /* ... */ });
|
||||
```
|
||||
|
||||
In both cases, the return value is an opaque object that offers a `then` member
|
||||
function used to create chains of processes to run sequentially.<br/>
|
||||
As a minimal example of use:
|
||||
|
||||
```cpp
|
||||
// schedules a task in the form of a lambda function
|
||||
scheduler.attach([](auto delta, void *, auto succeed, auto fail) {
|
||||
// ...
|
||||
})
|
||||
// appends a child in the form of another lambda function
|
||||
.then([](auto delta, void *, auto succeed, auto fail) {
|
||||
// ...
|
||||
})
|
||||
// appends a child in the form of a process class
|
||||
.then<my_process>(1000u);
|
||||
```
|
||||
|
||||
To update a scheduler and therefore all its processes, the `update` member
|
||||
function is the way to go:
|
||||
|
||||
```cpp
|
||||
// updates all the processes, no user data are provided
|
||||
scheduler.update(delta);
|
||||
|
||||
// updates all the processes and provides them with custom data
|
||||
scheduler.update(delta, &data);
|
||||
```
|
||||
|
||||
In addition to these functions, the scheduler offers an `abort` member function
|
||||
that is used to discard all the running processes at once:
|
||||
|
||||
```cpp
|
||||
// aborts all the processes abruptly ...
|
||||
scheduler.abort(true);
|
||||
|
||||
// ... or gracefully during the next tick
|
||||
scheduler.abort();
|
||||
```
|
||||
91
docs/md/reference.md
Normal file
91
docs/md/reference.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# Similar projects
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Similar projects](#similar-projects)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
There are many projects similar to `EnTT`, both open source and not.<br/>
|
||||
Some even borrowed some ideas from this library and expressed them in different
|
||||
languages.<br/>
|
||||
Others developed different architectures from scratch and therefore offer
|
||||
alternative solutions with their pros and cons.
|
||||
|
||||
If you know of other similar projects out there, feel free to open an issue or a
|
||||
PR and I'll be glad to add them to this page.<br/>
|
||||
I hope the following lists can grow much more in the future.
|
||||
|
||||
# Similar projects
|
||||
|
||||
Below an incomplete list of similar projects that I've come across so far.<br/>
|
||||
If some terms or designs aren't clear, I recommend referring to the
|
||||
[_ECS Back and Forth_](https://skypjack.github.io/tags/#ecs) series for all the
|
||||
details.
|
||||
|
||||
* C:
|
||||
* [destral_ecs](https://github.com/roig/destral_ecs): a single-file ECS based
|
||||
on sparse sets.
|
||||
* [Diana](https://github.com/discoloda/Diana): an ECS that uses sparse sets to
|
||||
keep track of entities in systems.
|
||||
* [Flecs](https://github.com/SanderMertens/flecs): a multithreaded archetype
|
||||
ECS based on semi-contiguous arrays rather than chunks.
|
||||
* [lent](https://github.com/nem0/lent): the Donald Trump of the ECS libraries.
|
||||
|
||||
* C++:
|
||||
* [decs](https://github.com/vblanco20-1/decs): a chunk based archetype ECS.
|
||||
* [ecst](https://github.com/SuperV1234/ecst): a multithreaded compile-time
|
||||
ECS that uses sparse sets to keep track of entities in systems.
|
||||
* [EntityX](https://github.com/alecthomas/entityx): a bitset based ECS that
|
||||
uses a single large matrix of components indexed with entities.
|
||||
* [Gaia-ECS](https://github.com/richardbiely/gaia-ecs): a chunk based
|
||||
archetype ECS.
|
||||
* [Polypropylene](https://github.com/pmbittner/Polypropylene): a hybrid
|
||||
solution between an ECS and dynamic mixins.
|
||||
|
||||
* C#
|
||||
* [Arch](https://github.com/genaray/Arch): a simple, fast and _unity entities_
|
||||
inspired archetype ECS with optional multithreading.
|
||||
* [Entitas](https://github.com/sschmid/Entitas-CSharp): the ECS framework for
|
||||
C# and Unity, where _reactive systems_ were invented.
|
||||
* [LeoECS](https://github.com/Leopotam/ecs): simple lightweight C# Entity
|
||||
Component System framework.
|
||||
* [Svelto.ECS](https://github.com/sebas77/Svelto.ECS): a very interesting
|
||||
platform agnostic and table based ECS framework.
|
||||
|
||||
* Go:
|
||||
* [gecs](https://github.com/tutumagi/gecs): a sparse sets based ECS inspired
|
||||
by `EnTT`.
|
||||
|
||||
* Javascript:
|
||||
* [\@javelin/ecs](https://github.com/3mcd/javelin/tree/master/packages/ecs):
|
||||
an archetype ECS in TypeScript.
|
||||
* [ecsy](https://github.com/MozillaReality/ecsy): I haven't had the time to
|
||||
investigate the underlying design of `ecsy` but it looks cool anyway.
|
||||
|
||||
* Perl:
|
||||
* [Game::Entities](https://gitlab.com/jjatria/perl-game-entities): a simple
|
||||
entity registry for ECS designs inspired by `EnTT`.
|
||||
|
||||
* Raku:
|
||||
* [Game::Entities](https://gitlab.com/jjatria/raku-game-entities): a simple
|
||||
entity registry for ECS designs inspired by `EnTT`.
|
||||
|
||||
* Rust:
|
||||
* [Legion](https://github.com/TomGillen/legion): a chunk based archetype ECS.
|
||||
* [Shipyard](https://github.com/leudz/shipyard): it borrows some ideas from
|
||||
`EnTT` and offers a sparse sets based ECS with grouping functionalities.
|
||||
* [Sparsey](https://github.com/LechintanTudor/sparsey): sparse set based ECS
|
||||
written in Rust.
|
||||
* [Specs](https://github.com/amethyst/specs): a parallel ECS based mainly on
|
||||
hierarchical bitsets that allows different types of storage as needed.
|
||||
|
||||
* Zig
|
||||
* [zig-ecs](https://github.com/prime31/zig-ecs): a _zig-ification_ of `EnTT`.
|
||||
191
docs/md/resource.md
Normal file
191
docs/md/resource.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# Crash Course: resource management
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [The resource, the loader and the cache](#the-resource-the-loader-and-the-cache)
|
||||
* [Resource handle](#resource-handle)
|
||||
* [Loaders](#loader)
|
||||
* [The cache class](#the-cache)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
Resource management is usually one of the most critical parts of a game.
|
||||
Solutions are often tuned to the particular application. There exist several
|
||||
approaches and all of them are perfectly fine as long as they fit the
|
||||
requirements of the piece of software in which they are used.<br/>
|
||||
Examples are loading everything on start, loading on request, predictive
|
||||
loading, and so on.
|
||||
|
||||
`EnTT` doesn't pretend to offer a _one-fits-all_ solution for the different
|
||||
cases.<br/>
|
||||
Instead, the library comes with a minimal, general purpose resource cache that
|
||||
might be useful in many cases.
|
||||
|
||||
# The resource, the loader and the cache
|
||||
|
||||
Resource, loader and cache are the three main actors for the purpose.<br/>
|
||||
The _resource_ is an image, an audio, a video or any other type:
|
||||
|
||||
```cpp
|
||||
struct my_resource { const int value; };
|
||||
```
|
||||
|
||||
The _loader_ is a callable type the aim of which is to load a specific resource:
|
||||
|
||||
```cpp
|
||||
struct my_loader final {
|
||||
using result_type = std::shared_ptr<my_resource>;
|
||||
|
||||
result_type operator()(int value) const {
|
||||
// ...
|
||||
return std::make_shared<my_resource>(value);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Its function operator can accept any arguments and should return a value of the
|
||||
declared result type (`std::shared_ptr<my_resource>` in the example).<br/>
|
||||
A loader can also overload its function call operator to make it possible to
|
||||
construct the same or another resource from different lists of arguments.
|
||||
|
||||
Finally, a cache is a specialization of a class template tailored to a specific
|
||||
resource and (optionally) a loader:
|
||||
|
||||
```cpp
|
||||
using my_cache = entt::resource_cache<my_resource, my_loader>;
|
||||
|
||||
// ...
|
||||
|
||||
my_cache cache{};
|
||||
```
|
||||
|
||||
The class is designed to create different caches for different resource types
|
||||
and to manage each one independently in the most appropriate way.<br/>
|
||||
As a (very) trivial example, audio tracks can survive in most of the scenes of
|
||||
an application while meshes can be associated with a single scene only, then
|
||||
discarded when a player leaves it.
|
||||
|
||||
## Resource handle
|
||||
|
||||
Resources aren't returned directly to the caller. Instead, they are wrapped in a
|
||||
_resource handle_, an instance of the `entt::resource` class template.<br/>
|
||||
For those who know the _flyweight design pattern_ already, that's exactly what
|
||||
it is. To all others, this is the time to brush up on some notions instead.
|
||||
|
||||
A shared pointer could have been used as a resource handle. In fact, the default
|
||||
implementation mostly maps the interface of its standard counterpart and only
|
||||
adds a few things on top of it.<br/>
|
||||
However, the handle in `EnTT` is designed as a standalone class template. This
|
||||
is due to the fact that specializing a class in the standard library is often
|
||||
undefined behavior while having the ability to specialize the handle for one,
|
||||
more or all resource types could help over time.
|
||||
|
||||
## Loaders
|
||||
|
||||
A loader is responsible for _loading_ resources (quite obviously).<br/>
|
||||
By default, it's just a callable object that forwards its arguments to the
|
||||
resource itself. That is, a _passthrough type_. All the work is demanded to the
|
||||
constructor(s) of the resource itself.<br/>
|
||||
Loaders also are fully customizable as expected.
|
||||
|
||||
A custom loader is a class with at least one function call operator and a member
|
||||
type named `result_type`.<br/>
|
||||
The loader isn't required to return a resource handle. As long as `return_type`
|
||||
is suitable for constructing a handle, that's fine.
|
||||
|
||||
When using the default handle, it expects a resource type which is convertible
|
||||
to or suitable for constructing an `std::shared_ptr<Type>` (where `Type` is the
|
||||
actual resource type).<br/>
|
||||
In other terms, the loader should return shared pointers to the given resource
|
||||
type. However, this isn't mandatory. Users can easily get around this constraint
|
||||
by specializing both the handle and the loader.
|
||||
|
||||
A cache forwards all its arguments to the loader if required. This means that
|
||||
loaders can also support tag dispatching to offer different loading policies:
|
||||
|
||||
```cpp
|
||||
struct my_loader {
|
||||
using result_type = std::shared_ptr<my_resource>;
|
||||
|
||||
struct from_disk_tag{};
|
||||
struct from_network_tag{};
|
||||
|
||||
template<typename Args>
|
||||
result_type operator()(from_disk_tag, Args&&... args) {
|
||||
// ...
|
||||
return std::make_shared<my_resource>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Args>
|
||||
result_type operator()(from_network_tag, Args&&... args) {
|
||||
// ...
|
||||
return std::make_shared<my_resource>(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This makes the whole loading logic quite flexible and easy to extend over time.
|
||||
|
||||
## The cache class
|
||||
|
||||
The cache is the class that is asked to _connect the dots_.<br/>
|
||||
It loads the resources, stores them aside and returns handles as needed:
|
||||
|
||||
```cpp
|
||||
entt::resource_cache<my_resource, my_loader> cache{};
|
||||
```
|
||||
|
||||
Under the hood, a cache is nothing more than a map where the key value has type
|
||||
`entt::id_type` while the mapped value is whatever type its loader returns.<br/>
|
||||
For this reason, it offers most of the functionalities a user would expect from
|
||||
a map, such as `empty` or `size` and so on. Similarly, it's an iterable type
|
||||
that also supports indexing by resource id:
|
||||
|
||||
```cpp
|
||||
for(auto [id, res]: cache) {
|
||||
// ...
|
||||
}
|
||||
|
||||
if(entt::resource<my_resource> res = cache["resource/id"_hs]; res) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Please, refer to the inline documentation for all the details about the other
|
||||
functions (such as `contains` or `erase`).
|
||||
|
||||
Set aside the part of the API that this class _shares_ with a map, it also adds
|
||||
something on top of it in order to address the most common requirements of a
|
||||
resource cache.<br/>
|
||||
In particular, it doesn't have an `emplace` member function which is replaced by
|
||||
`load` and `force_load` instead (where the former loads a new resource only if
|
||||
not present while the second triggers a forced loading in any case):
|
||||
|
||||
```cpp
|
||||
auto ret = cache.load("resource/id"_hs);
|
||||
|
||||
// true only if the resource was not already present
|
||||
const bool loaded = ret.second;
|
||||
|
||||
// takes the resource handle pointed to by the returned iterator
|
||||
entt::resource<my_resource> res = ret.first->second;
|
||||
```
|
||||
|
||||
Note that the hashed string is used for convenience in the example above.<br/>
|
||||
Resource identifiers are nothing more than integral values. Therefore, plain
|
||||
numbers as well as non-class enum value are accepted.
|
||||
|
||||
It's worth mentioning that the iterators of a cache as well as its indexing
|
||||
operators return resource handles rather than instances of the mapped type.<br/>
|
||||
Since the cache has no control over the loader and a resource isn't required to
|
||||
also be convertible to bool, these handles can be invalid. This usually means an
|
||||
error in the user logic but it may also be an _expected_ event.<br/>
|
||||
It's therefore recommended to verify handles validity with a check in debug (for
|
||||
example, when loading) or an appropriate logic in retail.
|
||||
565
docs/md/signal.md
Normal file
565
docs/md/signal.md
Normal file
@@ -0,0 +1,565 @@
|
||||
# Crash Course: events, signals and everything in between
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Introduction](#introduction)
|
||||
* [Delegate](#delegate)
|
||||
* [Runtime arguments](#runtime-arguments)
|
||||
* [Lambda support](#lambda-support)
|
||||
* [Raw access](#raw-access)
|
||||
* [Signals](#signals)
|
||||
* [Event dispatcher](#event-dispatcher)
|
||||
* [Named queues](#named-queues)
|
||||
* [Event emitter](#event-emitter)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
# Introduction
|
||||
|
||||
Signals are more often than not a core part of games and software architectures
|
||||
in general.<br/>
|
||||
They help to decouple the various parts of a system while allowing them to
|
||||
communicate with each other somehow.
|
||||
|
||||
The so called _modern C++_ comes with a tool that can be useful in this regard,
|
||||
the `std::function`. As an example, it can be used to create delegates.<br/>
|
||||
However, there is no guarantee that an `std::function` doesn't perform
|
||||
allocations under the hood and this could be problematic sometimes. Furthermore,
|
||||
it solves a problem but may not adapt well to other requirements that may arise
|
||||
from time to time.
|
||||
|
||||
In case that the flexibility and power of an `std::function` isn't required or
|
||||
if the price to pay for them is too high, `EnTT` offers a complete set of
|
||||
lightweight classes to solve the same and many other problems.
|
||||
|
||||
# Delegate
|
||||
|
||||
A delegate can be used as a general purpose invoker with no memory overhead for
|
||||
free functions, lambdas and members provided along with an instance on which to
|
||||
invoke them.<br/>
|
||||
It doesn't claim to be a drop-in replacement for an `std::function`, so don't
|
||||
expect to use it whenever an `std::function` fits well. That said, it's most
|
||||
likely even a better fit than an `std::function` in a lot of cases, so expect to
|
||||
use it quite a lot anyway.
|
||||
|
||||
The interface is trivial. It offers a default constructor to create empty
|
||||
delegates:
|
||||
|
||||
```cpp
|
||||
entt::delegate<int(int)> delegate{};
|
||||
```
|
||||
|
||||
What is needed to create an instance is to specify the type of the function the
|
||||
delegate _accepts_, that is the signature of the functions it models.<br/>
|
||||
However, attempting to use an empty delegate by invoking its function call
|
||||
operator results in undefined behavior or most likely a crash.
|
||||
|
||||
There exist a few overloads of the `connect` member function to initialize a
|
||||
delegate:
|
||||
|
||||
```cpp
|
||||
int f(int i) { return i; }
|
||||
|
||||
struct my_struct {
|
||||
int f(const int &i) const { return i; }
|
||||
};
|
||||
|
||||
// bind a free function to the delegate
|
||||
delegate.connect<&f>();
|
||||
|
||||
// bind a member function to the delegate
|
||||
my_struct instance;
|
||||
delegate.connect<&my_struct::f>(instance);
|
||||
```
|
||||
|
||||
The delegate class also accepts data members, if needed. In this case, the
|
||||
function type of the delegate is such that the parameter list is empty and the
|
||||
value of the data member is at least convertible to the return type.
|
||||
|
||||
Free functions having type equivalent to `void(T &, args...)` are accepted as
|
||||
well. The first argument `T &` is considered a payload and the function will
|
||||
receive it back every time it's invoked. In other terms, this works just fine
|
||||
with the above definition:
|
||||
|
||||
```cpp
|
||||
void g(const char &c, int i) { /* ... */ }
|
||||
const char c = 'c';
|
||||
|
||||
delegate.connect<&g>(c);
|
||||
delegate(42);
|
||||
```
|
||||
|
||||
Function `g` is invoked with a reference to `c` and `42`. However, the function
|
||||
type of the delegate is still `void(int)`. This is also the signature of its
|
||||
function call operator.<br/>
|
||||
Another interesting aspect of the delegate class is that it accepts functions
|
||||
with a list of parameters that is shorter than that of its function type:
|
||||
|
||||
```cpp
|
||||
void g() { /* ... */ }
|
||||
delegate.connect<&g>();
|
||||
delegate(42);
|
||||
```
|
||||
|
||||
Where the function type of the delegate is `void(int)` as above. It goes without
|
||||
saying that the extra arguments are silently discarded internally. This is a
|
||||
nice-to-have feature in a lot of cases, as an example when the `delegate` class
|
||||
is used as a building block of a signal-slot system.<br/>
|
||||
In fact, this filtering works both ways. The class tries to pass its first
|
||||
_count_ arguments **first**, then the last _count_. Watch out for conversion
|
||||
rules if in doubt when connecting a listener!<br/>
|
||||
Arbitrary functions that pull random arguments from the delegate list aren't
|
||||
supported instead. Other feature were preferred, such as support for functions
|
||||
with compatible argument lists although not equal to those of the delegate.
|
||||
|
||||
To create and initialize a delegate at once, there are a few specialized
|
||||
constructors. Because of the rules of the language, the listener is provided by
|
||||
means of the `entt::connect_arg` variable template:
|
||||
|
||||
```cpp
|
||||
entt::delegate<int(int)> func{entt::connect_arg<&f>};
|
||||
```
|
||||
|
||||
Aside `connect`, a `disconnect` counterpart isn't provided. Instead, there
|
||||
exists a `reset` member function to use to clear a delegate.<br/>
|
||||
To know if a delegate is empty, it can be used explicitly in every conditional
|
||||
statement:
|
||||
|
||||
```cpp
|
||||
if(delegate) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Finally, to invoke a delegate, the function call operator is the way to go as
|
||||
already shown in the examples above:
|
||||
|
||||
```cpp
|
||||
auto ret = delegate(42);
|
||||
```
|
||||
|
||||
In all cases, listeners don't have to strictly follow the signature of the
|
||||
delegate. As long as a listener can be invoked with the given arguments to yield
|
||||
a result that is convertible to the given result type, everything works just
|
||||
fine.
|
||||
|
||||
As a side note, members of classes may or may not be associated with instances.
|
||||
If they are not, the first argument of the function type must be that of the
|
||||
class on which the members operate and an instance of this class must obviously
|
||||
be passed when invoking the delegate:
|
||||
|
||||
```cpp
|
||||
entt::delegate<void(my_struct &, int)> delegate;
|
||||
delegate.connect<&my_struct::f>();
|
||||
|
||||
my_struct instance;
|
||||
delegate(instance, 42);
|
||||
```
|
||||
|
||||
In this case, it's not possible to _deduce_ the function type since the first
|
||||
argument doesn't necessarily have to be a reference (for example, it can be a
|
||||
pointer, as well as a const reference).<br/>
|
||||
Therefore, the function type must be declared explicitly for unbound members.
|
||||
|
||||
## Runtime arguments
|
||||
|
||||
The `delegate` class is meant to be used primarily with template arguments.
|
||||
However, as a consequence of its design, it also offers minimal support for
|
||||
runtime arguments.<br/>
|
||||
When used like this, some features aren't supported though. In particular:
|
||||
|
||||
* Curried functions aren't accepted.
|
||||
* Functions with an argument list that differs from that of the delegate aren't
|
||||
supported.
|
||||
* Return type and types of arguments **must** coincide with those of the
|
||||
delegate and _being at least convertible_ isn't enough anymore.
|
||||
|
||||
Moreover, for a given function type `Ret(Args...)`, the signature of the
|
||||
functions connected at runtime must necessarily be `Ret(const void *, Args...)`.
|
||||
|
||||
Runtime arguments can be passed both to the constructor of a delegate and to the
|
||||
`connect` member function. An optional parameter is also accepted in both cases.
|
||||
This argument is used to pass arbitrary user data back and forth as a
|
||||
`const void *` upon invocation.<br/>
|
||||
To connect a function to a delegate _in the hard way_:
|
||||
|
||||
```cpp
|
||||
int func(const void *ptr, int i) { return *static_cast<const int *>(ptr) * i; }
|
||||
const int value = 42;
|
||||
|
||||
// use the constructor ...
|
||||
entt::delegate delegate{&func, &value};
|
||||
|
||||
// ... or the connect member function
|
||||
delegate.connect(&func, &value);
|
||||
```
|
||||
|
||||
The type of the delegate is deduced from the function if possible. In this case,
|
||||
since the first argument is an implementation detail, the deduced function type
|
||||
is `int(int)`.<br/>
|
||||
Invoking a delegate built in this way follows the same rules as previously
|
||||
explained.
|
||||
|
||||
## Lambda support
|
||||
|
||||
In general, the `delegate` class doesn't fully support lambda functions in all
|
||||
their nuances. The reason is pretty simple: a `delegate` isn't a drop-in
|
||||
replacement for an `std::function`. Instead, it tries to overcome the problems
|
||||
with the latter.<br/>
|
||||
That being said, non-capturing lambda functions are supported, even though some
|
||||
features aren't available in this case.
|
||||
|
||||
This is a logical consequence of the support for connecting functions at
|
||||
runtime. Therefore, lambda functions undergo the same rules and
|
||||
limitations.<br/>
|
||||
In fact, since non-capturing lambda functions decay to pointers to functions,
|
||||
they can be used with a `delegate` as if they were _normal functions_ with
|
||||
optional payload:
|
||||
|
||||
```cpp
|
||||
my_struct instance;
|
||||
|
||||
// use the constructor ...
|
||||
entt::delegate delegate{+[](const void *ptr, int value) {
|
||||
return static_cast<const my_struct *>(ptr)->f(value);
|
||||
}, &instance};
|
||||
|
||||
// ... or the connect member function
|
||||
delegate.connect([](const void *ptr, int value) {
|
||||
return static_cast<const my_struct *>(ptr)->f(value);
|
||||
}, &instance);
|
||||
```
|
||||
|
||||
As above, the first parameter (`const void *`) isn't part of the function type
|
||||
of the delegate and is used to dispatch arbitrary user data back and forth. In
|
||||
other terms, the function type of the delegate above is `int(int)`.
|
||||
|
||||
## Raw access
|
||||
|
||||
While not recommended, a delegate also allows direct access to the stored
|
||||
callable function target and underlying data, if any.<br/>
|
||||
This makes it possible to bypass the behavior of the delegate itself and force
|
||||
calls on different instances:
|
||||
|
||||
```cpp
|
||||
my_struct other;
|
||||
delegate.target(&other, 42);
|
||||
```
|
||||
|
||||
It goes without saying that this type of approach is **very** risky, especially
|
||||
since there is no way of knowing whether the contained function was originally a
|
||||
member function of some class, a free function or a lambda.<br/>
|
||||
Another possible (and meaningful) use of this feature is that of identifying a
|
||||
particular delegate through its descriptive _traits_ instead.
|
||||
|
||||
# Signals
|
||||
|
||||
Signal handlers work with references to classes, function pointers and pointers
|
||||
to members. Listeners can be any kind of objects and users are in charge of
|
||||
connecting and disconnecting them from a signal to avoid crashes due to
|
||||
different lifetimes. On the other side, performance shouldn't be affected that
|
||||
much by the presence of such a signal handler.<br/>
|
||||
Signals make use of delegates internally and therefore they undergo the same
|
||||
rules and offer similar functionalities. It may be a good idea to consult the
|
||||
documentation of the `delegate` class for further information.
|
||||
|
||||
A signal handler is can be used as a private data member without exposing any
|
||||
_publish_ functionality to the clients of a class.<br/>
|
||||
The basic idea is to impose a clear separation between the signal itself and the
|
||||
`sink` class, that is a tool to be used to connect and disconnect listeners on
|
||||
the fly.
|
||||
|
||||
The API of a signal handler is straightforward. If a collector is supplied to
|
||||
the signal when something is published, all the values returned by its listeners
|
||||
are literally _collected_ and used later by the caller. Otherwise, the class
|
||||
works just like a plain signal that emits events from time to time.<br/>
|
||||
To create instances of signal handlers it's sufficient to provide the type of
|
||||
function to which they refer:
|
||||
|
||||
```cpp
|
||||
entt::sigh<void(int, char)> signal;
|
||||
```
|
||||
|
||||
Signals offer all the basic functionalities required to know how many listeners
|
||||
they contain (`size`) or if they contain at least a listener (`empty`), as well
|
||||
as a function to use to swap handlers (`swap`).
|
||||
|
||||
Besides them, there are member functions to use both to connect and disconnect
|
||||
listeners in all their forms by means of a sink:
|
||||
|
||||
```cpp
|
||||
void foo(int, char) { /* ... */ }
|
||||
|
||||
struct listener {
|
||||
void bar(const int &, char) { /* ... */ }
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
entt::sink sink{signal};
|
||||
listener instance;
|
||||
|
||||
sink.connect<&foo>();
|
||||
sink.connect<&listener::bar>(instance);
|
||||
|
||||
// ...
|
||||
|
||||
// disconnects a free function
|
||||
sink.disconnect<&foo>();
|
||||
|
||||
// disconnect a member function of an instance
|
||||
sink.disconnect<&listener::bar>(instance);
|
||||
|
||||
// disconnect all member functions of an instance, if any
|
||||
sink.disconnect(&instance);
|
||||
|
||||
// discards all listeners at once
|
||||
sink.disconnect();
|
||||
```
|
||||
|
||||
As shown above, listeners don't have to strictly follow the signature of the
|
||||
signal. As long as a listener can be invoked with the given arguments to yield a
|
||||
result that is convertible to the given return type, everything works just
|
||||
fine.<br/>
|
||||
In all cases, the `connect` member function returns by default a `connection`
|
||||
object to be used as an alternative to break a connection by means of its
|
||||
`release` member function.<br/>
|
||||
A `scoped_connection` can also be created from a connection. In this case, the
|
||||
link is broken automatically as soon as the object goes out of scope.
|
||||
|
||||
Once listeners are attached (or even if there are no listeners at all), events
|
||||
and data in general are published through a signal by means of the `publish`
|
||||
member function:
|
||||
|
||||
```cpp
|
||||
signal.publish(42, 'c');
|
||||
```
|
||||
|
||||
To collect data, the `collect` member function is used instead:
|
||||
|
||||
```cpp
|
||||
int f() { return 0; }
|
||||
int g() { return 1; }
|
||||
|
||||
// ...
|
||||
|
||||
entt::sigh<int()> signal;
|
||||
entt::sink sink{signal};
|
||||
|
||||
sink.connect<&f>();
|
||||
sink.connect<&g>();
|
||||
|
||||
std::vector<int> vec{};
|
||||
signal.collect([&vec](int value) { vec.push_back(value); });
|
||||
|
||||
assert(vec[0] == 0);
|
||||
assert(vec[1] == 1);
|
||||
```
|
||||
|
||||
A collector must expose a function operator that accepts as an argument a type
|
||||
to which the return type of the listeners can be converted. Moreover, it can
|
||||
optionally return a boolean value that is true to stop collecting data, false
|
||||
otherwise. This way one can avoid calling all the listeners in case it isn't
|
||||
necessary.<br/>
|
||||
Functors can also be used in place of a lambda. Since the collector is copied
|
||||
when invoking the `collect` member function, `std::ref` is the way to go in this
|
||||
case:
|
||||
|
||||
```cpp
|
||||
struct my_collector {
|
||||
std::vector<int> vec{};
|
||||
|
||||
bool operator()(int v) {
|
||||
vec.push_back(v);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
my_collector collector;
|
||||
signal.collect(std::ref(collector));
|
||||
```
|
||||
|
||||
# Event dispatcher
|
||||
|
||||
The event dispatcher class allows users to trigger immediate events or to queue
|
||||
and publish them all together later.<br/>
|
||||
This class lazily instantiates its queues. Therefore, it's not necessary to
|
||||
_announce_ the event types in advance:
|
||||
|
||||
```cpp
|
||||
// define a general purpose dispatcher
|
||||
entt::dispatcher dispatcher{};
|
||||
```
|
||||
|
||||
A listener registered with a dispatcher is such that its type offers one or more
|
||||
member functions that take arguments of type `Event &` for any type of event,
|
||||
regardless of the return value.<br/>
|
||||
These functions are linked directly via `connect` to a _sink_:
|
||||
|
||||
```cpp
|
||||
struct an_event { int value; };
|
||||
struct another_event {};
|
||||
|
||||
struct listener {
|
||||
void receive(const an_event &) { /* ... */ }
|
||||
void method(const another_event &) { /* ... */ }
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
listener listener;
|
||||
dispatcher.sink<an_event>().connect<&listener::receive>(listener);
|
||||
dispatcher.sink<another_event>().connect<&listener::method>(listener);
|
||||
```
|
||||
|
||||
Note that connecting listeners within event handlers can result in undefined
|
||||
behavior.<br/>
|
||||
The `disconnect` member function is used to remove one listener at a time or all
|
||||
of them at once:
|
||||
|
||||
```cpp
|
||||
dispatcher.sink<an_event>().disconnect<&listener::receive>(listener);
|
||||
dispatcher.sink<another_event>().disconnect(&listener);
|
||||
```
|
||||
|
||||
The `trigger` member function serves the purpose of sending an immediate event
|
||||
to all the listeners registered so far:
|
||||
|
||||
```cpp
|
||||
dispatcher.trigger(an_event{42});
|
||||
dispatcher.trigger<another_event>();
|
||||
```
|
||||
|
||||
Listeners are invoked immediately, order of execution isn't guaranteed. This
|
||||
method can be used to push around urgent messages like an _is terminating_
|
||||
notification on a mobile app.
|
||||
|
||||
On the other hand, the `enqueue` member function queues messages together and
|
||||
helps to maintain control over the moment they are sent to listeners:
|
||||
|
||||
```cpp
|
||||
dispatcher.enqueue<an_event>(42);
|
||||
dispatcher.enqueue(another_event{});
|
||||
```
|
||||
|
||||
Events are stored aside until the `update` member function is invoked:
|
||||
|
||||
```cpp
|
||||
// emits all the events of the given type at once
|
||||
dispatcher.update<an_event>();
|
||||
|
||||
// emits all the events queued so far at once
|
||||
dispatcher.update();
|
||||
```
|
||||
|
||||
This way users can embed the dispatcher in a loop and literally dispatch events
|
||||
once per tick to their systems.
|
||||
|
||||
## Named queues
|
||||
|
||||
All queues within a dispatcher are associated by default with an event type and
|
||||
then retrieved from it.<br/>
|
||||
However, it's possible to create queues with different _names_ (and therefore
|
||||
also multiple queues for a single type). In fact, more or less all functions
|
||||
also take an additional parameter. As an example:
|
||||
|
||||
```cpp
|
||||
dispatcher.sink<an_event>("custom"_hs).connect<&listener::receive>(listener);
|
||||
```
|
||||
|
||||
In this case, the term _name_ is misused as these are actual numeric identifiers
|
||||
of type `id_type`.<br/>
|
||||
An exception to this rule is the `enqueue` function. There is no additional
|
||||
parameter for it but rather a different function:
|
||||
|
||||
```cpp
|
||||
dispatcher.enqueue_hint<an_event>("custom"_hs, 42);
|
||||
```
|
||||
|
||||
This is mainly due to the template argument deduction rules and unfortunately
|
||||
there is no real (elegant) way to avoid it.
|
||||
|
||||
# Event emitter
|
||||
|
||||
A general purpose event emitter thought mainly for those cases where it comes to
|
||||
working with asynchronous stuff.<br/>
|
||||
Originally designed to fit the requirements of
|
||||
[`uvw`](https://github.com/skypjack/uvw) (a wrapper for `libuv` written in
|
||||
modern C++), it was adapted later to be included in this library.
|
||||
|
||||
To create an emitter type, derived classes must inherit from the base as:
|
||||
|
||||
```cpp
|
||||
struct my_emitter: emitter<my_emitter> {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Handlers for the different events are created internally on the fly. It's not
|
||||
required to specify in advance the full list of accepted events.<br/>
|
||||
Moreover, whenever an event is published, an emitter also passes a reference
|
||||
to itself to its listeners.
|
||||
|
||||
To create new instances of an emitter, no arguments are required:
|
||||
|
||||
```cpp
|
||||
my_emitter emitter{};
|
||||
```
|
||||
|
||||
Listeners are movable and callable objects (free functions, lambdas, functors,
|
||||
`std::function`s, whatever) whose function type is compatible with:
|
||||
|
||||
```cpp
|
||||
void(Type &, my_emitter &)
|
||||
```
|
||||
|
||||
Where `Type` is the type of event they want to receive.<br/>
|
||||
To attach a listener to an emitter, there exists the `on` member function:
|
||||
|
||||
```cpp
|
||||
emitter.on<my_event>([](const my_event &event, my_emitter &emitter) {
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
Similarly, the `reset` member function is used to disconnect listeners given a
|
||||
type while `clear` is used to disconnect all listeners at once:
|
||||
|
||||
```cpp
|
||||
// resets the listener for my_event
|
||||
emitter.erase<my_event>();
|
||||
|
||||
// resets all listeners
|
||||
emitter.clear()
|
||||
```
|
||||
|
||||
To send an event to the listener registered on a given type, the `publish`
|
||||
function is the way to go:
|
||||
|
||||
```cpp
|
||||
struct my_event { int i; };
|
||||
|
||||
// ...
|
||||
|
||||
emitter.publish(my_event{42});
|
||||
```
|
||||
|
||||
Finally, the `empty` member function tests if there exists at least a listener
|
||||
registered with the event emitter while `contains` is used to check if a given
|
||||
event type is associated with a valid listener:
|
||||
|
||||
```cpp
|
||||
if(emitter.contains<my_event>()) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
This class introduces a _nice-to-have_ model based on events and listeners.<br/>
|
||||
More in general, it's a handy tool when the derived classes _wrap_ asynchronous
|
||||
operations but it's not limited to such uses.
|
||||
107
docs/md/unreal.md
Normal file
107
docs/md/unreal.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# EnTT and Unreal Engine
|
||||
|
||||
<!--
|
||||
@cond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
# Table of Contents
|
||||
|
||||
* [Enable Cpp17](#enable-cpp17)
|
||||
* [EnTT as a third party module](#entt-as-a-third-party-module)
|
||||
* [Include EnTT](#include-entt)
|
||||
<!--
|
||||
@endcond TURN_OFF_DOXYGEN
|
||||
-->
|
||||
|
||||
## Enable Cpp17
|
||||
|
||||
As of writing (Unreal Engine v4.25), the default C++ standard of Unreal Engine
|
||||
is C++14.<br/>
|
||||
On the other hand, note that `EnTT` requires C++17 to compile. To enable it, in
|
||||
the main module of the project there should be a `<Game Name>.Build.cs` file,
|
||||
the constructor of which must contain the following lines:
|
||||
|
||||
```cs
|
||||
PCHUsage = PCHUsageMode.NoSharedPCHs;
|
||||
PrivatePCHHeaderFile = "<PCH filename>.h";
|
||||
CppStandard = CppStandardVersion.Cpp17;
|
||||
```
|
||||
|
||||
Replace `<PCH filename>.h` with the name of the already existing PCH header
|
||||
file, if any.<br/>
|
||||
In case the project doesn't already contain a file of this type, it's possible
|
||||
to create one with the following content:
|
||||
|
||||
```cpp
|
||||
#pragma once
|
||||
#include "CoreMinimal.h"
|
||||
```
|
||||
|
||||
Remember to remove any old `PCHUsage = <...>` line that was previously there. At
|
||||
this point, C++17 support should be in place.<br/>
|
||||
Try to compile the project to ensure it works as expected before following
|
||||
further steps.
|
||||
|
||||
Note that updating a *project* to C++17 doesn't necessarily mean that the IDE in
|
||||
use will also start to recognize its syntax.<br/>
|
||||
If the plan is to use C++17 in the project too, check the specific instructions
|
||||
for the IDE in use.
|
||||
|
||||
## EnTT as a third party module
|
||||
|
||||
Once this point is reached, the `Source` directory should look like this:
|
||||
|
||||
```
|
||||
Source
|
||||
| MyGame.Target.cs
|
||||
| MyGameEditor.Target.cs
|
||||
|
|
||||
+---MyGame
|
||||
| | MyGame.Build.cs
|
||||
| | MyGame.h (PCH Header file)
|
||||
|
|
||||
\---ThirdParty
|
||||
\---EnTT
|
||||
| EnTT.Build.cs
|
||||
|
|
||||
\---entt (GitHub repository content inside)
|
||||
```
|
||||
|
||||
To make this happen, create the folder `ThirdParty` under `Source` if it doesn't
|
||||
exist already. Then, add an `EnTT` folder under `ThirdParty`.<br/>
|
||||
Within the latter, create a new file `EnTT.Build.cs` with the following content:
|
||||
|
||||
```cs
|
||||
using System.IO;
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class EnTT: ModuleRules {
|
||||
public EnTT(ReadOnlyTargetRules Target) : base(Target) {
|
||||
Type = ModuleType.External;
|
||||
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "entt", "src", "entt"));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The last line indicates that the actual files will be found in the directory
|
||||
`EnTT/entt/src/entt`.<br/>
|
||||
Download the repository for `EnTT` and place it next to `EnTT.Build.cs` or
|
||||
update the path above accordingly.
|
||||
|
||||
Finally, open the `<Game Name>.Build.cs` file and add `EnTT` as a dependency at
|
||||
the end of the list:
|
||||
|
||||
```cs
|
||||
PublicDependencyModuleNames.AddRange(new[] {
|
||||
"Core", "CoreUObject", "Engine", "InputCore", [...], "EnTT"
|
||||
});
|
||||
```
|
||||
|
||||
Note that some IDEs might require a restart to start recognizing the new module
|
||||
for code-highlighting features and such.
|
||||
|
||||
## Include EnTT
|
||||
|
||||
In any source file of the project, add `#include "entt.hpp"` or any other path
|
||||
to the file from `EnTT` to use it.<br/>
|
||||
Try to create a registry as `entt::registry registry;` to make sure everything
|
||||
compiles fine.
|
||||
34
entt.imp
Normal file
34
entt.imp
Normal file
@@ -0,0 +1,34 @@
|
||||
[
|
||||
{ "include": [ "@<gtest/internal/.*>", "private", "<gtest/gtest.h>", "public" ] },
|
||||
{ "include": [ "@<gtest/gtest-.*>", "private", "<gtest/gtest.h>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_map.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_set.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/any.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/family.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/hashed_string.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/ident.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/monostate.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_info.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_traits.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/entity.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/group.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/handle.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/helper.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/observer.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/organizer.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/registry.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/runtime_view.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/snapshot.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/sparse_set.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/storage.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/view.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/meta/fwd.hpp[\">]", "private", "<entt/meta/meta.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/poly/fwd.hpp[\">]", "private", "<entt/poly/poly.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/cache.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/loader.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/resource.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/delegate.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/dispatcher.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/emitter.hpp>", "public" ] },
|
||||
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/sigh.hpp>", "public" ] }
|
||||
]
|
||||
3
natvis/entt/config.natvis
Normal file
3
natvis/entt/config.natvis
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
33
natvis/entt/container.natvis
Normal file
33
natvis/entt/container.natvis
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::dense_map<*>">
|
||||
<Intrinsic Name="size" Expression="packed.first_base::value.size()"/>
|
||||
<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/>
|
||||
<DisplayString>{{ size={ size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" ExcludeView="simple">packed.first_base::value.capacity()</Item>
|
||||
<Item Name="[bucket_count]" ExcludeView="simple">bucket_count()</Item>
|
||||
<Item Name="[load_factor]" ExcludeView="simple">(float)size() / (float)bucket_count()</Item>
|
||||
<Item Name="[max_load_factor]" ExcludeView="simple">threshold</Item>
|
||||
<IndexListItems>
|
||||
<Size>size()</Size>
|
||||
<ValueNode>packed.first_base::value[$i].element</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::dense_set<*>">
|
||||
<Intrinsic Name="size" Expression="packed.first_base::value.size()"/>
|
||||
<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/>
|
||||
<DisplayString>{{ size={ size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" ExcludeView="simple">packed.first_base::value.capacity()</Item>
|
||||
<Item Name="[bucket_count]" ExcludeView="simple">bucket_count()</Item>
|
||||
<Item Name="[load_factor]" ExcludeView="simple">(float)size() / (float)bucket_count()</Item>
|
||||
<Item Name="[max_load_factor]" ExcludeView="simple">threshold</Item>
|
||||
<IndexListItems>
|
||||
<Size>size()</Size>
|
||||
<ValueNode>packed.first_base::value[$i].second</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
32
natvis/entt/core.natvis
Normal file
32
natvis/entt/core.natvis
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::basic_any<*>">
|
||||
<DisplayString>{{ type={ info->alias,na }, policy={ mode,en } }}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::compressed_pair<*>">
|
||||
<Intrinsic Name="first" Optional="true" Expression="((first_base*)this)->value"/>
|
||||
<Intrinsic Name="first" Optional="true" Expression="*(first_base::base_type*)this"/>
|
||||
<Intrinsic Name="second" Optional="true" Expression="((second_base*)this)->value"/>
|
||||
<Intrinsic Name="second" Optional="true" Expression="*(second_base::base_type*)this"/>
|
||||
<DisplayString >({ first() }, { second() })</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[first]">first()</Item>
|
||||
<Item Name="[second]">second()</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_hashed_string<*>">
|
||||
<DisplayString Condition="base_type::repr != nullptr">{{ hash={ base_type::hash } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[data]">base_type::repr,na</Item>
|
||||
<Item Name="[length]">base_type::length</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::type_info">
|
||||
<DisplayString>{{ name={ alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[hash]">identifier</Item>
|
||||
<Item Name="[index]">seq</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
123
natvis/entt/entity.natvis
Normal file
123
natvis/entt/entity.natvis
Normal file
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::basic_registry<*>">
|
||||
<Intrinsic Name="to_entity" Expression="*((traits_type::entity_type *)&entity) & traits_type::entity_mask">
|
||||
<Parameter Name="entity" Type="traits_type::value_type &"/>
|
||||
</Intrinsic>
|
||||
<DisplayString>{{ pools={ pools.size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[entities]">entities</Item>
|
||||
<Synthetic Name="[pools]">
|
||||
<DisplayString>{ pools.size() }</DisplayString>
|
||||
<Expand>
|
||||
<IndexListItems ExcludeView="simple">
|
||||
<Size>pools.size()</Size>
|
||||
<ValueNode>*pools.packed.first_base::value[$i].element.second</ValueNode>
|
||||
</IndexListItems>
|
||||
<IndexListItems IncludeView="simple">
|
||||
<Size>pools.size()</Size>
|
||||
<ValueNode>*pools.packed.first_base::value[$i].element.second,view(simple)</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Item Name="[groups]" ExcludeView="simple">groups.size()</Item>
|
||||
<Synthetic Name="[vars]">
|
||||
<DisplayString>{ vars.ctx.size() }</DisplayString>
|
||||
<Expand>
|
||||
<IndexListItems>
|
||||
<Size>vars.ctx.size()</Size>
|
||||
<ValueNode>vars.ctx.packed.first_base::value[$i].element.second</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_sparse_set<*>">
|
||||
<DisplayString>{{ size={ packed.size() }, type={ info->alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" ExcludeView="simple">packed.capacity()</Item>
|
||||
<Item Name="[policy]">mode,en</Item>
|
||||
<Synthetic Name="[sparse]">
|
||||
<DisplayString>{ sparse.size() * traits_type::page_size }</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem IncludeView="simple">sparse,view(simple)</ExpandedItem>
|
||||
<CustomListItems ExcludeView="simple">
|
||||
<Variable Name="pos" InitialValue="0"/>
|
||||
<Variable Name="page" InitialValue="0"/>
|
||||
<Variable Name="offset" InitialValue="0"/>
|
||||
<Variable Name="last" InitialValue="sparse.size() * traits_type::page_size"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<Exec>page = pos / traits_type::page_size</Exec>
|
||||
<Exec>offset = pos & (traits_type::page_size - 1)</Exec>
|
||||
<If Condition="sparse[page] && (*((traits_type::entity_type *)&sparse[page][offset]) < ~traits_type::entity_mask)">
|
||||
<Item Name="[{ pos }]">*((traits_type::entity_type *)&sparse[page][offset]) & traits_type::entity_mask</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
<Synthetic Name="[packed]">
|
||||
<DisplayString>{ packed.size() }</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem IncludeView="simple">packed,view(simple)</ExpandedItem>
|
||||
<CustomListItems ExcludeView="simple">
|
||||
<Variable Name="pos" InitialValue="0"/>
|
||||
<Variable Name="last" InitialValue="packed.size()"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="*((traits_type::entity_type *)&packed[pos]) < ~traits_type::entity_mask">
|
||||
<Item Name="[{ pos }]">packed[pos]</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_storage<*>">
|
||||
<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::info->alias,na } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[capacity]" Optional="true" ExcludeView="simple">payload.capacity() * traits_type::page_size</Item>
|
||||
<Item Name="[page size]" Optional="true" ExcludeView="simple">traits_type::page_size</Item>
|
||||
<Item Name="[length]" Optional="true" ExcludeView="simple">length</Item>
|
||||
<Item Name="[base]" ExcludeView="simple">(base_type*)this,nand</Item>
|
||||
<Item Name="[base]" IncludeView="simple">(base_type*)this,view(simple)nand</Item>
|
||||
<!-- having SFINAE-like techniques in natvis is priceless :) -->
|
||||
<CustomListItems Condition="payload.size() != 0" Optional="true">
|
||||
<Variable Name="pos" InitialValue="0" />
|
||||
<Variable Name="last" InitialValue="base_type::packed.size()"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="*((base_type::traits_type::entity_type *)&base_type::packed[pos]) < ~base_type::traits_type::entity_mask">
|
||||
<Item Name="[{ pos }:{ base_type::packed[pos] }]">payload[pos / traits_type::page_size][pos & (traits_type::page_size - 1)]</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_view<*>">
|
||||
<DisplayString>{{ size_hint={ view->packed.size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[pools]">pools,na</Item>
|
||||
<Item Name="[filter]">filter,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_runtime_view<*>">
|
||||
<DisplayString Condition="pools.size() != 0u">{{ size_hint={ pools[0]->packed.size() } }}</DisplayString>
|
||||
<DisplayString>{{ size_hint=0 }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[pools]">pools,na</Item>
|
||||
<Item Name="[filter]">filter,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::null_t">
|
||||
<DisplayString><null></DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::tombstone_t">
|
||||
<DisplayString><tombstone></DisplayString>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
19
natvis/entt/graph.natvis
Normal file
19
natvis/entt/graph.natvis
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::adjacency_matrix<*>">
|
||||
<DisplayString>{{ size={ vert } }}</DisplayString>
|
||||
<Expand>
|
||||
<CustomListItems>
|
||||
<Variable Name="pos" InitialValue="0" />
|
||||
<Variable Name="last" InitialValue="vert * vert"/>
|
||||
<Loop>
|
||||
<Break Condition="pos == last"/>
|
||||
<If Condition="matrix[pos] != 0u">
|
||||
<Item Name="{pos / vert}">pos % vert</Item>
|
||||
</If>
|
||||
<Exec>++pos</Exec>
|
||||
</Loop>
|
||||
</CustomListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
3
natvis/entt/locator.natvis
Normal file
3
natvis/entt/locator.natvis
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
121
natvis/entt/meta.natvis
Normal file
121
natvis/entt/meta.natvis
Normal file
@@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::internal::meta_base_node">
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_conv_node">
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_ctor_node">
|
||||
<DisplayString>{{ arity={ arity } }}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_data_node">
|
||||
<Intrinsic Name="has_property" Expression="!!(traits & property)">
|
||||
<Parameter Name="property" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString>{{ arity={ arity } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[arity]">arity</Item>
|
||||
<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item>
|
||||
<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item>
|
||||
<Item Name="[prop]">prop</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_func_node" >
|
||||
<Intrinsic Name="has_property" Expression="!!(traits & property)">
|
||||
<Parameter Name="property" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString>{{ arity={ arity } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item>
|
||||
<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item>
|
||||
<Item Name="[next]" Condition="next != nullptr">*next</Item>
|
||||
<Item Name="[prop]">prop</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_prop_node">
|
||||
<DisplayString>{ value }</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_template_node">
|
||||
<DisplayString>{{ arity={ arity } }}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::internal::meta_type_node">
|
||||
<Intrinsic Name="has_property" Expression="!!(traits & property)">
|
||||
<Parameter Name="property" Type="int"/>
|
||||
</Intrinsic>
|
||||
<DisplayString Condition="info != nullptr">{{ type={ info->alias,na } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[id]">id</Item>
|
||||
<Item Name="[sizeof]">size_of</Item>
|
||||
<Item Name="[is_arithmetic]">has_property(entt::internal::meta_traits::is_arithmetic)</Item>
|
||||
<Item Name="[is_integral]">has_property(entt::internal::meta_traits::is_integral)</Item>
|
||||
<Item Name="[is_signed]">has_property(entt::internal::meta_traits::is_signed)</Item>
|
||||
<Item Name="[is_array]">has_property(entt::internal::meta_traits::is_array)</Item>
|
||||
<Item Name="[is_enum]">has_property(entt::internal::meta_traits::is_enum)</Item>
|
||||
<Item Name="[is_class]">has_property(entt::internal::meta_traits::is_class)</Item>
|
||||
<Item Name="[is_meta_pointer_like]">has_property(entt::internal::meta_traits::is_meta_pointer_like)</Item>
|
||||
<Item Name="[is_meta_sequence_container]">has_property(entt::internal::meta_traits::is_meta_sequence_container)</Item>
|
||||
<Item Name="[is_meta_associative_container]">has_property(entt::internal::meta_traits::is_meta_associative_container)</Item>
|
||||
<Item Name="[default_constructor]">default_constructor != nullptr</Item>
|
||||
<Item Name="[conversion_helper]">conversion_helper != nullptr</Item>
|
||||
<Item Name="[from_void]">from_void != nullptr</Item>
|
||||
<Item Name="[template_info]">templ</Item>
|
||||
<Item Name="[details]" Condition="details != nullptr">*details</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_any">
|
||||
<DisplayString Condition="node.info != nullptr">{{ type={ node.info->alias,na }, policy={ storage.mode,en } }}</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_handle">
|
||||
<DisplayString>{ any }</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::meta_associative_container">
|
||||
<DisplayString>{ storage }</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_sequence_container">
|
||||
<DisplayString>{ storage }</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_data">
|
||||
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_func">
|
||||
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_prop">
|
||||
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
|
||||
<DisplayString>{{}}</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::meta_type">
|
||||
<DisplayString>{ node }</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>node</ExpandedItem>
|
||||
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
3
natvis/entt/platform.natvis
Normal file
3
natvis/entt/platform.natvis
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
6
natvis/entt/poly.natvis
Normal file
6
natvis/entt/poly.natvis
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::basic_poly<*>">
|
||||
<DisplayString>{ storage }</DisplayString>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
3
natvis/entt/process.natvis
Normal file
3
natvis/entt/process.natvis
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
15
natvis/entt/resource.natvis
Normal file
15
natvis/entt/resource.natvis
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::resource<*>">
|
||||
<DisplayString>{ value }</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>value</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::resource_cache<*>">
|
||||
<DisplayString>{ pool.first_base::value }</DisplayString>
|
||||
<Expand>
|
||||
<ExpandedItem>pool.first_base::value</ExpandedItem>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
55
natvis/entt/signal.natvis
Normal file
55
natvis/entt/signal.natvis
Normal file
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="entt::delegate<*>">
|
||||
<DisplayString>{{ type={ "$T1" } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[empty]">fn == nullptr</Item>
|
||||
<Item Name="[data]">instance</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::basic_dispatcher<*>">
|
||||
<Intrinsic Name="size" Expression="pools.first_base::value.size()"/>
|
||||
<DisplayString>{{ size={ size() } }}</DisplayString>
|
||||
<Expand>
|
||||
<Synthetic Name="[pools]">
|
||||
<DisplayString>{ size() }</DisplayString>
|
||||
<Expand>
|
||||
<IndexListItems>
|
||||
<Size>size()</Size>
|
||||
<ValueNode>*pools.first_base::value.packed.first_base::value[$i].element.second</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::internal::dispatcher_handler<*>">
|
||||
<DisplayString>{{ size={ events.size() }, event={ "$T1" } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[signal]">signal</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::emitter<*>">
|
||||
<DisplayString>{{ size={ handlers.first_base::value.packed.first_base::value.size() } }}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::connection">
|
||||
<DisplayString>{{ bound={ signal != nullptr } }}</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::scoped_connection">
|
||||
<DisplayString>{ conn }</DisplayString>
|
||||
</Type>
|
||||
<Type Name="entt::sigh<*>">
|
||||
<DisplayString>{{ size={ calls.size() }, type={ "$T1" } }}</DisplayString>
|
||||
<Expand>
|
||||
<IndexListItems>
|
||||
<Size>calls.size()</Size>
|
||||
<ValueNode>calls[$i]</ValueNode>
|
||||
</IndexListItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
<Type Name="entt::sink<*>">
|
||||
<DisplayString>{{ type={ "$T1" } }}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[signal]">signal,na</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
299
scripts/amalgamate.py
Normal file
299
scripts/amalgamate.py
Normal file
@@ -0,0 +1,299 @@
|
||||
#!/usr/bin/env python
|
||||
# coding=utf-8
|
||||
|
||||
# amalgamate.py - Amalgamate C source and header files.
|
||||
# Copyright (c) 2012, Erik Edlund <erik.edlund@32767.se>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without modification,
|
||||
# are permitted provided that the following conditions are met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# * Neither the name of Erik Edlund, nor the names of its contributors may
|
||||
# be used to endorse or promote products derived from this software without
|
||||
# specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import argparse
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
class Amalgamation(object):
|
||||
|
||||
# Prepends self.source_path to file_path if needed.
|
||||
def actual_path(self, file_path):
|
||||
if not os.path.isabs(file_path):
|
||||
file_path = os.path.join(self.source_path, file_path)
|
||||
return file_path
|
||||
|
||||
# Search included file_path in self.include_paths and
|
||||
# in source_dir if specified.
|
||||
def find_included_file(self, file_path, source_dir):
|
||||
search_dirs = self.include_paths[:]
|
||||
if source_dir:
|
||||
search_dirs.insert(0, source_dir)
|
||||
|
||||
for search_dir in search_dirs:
|
||||
search_path = os.path.join(search_dir, file_path)
|
||||
if os.path.isfile(self.actual_path(search_path)):
|
||||
return search_path
|
||||
return None
|
||||
|
||||
def __init__(self, args):
|
||||
with open(args.config, 'r') as f:
|
||||
config = json.loads(f.read())
|
||||
for key in config:
|
||||
setattr(self, key, config[key])
|
||||
|
||||
self.verbose = args.verbose == "yes"
|
||||
self.prologue = args.prologue
|
||||
self.source_path = args.source_path
|
||||
self.included_files = []
|
||||
|
||||
# Generate the amalgamation and write it to the target file.
|
||||
def generate(self):
|
||||
amalgamation = ""
|
||||
|
||||
if self.prologue:
|
||||
with open(self.prologue, 'r') as f:
|
||||
amalgamation += datetime.datetime.now().strftime(f.read())
|
||||
|
||||
if self.verbose:
|
||||
print("Config:")
|
||||
print(" target = {0}".format(self.target))
|
||||
print(" working_dir = {0}".format(os.getcwd()))
|
||||
print(" include_paths = {0}".format(self.include_paths))
|
||||
print("Creating amalgamation:")
|
||||
for file_path in self.sources:
|
||||
# Do not check the include paths while processing the source
|
||||
# list, all given source paths must be correct.
|
||||
# actual_path = self.actual_path(file_path)
|
||||
print(" - processing \"{0}\"".format(file_path))
|
||||
t = TranslationUnit(file_path, self, True)
|
||||
amalgamation += t.content
|
||||
|
||||
with open(self.target, 'w') as f:
|
||||
f.write(amalgamation)
|
||||
|
||||
print("...done!\n")
|
||||
if self.verbose:
|
||||
print("Files processed: {0}".format(self.sources))
|
||||
print("Files included: {0}".format(self.included_files))
|
||||
print("")
|
||||
|
||||
|
||||
def _is_within(match, matches):
|
||||
for m in matches:
|
||||
if match.start() > m.start() and \
|
||||
match.end() < m.end():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class TranslationUnit(object):
|
||||
# // C++ comment.
|
||||
cpp_comment_pattern = re.compile(r"//.*?\n")
|
||||
|
||||
# /* C comment. */
|
||||
c_comment_pattern = re.compile(r"/\*.*?\*/", re.S)
|
||||
|
||||
# "complex \"stri\\\ng\" value".
|
||||
string_pattern = re.compile("[^']" r'".*?(?<=[^\\])"', re.S)
|
||||
|
||||
# Handle simple include directives. Support for advanced
|
||||
# directives where macros and defines needs to expanded is
|
||||
# not a concern right now.
|
||||
include_pattern = re.compile(
|
||||
r'#\s*include\s+(<|")(?P<path>.*?)("|>)', re.S)
|
||||
|
||||
# #pragma once
|
||||
pragma_once_pattern = re.compile(r'#\s*pragma\s+once', re.S)
|
||||
|
||||
# Search for pattern in self.content, add the match to
|
||||
# contexts if found and update the index accordingly.
|
||||
def _search_content(self, index, pattern, contexts):
|
||||
match = pattern.search(self.content, index)
|
||||
if match:
|
||||
contexts.append(match)
|
||||
return match.end()
|
||||
return index + 2
|
||||
|
||||
# Return all the skippable contexts, i.e., comments and strings
|
||||
def _find_skippable_contexts(self):
|
||||
# Find contexts in the content in which a found include
|
||||
# directive should not be processed.
|
||||
skippable_contexts = []
|
||||
|
||||
# Walk through the content char by char, and try to grab
|
||||
# skippable contexts using regular expressions when found.
|
||||
i = 1
|
||||
content_len = len(self.content)
|
||||
while i < content_len:
|
||||
j = i - 1
|
||||
current = self.content[i]
|
||||
previous = self.content[j]
|
||||
|
||||
if current == '"':
|
||||
# String value.
|
||||
i = self._search_content(j, self.string_pattern,
|
||||
skippable_contexts)
|
||||
elif current == '*' and previous == '/':
|
||||
# C style comment.
|
||||
i = self._search_content(j, self.c_comment_pattern,
|
||||
skippable_contexts)
|
||||
elif current == '/' and previous == '/':
|
||||
# C++ style comment.
|
||||
i = self._search_content(j, self.cpp_comment_pattern,
|
||||
skippable_contexts)
|
||||
else:
|
||||
# Skip to the next char.
|
||||
i += 1
|
||||
|
||||
return skippable_contexts
|
||||
|
||||
# Returns True if the match is within list of other matches
|
||||
|
||||
# Removes pragma once from content
|
||||
def _process_pragma_once(self):
|
||||
content_len = len(self.content)
|
||||
if content_len < len("#include <x>"):
|
||||
return 0
|
||||
|
||||
# Find contexts in the content in which a found include
|
||||
# directive should not be processed.
|
||||
skippable_contexts = self._find_skippable_contexts()
|
||||
|
||||
pragmas = []
|
||||
pragma_once_match = self.pragma_once_pattern.search(self.content)
|
||||
while pragma_once_match:
|
||||
if not _is_within(pragma_once_match, skippable_contexts):
|
||||
pragmas.append(pragma_once_match)
|
||||
|
||||
pragma_once_match = self.pragma_once_pattern.search(self.content,
|
||||
pragma_once_match.end())
|
||||
|
||||
# Handle all collected pragma once directives.
|
||||
prev_end = 0
|
||||
tmp_content = ''
|
||||
for pragma_match in pragmas:
|
||||
tmp_content += self.content[prev_end:pragma_match.start()]
|
||||
prev_end = pragma_match.end()
|
||||
tmp_content += self.content[prev_end:]
|
||||
self.content = tmp_content
|
||||
|
||||
# Include all trivial #include directives into self.content.
|
||||
def _process_includes(self):
|
||||
content_len = len(self.content)
|
||||
if content_len < len("#include <x>"):
|
||||
return 0
|
||||
|
||||
# Find contexts in the content in which a found include
|
||||
# directive should not be processed.
|
||||
skippable_contexts = self._find_skippable_contexts()
|
||||
|
||||
# Search for include directives in the content, collect those
|
||||
# which should be included into the content.
|
||||
includes = []
|
||||
include_match = self.include_pattern.search(self.content)
|
||||
while include_match:
|
||||
if not _is_within(include_match, skippable_contexts):
|
||||
include_path = include_match.group("path")
|
||||
search_same_dir = include_match.group(1) == '"'
|
||||
found_included_path = self.amalgamation.find_included_file(
|
||||
include_path, self.file_dir if search_same_dir else None)
|
||||
if found_included_path:
|
||||
includes.append((include_match, found_included_path))
|
||||
|
||||
include_match = self.include_pattern.search(self.content,
|
||||
include_match.end())
|
||||
|
||||
# Handle all collected include directives.
|
||||
prev_end = 0
|
||||
tmp_content = ''
|
||||
for include in includes:
|
||||
include_match, found_included_path = include
|
||||
tmp_content += self.content[prev_end:include_match.start()]
|
||||
tmp_content += "// {0}\n".format(include_match.group(0))
|
||||
if found_included_path not in self.amalgamation.included_files:
|
||||
t = TranslationUnit(found_included_path, self.amalgamation, False)
|
||||
tmp_content += t.content
|
||||
prev_end = include_match.end()
|
||||
tmp_content += self.content[prev_end:]
|
||||
self.content = tmp_content
|
||||
|
||||
return len(includes)
|
||||
|
||||
# Make all content processing
|
||||
def _process(self):
|
||||
if not self.is_root:
|
||||
self._process_pragma_once()
|
||||
self._process_includes()
|
||||
|
||||
def __init__(self, file_path, amalgamation, is_root):
|
||||
self.file_path = file_path
|
||||
self.file_dir = os.path.dirname(file_path)
|
||||
self.amalgamation = amalgamation
|
||||
self.is_root = is_root
|
||||
|
||||
self.amalgamation.included_files.append(self.file_path)
|
||||
|
||||
actual_path = self.amalgamation.actual_path(file_path)
|
||||
if not os.path.isfile(actual_path):
|
||||
raise IOError("File not found: \"{0}\"".format(file_path))
|
||||
with open(actual_path, 'r') as f:
|
||||
self.content = f.read()
|
||||
self._process()
|
||||
|
||||
|
||||
def main():
|
||||
description = "Amalgamate C source and header files."
|
||||
usage = " ".join([
|
||||
"amalgamate.py",
|
||||
"[-v]",
|
||||
"-c path/to/config.json",
|
||||
"-s path/to/source/dir",
|
||||
"[-p path/to/prologue.(c|h)]"
|
||||
])
|
||||
argsparser = argparse.ArgumentParser(
|
||||
description=description, usage=usage)
|
||||
|
||||
argsparser.add_argument("-v", "--verbose", dest="verbose",
|
||||
choices=["yes", "no"], metavar="", help="be verbose")
|
||||
|
||||
argsparser.add_argument("-c", "--config", dest="config",
|
||||
required=True, metavar="", help="path to a JSON config file")
|
||||
|
||||
argsparser.add_argument("-s", "--source", dest="source_path",
|
||||
required=True, metavar="", help="source code path")
|
||||
|
||||
argsparser.add_argument("-p", "--prologue", dest="prologue",
|
||||
required=False, metavar="", help="path to a C prologue file")
|
||||
|
||||
amalgamation = Amalgamation(argsparser.parse_args())
|
||||
amalgamation.generate()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
8
scripts/config.json
Normal file
8
scripts/config.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"project": "entt",
|
||||
"target": "single_include/entt/entt.hpp",
|
||||
"sources": [
|
||||
"src/entt/entt.hpp"
|
||||
],
|
||||
"include_paths": ["src"]
|
||||
}
|
||||
60
scripts/update_homebrew.sh
Executable file
60
scripts/update_homebrew.sh
Executable file
@@ -0,0 +1,60 @@
|
||||
#!/bin/sh
|
||||
|
||||
# only argument should be the version to upgrade to
|
||||
if [ $# != 1 ]
|
||||
then
|
||||
echo "Expected a version tag like v2.7.1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERSION="$1"
|
||||
URL="https://github.com/skypjack/entt/archive/$VERSION.tar.gz"
|
||||
FORMULA="entt.rb"
|
||||
|
||||
echo "Updating homebrew package to $VERSION"
|
||||
|
||||
echo "Cloning..."
|
||||
git clone https://github.com/skypjack/homebrew-entt.git
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
cd homebrew-entt
|
||||
|
||||
# download the repo at the version
|
||||
# exit with error messages if curl fails
|
||||
echo "Curling..."
|
||||
curl "$URL" --location --fail --silent --show-error --output archive.tar.gz
|
||||
if [ $? != 0 ]
|
||||
then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# compute sha256 hash
|
||||
echo "Hashing..."
|
||||
HASH="$(openssl sha256 archive.tar.gz | cut -d " " -f 2)"
|
||||
|
||||
# delete the archive
|
||||
rm archive.tar.gz
|
||||
|
||||
echo "Sedding..."
|
||||
|
||||
# change the url in the formula file
|
||||
# the slashes in the URL must be escaped
|
||||
ESCAPED_URL="$(echo "$URL" | sed -e 's/[\/&]/\\&/g')"
|
||||
sed -i -e '/url/s/".*"/"'$ESCAPED_URL'"/' $FORMULA
|
||||
|
||||
# change the hash in the formula file
|
||||
sed -i -e '/sha256/s/".*"/"'$HASH'"/' $FORMULA
|
||||
|
||||
# delete temporary file created by sed
|
||||
rm -rf "$FORMULA-e"
|
||||
|
||||
# update remote repo
|
||||
echo "Gitting..."
|
||||
git add entt.rb
|
||||
git commit -m "Update to $VERSION"
|
||||
git push origin master
|
||||
|
||||
# out of homebrew-entt dir
|
||||
cd ..
|
||||
88701
single_include/entt/entt.hpp
Normal file
88701
single_include/entt/entt.hpp
Normal file
File diff suppressed because it is too large
Load Diff
83
src/entt/config/config.h
Normal file
83
src/entt/config/config.h
Normal file
@@ -0,0 +1,83 @@
|
||||
#ifndef ENTT_CONFIG_CONFIG_H
|
||||
#define ENTT_CONFIG_CONFIG_H
|
||||
|
||||
#include "version.h"
|
||||
|
||||
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
|
||||
# define ENTT_CONSTEXPR
|
||||
# define ENTT_THROW throw
|
||||
# define ENTT_TRY try
|
||||
# define ENTT_CATCH catch(...)
|
||||
#else
|
||||
# define ENTT_CONSTEXPR constexpr // use only with throwing functions (waiting for C++20)
|
||||
# define ENTT_THROW
|
||||
# define ENTT_TRY if(true)
|
||||
# define ENTT_CATCH if(false)
|
||||
#endif
|
||||
|
||||
#ifdef ENTT_USE_ATOMIC
|
||||
# include <atomic>
|
||||
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
|
||||
#else
|
||||
# define ENTT_MAYBE_ATOMIC(Type) Type
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_ID_TYPE
|
||||
# include <cstdint>
|
||||
# define ENTT_ID_TYPE std::uint32_t
|
||||
#endif
|
||||
|
||||
#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(condition, msg) (void(0))
|
||||
#elif !defined ENTT_ASSERT
|
||||
# include <cassert>
|
||||
# define ENTT_ASSERT(condition, msg) assert(condition)
|
||||
#endif
|
||||
|
||||
#ifdef ENTT_DISABLE_ASSERT
|
||||
# undef ENTT_ASSERT_CONSTEXPR
|
||||
# define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0))
|
||||
#elif !defined ENTT_ASSERT_CONSTEXPR
|
||||
# define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg)
|
||||
#endif
|
||||
|
||||
#define ENTT_FAIL(msg) ENTT_ASSERT(false, msg);
|
||||
|
||||
#ifdef ENTT_NO_ETO
|
||||
# define ENTT_ETO_TYPE(Type) void
|
||||
#else
|
||||
# define ENTT_ETO_TYPE(Type) Type
|
||||
#endif
|
||||
|
||||
#ifdef ENTT_STANDARD_CPP
|
||||
# define ENTT_NONSTD false
|
||||
#else
|
||||
# define ENTT_NONSTD true
|
||||
# if defined __clang__ || defined __GNUC__
|
||||
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
# define ENTT_PRETTY_FUNCTION_PREFIX '='
|
||||
# define ENTT_PRETTY_FUNCTION_SUFFIX ']'
|
||||
# elif defined _MSC_VER
|
||||
# define ENTT_PRETTY_FUNCTION __FUNCSIG__
|
||||
# define ENTT_PRETTY_FUNCTION_PREFIX '<'
|
||||
# define ENTT_PRETTY_FUNCTION_SUFFIX '>'
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined _MSC_VER
|
||||
# pragma detect_mismatch("entt.version", ENTT_VERSION)
|
||||
# pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY))
|
||||
# pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE))
|
||||
# pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
7
src/entt/config/macro.h
Normal file
7
src/entt/config/macro.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef ENTT_CONFIG_MACRO_H
|
||||
#define ENTT_CONFIG_MACRO_H
|
||||
|
||||
#define ENTT_STR(arg) #arg
|
||||
#define ENTT_XSTR(arg) ENTT_STR(arg)
|
||||
|
||||
#endif
|
||||
14
src/entt/config/version.h
Normal file
14
src/entt/config/version.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef ENTT_CONFIG_VERSION_H
|
||||
#define ENTT_CONFIG_VERSION_H
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
#define ENTT_VERSION_MAJOR 3
|
||||
#define ENTT_VERSION_MINOR 12
|
||||
#define ENTT_VERSION_PATCH 2
|
||||
|
||||
#define ENTT_VERSION \
|
||||
ENTT_XSTR(ENTT_VERSION_MAJOR) \
|
||||
"." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH)
|
||||
|
||||
#endif
|
||||
1054
src/entt/container/dense_map.hpp
Normal file
1054
src/entt/container/dense_map.hpp
Normal file
File diff suppressed because it is too large
Load Diff
889
src/entt/container/dense_set.hpp
Normal file
889
src/entt/container/dense_set.hpp
Normal file
@@ -0,0 +1,889 @@
|
||||
#ifndef ENTT_CONTAINER_DENSE_SET_HPP
|
||||
#define ENTT_CONTAINER_DENSE_SET_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../config/config.h"
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "../core/memory.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
class dense_set_iterator final {
|
||||
template<typename>
|
||||
friend class dense_set_iterator;
|
||||
|
||||
public:
|
||||
using value_type = typename It::value_type::second_type;
|
||||
using pointer = const value_type *;
|
||||
using reference = const value_type &;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
constexpr dense_set_iterator() noexcept
|
||||
: it{} {}
|
||||
|
||||
constexpr dense_set_iterator(const It iter) noexcept
|
||||
: it{iter} {}
|
||||
|
||||
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
|
||||
constexpr dense_set_iterator(const dense_set_iterator<Other> &other) noexcept
|
||||
: it{other.it} {}
|
||||
|
||||
constexpr dense_set_iterator &operator++() noexcept {
|
||||
return ++it, *this;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator operator++(int) noexcept {
|
||||
dense_set_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator &operator--() noexcept {
|
||||
return --it, *this;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator operator--(int) noexcept {
|
||||
dense_set_iterator orig = *this;
|
||||
return operator--(), orig;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator &operator+=(const difference_type value) noexcept {
|
||||
it += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator operator+(const difference_type value) const noexcept {
|
||||
dense_set_iterator copy = *this;
|
||||
return (copy += value);
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator &operator-=(const difference_type value) noexcept {
|
||||
return (*this += -value);
|
||||
}
|
||||
|
||||
constexpr dense_set_iterator operator-(const difference_type value) const noexcept {
|
||||
return (*this + -value);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
|
||||
return it[value].second;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::addressof(it->second);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr bool operator==(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
friend constexpr bool operator<(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
|
||||
|
||||
private:
|
||||
It it;
|
||||
};
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it - rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator<(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.it < rhs.it;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator>(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator<=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs > rhs);
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator>=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
class dense_set_local_iterator final {
|
||||
template<typename>
|
||||
friend class dense_set_local_iterator;
|
||||
|
||||
public:
|
||||
using value_type = typename It::value_type::second_type;
|
||||
using pointer = const value_type *;
|
||||
using reference = const value_type &;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
constexpr dense_set_local_iterator() noexcept
|
||||
: it{},
|
||||
offset{} {}
|
||||
|
||||
constexpr dense_set_local_iterator(It iter, const std::size_t pos) noexcept
|
||||
: it{iter},
|
||||
offset{pos} {}
|
||||
|
||||
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
|
||||
constexpr dense_set_local_iterator(const dense_set_local_iterator<Other> &other) noexcept
|
||||
: it{other.it},
|
||||
offset{other.offset} {}
|
||||
|
||||
constexpr dense_set_local_iterator &operator++() noexcept {
|
||||
return offset = it[offset].first, *this;
|
||||
}
|
||||
|
||||
constexpr dense_set_local_iterator operator++(int) noexcept {
|
||||
dense_set_local_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return std::addressof(it[offset].second);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr std::size_t index() const noexcept {
|
||||
return offset;
|
||||
}
|
||||
|
||||
private:
|
||||
It it;
|
||||
std::size_t offset;
|
||||
};
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
|
||||
return lhs.index() == rhs.index();
|
||||
}
|
||||
|
||||
template<typename Lhs, typename Rhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Associative container for unique objects of a given type.
|
||||
*
|
||||
* Internally, elements are organized into buckets. Which bucket an element is
|
||||
* placed into depends entirely on its hash. Elements with the same hash code
|
||||
* appear in the same bucket.
|
||||
*
|
||||
* @tparam Type Value type of the associative container.
|
||||
* @tparam Hash Type of function to use to hash the values.
|
||||
* @tparam KeyEqual Type of function to use to compare the values for equality.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Hash, typename KeyEqual, typename Allocator>
|
||||
class dense_set {
|
||||
static constexpr float default_threshold = 0.875f;
|
||||
static constexpr std::size_t minimum_capacity = 8u;
|
||||
|
||||
using node_type = std::pair<std::size_t, Type>;
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
|
||||
using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
|
||||
using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::size_t value_to_bucket(const Other &value) const noexcept {
|
||||
return fast_mod(static_cast<size_type>(sparse.second()(value)), bucket_count());
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) {
|
||||
for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
|
||||
if(packed.second()(*it, value)) {
|
||||
return begin() + static_cast<typename iterator::difference_type>(it.index());
|
||||
}
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) const {
|
||||
for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
|
||||
if(packed.second()(*it, value)) {
|
||||
return cbegin() + static_cast<typename iterator::difference_type>(it.index());
|
||||
}
|
||||
}
|
||||
|
||||
return cend();
|
||||
}
|
||||
|
||||
template<typename Other>
|
||||
[[nodiscard]] auto insert_or_do_nothing(Other &&value) {
|
||||
const auto index = value_to_bucket(value);
|
||||
|
||||
if(auto it = constrained_find(value, index); it != end()) {
|
||||
return std::make_pair(it, false);
|
||||
}
|
||||
|
||||
packed.first().emplace_back(sparse.first()[index], std::forward<Other>(value));
|
||||
sparse.first()[index] = packed.first().size() - 1u;
|
||||
rehash_if_required();
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
}
|
||||
|
||||
void move_and_pop(const std::size_t pos) {
|
||||
if(const auto last = size() - 1u; pos != last) {
|
||||
size_type *curr = sparse.first().data() + value_to_bucket(packed.first().back().second);
|
||||
packed.first()[pos] = std::move(packed.first().back());
|
||||
for(; *curr != last; curr = &packed.first()[*curr].first) {}
|
||||
*curr = pos;
|
||||
}
|
||||
|
||||
packed.first().pop_back();
|
||||
}
|
||||
|
||||
void rehash_if_required() {
|
||||
if(size() > (bucket_count() * max_load_factor())) {
|
||||
rehash(bucket_count() * 2u);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Key type of the container. */
|
||||
using key_type = Type;
|
||||
/*! @brief Value type of the container. */
|
||||
using value_type = Type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Type of function to use to hash the elements. */
|
||||
using hasher = Hash;
|
||||
/*! @brief Type of function to use to compare the elements for equality. */
|
||||
using key_equal = KeyEqual;
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>;
|
||||
/*! @brief Constant random access iterator type. */
|
||||
using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_iterator>;
|
||||
/*! @brief Forward iterator type. */
|
||||
using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>;
|
||||
/*! @brief Constant forward iterator type. */
|
||||
using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_iterator>;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
dense_set()
|
||||
: dense_set{minimum_capacity} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit dense_set(const allocator_type &allocator)
|
||||
: dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator and user
|
||||
* supplied minimal number of buckets.
|
||||
* @param cnt Minimal number of buckets.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_set(const size_type cnt, const allocator_type &allocator)
|
||||
: dense_set{cnt, hasher{}, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator, hash
|
||||
* function and user supplied minimal number of buckets.
|
||||
* @param cnt Minimal number of buckets.
|
||||
* @param hash Hash function to use.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator)
|
||||
: dense_set{cnt, hash, key_equal{}, allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty container with a given allocator, hash
|
||||
* function, compare function and user supplied minimal number of buckets.
|
||||
* @param cnt Minimal number of buckets.
|
||||
* @param hash Hash function to use.
|
||||
* @param equal Compare function to use.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{})
|
||||
: sparse{allocator, hash},
|
||||
packed{allocator, equal},
|
||||
threshold{default_threshold} {
|
||||
rehash(cnt);
|
||||
}
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
dense_set(const dense_set &) = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_set(const dense_set &other, const allocator_type &allocator)
|
||||
: sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())},
|
||||
packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/*! @brief Default move constructor. */
|
||||
dense_set(dense_set &&) noexcept(std::is_nothrow_move_constructible_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_constructible_v<compressed_pair<packed_container_type, key_equal>>) = default;
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
dense_set(dense_set &&other, const allocator_type &allocator)
|
||||
: sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))},
|
||||
packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))},
|
||||
threshold{other.threshold} {}
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator.
|
||||
* @return This container.
|
||||
*/
|
||||
dense_set &operator=(const dense_set &) = default;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator.
|
||||
* @return This container.
|
||||
*/
|
||||
dense_set &operator=(dense_set &&) noexcept(std::is_nothrow_move_assignable_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_assignable_v<compressed_pair<packed_container_type, key_equal>>) = default;
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return sparse.first().get_allocator();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning.
|
||||
*
|
||||
* If the array is empty, the returned iterator will be equal to `end()`.
|
||||
*
|
||||
* @return An iterator to the first instance of the internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cbegin() const noexcept {
|
||||
return packed.first().begin();
|
||||
}
|
||||
|
||||
/*! @copydoc cbegin */
|
||||
[[nodiscard]] const_iterator begin() const noexcept {
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] iterator begin() noexcept {
|
||||
return packed.first().begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end.
|
||||
* @return An iterator to the element following the last instance of the
|
||||
* internal array.
|
||||
*/
|
||||
[[nodiscard]] const_iterator cend() const noexcept {
|
||||
return packed.first().end();
|
||||
}
|
||||
|
||||
/*! @copydoc cend */
|
||||
[[nodiscard]] const_iterator end() const noexcept {
|
||||
return cend();
|
||||
}
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] iterator end() noexcept {
|
||||
return packed.first().end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether a container is empty.
|
||||
* @return True if the container is empty, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept {
|
||||
return packed.first().empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a container.
|
||||
* @return Number of elements in a container.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return packed.first().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum possible number of elements.
|
||||
* @return Maximum possible number of elements.
|
||||
*/
|
||||
[[nodiscard]] size_type max_size() const noexcept {
|
||||
return packed.first().max_size();
|
||||
}
|
||||
|
||||
/*! @brief Clears the container. */
|
||||
void clear() noexcept {
|
||||
sparse.first().clear();
|
||||
packed.first().clear();
|
||||
rehash(0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts an element into the container, if it does not exist.
|
||||
* @param value An element to insert into the container.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
std::pair<iterator, bool> insert(const value_type &value) {
|
||||
return insert_or_do_nothing(value);
|
||||
}
|
||||
|
||||
/*! @copydoc insert */
|
||||
std::pair<iterator, bool> insert(value_type &&value) {
|
||||
return insert_or_do_nothing(std::move(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Inserts elements into the container, if they do not exist.
|
||||
* @tparam It Type of input iterator.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
*/
|
||||
template<typename It>
|
||||
void insert(It first, It last) {
|
||||
for(; first != last; ++first) {
|
||||
insert(*first);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an element in-place, if it does not exist.
|
||||
*
|
||||
* The element is also constructed when the container already has the key,
|
||||
* in which case the newly constructed object is destroyed immediately.
|
||||
*
|
||||
* @tparam Args Types of arguments to forward to the constructor of the
|
||||
* element.
|
||||
* @param args Arguments to forward to the constructor of the element.
|
||||
* @return A pair consisting of an iterator to the inserted element (or to
|
||||
* the element that prevented the insertion) and a bool denoting whether the
|
||||
* insertion took place.
|
||||
*/
|
||||
template<typename... Args>
|
||||
std::pair<iterator, bool> emplace(Args &&...args) {
|
||||
if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::decay_t<Args>, value_type>)) {
|
||||
return insert_or_do_nothing(std::forward<Args>(args)...);
|
||||
} else {
|
||||
auto &node = packed.first().emplace_back(std::piecewise_construct, std::make_tuple(packed.first().size()), std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
const auto index = value_to_bucket(node.second);
|
||||
|
||||
if(auto it = constrained_find(node.second, index); it != end()) {
|
||||
packed.first().pop_back();
|
||||
return std::make_pair(it, false);
|
||||
}
|
||||
|
||||
std::swap(node.first, sparse.first()[index]);
|
||||
rehash_if_required();
|
||||
|
||||
return std::make_pair(--end(), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes an element from a given position.
|
||||
* @param pos An iterator to the element to remove.
|
||||
* @return An iterator following the removed element.
|
||||
*/
|
||||
iterator erase(const_iterator pos) {
|
||||
const auto diff = pos - cbegin();
|
||||
erase(*pos);
|
||||
return begin() + diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the given elements from a container.
|
||||
* @param first An iterator to the first element of the range of elements.
|
||||
* @param last An iterator past the last element of the range of elements.
|
||||
* @return An iterator following the last removed element.
|
||||
*/
|
||||
iterator erase(const_iterator first, const_iterator last) {
|
||||
const auto dist = first - cbegin();
|
||||
|
||||
for(auto from = last - cbegin(); from != dist; --from) {
|
||||
erase(packed.first()[from - 1u].second);
|
||||
}
|
||||
|
||||
return (begin() + dist);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the element associated with a given value.
|
||||
* @param value Value of an element to remove.
|
||||
* @return Number of elements removed (either 0 or 1).
|
||||
*/
|
||||
size_type erase(const value_type &value) {
|
||||
for(size_type *curr = sparse.first().data() + value_to_bucket(value); *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].first) {
|
||||
if(packed.second()(packed.first()[*curr].second, value)) {
|
||||
const auto index = *curr;
|
||||
*curr = packed.first()[*curr].first;
|
||||
move_and_pop(index);
|
||||
return 1u;
|
||||
}
|
||||
}
|
||||
|
||||
return 0u;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given container.
|
||||
* @param other Container to exchange the content with.
|
||||
*/
|
||||
void swap(dense_set &other) {
|
||||
using std::swap;
|
||||
swap(sparse, other.sparse);
|
||||
swap(packed, other.packed);
|
||||
swap(threshold, other.threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements matching a value (either 1 or 0).
|
||||
* @param key Key value of an element to search for.
|
||||
* @return Number of elements matching the key (either 1 or 0).
|
||||
*/
|
||||
[[nodiscard]] size_type count(const value_type &key) const {
|
||||
return find(key) != end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements matching a key (either 1 or 0).
|
||||
* @tparam Other Type of the key value of an element to search for.
|
||||
* @param key Key value of an element to search for.
|
||||
* @return Number of elements matching the key (either 1 or 0).
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>>
|
||||
count(const Other &key) const {
|
||||
return find(key) != end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an element with a given value.
|
||||
* @param value Value of an element to search for.
|
||||
* @return An iterator to an element with the given value. If no such
|
||||
* element is found, a past-the-end iterator is returned.
|
||||
*/
|
||||
[[nodiscard]] iterator find(const value_type &value) {
|
||||
return constrained_find(value, value_to_bucket(value));
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
[[nodiscard]] const_iterator find(const value_type &value) const {
|
||||
return constrained_find(value, value_to_bucket(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finds an element that compares _equivalent_ to a given value.
|
||||
* @tparam Other Type of an element to search for.
|
||||
* @param value Value of an element to search for.
|
||||
* @return An iterator to an element with the given value. If no such
|
||||
* element is found, a past-the-end iterator is returned.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
|
||||
find(const Other &value) {
|
||||
return constrained_find(value, value_to_bucket(value));
|
||||
}
|
||||
|
||||
/*! @copydoc find */
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
|
||||
find(const Other &value) const {
|
||||
return constrained_find(value, value_to_bucket(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a range containing all elements with a given value.
|
||||
* @param value Value of an element to search for.
|
||||
* @return A pair of iterators pointing to the first element and past the
|
||||
* last element of the range.
|
||||
*/
|
||||
[[nodiscard]] std::pair<iterator, iterator> equal_range(const value_type &value) {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == end())};
|
||||
}
|
||||
|
||||
/*! @copydoc equal_range */
|
||||
[[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const value_type &value) const {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == cend())};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a range containing all elements that compare _equivalent_
|
||||
* to a given value.
|
||||
* @tparam Other Type of an element to search for.
|
||||
* @param value Value of an element to search for.
|
||||
* @return A pair of iterators pointing to the first element and past the
|
||||
* last element of the range.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>>
|
||||
equal_range(const Other &value) {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == end())};
|
||||
}
|
||||
|
||||
/*! @copydoc equal_range */
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<const_iterator, const_iterator>>>
|
||||
equal_range(const Other &value) const {
|
||||
const auto it = find(value);
|
||||
return {it, it + !(it == cend())};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the container contains an element with a given value.
|
||||
* @param value Value of an element to search for.
|
||||
* @return True if there is such an element, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool contains(const value_type &value) const {
|
||||
return (find(value) != cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the container contains an element that compares
|
||||
* _equivalent_ to a given value.
|
||||
* @tparam Other Type of an element to search for.
|
||||
* @param value Value of an element to search for.
|
||||
* @return True if there is such an element, false otherwise.
|
||||
*/
|
||||
template<typename Other>
|
||||
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, bool>>
|
||||
contains(const Other &value) const {
|
||||
return (find(value) != cend());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator cbegin(const size_type index) const {
|
||||
return {packed.first().begin(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator begin(const size_type index) const {
|
||||
return cbegin(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the beginning of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] local_iterator begin(const size_type index) {
|
||||
return {packed.first().begin(), sparse.first()[index]};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
|
||||
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] const_local_iterator end(const size_type index) const {
|
||||
return cend(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end of a given bucket.
|
||||
* @param index An index of a bucket to access.
|
||||
* @return An iterator to the end of the given bucket.
|
||||
*/
|
||||
[[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
|
||||
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of buckets.
|
||||
* @return The number of buckets.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket_count() const {
|
||||
return sparse.first().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum number of buckets.
|
||||
* @return The maximum number of buckets.
|
||||
*/
|
||||
[[nodiscard]] size_type max_bucket_count() const {
|
||||
return sparse.first().max_size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in a given bucket.
|
||||
* @param index The index of the bucket to examine.
|
||||
* @return The number of elements in the given bucket.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket_size(const size_type index) const {
|
||||
return static_cast<size_type>(std::distance(begin(index), end(index)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the bucket for a given element.
|
||||
* @param value The value of the element to examine.
|
||||
* @return The bucket for the given element.
|
||||
*/
|
||||
[[nodiscard]] size_type bucket(const value_type &value) const {
|
||||
return value_to_bucket(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the average number of elements per bucket.
|
||||
* @return The average number of elements per bucket.
|
||||
*/
|
||||
[[nodiscard]] float load_factor() const {
|
||||
return size() / static_cast<float>(bucket_count());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the maximum average number of elements per bucket.
|
||||
* @return The maximum average number of elements per bucket.
|
||||
*/
|
||||
[[nodiscard]] float max_load_factor() const {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the desired maximum average number of elements per bucket.
|
||||
* @param value A desired maximum average number of elements per bucket.
|
||||
*/
|
||||
void max_load_factor(const float value) {
|
||||
ENTT_ASSERT(value > 0.f, "Invalid load factor");
|
||||
threshold = value;
|
||||
rehash(0u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserves at least the specified number of buckets and regenerates
|
||||
* the hash table.
|
||||
* @param cnt New number of buckets.
|
||||
*/
|
||||
void rehash(const size_type cnt) {
|
||||
auto value = cnt > minimum_capacity ? cnt : minimum_capacity;
|
||||
const auto cap = static_cast<size_type>(size() / max_load_factor());
|
||||
value = value > cap ? value : cap;
|
||||
|
||||
if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
|
||||
sparse.first().resize(sz);
|
||||
|
||||
for(auto &&elem: sparse.first()) {
|
||||
elem = std::numeric_limits<size_type>::max();
|
||||
}
|
||||
|
||||
for(size_type pos{}, last = size(); pos < last; ++pos) {
|
||||
const auto index = value_to_bucket(packed.first()[pos].second);
|
||||
packed.first()[pos].first = std::exchange(sparse.first()[index], pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reserves space for at least the specified number of elements and
|
||||
* regenerates the hash table.
|
||||
* @param cnt New number of elements.
|
||||
*/
|
||||
void reserve(const size_type cnt) {
|
||||
packed.first().reserve(cnt);
|
||||
rehash(static_cast<size_type>(std::ceil(cnt / max_load_factor())));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function used to hash the elements.
|
||||
* @return The function used to hash the elements.
|
||||
*/
|
||||
[[nodiscard]] hasher hash_function() const {
|
||||
return sparse.second();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function used to compare elements for equality.
|
||||
* @return The function used to compare elements for equality.
|
||||
*/
|
||||
[[nodiscard]] key_equal key_eq() const {
|
||||
return packed.second();
|
||||
}
|
||||
|
||||
private:
|
||||
compressed_pair<sparse_container_type, hasher> sparse;
|
||||
compressed_pair<packed_container_type, key_equal> packed;
|
||||
float threshold;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
26
src/entt/container/fwd.hpp
Normal file
26
src/entt/container/fwd.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef ENTT_CONTAINER_FWD_HPP
|
||||
#define ENTT_CONTAINER_FWD_HPP
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<
|
||||
typename Key,
|
||||
typename Type,
|
||||
typename = std::hash<Key>,
|
||||
typename = std::equal_to<Key>,
|
||||
typename = std::allocator<std::pair<const Key, Type>>>
|
||||
class dense_map;
|
||||
|
||||
template<
|
||||
typename Type,
|
||||
typename = std::hash<Type>,
|
||||
typename = std::equal_to<Type>,
|
||||
typename = std::allocator<Type>>
|
||||
class dense_set;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
138
src/entt/core/algorithm.hpp
Normal file
138
src/entt/core/algorithm.hpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#ifndef ENTT_CORE_ALGORITHM_HPP
|
||||
#define ENTT_CORE_ALGORITHM_HPP
|
||||
|
||||
#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.
|
||||
*
|
||||
* Unfortunately, `std::sort` cannot be passed as template argument to a class
|
||||
* template or a function template.<br/>
|
||||
* This class fills the gap by wrapping some flavors of `std::sort` in a
|
||||
* function object.
|
||||
*/
|
||||
struct std_sort {
|
||||
/**
|
||||
* @brief Sorts the elements in a range.
|
||||
*
|
||||
* Sorts the elements in a range using the given binary comparison function.
|
||||
*
|
||||
* @tparam It Type of random access iterator.
|
||||
* @tparam Compare Type of comparison function object.
|
||||
* @tparam Args Types of arguments to forward to the sort function.
|
||||
* @param first An iterator to the first element of the range to sort.
|
||||
* @param last An iterator past the last element of the range to sort.
|
||||
* @param compare A valid comparison function object.
|
||||
* @param args Arguments to forward to the sort function, if any.
|
||||
*/
|
||||
template<typename It, typename Compare = std::less<>, typename... Args>
|
||||
void operator()(It first, It last, Compare compare = Compare{}, Args &&...args) const {
|
||||
std::sort(std::forward<Args>(args)..., std::move(first), std::move(last), std::move(compare));
|
||||
}
|
||||
};
|
||||
|
||||
/*! @brief Function object for performing insertion sort. */
|
||||
struct insertion_sort {
|
||||
/**
|
||||
* @brief Sorts the elements in a range.
|
||||
*
|
||||
* Sorts the elements in a range using the given binary comparison function.
|
||||
*
|
||||
* @tparam It Type of random access iterator.
|
||||
* @tparam Compare Type of comparison function object.
|
||||
* @param first An iterator to the first element of the range to sort.
|
||||
* @param last An iterator past the last element of the range to sort.
|
||||
* @param compare A valid comparison function object.
|
||||
*/
|
||||
template<typename It, typename Compare = std::less<>>
|
||||
void operator()(It first, It last, Compare compare = Compare{}) const {
|
||||
if(first < last) {
|
||||
for(auto it = first + 1; it < last; ++it) {
|
||||
auto value = std::move(*it);
|
||||
auto pre = it;
|
||||
|
||||
for(; pre > first && compare(value, *(pre - 1)); --pre) {
|
||||
*pre = std::move(*(pre - 1));
|
||||
}
|
||||
|
||||
*pre = std::move(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Function object for performing LSD radix sort.
|
||||
* @tparam Bit Number of bits processed per pass.
|
||||
* @tparam N Maximum number of bits to sort.
|
||||
*/
|
||||
template<std::size_t Bit, std::size_t N>
|
||||
struct radix_sort {
|
||||
static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass");
|
||||
|
||||
/**
|
||||
* @brief Sorts the elements in a range.
|
||||
*
|
||||
* Sorts the elements in a range using the given _getter_ to access the
|
||||
* actual data to be sorted.
|
||||
*
|
||||
* This implementation is inspired by the online book
|
||||
* [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort).
|
||||
*
|
||||
* @tparam It Type of random access iterator.
|
||||
* @tparam Getter Type of _getter_ function object.
|
||||
* @param first An iterator to the first element of the range to sort.
|
||||
* @param last An iterator past the last element of the range to sort.
|
||||
* @param getter A valid _getter_ function object.
|
||||
*/
|
||||
template<typename It, typename Getter = identity>
|
||||
void operator()(It first, It last, Getter getter = Getter{}) const {
|
||||
if(first < last) {
|
||||
constexpr auto passes = N / Bit;
|
||||
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
std::vector<value_type> aux(std::distance(first, last));
|
||||
|
||||
auto part = [getter = std::move(getter)](auto from, auto to, auto out, auto start) {
|
||||
constexpr auto mask = (1 << Bit) - 1;
|
||||
constexpr auto buckets = 1 << Bit;
|
||||
|
||||
std::size_t index[buckets]{};
|
||||
std::size_t count[buckets]{};
|
||||
|
||||
for(auto it = from; it != to; ++it) {
|
||||
++count[(getter(*it) >> start) & mask];
|
||||
}
|
||||
|
||||
for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
|
||||
index[pos + 1u] = index[pos] + count[pos];
|
||||
}
|
||||
|
||||
for(auto it = from; it != to; ++it) {
|
||||
out[index[(getter(*it) >> start) & mask]++] = std::move(*it);
|
||||
}
|
||||
};
|
||||
|
||||
for(std::size_t pass = 0; pass < (passes & ~1); pass += 2) {
|
||||
part(first, last, aux.begin(), pass * Bit);
|
||||
part(aux.begin(), aux.end(), first, (pass + 1) * Bit);
|
||||
}
|
||||
|
||||
if constexpr(passes & 1) {
|
||||
part(first, last, aux.begin(), (passes - 1) * Bit);
|
||||
std::move(aux.begin(), aux.end(), first);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
510
src/entt/core/any.hpp
Normal file
510
src/entt/core/any.hpp
Normal file
@@ -0,0 +1,510 @@
|
||||
#ifndef ENTT_CORE_ANY_HPP
|
||||
#define ENTT_CORE_ANY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
enum class any_operation : std::uint8_t {
|
||||
copy,
|
||||
move,
|
||||
transfer,
|
||||
assign,
|
||||
destroy,
|
||||
compare,
|
||||
get
|
||||
};
|
||||
|
||||
enum class any_policy : std::uint8_t {
|
||||
owner,
|
||||
ref,
|
||||
cref
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief A SBO friendly, type-safe container for single values of any type.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Optional alignment requirement.
|
||||
*/
|
||||
template<std::size_t Len, std::size_t Align>
|
||||
class basic_any {
|
||||
using operation = internal::any_operation;
|
||||
using policy = internal::any_policy;
|
||||
using vtable_type = const void *(const operation, const basic_any &, const void *);
|
||||
|
||||
struct storage_type {
|
||||
alignas(Align) std::byte data[Len + !Len];
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
static constexpr bool in_situ = Len && alignof(Type) <= Align && sizeof(Type) <= Len && std::is_nothrow_move_constructible_v<Type>;
|
||||
|
||||
template<typename Type>
|
||||
static const void *basic_vtable(const operation op, const basic_any &value, const void *other) {
|
||||
static_assert(!std::is_same_v<Type, void> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
|
||||
const Type *element = nullptr;
|
||||
|
||||
if constexpr(in_situ<Type>) {
|
||||
element = value.owner() ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance);
|
||||
} else {
|
||||
element = static_cast<const Type *>(value.instance);
|
||||
}
|
||||
|
||||
switch(op) {
|
||||
case operation::copy:
|
||||
if constexpr(std::is_copy_constructible_v<Type>) {
|
||||
static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*element);
|
||||
}
|
||||
break;
|
||||
case operation::move:
|
||||
if constexpr(in_situ<Type>) {
|
||||
if(value.owner()) {
|
||||
return new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(element))};
|
||||
}
|
||||
}
|
||||
|
||||
return (static_cast<basic_any *>(const_cast<void *>(other))->instance = std::exchange(const_cast<basic_any &>(value).instance, nullptr));
|
||||
case operation::transfer:
|
||||
if constexpr(std::is_move_assignable_v<Type>) {
|
||||
*const_cast<Type *>(element) = std::move(*static_cast<Type *>(const_cast<void *>(other)));
|
||||
return other;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case operation::assign:
|
||||
if constexpr(std::is_copy_assignable_v<Type>) {
|
||||
*const_cast<Type *>(element) = *static_cast<const Type *>(other);
|
||||
return other;
|
||||
}
|
||||
break;
|
||||
case operation::destroy:
|
||||
if constexpr(in_situ<Type>) {
|
||||
element->~Type();
|
||||
} else if constexpr(std::is_array_v<Type>) {
|
||||
delete[] element;
|
||||
} else {
|
||||
delete element;
|
||||
}
|
||||
break;
|
||||
case operation::compare:
|
||||
if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
|
||||
return *element == *static_cast<const Type *>(other) ? other : nullptr;
|
||||
} else {
|
||||
return (element == other) ? other : nullptr;
|
||||
}
|
||||
case operation::get:
|
||||
return element;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename Type, typename... Args>
|
||||
void initialize([[maybe_unused]] Args &&...args) {
|
||||
info = &type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
|
||||
if constexpr(!std::is_void_v<Type>) {
|
||||
vtable = basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
|
||||
|
||||
if constexpr(std::is_lvalue_reference_v<Type>) {
|
||||
static_assert((std::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "Invalid arguments");
|
||||
mode = std::is_const_v<std::remove_reference_t<Type>> ? policy::cref : policy::ref;
|
||||
instance = (std::addressof(args), ...);
|
||||
} else if constexpr(in_situ<std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
if constexpr(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>)) {
|
||||
new(&storage) std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...};
|
||||
} else {
|
||||
new(&storage) std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...);
|
||||
}
|
||||
} else {
|
||||
if constexpr(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>)) {
|
||||
instance = new std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...};
|
||||
} else {
|
||||
instance = new std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
basic_any(const basic_any &other, const policy pol) noexcept
|
||||
: instance{other.data()},
|
||||
info{other.info},
|
||||
vtable{other.vtable},
|
||||
mode{pol} {}
|
||||
|
||||
public:
|
||||
/*! @brief Size of the internal storage. */
|
||||
static constexpr auto length = Len;
|
||||
/*! @brief Alignment requirement. */
|
||||
static constexpr auto alignment = Align;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
constexpr basic_any() noexcept
|
||||
: basic_any{std::in_place_type<void>} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a wrapper by directly initializing the new object.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
explicit basic_any(std::in_place_type_t<Type>, Args &&...args)
|
||||
: instance{},
|
||||
info{},
|
||||
vtable{},
|
||||
mode{policy::owner} {
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a wrapper from a given value.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
*/
|
||||
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
|
||||
basic_any(Type &&value)
|
||||
: basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
basic_any(const basic_any &other)
|
||||
: basic_any{} {
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::copy, other, this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
basic_any(basic_any &&other) noexcept
|
||||
: instance{},
|
||||
info{other.info},
|
||||
vtable{other.vtable},
|
||||
mode{other.mode} {
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::move, other, this);
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Frees the internal storage, whatever it means. */
|
||||
~basic_any() {
|
||||
if(vtable && owner()) {
|
||||
vtable(operation::destroy, *this, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This any object.
|
||||
*/
|
||||
basic_any &operator=(const basic_any &other) {
|
||||
reset();
|
||||
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::copy, other, this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This any object.
|
||||
*/
|
||||
basic_any &operator=(basic_any &&other) noexcept {
|
||||
reset();
|
||||
|
||||
if(other.vtable) {
|
||||
other.vtable(operation::move, other, this);
|
||||
info = other.info;
|
||||
vtable = other.vtable;
|
||||
mode = other.mode;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Value assignment operator.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @param value An instance of an object to use to initialize the wrapper.
|
||||
* @return This any object.
|
||||
*/
|
||||
template<typename Type>
|
||||
std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>, basic_any &>
|
||||
operator=(Type &&value) {
|
||||
emplace<std::decay_t<Type>>(std::forward<Type>(value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the object type if any, `type_id<void>()` otherwise.
|
||||
* @return The object type if any, `type_id<void>()` otherwise.
|
||||
*/
|
||||
[[nodiscard]] const type_info &type() const noexcept {
|
||||
return *info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] const void *data() const noexcept {
|
||||
return vtable ? vtable(operation::get, *this, nullptr) : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @param req Expected type.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] const void *data(const type_info &req) const noexcept {
|
||||
return *info == req ? data() : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data() noexcept {
|
||||
return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an opaque pointer to the contained instance.
|
||||
* @param req Expected type.
|
||||
* @return An opaque pointer the contained instance, if any.
|
||||
*/
|
||||
[[nodiscard]] void *data(const type_info &req) noexcept {
|
||||
return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the contained object by creating a new instance directly.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
void emplace(Args &&...args) {
|
||||
reset();
|
||||
initialize<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a value to the contained object without replacing it.
|
||||
* @param other The value to assign to the contained object.
|
||||
* @return True in case of success, false otherwise.
|
||||
*/
|
||||
bool assign(const basic_any &other) {
|
||||
if(vtable && mode != policy::cref && *info == *other.info) {
|
||||
return (vtable(operation::assign, *this, other.data()) != nullptr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! @copydoc assign */
|
||||
bool assign(basic_any &&other) {
|
||||
if(vtable && mode != policy::cref && *info == *other.info) {
|
||||
if(auto *val = other.data(); val) {
|
||||
return (vtable(operation::transfer, *this, val) != nullptr);
|
||||
} else {
|
||||
return (vtable(operation::assign, *this, std::as_const(other).data()) != nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! @brief Destroys contained object */
|
||||
void reset() {
|
||||
if(vtable && owner()) {
|
||||
vtable(operation::destroy, *this, nullptr);
|
||||
}
|
||||
|
||||
// unnecessary but it helps to detect nasty bugs
|
||||
ENTT_ASSERT((instance = nullptr) == nullptr, "");
|
||||
info = &type_id<void>();
|
||||
vtable = nullptr;
|
||||
mode = policy::owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns false if a wrapper is empty, true otherwise.
|
||||
* @return False if the wrapper is empty, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] explicit operator bool() const noexcept {
|
||||
return vtable != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if two wrappers differ in their content.
|
||||
* @param other Wrapper with which to compare.
|
||||
* @return False if the two objects differ in their content, true otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool operator==(const basic_any &other) const noexcept {
|
||||
if(vtable && *info == *other.info) {
|
||||
return (vtable(operation::compare, *this, other.data()) != nullptr);
|
||||
}
|
||||
|
||||
return (!vtable && !other.vtable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if two wrappers differ in their content.
|
||||
* @param other Wrapper with which to compare.
|
||||
* @return True if the two objects differ in their content, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool operator!=(const basic_any &other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Aliasing constructor.
|
||||
* @return A wrapper that shares a reference to an unmanaged object.
|
||||
*/
|
||||
[[nodiscard]] basic_any as_ref() noexcept {
|
||||
return basic_any{*this, (mode == policy::cref ? policy::cref : policy::ref)};
|
||||
}
|
||||
|
||||
/*! @copydoc as_ref */
|
||||
[[nodiscard]] basic_any as_ref() const noexcept {
|
||||
return basic_any{*this, policy::cref};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a wrapper owns its object, false otherwise.
|
||||
* @return True if the wrapper owns its object, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool owner() const noexcept {
|
||||
return (mode == policy::owner);
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
const void *instance;
|
||||
storage_type storage;
|
||||
};
|
||||
const type_info *info;
|
||||
vtable_type *vtable;
|
||||
policy mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Performs type-safe access to the contained object.
|
||||
* @tparam Type Type to which conversion is required.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Alignment requirement.
|
||||
* @param data Target any object.
|
||||
* @return The element converted to the requested type.
|
||||
*/
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
[[nodiscard]] Type any_cast(const basic_any<Len, Align> &data) noexcept {
|
||||
const auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(*instance);
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
[[nodiscard]] Type any_cast(basic_any<Len, Align> &data) noexcept {
|
||||
// forces const on non-reference types to make them work also with wrappers for const references
|
||||
auto *const instance = any_cast<std::remove_reference_t<const Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(*instance);
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
[[nodiscard]] Type any_cast(basic_any<Len, Align> &&data) noexcept {
|
||||
if constexpr(std::is_copy_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
if(auto *const instance = any_cast<std::remove_reference_t<Type>>(&data); instance) {
|
||||
return static_cast<Type>(std::move(*instance));
|
||||
} else {
|
||||
return any_cast<Type>(data);
|
||||
}
|
||||
} else {
|
||||
auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
|
||||
ENTT_ASSERT(instance, "Invalid instance");
|
||||
return static_cast<Type>(std::move(*instance));
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
[[nodiscard]] const Type *any_cast(const basic_any<Len, Align> *data) noexcept {
|
||||
const auto &info = type_id<std::remove_cv_t<Type>>();
|
||||
return static_cast<const Type *>(data->data(info));
|
||||
}
|
||||
|
||||
/*! @copydoc any_cast */
|
||||
template<typename Type, std::size_t Len, std::size_t Align>
|
||||
[[nodiscard]] Type *any_cast(basic_any<Len, Align> *data) noexcept {
|
||||
if constexpr(std::is_const_v<Type>) {
|
||||
// last attempt to make wrappers for const references return their values
|
||||
return any_cast<Type>(&std::as_const(*data));
|
||||
} else {
|
||||
const auto &info = type_id<std::remove_cv_t<Type>>();
|
||||
return static_cast<Type *>(data->data(info));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a wrapper from a given type, passing it all arguments.
|
||||
* @tparam Type Type of object to use to initialize the wrapper.
|
||||
* @tparam Len Size of the storage reserved for the small buffer optimization.
|
||||
* @tparam Align Optional alignment requirement.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
* @return A properly initialized wrapper for an object of the given type.
|
||||
*/
|
||||
template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args>
|
||||
[[nodiscard]] 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>
|
||||
[[nodiscard]] basic_any<Len, Align> forward_as_any(Type &&value) {
|
||||
return basic_any<Len, Align>{std::in_place_type<Type &&>, std::forward<Type>(value)};
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
30
src/entt/core/attribute.h
Normal file
30
src/entt/core/attribute.h
Normal file
@@ -0,0 +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
|
||||
#endif
|
||||
|
||||
#ifndef ENTT_API
|
||||
# if defined ENTT_API_EXPORT
|
||||
# define ENTT_API ENTT_EXPORT
|
||||
# elif defined ENTT_API_IMPORT
|
||||
# define ENTT_API ENTT_IMPORT
|
||||
# else /* No API */
|
||||
# define ENTT_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
279
src/entt/core/compressed_pair.hpp
Normal file
279
src/entt/core/compressed_pair.hpp
Normal file
@@ -0,0 +1,279 @@
|
||||
#ifndef ENTT_CORE_COMPRESSED_PAIR_HPP
|
||||
#define ENTT_CORE_COMPRESSED_PAIR_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, std::size_t, typename = void>
|
||||
struct compressed_pair_element {
|
||||
using reference = Type &;
|
||||
using const_reference = const Type &;
|
||||
|
||||
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<Type>>>
|
||||
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<Type>)
|
||||
: value{} {}
|
||||
|
||||
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
|
||||
constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<Type, Arg>)
|
||||
: value{std::forward<Arg>(arg)} {}
|
||||
|
||||
template<typename... Args, std::size_t... Index>
|
||||
constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<Type, Args...>)
|
||||
: value{std::forward<Args>(std::get<Index>(args))...} {}
|
||||
|
||||
[[nodiscard]] constexpr reference get() noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_reference get() const noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
Type value;
|
||||
};
|
||||
|
||||
template<typename Type, std::size_t Tag>
|
||||
struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Type>>>: Type {
|
||||
using reference = Type &;
|
||||
using const_reference = const Type &;
|
||||
using base_type = Type;
|
||||
|
||||
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<base_type>>>
|
||||
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<base_type>)
|
||||
: base_type{} {}
|
||||
|
||||
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
|
||||
constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<base_type, Arg>)
|
||||
: base_type{std::forward<Arg>(arg)} {}
|
||||
|
||||
template<typename... Args, std::size_t... Index>
|
||||
constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<base_type, Args...>)
|
||||
: base_type{std::forward<Args>(std::get<Index>(args))...} {}
|
||||
|
||||
[[nodiscard]] constexpr reference get() noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const_reference get() const noexcept {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief A compressed pair.
|
||||
*
|
||||
* A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to
|
||||
* reduce its final size to a minimum.
|
||||
*
|
||||
* @tparam First The type of the first element that the pair stores.
|
||||
* @tparam Second The type of the second element that the pair stores.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
class compressed_pair final
|
||||
: internal::compressed_pair_element<First, 0u>,
|
||||
internal::compressed_pair_element<Second, 1u> {
|
||||
using first_base = internal::compressed_pair_element<First, 0u>;
|
||||
using second_base = internal::compressed_pair_element<Second, 1u>;
|
||||
|
||||
public:
|
||||
/*! @brief The type of the first element that the pair stores. */
|
||||
using first_type = First;
|
||||
/*! @brief The type of the second element that the pair stores. */
|
||||
using second_type = Second;
|
||||
|
||||
/**
|
||||
* @brief Default constructor, conditionally enabled.
|
||||
*
|
||||
* This constructor is only available when the types that the pair stores
|
||||
* are both at least default constructible.
|
||||
*
|
||||
* @tparam Dummy Dummy template parameter used for internal purposes.
|
||||
*/
|
||||
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>>
|
||||
constexpr compressed_pair() noexcept(std::is_nothrow_default_constructible_v<first_base> &&std::is_nothrow_default_constructible_v<second_base>)
|
||||
: first_base{},
|
||||
second_base{} {}
|
||||
|
||||
/**
|
||||
* @brief Copy constructor.
|
||||
* @param other The instance to copy from.
|
||||
*/
|
||||
constexpr compressed_pair(const compressed_pair &other) noexcept(std::is_nothrow_copy_constructible_v<first_base> &&std::is_nothrow_copy_constructible_v<second_base>) = default;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
constexpr compressed_pair(compressed_pair &&other) noexcept(std::is_nothrow_move_constructible_v<first_base> &&std::is_nothrow_move_constructible_v<second_base>) = default;
|
||||
|
||||
/**
|
||||
* @brief Constructs a pair from its values.
|
||||
* @tparam Arg Type of value to use to initialize the first element.
|
||||
* @tparam Other Type of value to use to initialize the second element.
|
||||
* @param arg Value to use to initialize the first element.
|
||||
* @param other Value to use to initialize the second element.
|
||||
*/
|
||||
template<typename Arg, typename Other>
|
||||
constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(std::is_nothrow_constructible_v<first_base, Arg> &&std::is_nothrow_constructible_v<second_base, Other>)
|
||||
: first_base{std::forward<Arg>(arg)},
|
||||
second_base{std::forward<Other>(other)} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a pair by forwarding the arguments to its parts.
|
||||
* @tparam Args Types of arguments to use to initialize the first element.
|
||||
* @tparam Other Types of arguments to use to initialize the second element.
|
||||
* @param args Arguments to use to initialize the first element.
|
||||
* @param other Arguments to use to initialize the second element.
|
||||
*/
|
||||
template<typename... Args, typename... Other>
|
||||
constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other) noexcept(std::is_nothrow_constructible_v<first_base, Args...> &&std::is_nothrow_constructible_v<second_base, Other...>)
|
||||
: first_base{std::move(args), std::index_sequence_for<Args...>{}},
|
||||
second_base{std::move(other), std::index_sequence_for<Other...>{}} {}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator.
|
||||
* @param other The instance to copy from.
|
||||
* @return This compressed pair object.
|
||||
*/
|
||||
constexpr compressed_pair &operator=(const compressed_pair &other) noexcept(std::is_nothrow_copy_assignable_v<first_base> &&std::is_nothrow_copy_assignable_v<second_base>) = default;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This compressed pair object.
|
||||
*/
|
||||
constexpr compressed_pair &operator=(compressed_pair &&other) noexcept(std::is_nothrow_move_assignable_v<first_base> &&std::is_nothrow_move_assignable_v<second_base>) = default;
|
||||
|
||||
/**
|
||||
* @brief Returns the first element that a pair stores.
|
||||
* @return The first element that a pair stores.
|
||||
*/
|
||||
[[nodiscard]] constexpr first_type &first() noexcept {
|
||||
return static_cast<first_base &>(*this).get();
|
||||
}
|
||||
|
||||
/*! @copydoc first */
|
||||
[[nodiscard]] constexpr const first_type &first() const noexcept {
|
||||
return static_cast<const first_base &>(*this).get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the second element that a pair stores.
|
||||
* @return The second element that a pair stores.
|
||||
*/
|
||||
[[nodiscard]] constexpr second_type &second() noexcept {
|
||||
return static_cast<second_base &>(*this).get();
|
||||
}
|
||||
|
||||
/*! @copydoc second */
|
||||
[[nodiscard]] constexpr const second_type &second() const noexcept {
|
||||
return static_cast<const second_base &>(*this).get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Swaps two compressed pair objects.
|
||||
* @param other The compressed pair to swap with.
|
||||
*/
|
||||
constexpr void swap(compressed_pair &other) noexcept(std::is_nothrow_swappable_v<first_type> &&std::is_nothrow_swappable_v<second_type>) {
|
||||
using std::swap;
|
||||
swap(first(), other.first());
|
||||
swap(second(), other.second());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Extracts an element from the compressed pair.
|
||||
* @tparam Index An integer value that is either 0 or 1.
|
||||
* @return Returns a reference to the first element if `Index` is 0 and a
|
||||
* reference to the second element if `Index` is 1.
|
||||
*/
|
||||
template<std::size_t Index>
|
||||
constexpr decltype(auto) get() noexcept {
|
||||
if constexpr(Index == 0u) {
|
||||
return first();
|
||||
} else {
|
||||
static_assert(Index == 1u, "Index out of bounds");
|
||||
return second();
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc get */
|
||||
template<std::size_t Index>
|
||||
constexpr decltype(auto) get() const noexcept {
|
||||
if constexpr(Index == 0u) {
|
||||
return first();
|
||||
} else {
|
||||
static_assert(Index == 1u, "Index out of bounds");
|
||||
return second();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Type Type of value to use to initialize the first element.
|
||||
* @tparam Other Type of value to use to initialize the second element.
|
||||
*/
|
||||
template<typename Type, typename Other>
|
||||
compressed_pair(Type &&, Other &&) -> compressed_pair<std::decay_t<Type>, std::decay_t<Other>>;
|
||||
|
||||
/**
|
||||
* @brief Swaps two compressed pair objects.
|
||||
* @tparam First The type of the first element that the pairs store.
|
||||
* @tparam Second The type of the second element that the pairs store.
|
||||
* @param lhs A valid compressed pair object.
|
||||
* @param rhs A valid compressed pair object.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
inline constexpr void swap(compressed_pair<First, Second> &lhs, compressed_pair<First, Second> &rhs) {
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
// disable structured binding support for clang 6, it messes when specializing tuple_size
|
||||
#if !defined __clang_major__ || __clang_major__ > 6
|
||||
namespace std {
|
||||
|
||||
/**
|
||||
* @brief `std::tuple_size` specialization for `compressed_pair`s.
|
||||
* @tparam First The type of the first element that the pair stores.
|
||||
* @tparam Second The type of the second element that the pair stores.
|
||||
*/
|
||||
template<typename First, typename Second>
|
||||
struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_t, 2u> {};
|
||||
|
||||
/**
|
||||
* @brief `std::tuple_element` specialization for `compressed_pair`s.
|
||||
* @tparam Index The index of the type to return.
|
||||
* @tparam First The type of the first element that the pair stores.
|
||||
* @tparam Second The type of the second element that the pair stores.
|
||||
*/
|
||||
template<size_t Index, typename First, typename Second>
|
||||
struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {
|
||||
static_assert(Index < 2u, "Index out of bounds");
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
#endif
|
||||
|
||||
#endif
|
||||
97
src/entt/core/enum.hpp
Normal file
97
src/entt/core/enum.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
#ifndef ENTT_CORE_ENUM_HPP
|
||||
#define ENTT_CORE_ENUM_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Enable bitmask support for enum classes.
|
||||
* @tparam Type The enum type for which to enable bitmask support.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct enum_as_bitmask: std::false_type {};
|
||||
|
||||
/*! @copydoc enum_as_bitmask */
|
||||
template<typename Type>
|
||||
struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>: std::is_enum<Type> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The enum class type for which to enable bitmask support.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
/**
|
||||
* @brief Operator available for enums for which bitmask support is enabled.
|
||||
* @tparam Type Enum class type.
|
||||
* @param lhs The first value to use.
|
||||
* @param rhs The second value to use.
|
||||
* @return The result of invoking the operator on the underlying types of the
|
||||
* two values provided.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator|(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator&(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator^(const Type lhs, const Type rhs) noexcept {
|
||||
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Operator available for enums for which bitmask support is enabled.
|
||||
* @tparam Type Enum class type.
|
||||
* @param value The value to use.
|
||||
* @return The result of invoking the operator on the underlying types of the
|
||||
* value provided.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
|
||||
operator~(const Type value) noexcept {
|
||||
return static_cast<Type>(~static_cast<std::underlying_type_t<Type>>(value));
|
||||
}
|
||||
|
||||
/*! @copydoc operator~ */
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, bool>
|
||||
operator!(const Type value) noexcept {
|
||||
return !static_cast<std::underlying_type_t<Type>>(value);
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
|
||||
operator|=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs | rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
|
||||
operator&=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs & rhs));
|
||||
}
|
||||
|
||||
/*! @copydoc operator| */
|
||||
template<typename Type>
|
||||
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
|
||||
operator^=(Type &lhs, const Type rhs) noexcept {
|
||||
return (lhs = (lhs ^ rhs));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,14 +1,11 @@
|
||||
#ifndef ENTT_CORE_FAMILY_HPP
|
||||
#define ENTT_CORE_FAMILY_HPP
|
||||
|
||||
|
||||
#include<type_traits>
|
||||
#include<cstddef>
|
||||
|
||||
#include "../config/config.h"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dynamic identifier generator.
|
||||
*
|
||||
@@ -17,34 +14,19 @@ namespace entt {
|
||||
* identifiers.
|
||||
*/
|
||||
template<typename...>
|
||||
class Family {
|
||||
static std::size_t identifier() noexcept {
|
||||
static std::size_t value = 0;
|
||||
return value++;
|
||||
}
|
||||
|
||||
template<typename...>
|
||||
static std::size_t family() noexcept {
|
||||
static const std::size_t value = identifier();
|
||||
return value;
|
||||
}
|
||||
class family {
|
||||
inline static ENTT_MAYBE_ATOMIC(id_type) identifier{};
|
||||
|
||||
public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using family_type = std::size_t;
|
||||
using value_type = id_type;
|
||||
|
||||
/**
|
||||
* @brief Returns an unique identifier for the given type.
|
||||
* @return Statically generated unique identifier for the given type.
|
||||
*/
|
||||
/*! @brief Statically generated unique identifier for the given type. */
|
||||
template<typename... Type>
|
||||
static family_type type() noexcept {
|
||||
return family<std::decay_t<Type>...>();
|
||||
}
|
||||
// at the time I'm writing, clang crashes during compilation if auto is used instead of family_type
|
||||
inline static const value_type value = identifier++;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_CORE_FAMILY_HPP
|
||||
#endif
|
||||
|
||||
20
src/entt/core/fwd.hpp
Normal file
20
src/entt/core/fwd.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef ENTT_CORE_FWD_HPP
|
||||
#define ENTT_CORE_FWD_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(double[2])>
|
||||
class basic_any;
|
||||
|
||||
/*! @brief Alias declaration for type identifiers. */
|
||||
using id_type = ENTT_ID_TYPE;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using any = basic_any<>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,109 +1,334 @@
|
||||
#ifndef ENTT_CORE_HASHED_STRING_HPP
|
||||
#define ENTT_CORE_HASHED_STRING_HPP
|
||||
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#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;
|
||||
static constexpr std::uint32_t offset = 2166136261;
|
||||
static constexpr std::uint32_t prime = 16777619;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct fnv1a_traits<std::uint64_t> {
|
||||
using type = std::uint64_t;
|
||||
static constexpr std::uint64_t offset = 14695981039346656037ull;
|
||||
static constexpr std::uint64_t prime = 1099511628211ull;
|
||||
};
|
||||
|
||||
template<typename Char>
|
||||
struct basic_hashed_string {
|
||||
using value_type = Char;
|
||||
using size_type = std::size_t;
|
||||
using hash_type = id_type;
|
||||
|
||||
const value_type *repr;
|
||||
size_type length;
|
||||
hash_type hash;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* @brief Zero overhead resource identifier.
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Zero overhead unique identifier.
|
||||
*
|
||||
* A hashed string is a compile-time tool that allows users to use
|
||||
* human-readable identifers in the codebase while using their numeric
|
||||
* human-readable identifiers in the codebase while using their numeric
|
||||
* counterparts at runtime.<br/>
|
||||
* Because of that, a hashed string can also be used in constant expressions if
|
||||
* required.
|
||||
*
|
||||
* @warning
|
||||
* This class doesn't take ownership of user-supplied strings nor does it make a
|
||||
* copy of them.
|
||||
*
|
||||
* @tparam Char Character type.
|
||||
*/
|
||||
class HashedString final {
|
||||
struct ConstCharWrapper final {
|
||||
template<typename Char>
|
||||
class basic_hashed_string: internal::basic_hashed_string<Char> {
|
||||
using base_type = internal::basic_hashed_string<Char>;
|
||||
using traits_type = internal::fnv1a_traits<id_type>;
|
||||
|
||||
struct const_wrapper {
|
||||
// non-explicit constructor on purpose
|
||||
constexpr ConstCharWrapper(const char *str) noexcept: str{str} {}
|
||||
const char *str;
|
||||
constexpr const_wrapper(const Char *str) noexcept
|
||||
: repr{str} {}
|
||||
|
||||
const Char *repr;
|
||||
};
|
||||
|
||||
static constexpr std::uint64_t offset = 14695981039346656037ull;
|
||||
static constexpr std::uint64_t prime = 1099511628211ull;
|
||||
// Fowler–Noll–Vo hash function v. 1a - the good
|
||||
[[nodiscard]] static constexpr auto helper(const Char *str) noexcept {
|
||||
base_type base{str, 0u, traits_type::offset};
|
||||
|
||||
for(; str[base.length]; ++base.length) {
|
||||
base.hash = (base.hash ^ static_cast<traits_type::type>(str[base.length])) * traits_type::prime;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
// Fowler–Noll–Vo hash function v. 1a - the good
|
||||
static constexpr std::uint64_t helper(std::uint64_t partial, const char *str) noexcept {
|
||||
return str[0] == 0 ? partial : helper((partial^str[0])*prime, str+1);
|
||||
[[nodiscard]] static constexpr auto helper(const Char *str, const std::size_t len) noexcept {
|
||||
base_type base{str, len, traits_type::offset};
|
||||
|
||||
for(size_type pos{}; pos < len; ++pos) {
|
||||
base.hash = (base.hash ^ static_cast<traits_type::type>(str[pos])) * traits_type::prime;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Character type. */
|
||||
using value_type = typename base_type::value_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using hash_type = std::uint64_t;
|
||||
using size_type = typename base_type::size_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using hash_type = typename base_type::hash_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs a hashed string from an array of const chars.
|
||||
*
|
||||
* Forcing template resolution avoids implicit conversions. An
|
||||
* human-readable identifier can be anything but a plain, old bunch of
|
||||
* characters.<br/>
|
||||
* Example of use:
|
||||
* @code{.cpp}
|
||||
* HashedString sh{"my.png"};
|
||||
* @endcode
|
||||
*
|
||||
* @tparam N Number of characters of the identifier.
|
||||
* @param str Human-readable identifer.
|
||||
* @brief Returns directly the numeric representation of a string view.
|
||||
* @param str Human-readable identifier.
|
||||
* @param len Length of the string to hash.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
template <std::size_t N>
|
||||
constexpr HashedString(const char (&str)[N]) noexcept
|
||||
: hash{helper(offset, str)}, str{str}
|
||||
{}
|
||||
[[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept {
|
||||
return basic_hashed_string{str, len};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns directly the numeric representation of a string.
|
||||
* @tparam N Number of characters of the identifier.
|
||||
* @param str Human-readable identifier.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
[[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) noexcept {
|
||||
return basic_hashed_string{str};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns directly the numeric representation of a string.
|
||||
* @param wrapper Helps achieving the purpose by relying on overloading.
|
||||
* @return The numeric representation of the string.
|
||||
*/
|
||||
[[nodiscard]] static constexpr hash_type value(const_wrapper wrapper) noexcept {
|
||||
return basic_hashed_string{wrapper};
|
||||
}
|
||||
|
||||
/*! @brief Constructs an empty hashed string. */
|
||||
constexpr basic_hashed_string() noexcept
|
||||
: base_type{} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a hashed string from a string view.
|
||||
* @param str Human-readable identifier.
|
||||
* @param len Length of the string to hash.
|
||||
*/
|
||||
constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept
|
||||
: base_type{helper(str, len)} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a hashed string from an array of const characters.
|
||||
* @tparam N Number of characters of the identifier.
|
||||
* @param str Human-readable identifier.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
constexpr basic_hashed_string(const value_type (&str)[N]) noexcept
|
||||
: base_type{helper(str)} {}
|
||||
|
||||
/**
|
||||
* @brief Explicit constructor on purpose to avoid constructing a hashed
|
||||
* string directly from a `const char *`.
|
||||
* 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 HashedString(ConstCharWrapper wrapper) noexcept
|
||||
: hash{helper(offset, wrapper.str)}, str{wrapper.str}
|
||||
{}
|
||||
explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept
|
||||
: base_type{helper(wrapper.repr)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns the size a hashed string.
|
||||
* @return The size of the hashed string.
|
||||
*/
|
||||
[[nodiscard]] constexpr size_type size() const noexcept {
|
||||
return base_type::length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the human-readable representation of a hashed string.
|
||||
* @return The string used to initialize the instance.
|
||||
* @return The string used to initialize the hashed string.
|
||||
*/
|
||||
constexpr operator const char *() const noexcept { return str; }
|
||||
[[nodiscard]] constexpr const value_type *data() const noexcept {
|
||||
return base_type::repr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the numeric representation of a hashed string.
|
||||
* @return The numeric representation of the instance.
|
||||
* @return The numeric representation of the hashed string.
|
||||
*/
|
||||
constexpr operator hash_type() const noexcept { return hash; }
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @param other Hashed string with which to compare.
|
||||
* @return True if the two hashed strings are identical, false otherwise.
|
||||
*/
|
||||
constexpr bool operator==(const HashedString &other) const noexcept {
|
||||
return hash == other.hash;
|
||||
[[nodiscard]] constexpr hash_type value() const noexcept {
|
||||
return base_type::hash;
|
||||
}
|
||||
|
||||
private:
|
||||
const hash_type hash;
|
||||
const char *str;
|
||||
/*! @copydoc data */
|
||||
[[nodiscard]] constexpr operator const value_type *() const noexcept {
|
||||
return data();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the numeric representation of a hashed string.
|
||||
* @return The numeric representation of the hashed string.
|
||||
*/
|
||||
[[nodiscard]] constexpr operator hash_type() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Char Character type.
|
||||
* @param str Human-readable identifier.
|
||||
* @param len Length of the string to hash.
|
||||
*/
|
||||
template<typename Char>
|
||||
basic_hashed_string(const Char *str, const std::size_t len) -> basic_hashed_string<Char>;
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Char Character type.
|
||||
* @tparam N Number of characters of the identifier.
|
||||
* @param str Human-readable identifier.
|
||||
*/
|
||||
template<typename Char, std::size_t N>
|
||||
basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>;
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the two hashed strings are identical, false otherwise.
|
||||
*/
|
||||
constexpr bool operator!=(const HashedString &lhs, const HashedString &rhs) noexcept {
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator==(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return lhs.value() == rhs.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the two hashed strings differ, false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is less than the second, false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator<(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return lhs.value() < rhs.value();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is less than or equal to the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator<=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
#endif // ENTT_CORE_HASHED_STRING_HPP
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is greater than the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator>(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two hashed strings.
|
||||
* @tparam Char Character type.
|
||||
* @param lhs A valid hashed string.
|
||||
* @param rhs A valid hashed string.
|
||||
* @return True if the first element is greater than or equal to the second,
|
||||
* false otherwise.
|
||||
*/
|
||||
template<typename Char>
|
||||
[[nodiscard]] constexpr bool operator>=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
/*! @brief Aliases for common character types. */
|
||||
using hashed_string = basic_hashed_string<char>;
|
||||
|
||||
/*! @brief Aliases for common character types. */
|
||||
using hashed_wstring = basic_hashed_string<wchar_t>;
|
||||
|
||||
inline namespace literals {
|
||||
|
||||
/**
|
||||
* @brief User defined literal for hashed strings.
|
||||
* @param str The literal without its suffix.
|
||||
* @return A properly initialized hashed string.
|
||||
*/
|
||||
[[nodiscard]] constexpr hashed_string operator"" _hs(const char *str, std::size_t) noexcept {
|
||||
return hashed_string{str};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief User defined literal for hashed wstrings.
|
||||
* @param str The literal without its suffix.
|
||||
* @return A properly initialized hashed wstring.
|
||||
*/
|
||||
[[nodiscard]] constexpr hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) noexcept {
|
||||
return hashed_wstring{str};
|
||||
}
|
||||
|
||||
} // namespace literals
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,96 +1,35 @@
|
||||
#ifndef ENTT_CORE_IDENT_HPP
|
||||
#define ENTT_CORE_IDENT_HPP
|
||||
|
||||
|
||||
#include<type_traits>
|
||||
#include<cstddef>
|
||||
#include<utility>
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "fwd.hpp"
|
||||
#include "type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
template<typename... Types>
|
||||
struct Identifier final: Identifier<Types>... {
|
||||
using identifier_type = std::size_t;
|
||||
|
||||
template<std::size_t... Indexes>
|
||||
constexpr Identifier(std::index_sequence<Indexes...>)
|
||||
: Identifier<Types>{std::index_sequence<Indexes>{}}...
|
||||
{}
|
||||
|
||||
template<typename Type>
|
||||
constexpr std::size_t get() const {
|
||||
return Identifier<std::decay_t<Type>>::get();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename Type>
|
||||
struct Identifier<Type> {
|
||||
using identifier_type = std::size_t;
|
||||
|
||||
template<std::size_t Index>
|
||||
constexpr Identifier(std::index_sequence<Index>)
|
||||
: index{Index}
|
||||
{}
|
||||
|
||||
constexpr std::size_t get() const {
|
||||
return index;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::size_t index;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Types identifers.
|
||||
*
|
||||
* Variable template used to generate identifiers at compile-time for the given
|
||||
* types. Use the `constexpr` `get` member function to know what's the
|
||||
* identifier associated to the specific type.
|
||||
*
|
||||
* @note
|
||||
* Identifiers are constant expression and can be used in any context where such
|
||||
* an expression is required. As an example:
|
||||
* @code{.cpp}
|
||||
* constexpr auto identifiers = entt::ident<AType, AnotherType>;
|
||||
*
|
||||
* switch(aTypeIdentifier) {
|
||||
* case identifers.get<AType>():
|
||||
* // ...
|
||||
* break;
|
||||
* case identifers.get<AnotherType>():
|
||||
* // ...
|
||||
* break;
|
||||
* default:
|
||||
* // ...
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @note
|
||||
* In case of single type list, `get` isn't a member function template:
|
||||
* @code{.cpp}
|
||||
* func(std::integral_constant<
|
||||
* entt::ident<AType>::identifier_type,
|
||||
* entt::ident<AType>::get()
|
||||
* >{});
|
||||
* @endcode
|
||||
*
|
||||
* @tparam Types List of types for which to generate identifiers.
|
||||
* @brief Type integral identifiers.
|
||||
* @tparam Type List of types for which to generate identifiers.
|
||||
*/
|
||||
template<typename... Types>
|
||||
constexpr auto ident = Identifier<std::decay_t<Types>...>{std::make_index_sequence<sizeof...(Types)>{}};
|
||||
template<typename... Type>
|
||||
class ident {
|
||||
template<typename Curr, std::size_t... Index>
|
||||
[[nodiscard]] static constexpr id_type get(std::index_sequence<Index...>) noexcept {
|
||||
static_assert((std::is_same_v<Curr, Type> || ...), "Invalid type");
|
||||
return (0 + ... + (std::is_same_v<Curr, type_list_element_t<Index, type_list<std::decay_t<Type>...>>> ? id_type{Index} : id_type{}));
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = id_type;
|
||||
|
||||
}
|
||||
/*! @brief Statically generated unique identifier for the given type. */
|
||||
template<typename Curr>
|
||||
static constexpr value_type value = get<std::decay_t<Curr>>(std::index_sequence_for<Type...>{});
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif // ENTT_CORE_IDENT_HPP
|
||||
#endif
|
||||
|
||||
197
src/entt/core/iterator.hpp
Normal file
197
src/entt/core/iterator.hpp
Normal file
@@ -0,0 +1,197 @@
|
||||
#ifndef ENTT_CORE_ITERATOR_HPP
|
||||
#define ENTT_CORE_ITERATOR_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Helper type to use as pointer with input iterators.
|
||||
* @tparam Type of wrapped value.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct input_iterator_pointer final {
|
||||
/*! @brief Value type. */
|
||||
using value_type = Type;
|
||||
/*! @brief Pointer type. */
|
||||
using pointer = Type *;
|
||||
/*! @brief Reference type. */
|
||||
using reference = Type &;
|
||||
|
||||
/**
|
||||
* @brief Constructs a proxy object by move.
|
||||
* @param val Value to use to initialize the proxy object.
|
||||
*/
|
||||
constexpr input_iterator_pointer(value_type &&val) noexcept(std::is_nothrow_move_constructible_v<value_type>)
|
||||
: value{std::move(val)} {}
|
||||
|
||||
/**
|
||||
* @brief Access operator for accessing wrapped values.
|
||||
* @return A pointer to the wrapped value.
|
||||
*/
|
||||
[[nodiscard]] constexpr pointer operator->() noexcept {
|
||||
return std::addressof(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dereference operator for accessing wrapped values.
|
||||
* @return A reference to the wrapped value.
|
||||
*/
|
||||
[[nodiscard]] constexpr reference operator*() noexcept {
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
Type value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Plain iota iterator (waiting for C++20).
|
||||
* @tparam Type Value type.
|
||||
*/
|
||||
template<typename Type>
|
||||
class iota_iterator final {
|
||||
static_assert(std::is_integral_v<Type>, "Not an integral type");
|
||||
|
||||
public:
|
||||
/*! @brief Value type, likely an integral one. */
|
||||
using value_type = Type;
|
||||
/*! @brief Invalid pointer type. */
|
||||
using pointer = void;
|
||||
/*! @brief Non-reference type, same as value type. */
|
||||
using reference = value_type;
|
||||
/*! @brief Difference type. */
|
||||
using difference_type = std::ptrdiff_t;
|
||||
/*! @brief Iterator category. */
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
constexpr iota_iterator() noexcept
|
||||
: current{} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an iota iterator from a given value.
|
||||
* @param init The initial value assigned to the iota iterator.
|
||||
*/
|
||||
constexpr iota_iterator(const value_type init) noexcept
|
||||
: current{init} {}
|
||||
|
||||
/**
|
||||
* @brief Pre-increment operator.
|
||||
* @return This iota iterator.
|
||||
*/
|
||||
constexpr iota_iterator &operator++() noexcept {
|
||||
return ++current, *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Post-increment operator.
|
||||
* @return This iota iterator.
|
||||
*/
|
||||
constexpr iota_iterator operator++(int) noexcept {
|
||||
iota_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Dereference operator.
|
||||
* @return The underlying value.
|
||||
*/
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return current;
|
||||
}
|
||||
|
||||
private:
|
||||
value_type current;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Comparison operator.
|
||||
* @tparam Type Value type of the iota iterator.
|
||||
* @param lhs A properly initialized iota iterator.
|
||||
* @param rhs A properly initialized iota iterator.
|
||||
* @return True if the two iterators are identical, false otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr bool operator==(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
|
||||
return *lhs == *rhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Comparison operator.
|
||||
* @tparam Type Value type of the iota iterator.
|
||||
* @param lhs A properly initialized iota iterator.
|
||||
* @param rhs A properly initialized iota iterator.
|
||||
* @return True if the two iterators differ, false otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr bool operator!=(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility class to create an iterable object from a pair of iterators.
|
||||
* @tparam It Type of iterator.
|
||||
* @tparam Sentinel Type of sentinel.
|
||||
*/
|
||||
template<typename It, typename Sentinel = It>
|
||||
struct iterable_adaptor final {
|
||||
/*! @brief Value type. */
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
/*! @brief Iterator type. */
|
||||
using iterator = It;
|
||||
/*! @brief Sentinel type. */
|
||||
using sentinel = Sentinel;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
constexpr iterable_adaptor() noexcept(std::is_nothrow_default_constructible_v<iterator> &&std::is_nothrow_default_constructible_v<sentinel>)
|
||||
: first{},
|
||||
last{} {}
|
||||
|
||||
/**
|
||||
* @brief Creates an iterable object from a pair of iterators.
|
||||
* @param from Begin iterator.
|
||||
* @param to End iterator.
|
||||
*/
|
||||
constexpr iterable_adaptor(iterator from, sentinel to) noexcept(std::is_nothrow_move_constructible_v<iterator> &&std::is_nothrow_move_constructible_v<sentinel>)
|
||||
: first{std::move(from)},
|
||||
last{std::move(to)} {}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the beginning.
|
||||
* @return An iterator to the first element of the range.
|
||||
*/
|
||||
[[nodiscard]] constexpr iterator begin() const noexcept {
|
||||
return first;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the end.
|
||||
* @return An iterator to the element following the last element of the
|
||||
* range.
|
||||
*/
|
||||
[[nodiscard]] constexpr sentinel end() const noexcept {
|
||||
return last;
|
||||
}
|
||||
|
||||
/*! @copydoc begin */
|
||||
[[nodiscard]] constexpr iterator cbegin() const noexcept {
|
||||
return begin();
|
||||
}
|
||||
|
||||
/*! @copydoc end */
|
||||
[[nodiscard]] constexpr sentinel cend() const noexcept {
|
||||
return end();
|
||||
}
|
||||
|
||||
private:
|
||||
It first;
|
||||
Sentinel last;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
289
src/entt/core/memory.hpp
Normal file
289
src/entt/core/memory.hpp
Normal file
@@ -0,0 +1,289 @@
|
||||
#ifndef ENTT_CORE_MEMORY_HPP
|
||||
#define ENTT_CORE_MEMORY_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Checks whether a value is a power of two or not.
|
||||
* @param value A value that may or may not be a power of two.
|
||||
* @return True if the value is a power of two, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr bool is_power_of_two(const std::size_t value) noexcept {
|
||||
return value && ((value & (value - 1)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the smallest power of two greater than or equal to a value.
|
||||
* @param value The value to use.
|
||||
* @return The smallest power of two greater than or equal to the given value.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr std::size_t next_power_of_two(const std::size_t value) noexcept {
|
||||
ENTT_ASSERT_CONSTEXPR(value < (std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)), "Numeric limits exceeded");
|
||||
std::size_t curr = value - (value != 0u);
|
||||
|
||||
for(int next = 1; next < std::numeric_limits<std::size_t>::digits; next = next * 2) {
|
||||
curr |= curr >> next;
|
||||
}
|
||||
|
||||
return ++curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fast module utility function (powers of two only).
|
||||
* @param value A value for which to calculate the modulus.
|
||||
* @param mod _Modulus_, it must be a power of two.
|
||||
* @return The common remainder.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) noexcept {
|
||||
ENTT_ASSERT_CONSTEXPR(is_power_of_two(mod), "Value must be a power of two");
|
||||
return value & (mod - 1u);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
|
||||
* @tparam Type Pointer type.
|
||||
* @param ptr Fancy or raw pointer.
|
||||
* @return A raw pointer that represents the address of the original pointer.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto to_address(Type &&ptr) noexcept {
|
||||
if constexpr(std::is_pointer_v<std::decay_t<Type>>) {
|
||||
return ptr;
|
||||
} else {
|
||||
return to_address(std::forward<Type>(ptr).operator->());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to design allocation-aware containers.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param lhs A valid allocator.
|
||||
* @param rhs Another valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
|
||||
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
|
||||
lhs = rhs;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to design allocation-aware containers.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param lhs A valid allocator.
|
||||
* @param rhs Another valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
|
||||
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
|
||||
lhs = std::move(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to design allocation-aware containers.
|
||||
* @tparam Allocator Type of allocator.
|
||||
* @param lhs A valid allocator.
|
||||
* @param rhs Another valid allocator.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
|
||||
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
|
||||
using std::swap;
|
||||
swap(lhs, rhs);
|
||||
} else {
|
||||
ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deleter for allocator-aware unique pointers (waiting for C++20).
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Allocator>
|
||||
struct allocation_deleter: private Allocator {
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Pointer type. */
|
||||
using pointer = typename std::allocator_traits<Allocator>::pointer;
|
||||
|
||||
/**
|
||||
* @brief Inherited constructors.
|
||||
* @param alloc The allocator to use.
|
||||
*/
|
||||
constexpr allocation_deleter(const allocator_type &alloc) noexcept(std::is_nothrow_copy_constructible_v<allocator_type>)
|
||||
: Allocator{alloc} {}
|
||||
|
||||
/**
|
||||
* @brief Destroys the pointed object and deallocates its memory.
|
||||
* @param ptr A valid pointer to an object of the given type.
|
||||
*/
|
||||
constexpr void operator()(pointer ptr) noexcept(std::is_nothrow_destructible_v<typename allocator_type::value_type>) {
|
||||
using alloc_traits = std::allocator_traits<Allocator>;
|
||||
alloc_traits::destroy(*this, to_address(ptr));
|
||||
alloc_traits::deallocate(*this, ptr, 1u);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Allows `std::unique_ptr` to use allocators (waiting for C++20).
|
||||
* @tparam Type Type of object to allocate for and to construct.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param allocator The allocator to use.
|
||||
* @param args Parameters to use to construct the object.
|
||||
* @return A properly initialized unique pointer with a custom deleter.
|
||||
*/
|
||||
template<typename Type, typename Allocator, typename... Args>
|
||||
ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) {
|
||||
static_assert(!std::is_array_v<Type>, "Array types are not supported");
|
||||
|
||||
using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Type>;
|
||||
using allocator_type = typename alloc_traits::allocator_type;
|
||||
|
||||
allocator_type alloc{allocator};
|
||||
auto ptr = alloc_traits::allocate(alloc, 1u);
|
||||
|
||||
ENTT_TRY {
|
||||
alloc_traits::construct(alloc, to_address(ptr), std::forward<Args>(args)...);
|
||||
}
|
||||
ENTT_CATCH {
|
||||
alloc_traits::deallocate(alloc, ptr, 1u);
|
||||
ENTT_THROW;
|
||||
}
|
||||
|
||||
return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
|
||||
}
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type>
|
||||
struct uses_allocator_construction {
|
||||
template<typename Allocator, typename... Params>
|
||||
static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept {
|
||||
if constexpr(!std::uses_allocator_v<Type, Allocator> && std::is_constructible_v<Type, Params...>) {
|
||||
return std::forward_as_tuple(std::forward<Params>(params)...);
|
||||
} else {
|
||||
static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request");
|
||||
|
||||
if constexpr(std::is_constructible_v<Type, std::allocator_arg_t, const Allocator &, Params...>) {
|
||||
return std::tuple<std::allocator_arg_t, const Allocator &, Params &&...>{std::allocator_arg, allocator, std::forward<Params>(params)...};
|
||||
} else {
|
||||
static_assert(std::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
|
||||
return std::forward_as_tuple(std::forward<Params>(params)..., allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type, typename Other>
|
||||
struct uses_allocator_construction<std::pair<Type, Other>> {
|
||||
using type = std::pair<Type, Other>;
|
||||
|
||||
template<typename Allocator, typename First, typename Second>
|
||||
static constexpr auto args(const Allocator &allocator, std::piecewise_construct_t, First &&first, Second &&second) noexcept {
|
||||
return std::make_tuple(
|
||||
std::piecewise_construct,
|
||||
std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<First>(first)),
|
||||
std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<Second>(second)));
|
||||
}
|
||||
|
||||
template<typename Allocator>
|
||||
static constexpr auto args(const Allocator &allocator) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
|
||||
}
|
||||
|
||||
template<typename Allocator, typename First, typename Second>
|
||||
static constexpr auto args(const Allocator &allocator, First &&first, Second &&second) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::forward<First>(first)), std::forward_as_tuple(std::forward<Second>(second)));
|
||||
}
|
||||
|
||||
template<typename Allocator, typename First, typename Second>
|
||||
static constexpr auto args(const Allocator &allocator, const std::pair<First, Second> &value) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(value.first), std::forward_as_tuple(value.second));
|
||||
}
|
||||
|
||||
template<typename Allocator, typename First, typename Second>
|
||||
static constexpr auto args(const Allocator &allocator, std::pair<First, Second> &&value) noexcept {
|
||||
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::move(value.first)), std::forward_as_tuple(std::move(value.second)));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Uses-allocator construction utility (waiting for C++20).
|
||||
*
|
||||
* Primarily intended for internal use. Prepares the argument list needed to
|
||||
* create an object of a given type by means of uses-allocator construction.
|
||||
*
|
||||
* @tparam Type Type to return arguments for.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param allocator The allocator to use.
|
||||
* @param args Parameters to use to construct the object.
|
||||
* @return The arguments needed to create an object of the given type.
|
||||
*/
|
||||
template<typename Type, typename Allocator, typename... Args>
|
||||
constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) noexcept {
|
||||
return internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Uses-allocator construction utility (waiting for C++20).
|
||||
*
|
||||
* Primarily intended for internal use. Creates an object of a given type by
|
||||
* means of uses-allocator construction.
|
||||
*
|
||||
* @tparam Type Type of object to create.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param allocator The allocator to use.
|
||||
* @param args Parameters to use to construct the object.
|
||||
* @return A newly created object of the given type.
|
||||
*/
|
||||
template<typename Type, typename Allocator, typename... Args>
|
||||
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args) {
|
||||
return std::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Uses-allocator construction utility (waiting for C++20).
|
||||
*
|
||||
* Primarily intended for internal use. Creates an object of a given type by
|
||||
* means of uses-allocator construction at an uninitialized memory location.
|
||||
*
|
||||
* @tparam Type Type of object to create.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the object.
|
||||
* @param value Memory location in which to place the object.
|
||||
* @param allocator The allocator to use.
|
||||
* @param args Parameters to use to construct the object.
|
||||
* @return A pointer to the newly created object of the given type.
|
||||
*/
|
||||
template<typename Type, typename Allocator, typename... Args>
|
||||
constexpr Type *uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args) {
|
||||
return std::apply([value](auto &&...curr) { return new(value) Type(std::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
56
src/entt/core/monostate.hpp
Normal file
56
src/entt/core/monostate.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#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.
|
||||
*
|
||||
* A minimal, yet complete configuration system built on top of the monostate
|
||||
* pattern. Thread safe by design, it works only with basic types like `int`s or
|
||||
* `bool`s.<br/>
|
||||
* Multiple types and therefore more than one value can be associated with a
|
||||
* single key. Because of this, users must pay attention to use the same type
|
||||
* both during an assignment and when they try to read back their data.
|
||||
* Otherwise, they can incur in unexpected results.
|
||||
*/
|
||||
template<id_type>
|
||||
struct monostate {
|
||||
/**
|
||||
* @brief Assigns a value of a specific type to a given key.
|
||||
* @tparam Type Type of the value to assign.
|
||||
* @param val User data to assign to the given key.
|
||||
*/
|
||||
template<typename Type>
|
||||
void operator=(Type val) const noexcept {
|
||||
value<Type> = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value of a specific type for a given key.
|
||||
* @tparam Type Type of the value to get.
|
||||
* @return Stored value, if any.
|
||||
*/
|
||||
template<typename Type>
|
||||
operator Type() const noexcept {
|
||||
return value<Type>;
|
||||
}
|
||||
|
||||
private:
|
||||
template<typename Type>
|
||||
inline static ENTT_MAYBE_ATOMIC(Type) value{};
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Value Value used to differentiate between different variables.
|
||||
*/
|
||||
template<id_type Value>
|
||||
inline monostate<Value> monostate_v = {};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
103
src/entt/core/tuple.hpp
Normal file
103
src/entt/core/tuple.hpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#ifndef ENTT_CORE_TUPLE_HPP
|
||||
#define ENTT_CORE_TUPLE_HPP
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename>
|
||||
struct is_tuple_impl: std::false_type {};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_tuple_impl<std::tuple<Args...>>: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is a
|
||||
* tuple, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_tuple: internal::is_tuple_impl<std::remove_cv_t<Type>> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_tuple_v = is_tuple<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Utility function to unwrap tuples of a single element.
|
||||
* @tparam Type Tuple type of any sizes.
|
||||
* @param value A tuple object of the given type.
|
||||
* @return The tuple itself if it contains more than one element, the first
|
||||
* element otherwise.
|
||||
*/
|
||||
template<typename Type>
|
||||
constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept {
|
||||
if constexpr(std::tuple_size_v<std::remove_reference_t<Type>> == 1u) {
|
||||
return std::get<0>(std::forward<Type>(value));
|
||||
} else {
|
||||
return std::forward<Type>(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility class to forward-and-apply tuple objects.
|
||||
* @tparam Func Type of underlying invocable object.
|
||||
*/
|
||||
template<typename Func>
|
||||
struct forward_apply: private Func {
|
||||
/**
|
||||
* @brief Constructs a forward-and-apply object.
|
||||
* @tparam Args Types of arguments to use to construct the new instance.
|
||||
* @param args Parameters to use to construct the instance.
|
||||
*/
|
||||
template<typename... Args>
|
||||
constexpr forward_apply(Args &&...args) noexcept(std::is_nothrow_constructible_v<Func, Args...>)
|
||||
: Func{std::forward<Args>(args)...} {}
|
||||
|
||||
/**
|
||||
* @brief Forwards and applies the arguments with the underlying function.
|
||||
* @tparam Type Tuple-like type to forward to the underlying function.
|
||||
* @param args Parameters to forward to the underlying function.
|
||||
* @return Return value of the underlying function, if any.
|
||||
*/
|
||||
template<typename Type>
|
||||
constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(std::apply(std::declval<Func &>(), args))) {
|
||||
return std::apply(static_cast<Func &>(*this), std::forward<Type>(args));
|
||||
}
|
||||
|
||||
/*! @copydoc operator()() */
|
||||
template<typename Type>
|
||||
constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(std::apply(std::declval<const Func &>(), args))) {
|
||||
return std::apply(static_cast<const Func &>(*this), std::forward<Type>(args));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Func Type of underlying invocable object.
|
||||
*/
|
||||
template<typename Func>
|
||||
forward_apply(Func) -> forward_apply<std::remove_reference_t<std::remove_cv_t<Func>>>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
274
src/entt/core/type_info.hpp
Normal file
274
src/entt/core/type_info.hpp
Normal file
@@ -0,0 +1,274 @@
|
||||
#ifndef ENTT_CORE_TYPE_INFO_HPP
|
||||
#define ENTT_CORE_TYPE_INFO_HPP
|
||||
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/attribute.h"
|
||||
#include "fwd.hpp"
|
||||
#include "hashed_string.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct ENTT_API type_index final {
|
||||
[[nodiscard]] static id_type next() noexcept {
|
||||
static ENTT_MAYBE_ATOMIC(id_type) value{};
|
||||
return value++;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr auto stripped_type_name() noexcept {
|
||||
#if defined ENTT_PRETTY_FUNCTION
|
||||
std::string_view pretty_function{ENTT_PRETTY_FUNCTION};
|
||||
auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1);
|
||||
auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first);
|
||||
return value;
|
||||
#else
|
||||
return std::string_view{""};
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
|
||||
[[nodiscard]] static constexpr std::string_view type_name(int) noexcept {
|
||||
constexpr auto value = stripped_type_name<Type>();
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static std::string_view type_name(char) noexcept {
|
||||
static const auto value = stripped_type_name<Type>();
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
|
||||
[[nodiscard]] static constexpr id_type type_hash(int) noexcept {
|
||||
constexpr auto stripped = stripped_type_name<Type>();
|
||||
constexpr auto value = hashed_string::value(stripped.data(), stripped.size());
|
||||
return value;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static id_type type_hash(char) noexcept {
|
||||
static const auto value = [](const auto stripped) {
|
||||
return hashed_string::value(stripped.data(), stripped.size());
|
||||
}(stripped_type_name<Type>());
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Type sequential identifier.
|
||||
* @tparam Type Type for which to generate a sequential identifier.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct ENTT_API type_index final {
|
||||
/**
|
||||
* @brief Returns the sequential identifier of a given type.
|
||||
* @return The sequential identifier of a given type.
|
||||
*/
|
||||
[[nodiscard]] static id_type value() noexcept {
|
||||
static const id_type value = internal::type_index::next();
|
||||
return value;
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator id_type() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type hash.
|
||||
* @tparam Type Type for which to generate a hash value.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct type_hash final {
|
||||
/**
|
||||
* @brief Returns the numeric representation of a given type.
|
||||
* @return The numeric representation of the given type.
|
||||
*/
|
||||
#if defined ENTT_PRETTY_FUNCTION
|
||||
[[nodiscard]] static constexpr id_type value() noexcept {
|
||||
return internal::type_hash<Type>(0);
|
||||
#else
|
||||
[[nodiscard]] static constexpr id_type value() noexcept {
|
||||
return type_index<Type>::value();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator id_type() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Type name.
|
||||
* @tparam Type Type for which to generate a name.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct type_name final {
|
||||
/**
|
||||
* @brief Returns the name of a given type.
|
||||
* @return The name of the given type.
|
||||
*/
|
||||
[[nodiscard]] static constexpr std::string_view value() noexcept {
|
||||
return internal::type_name<Type>(0);
|
||||
}
|
||||
|
||||
/*! @copydoc value */
|
||||
[[nodiscard]] constexpr operator std::string_view() const noexcept {
|
||||
return value();
|
||||
}
|
||||
};
|
||||
|
||||
/*! @brief Implementation specific information about a type. */
|
||||
struct type_info final {
|
||||
/**
|
||||
* @brief Constructs a type info object for a given type.
|
||||
* @tparam Type Type for which to construct a type info object.
|
||||
*/
|
||||
template<typename Type>
|
||||
constexpr type_info(std::in_place_type_t<Type>) noexcept
|
||||
: seq{type_index<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
|
||||
identifier{type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
|
||||
alias{type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()} {}
|
||||
|
||||
/**
|
||||
* @brief Type index.
|
||||
* @return Type index.
|
||||
*/
|
||||
[[nodiscard]] constexpr id_type index() const noexcept {
|
||||
return seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Type hash.
|
||||
* @return Type hash.
|
||||
*/
|
||||
[[nodiscard]] constexpr id_type hash() const noexcept {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Type name.
|
||||
* @return Type name.
|
||||
*/
|
||||
[[nodiscard]] constexpr std::string_view name() const noexcept {
|
||||
return alias;
|
||||
}
|
||||
|
||||
private:
|
||||
id_type seq;
|
||||
id_type identifier;
|
||||
std::string_view alias;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares the contents of two type info objects.
|
||||
* @param lhs A type info object.
|
||||
* @param rhs A type info object.
|
||||
* @return True if the two type info objects are identical, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr bool operator==(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return lhs.hash() == rhs.hash();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares the contents of two type info objects.
|
||||
* @param lhs A type info object.
|
||||
* @param rhs A type info object.
|
||||
* @return True if the two type info objects differ, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] inline constexpr bool operator!=(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is less than the second, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator<(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return lhs.index() < rhs.index();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is less than or equal to the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator<=(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is greater than the second, false
|
||||
* otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator>(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two type info objects.
|
||||
* @param lhs A valid type info object.
|
||||
* @param rhs A valid type info object.
|
||||
* @return True if the first element is greater than or equal to the second,
|
||||
* false otherwise.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator>=(const type_info &lhs, const type_info &rhs) noexcept {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the type info object associated to a given type.
|
||||
*
|
||||
* The returned element refers to an object with static storage duration.<br/>
|
||||
* The type doesn't need to be a complete type. If the type is a reference, the
|
||||
* result refers to the referenced type. In all cases, top-level cv-qualifiers
|
||||
* are ignored.
|
||||
*
|
||||
* @tparam Type Type for which to generate a type info object.
|
||||
* @return A reference to a properly initialized type info object.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] const type_info &type_id() noexcept {
|
||||
if constexpr(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>) {
|
||||
static type_info instance{std::in_place_type<Type>};
|
||||
return instance;
|
||||
} else {
|
||||
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
}
|
||||
}
|
||||
|
||||
/*! @copydoc type_id */
|
||||
template<typename Type>
|
||||
[[nodiscard]] const type_info &type_id(Type &&) noexcept {
|
||||
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
920
src/entt/core/type_traits.hpp
Normal file
920
src/entt/core/type_traits.hpp
Normal file
@@ -0,0 +1,920 @@
|
||||
#ifndef ENTT_CORE_TYPE_TRAITS_HPP
|
||||
#define ENTT_CORE_TYPE_TRAITS_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Utility class to disambiguate overloaded functions.
|
||||
* @tparam N Number of choices available.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
struct choice_t
|
||||
// Unfortunately, doxygen cannot parse such a construct.
|
||||
: /*! @cond TURN_OFF_DOXYGEN */ choice_t<N - 1> /*! @endcond */
|
||||
{};
|
||||
|
||||
/*! @copybrief choice_t */
|
||||
template<>
|
||||
struct choice_t<0> {};
|
||||
|
||||
/**
|
||||
* @brief Variable template for the choice trick.
|
||||
* @tparam N Number of choices available.
|
||||
*/
|
||||
template<std::size_t N>
|
||||
inline constexpr choice_t<N> choice{};
|
||||
|
||||
/**
|
||||
* @brief Identity type trait.
|
||||
*
|
||||
* Useful to establish non-deduced contexts in template argument deduction
|
||||
* (waiting for C++20) or to provide types through function arguments.
|
||||
*
|
||||
* @tparam Type A type.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct type_identity {
|
||||
/*! @brief Identity type. */
|
||||
using type = Type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type A type.
|
||||
*/
|
||||
template<typename Type>
|
||||
using type_identity_t = typename type_identity<Type>::type;
|
||||
|
||||
/**
|
||||
* @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains.
|
||||
* @tparam Type The type of which to return the size.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct size_of: std::integral_constant<std::size_t, 0u> {};
|
||||
|
||||
/*! @copydoc size_of */
|
||||
template<typename Type>
|
||||
struct size_of<Type, std::void_t<decltype(sizeof(Type))>>
|
||||
: std::integral_constant<std::size_t, sizeof(Type)> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type of which to return the size.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr std::size_t size_of_v = size_of<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Using declaration to be used to _repeat_ the same type a number of
|
||||
* times equal to the size of a given parameter pack.
|
||||
* @tparam Type A type to repeat.
|
||||
*/
|
||||
template<typename Type, typename>
|
||||
using unpack_as_type = Type;
|
||||
|
||||
/**
|
||||
* @brief Helper variable template to be used to _repeat_ the same value a
|
||||
* number of times equal to the size of a given parameter pack.
|
||||
* @tparam Value A value to repeat.
|
||||
*/
|
||||
template<auto Value, typename>
|
||||
inline constexpr auto unpack_as_value = Value;
|
||||
|
||||
/**
|
||||
* @brief Wraps a static constant.
|
||||
* @tparam Value A static constant.
|
||||
*/
|
||||
template<auto Value>
|
||||
using integral_constant = std::integral_constant<decltype(Value), Value>;
|
||||
|
||||
/**
|
||||
* @brief Alias template to facilitate the creation of named values.
|
||||
* @tparam Value A constant value at least convertible to `id_type`.
|
||||
*/
|
||||
template<id_type Value>
|
||||
using tag = integral_constant<Value>;
|
||||
|
||||
/**
|
||||
* @brief A class to use to push around lists of types, nothing more.
|
||||
* @tparam Type Types provided by the type list.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct type_list {
|
||||
/*! @brief Type list type. */
|
||||
using type = type_list;
|
||||
/*! @brief Compile-time number of elements in the type list. */
|
||||
static constexpr auto size = sizeof...(Type);
|
||||
};
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<std::size_t, typename>
|
||||
struct type_list_element;
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the types of a type list.
|
||||
* @tparam Index Index of the type to return.
|
||||
* @tparam First First type provided by the type list.
|
||||
* @tparam Other Other types provided by the type list.
|
||||
*/
|
||||
template<std::size_t Index, typename First, typename... Other>
|
||||
struct type_list_element<Index, type_list<First, Other...>>
|
||||
: type_list_element<Index - 1u, type_list<Other...>> {};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the types of a type list.
|
||||
* @tparam First First type provided by the type list.
|
||||
* @tparam Other Other types provided by the type list.
|
||||
*/
|
||||
template<typename First, typename... Other>
|
||||
struct type_list_element<0u, type_list<First, Other...>> {
|
||||
/*! @brief Searched type. */
|
||||
using type = First;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Index Index of the type to return.
|
||||
* @tparam List Type list to search into.
|
||||
*/
|
||||
template<std::size_t Index, typename List>
|
||||
using type_list_element_t = typename type_list_element<Index, List>::type;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename, typename>
|
||||
struct type_list_index;
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time type access to the types of a type list.
|
||||
* @tparam Type Type to look for and for which to return the index.
|
||||
* @tparam First First type provided by the type list.
|
||||
* @tparam Other Other types provided by the type list.
|
||||
*/
|
||||
template<typename Type, typename First, typename... Other>
|
||||
struct type_list_index<Type, type_list<First, Other...>> {
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 1u + type_list_index<Type, type_list<Other...>>::value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time type access to the types of a type list.
|
||||
* @tparam Type Type to look for and for which to return the index.
|
||||
* @tparam Other Other types provided by the type list.
|
||||
*/
|
||||
template<typename Type, typename... Other>
|
||||
struct type_list_index<Type, type_list<Type, Other...>> {
|
||||
static_assert(type_list_index<Type, type_list<Other...>>::value == sizeof...(Other), "Non-unique type");
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time type access to the types of a type list.
|
||||
* @tparam Type Type to look for and for which to return the index.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct type_list_index<Type, type_list<>> {
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam List Type list.
|
||||
* @tparam Type Type to look for and for which to return the index.
|
||||
*/
|
||||
template<typename Type, typename List>
|
||||
inline constexpr std::size_t type_list_index_v = type_list_index<Type, List>::value;
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
* @tparam Type Types provided by the first type list.
|
||||
* @tparam Other Types provided by the second type list.
|
||||
* @return A type list composed by the types of both the type lists.
|
||||
*/
|
||||
template<typename... Type, typename... Other>
|
||||
constexpr type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct type_list_cat;
|
||||
|
||||
/*! @brief Concatenates multiple type lists. */
|
||||
template<>
|
||||
struct type_list_cat<> {
|
||||
/*! @brief A type list composed by the types of all the type lists. */
|
||||
using type = type_list<>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
* @tparam Type Types provided by the first type list.
|
||||
* @tparam Other Types provided by the second type list.
|
||||
* @tparam List Other type lists, if any.
|
||||
*/
|
||||
template<typename... Type, typename... Other, typename... List>
|
||||
struct type_list_cat<type_list<Type...>, type_list<Other...>, List...> {
|
||||
/*! @brief A type list composed by the types of all the type lists. */
|
||||
using type = typename type_list_cat<type_list<Type..., Other...>, List...>::type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple type lists.
|
||||
* @tparam Type Types provided by the type list.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct type_list_cat<type_list<Type...>> {
|
||||
/*! @brief A type list composed by the types of all the type lists. */
|
||||
using type = type_list<Type...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Type lists to concatenate.
|
||||
*/
|
||||
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.
|
||||
* @tparam Other The other types provided by the given type list.
|
||||
*/
|
||||
template<typename Type, typename... Other>
|
||||
struct type_list_unique<type_list<Type, Other...>> {
|
||||
/*! @brief A type list without duplicate types. */
|
||||
using type = std::conditional_t<
|
||||
(std::is_same_v<Type, Other> || ...),
|
||||
typename type_list_unique<type_list<Other...>>::type,
|
||||
type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>>;
|
||||
};
|
||||
|
||||
/*! @brief Removes duplicates types from a type list. */
|
||||
template<>
|
||||
struct type_list_unique<type_list<>> {
|
||||
/*! @brief A type list without duplicate types. */
|
||||
using type = type_list<>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type A type list.
|
||||
*/
|
||||
template<typename Type>
|
||||
using type_list_unique_t = typename type_list_unique<Type>::type;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a type list contains a
|
||||
* given type, false otherwise.
|
||||
* @tparam List Type list.
|
||||
* @tparam Type Type to look for.
|
||||
*/
|
||||
template<typename List, typename Type>
|
||||
struct type_list_contains;
|
||||
|
||||
/**
|
||||
* @copybrief type_list_contains
|
||||
* @tparam Type Types provided by the type list.
|
||||
* @tparam Other Type to look for.
|
||||
*/
|
||||
template<typename... Type, typename Other>
|
||||
struct type_list_contains<type_list<Type...>, Other>
|
||||
: std::bool_constant<(std::is_same_v<Type, Other> || ...)> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam List Type list.
|
||||
* @tparam Type Type to look for.
|
||||
*/
|
||||
template<typename List, typename Type>
|
||||
inline constexpr bool type_list_contains_v = type_list_contains<List, Type>::value;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct type_list_diff;
|
||||
|
||||
/**
|
||||
* @brief Computes the difference between two type lists.
|
||||
* @tparam Type Types provided by the first type list.
|
||||
* @tparam Other Types provided by the second type list.
|
||||
*/
|
||||
template<typename... Type, typename... Other>
|
||||
struct type_list_diff<type_list<Type...>, type_list<Other...>> {
|
||||
/*! @brief A type list that is the difference between the two type lists. */
|
||||
using type = type_list_cat_t<std::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Type lists between which to compute the difference.
|
||||
*/
|
||||
template<typename... List>
|
||||
using type_list_diff_t = typename type_list_diff<List...>::type;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename, template<typename...> class>
|
||||
struct type_list_transform;
|
||||
|
||||
/**
|
||||
* @brief Applies a given _function_ to a type list and generate a new list.
|
||||
* @tparam Type Types provided by the type list.
|
||||
* @tparam Op Unary operation as template class with a type member named `type`.
|
||||
*/
|
||||
template<typename... Type, template<typename...> class Op>
|
||||
struct type_list_transform<type_list<Type...>, Op> {
|
||||
/*! @brief Resulting type list after applying the transform function. */
|
||||
using type = type_list<typename Op<Type>::type...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Type list.
|
||||
* @tparam Op Unary operation as template class with a type member named `type`.
|
||||
*/
|
||||
template<typename List, template<typename...> class Op>
|
||||
using type_list_transform_t = typename type_list_transform<List, Op>::type;
|
||||
|
||||
/**
|
||||
* @brief A class to use to push around lists of constant values, nothing more.
|
||||
* @tparam Value Values provided by the value list.
|
||||
*/
|
||||
template<auto... Value>
|
||||
struct value_list {
|
||||
/*! @brief Value list type. */
|
||||
using type = value_list;
|
||||
/*! @brief Compile-time number of elements in the value list. */
|
||||
static constexpr auto size = sizeof...(Value);
|
||||
};
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<std::size_t, typename>
|
||||
struct value_list_element;
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the values of a value list.
|
||||
* @tparam Index Index of the value to return.
|
||||
* @tparam Value First value provided by the value list.
|
||||
* @tparam Other Other values provided by the value list.
|
||||
*/
|
||||
template<std::size_t Index, auto Value, auto... Other>
|
||||
struct value_list_element<Index, value_list<Value, Other...>>
|
||||
: value_list_element<Index - 1u, value_list<Other...>> {};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time indexed access to the types of a type list.
|
||||
* @tparam Value First value provided by the value list.
|
||||
* @tparam Other Other values provided by the value list.
|
||||
*/
|
||||
template<auto Value, auto... Other>
|
||||
struct value_list_element<0u, value_list<Value, Other...>> {
|
||||
/*! @brief Searched type. */
|
||||
using type = decltype(Value);
|
||||
/*! @brief Searched value. */
|
||||
static constexpr auto value = Value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Index Index of the type to return.
|
||||
* @tparam List Value list to search into.
|
||||
*/
|
||||
template<std::size_t Index, typename List>
|
||||
using value_list_element_t = typename value_list_element<Index, List>::type;
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Index Index of the value to return.
|
||||
* @tparam List Value list to search into.
|
||||
*/
|
||||
template<std::size_t Index, typename List>
|
||||
inline constexpr auto value_list_element_v = value_list_element<Index, List>::value;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<auto, typename>
|
||||
struct value_list_index;
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time type access to the values of a value list.
|
||||
* @tparam Value Value to look for and for which to return the index.
|
||||
* @tparam First First value provided by the value list.
|
||||
* @tparam Other Other values provided by the value list.
|
||||
*/
|
||||
template<auto Value, auto First, auto... Other>
|
||||
struct value_list_index<Value, value_list<First, Other...>> {
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
/*! @brief Compile-time position of the given value in the sublist. */
|
||||
static constexpr value_type value = 1u + value_list_index<Value, value_list<Other...>>::value;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time type access to the values of a value list.
|
||||
* @tparam Value Value to look for and for which to return the index.
|
||||
* @tparam Other Other values provided by the value list.
|
||||
*/
|
||||
template<auto Value, auto... Other>
|
||||
struct value_list_index<Value, value_list<Value, Other...>> {
|
||||
static_assert(value_list_index<Value, value_list<Other...>>::value == sizeof...(Other), "Non-unique type");
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
/*! @brief Compile-time position of the given value in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Provides compile-time type access to the values of a value list.
|
||||
* @tparam Value Value to look for and for which to return the index.
|
||||
*/
|
||||
template<auto Value>
|
||||
struct value_list_index<Value, value_list<>> {
|
||||
/*! @brief Unsigned integer type. */
|
||||
using value_type = std::size_t;
|
||||
/*! @brief Compile-time position of the given type in the sublist. */
|
||||
static constexpr value_type value = 0u;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam List Value list.
|
||||
* @tparam Value Value to look for and for which to return the index.
|
||||
*/
|
||||
template<auto Value, typename List>
|
||||
inline constexpr std::size_t value_list_index_v = value_list_index<Value, List>::value;
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
* @tparam Value Values provided by the first value list.
|
||||
* @tparam Other Values provided by the second value list.
|
||||
* @return A value list composed by the values of both the value lists.
|
||||
*/
|
||||
template<auto... Value, auto... Other>
|
||||
constexpr value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct value_list_cat;
|
||||
|
||||
/*! @brief Concatenates multiple value lists. */
|
||||
template<>
|
||||
struct value_list_cat<> {
|
||||
/*! @brief A value list composed by the values of all the value lists. */
|
||||
using type = value_list<>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
* @tparam Value Values provided by the first value list.
|
||||
* @tparam Other Values provided by the second value list.
|
||||
* @tparam List Other value lists, if any.
|
||||
*/
|
||||
template<auto... Value, auto... Other, typename... List>
|
||||
struct value_list_cat<value_list<Value...>, value_list<Other...>, List...> {
|
||||
/*! @brief A value list composed by the values of all the value lists. */
|
||||
using type = typename value_list_cat<value_list<Value..., Other...>, List...>::type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Concatenates multiple value lists.
|
||||
* @tparam Value Values provided by the value list.
|
||||
*/
|
||||
template<auto... Value>
|
||||
struct value_list_cat<value_list<Value...>> {
|
||||
/*! @brief A value list composed by the values of all the value lists. */
|
||||
using type = value_list<Value...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Value lists to concatenate.
|
||||
*/
|
||||
template<typename... List>
|
||||
using value_list_cat_t = typename value_list_cat<List...>::type;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename>
|
||||
struct value_list_unique;
|
||||
|
||||
/**
|
||||
* @brief Removes duplicates values from a value list.
|
||||
* @tparam Value One of the values provided by the given value list.
|
||||
* @tparam Other The other values provided by the given value list.
|
||||
*/
|
||||
template<auto Value, auto... Other>
|
||||
struct value_list_unique<value_list<Value, Other...>> {
|
||||
/*! @brief A value list without duplicate types. */
|
||||
using type = std::conditional_t<
|
||||
((Value == Other) || ...),
|
||||
typename value_list_unique<value_list<Other...>>::type,
|
||||
value_list_cat_t<value_list<Value>, typename value_list_unique<value_list<Other...>>::type>>;
|
||||
};
|
||||
|
||||
/*! @brief Removes duplicates values from a value list. */
|
||||
template<>
|
||||
struct value_list_unique<value_list<>> {
|
||||
/*! @brief A value list without duplicate types. */
|
||||
using type = value_list<>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Type A value list.
|
||||
*/
|
||||
template<typename Type>
|
||||
using value_list_unique_t = typename value_list_unique<Type>::type;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a value list contains
|
||||
* a given value, false otherwise.
|
||||
* @tparam List Value list.
|
||||
* @tparam Value Value to look for.
|
||||
*/
|
||||
template<typename List, auto Value>
|
||||
struct value_list_contains;
|
||||
|
||||
/**
|
||||
* @copybrief value_list_contains
|
||||
* @tparam Value Values provided by the value list.
|
||||
* @tparam Other Value to look for.
|
||||
*/
|
||||
template<auto... Value, auto Other>
|
||||
struct value_list_contains<value_list<Value...>, Other>
|
||||
: std::bool_constant<((Value == Other) || ...)> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam List Value list.
|
||||
* @tparam Value Value to look for.
|
||||
*/
|
||||
template<typename List, auto Value>
|
||||
inline constexpr bool value_list_contains_v = value_list_contains<List, Value>::value;
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
class value_list_diff;
|
||||
|
||||
/**
|
||||
* @brief Computes the difference between two value lists.
|
||||
* @tparam Value Values provided by the first value list.
|
||||
* @tparam Other Values provided by the second value list.
|
||||
*/
|
||||
template<auto... Value, auto... Other>
|
||||
class value_list_diff<value_list<Value...>, value_list<Other...>> {
|
||||
using v141_toolset_workaround = value_list<Other...>;
|
||||
|
||||
public:
|
||||
/*! @brief A value list that is the difference between the two value lists. */
|
||||
using type = value_list_cat_t<std::conditional_t<value_list_contains_v<v141_toolset_workaround, Value>, value_list<>, value_list<Value>>...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam List Value lists between which to compute the difference.
|
||||
*/
|
||||
template<typename... List>
|
||||
using value_list_diff_t = typename value_list_diff<List...>::type;
|
||||
|
||||
/*! @brief Same as std::is_invocable, but with tuples. */
|
||||
template<typename, typename>
|
||||
struct is_applicable: std::false_type {};
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Tuple Tuple-like type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Func, template<typename...> class Tuple, typename... Args>
|
||||
struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Tuple Tuple-like type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Func, template<typename...> class Tuple, typename... Args>
|
||||
struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args...> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Func, typename Args>
|
||||
inline constexpr bool is_applicable_v = is_applicable<Func, Args>::value;
|
||||
|
||||
/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */
|
||||
template<typename, typename, typename>
|
||||
struct is_applicable_r: std::false_type {};
|
||||
|
||||
/**
|
||||
* @copybrief is_applicable_r
|
||||
* @tparam Ret The type to which the return type of the function should be
|
||||
* convertible.
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Ret, typename Func, typename... Args>
|
||||
struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret, Func, Args...> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Ret The type to which the return type of the function should be
|
||||
* convertible.
|
||||
* @tparam Func A valid function type.
|
||||
* @tparam Args The list of arguments to use to probe the function type.
|
||||
*/
|
||||
template<typename Ret, typename Func, typename Args>
|
||||
inline constexpr bool is_applicable_r_v = is_applicable_r<Ret, Func, Args>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is
|
||||
* complete, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_complete: std::false_type {};
|
||||
|
||||
/*! @copydoc is_complete */
|
||||
template<typename Type>
|
||||
struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_complete_v = is_complete<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is an
|
||||
* iterator, false otherwise.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct is_iterator: std::false_type {};
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_iterator_category: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/*! @copydoc is_iterator */
|
||||
template<typename Type>
|
||||
struct is_iterator<Type, std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_pointer_t<Type>>, void>>>
|
||||
: internal::has_iterator_category<Type> {};
|
||||
|
||||
/**
|
||||
* @brief Helper variable template.
|
||||
* @tparam Type The type to test.
|
||||
*/
|
||||
template<typename Type>
|
||||
inline constexpr bool is_iterator_v = is_iterator<Type>::value;
|
||||
|
||||
/**
|
||||
* @brief Provides the member constant `value` to true if a given type is both
|
||||
* an empty and non-final class, false otherwise.
|
||||
* @tparam Type The type to test
|
||||
*/
|
||||
template<typename Type>
|
||||
struct is_ebco_eligible
|
||||
: std::bool_constant<std::is_empty_v<Type> && !std::is_final_v<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_cv_t<Type>>>, bool> maybe_equality_comparable(choice_t<2>) {
|
||||
if constexpr(has_tuple_size_value<Type>::value) {
|
||||
return unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
|
||||
} else {
|
||||
return maybe_equality_comparable<Type>(choice<1>);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/*! @copydoc is_equality_comparable */
|
||||
template<typename Type>
|
||||
struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>>
|
||||
: std::bool_constant<internal::maybe_equality_comparable<Type>(choice<2>)> {};
|
||||
|
||||
/*! @copydoc is_equality_comparable */
|
||||
template<typename Type, auto N>
|
||||
struct is_equality_comparable<Type[N]>: std::false_type {};
|
||||
|
||||
/**
|
||||
* @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.
|
||||
* @tparam To The type to which to transcribe the constness.
|
||||
* @tparam From The type from which to transcribe the constness.
|
||||
*/
|
||||
template<typename To, typename From>
|
||||
struct constness_as {
|
||||
/*! @brief The type resulting from the transcription of the constness. */
|
||||
using type = std::remove_const_t<To>;
|
||||
};
|
||||
|
||||
/*! @copydoc constness_as */
|
||||
template<typename To, typename From>
|
||||
struct constness_as<To, const From> {
|
||||
/*! @brief The type resulting from the transcription of the constness. */
|
||||
using type = const To;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Alias template to facilitate the transcription of the constness.
|
||||
* @tparam To The type to which to transcribe the constness.
|
||||
* @tparam From The type from which to transcribe the constness.
|
||||
*/
|
||||
template<typename To, typename From>
|
||||
using constness_as_t = typename constness_as<To, From>::type;
|
||||
|
||||
/**
|
||||
* @brief Extracts the class of a non-static member object or function.
|
||||
* @tparam Member A pointer to a non-static member object or function.
|
||||
*/
|
||||
template<typename Member>
|
||||
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...));
|
||||
|
||||
template<typename Class, typename Ret, typename... Args>
|
||||
static Class *clazz(Ret (Class::*)(Args...) const);
|
||||
|
||||
template<typename Class, typename Type>
|
||||
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.
|
||||
*/
|
||||
template<typename Member>
|
||||
using member_class_t = typename member_class<Member>::type;
|
||||
|
||||
/**
|
||||
* @brief Extracts the n-th argument of a given function or member function.
|
||||
* @tparam Index The index of the argument to extract.
|
||||
* @tparam Candidate A valid function, member function or data member.
|
||||
*/
|
||||
template<std::size_t Index, auto Candidate>
|
||||
class nth_argument {
|
||||
template<typename Ret, typename... Args>
|
||||
static constexpr type_list<Args...> pick_up(Ret (*)(Args...));
|
||||
|
||||
template<typename Ret, typename Class, typename... Args>
|
||||
static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...));
|
||||
|
||||
template<typename Ret, typename Class, typename... Args>
|
||||
static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...) const);
|
||||
|
||||
template<typename Type, typename Class>
|
||||
static constexpr type_list<Type> pick_up(Type Class ::*);
|
||||
|
||||
public:
|
||||
/*! @brief N-th argument of the given function or member function. */
|
||||
using type = type_list_element_t<Index, decltype(pick_up(Candidate))>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Index The index of the argument to extract.
|
||||
* @tparam Candidate A valid function, member function or data member.
|
||||
*/
|
||||
template<std::size_t Index, auto Candidate>
|
||||
using nth_argument_t = typename nth_argument<Index, Candidate>::type;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
template<typename... Type>
|
||||
struct std::tuple_size<entt::type_list<Type...>>: std::integral_constant<std::size_t, entt::type_list<Type...>::size> {};
|
||||
|
||||
template<std::size_t Index, typename... Type>
|
||||
struct std::tuple_element<Index, entt::type_list<Type...>>: entt::type_list_element<Index, entt::type_list<Type...>> {};
|
||||
|
||||
template<auto... Value>
|
||||
struct std::tuple_size<entt::value_list<Value...>>: std::integral_constant<std::size_t, entt::value_list<Value...>::size> {};
|
||||
|
||||
template<std::size_t Index, auto... Value>
|
||||
struct std::tuple_element<Index, entt::value_list<Value...>>: entt::value_list_element<Index, entt::value_list<Value...>> {};
|
||||
|
||||
#endif
|
||||
101
src/entt/core/utility.hpp
Normal file
101
src/entt/core/utility.hpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#ifndef ENTT_CORE_UTILITY_HPP
|
||||
#define ENTT_CORE_UTILITY_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @brief Identity function object (waiting for C++20). */
|
||||
struct identity {
|
||||
/*! @brief Indicates that this is a transparent function object. */
|
||||
using is_transparent = void;
|
||||
|
||||
/**
|
||||
* @brief Returns its argument unchanged.
|
||||
* @tparam Type Type of the argument.
|
||||
* @param value The actual argument.
|
||||
* @return The submitted value as-is.
|
||||
*/
|
||||
template<typename Type>
|
||||
[[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept {
|
||||
return std::forward<Type>(value);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constant utility to disambiguate overloaded members of a class.
|
||||
* @tparam Type Type of the desired overload.
|
||||
* @tparam Class Type of class to which the member belongs.
|
||||
* @param member A valid pointer to a member.
|
||||
* @return Pointer to the member.
|
||||
*/
|
||||
template<typename Type, typename Class>
|
||||
[[nodiscard]] constexpr auto overload(Type Class::*member) noexcept {
|
||||
return member;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constant utility to disambiguate overloaded functions.
|
||||
* @tparam Func Function type of the desired overload.
|
||||
* @param func A valid pointer to a function.
|
||||
* @return Pointer to the function.
|
||||
*/
|
||||
template<typename Func>
|
||||
[[nodiscard]] constexpr auto overload(Func *func) noexcept {
|
||||
return func;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper type for visitors.
|
||||
* @tparam Func Types of function objects.
|
||||
*/
|
||||
template<typename... Func>
|
||||
struct overloaded: Func... {
|
||||
using Func::operator()...;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Func Types of function objects.
|
||||
*/
|
||||
template<typename... Func>
|
||||
overloaded(Func...) -> overloaded<Func...>;
|
||||
|
||||
/**
|
||||
* @brief Basic implementation of a y-combinator.
|
||||
* @tparam Func Type of a potentially recursive function.
|
||||
*/
|
||||
template<typename Func>
|
||||
struct y_combinator {
|
||||
/**
|
||||
* @brief Constructs a y-combinator from a given function.
|
||||
* @param recursive A potentially recursive function.
|
||||
*/
|
||||
constexpr y_combinator(Func recursive) noexcept(std::is_nothrow_move_constructible_v<Func>)
|
||||
: func{std::move(recursive)} {}
|
||||
|
||||
/**
|
||||
* @brief Invokes a y-combinator and therefore its underlying function.
|
||||
* @tparam Args Types of arguments to use to invoke the underlying function.
|
||||
* @param args Parameters to use to invoke the underlying function.
|
||||
* @return Return value of the underlying function, if any.
|
||||
*/
|
||||
template<typename... Args>
|
||||
constexpr decltype(auto) operator()(Args &&...args) const noexcept(std::is_nothrow_invocable_v<Func, const y_combinator &, Args...>) {
|
||||
return func(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/*! @copydoc operator()() */
|
||||
template<typename... Args>
|
||||
constexpr decltype(auto) operator()(Args &&...args) noexcept(std::is_nothrow_invocable_v<Func, y_combinator &, Args...>) {
|
||||
return func(*this, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
Func func;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
@@ -1,152 +0,0 @@
|
||||
#ifndef ENTT_ENTITY_ACTOR_HPP
|
||||
#define ENTT_ENTITY_ACTOR_HPP
|
||||
|
||||
|
||||
#include <utility>
|
||||
#include "registry.hpp"
|
||||
|
||||
|
||||
namespace entt {
|
||||
|
||||
|
||||
/**
|
||||
* @brief Dedicated to those who aren't confident with entity-component systems.
|
||||
*
|
||||
* Tiny wrapper around a registry, for all those users that aren't confident
|
||||
* with entity-component systems and prefer to iterate objects directly.
|
||||
*
|
||||
* @tparam Entity A valid entity type (see entt_traits for more details).
|
||||
* @tparam Delta Type to use to provide elapsed time.
|
||||
*/
|
||||
template<typename Entity, typename Delta>
|
||||
struct Actor {
|
||||
/*! @brief Type of registry used internally. */
|
||||
using registry_type = Registry<Entity>;
|
||||
/*! @brief Type used to provide elapsed time. */
|
||||
using delta_type = Delta;
|
||||
|
||||
/**
|
||||
* @brief Constructs an actor by using the given registry.
|
||||
* @param reg An entity-component system properly initialized.
|
||||
*/
|
||||
Actor(Registry<Entity> ®)
|
||||
: reg{reg}, entity{reg.create()}
|
||||
{}
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
virtual ~Actor() {
|
||||
reg.destroy(entity);
|
||||
}
|
||||
|
||||
/*! @brief Default copy constructor. */
|
||||
Actor(const Actor &) = default;
|
||||
/*! @brief Default move constructor. */
|
||||
Actor(Actor &&) = default;
|
||||
|
||||
/*! @brief Default copy assignment operator. @return This actor. */
|
||||
Actor & operator=(const Actor &) = default;
|
||||
/*! @brief Default move assignment operator. @return This actor. */
|
||||
Actor & operator=(Actor &&) = default;
|
||||
|
||||
/**
|
||||
* @brief Assigns the given component to an actor.
|
||||
*
|
||||
* A new instance of the given component is created and initialized with the
|
||||
* arguments provided (the component must have a proper constructor or be of
|
||||
* aggregate type). Then the component is assigned to the actor.<br/>
|
||||
* In case the actor already has a component of the given type, it's
|
||||
* replaced with the new one.
|
||||
*
|
||||
* @tparam Component Type of the component to create.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return A reference to the newly created component.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
Component & set(Args&&... args) {
|
||||
return reg.template accomodate<Component>(entity, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the given component from an actor.
|
||||
* @tparam Component Type of the component to remove.
|
||||
*/
|
||||
template<typename Component>
|
||||
void unset() {
|
||||
reg.template remove<Component>(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if an actor has the given component.
|
||||
* @tparam Component Type of the component for which to perform the check.
|
||||
* @return True if the actor has the component, false otherwise.
|
||||
*/
|
||||
template<typename Component>
|
||||
bool has() const noexcept {
|
||||
return reg.template has<Component>(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the given component for an actor.
|
||||
* @tparam Component Type of the component to get.
|
||||
* @return A reference to the instance of the component owned by the entity.
|
||||
*/
|
||||
template<typename Component>
|
||||
const Component & get() const noexcept {
|
||||
return reg.template get<Component>(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the given component for an actor.
|
||||
* @tparam Component Type of the component to get.
|
||||
* @return A reference to the instance of the component owned by the entity.
|
||||
*/
|
||||
template<typename Component>
|
||||
Component & get() noexcept {
|
||||
return const_cast<Component &>(const_cast<const Actor *>(this)->get<Component>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the underlying registry.
|
||||
* @return A reference to the underlying registry
|
||||
*/
|
||||
const registry_type & registry() const noexcept {
|
||||
return reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the underlying registry.
|
||||
* @return A reference to the underlying registry
|
||||
*/
|
||||
registry_type & registry() noexcept {
|
||||
return const_cast<registry_type &>(const_cast<const Actor *>(this)->registry());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates an actor, whatever it means to update it.
|
||||
* @param delta Elapsed time.
|
||||
*/
|
||||
virtual void update(delta_type delta) = 0;
|
||||
|
||||
private:
|
||||
registry_type ®
|
||||
Entity entity;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Default actor class.
|
||||
*
|
||||
* The default actor is the best choice for almost all the applications.<br/>
|
||||
* Users should have a really good reason to choose something different.
|
||||
*
|
||||
* @tparam Delta Type to use to provide elapsed time.
|
||||
*/
|
||||
template<typename Delta>
|
||||
using DefaultActor = Actor<std::uint32_t, Delta>;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // ENTT_ENTITY_ACTOR_HPP
|
||||
64
src/entt/entity/component.hpp
Normal file
64
src/entt/entity/component.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef ENTT_ENTITY_COMPONENT_HPP
|
||||
#define ENTT_ENTITY_COMPONENT_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include "../config/config.h"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename Type, typename = void>
|
||||
struct in_place_delete: std::bool_constant<!(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>)> {};
|
||||
|
||||
template<>
|
||||
struct in_place_delete<void>: std::false_type {};
|
||||
|
||||
template<typename Type>
|
||||
struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>>
|
||||
: std::true_type {};
|
||||
|
||||
template<typename Type, typename = void>
|
||||
struct page_size: std::integral_constant<std::size_t, !std::is_empty_v<ENTT_ETO_TYPE(Type)> * ENTT_PACKED_PAGE> {};
|
||||
|
||||
template<>
|
||||
struct page_size<void>: std::integral_constant<std::size_t, 0u> {};
|
||||
|
||||
template<typename Type>
|
||||
struct page_size<Type, std::enable_if_t<std::is_convertible_v<decltype(Type::page_size), std::size_t>>>
|
||||
: std::integral_constant<std::size_t, Type::page_size> {};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Common way to access various properties of components.
|
||||
* @tparam Type Type of component.
|
||||
*/
|
||||
template<typename Type, typename = void>
|
||||
struct component_traits {
|
||||
static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
|
||||
|
||||
/*! @brief Component type. */
|
||||
using type = Type;
|
||||
|
||||
/*! @brief Pointer stability, default is `false`. */
|
||||
static constexpr bool in_place_delete = internal::in_place_delete<Type>::value;
|
||||
/*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */
|
||||
static constexpr std::size_t page_size = internal::page_size<Type>::value;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
379
src/entt/entity/entity.hpp
Normal file
379
src/entt/entity/entity.hpp
Normal file
@@ -0,0 +1,379 @@
|
||||
#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 {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
// waiting for C++20 (and std::popcount)
|
||||
template<typename Type>
|
||||
static constexpr int popcount(Type value) noexcept {
|
||||
return value ? (int(value & 1) + popcount(value >> 1)) : 0;
|
||||
}
|
||||
|
||||
template<typename, typename = void>
|
||||
struct entt_traits;
|
||||
|
||||
template<typename Type>
|
||||
struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>>
|
||||
: entt_traits<std::underlying_type_t<Type>> {
|
||||
using value_type = Type;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>>
|
||||
: entt_traits<typename Type::entity_type> {
|
||||
using value_type = Type;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct entt_traits<std::uint32_t> {
|
||||
using value_type = std::uint32_t;
|
||||
|
||||
using entity_type = std::uint32_t;
|
||||
using version_type = std::uint16_t;
|
||||
|
||||
static constexpr entity_type entity_mask = 0xFFFFF;
|
||||
static constexpr entity_type version_mask = 0xFFF;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct entt_traits<std::uint64_t> {
|
||||
using value_type = std::uint64_t;
|
||||
|
||||
using entity_type = std::uint64_t;
|
||||
using version_type = std::uint32_t;
|
||||
|
||||
static constexpr entity_type entity_mask = 0xFFFFFFFF;
|
||||
static constexpr entity_type version_mask = 0xFFFFFFFF;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Common basic entity traits implementation.
|
||||
* @tparam Traits Actual entity traits to use.
|
||||
*/
|
||||
template<typename Traits>
|
||||
class basic_entt_traits {
|
||||
static constexpr auto length = internal::popcount(Traits::entity_mask);
|
||||
|
||||
static_assert(Traits::entity_mask && ((typename Traits::entity_type{1} << length) == (Traits::entity_mask + 1)), "Invalid entity mask");
|
||||
static_assert((typename Traits::entity_type{1} << internal::popcount(Traits::version_mask)) == (Traits::version_mask + 1), "Invalid version mask");
|
||||
|
||||
public:
|
||||
/*! @brief Value type. */
|
||||
using value_type = typename Traits::value_type;
|
||||
/*! @brief Underlying entity type. */
|
||||
using entity_type = typename Traits::entity_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename Traits::version_type;
|
||||
|
||||
/*! @brief Entity mask size. */
|
||||
static constexpr entity_type entity_mask = Traits::entity_mask;
|
||||
/*! @brief Version mask size */
|
||||
static constexpr entity_type version_mask = Traits::version_mask;
|
||||
|
||||
/**
|
||||
* @brief Converts an entity to its underlying type.
|
||||
* @param value The value to convert.
|
||||
* @return The integral representation of the given value.
|
||||
*/
|
||||
[[nodiscard]] static constexpr entity_type to_integral(const value_type value) noexcept {
|
||||
return static_cast<entity_type>(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the entity part once converted to the underlying type.
|
||||
* @param value The value to convert.
|
||||
* @return The integral representation of the entity part.
|
||||
*/
|
||||
[[nodiscard]] static constexpr entity_type to_entity(const value_type value) noexcept {
|
||||
return (to_integral(value) & entity_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the version part once converted to the underlying type.
|
||||
* @param value The value to convert.
|
||||
* @return The integral representation of the version part.
|
||||
*/
|
||||
[[nodiscard]] static constexpr version_type to_version(const value_type value) noexcept {
|
||||
return static_cast<version_type>(to_integral(value) >> length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the successor of a given identifier.
|
||||
* @param value The identifier of which to return the successor.
|
||||
* @return The successor of the given identifier.
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type next(const value_type value) noexcept {
|
||||
const auto vers = to_version(value) + 1;
|
||||
return construct(to_entity(value), static_cast<version_type>(vers + (vers == version_mask)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs an identifier from its parts.
|
||||
*
|
||||
* If the version part is not provided, a tombstone is returned.<br/>
|
||||
* If the entity part is not provided, a null identifier is returned.
|
||||
*
|
||||
* @param entity The entity part of the identifier.
|
||||
* @param version The version part of the identifier.
|
||||
* @return A properly constructed identifier.
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) noexcept {
|
||||
return value_type{(entity & entity_mask) | (static_cast<entity_type>(version) << length)};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Combines two identifiers in a single one.
|
||||
*
|
||||
* The returned identifier is a copy of the first element except for its
|
||||
* version, which is taken from the second element.
|
||||
*
|
||||
* @param lhs The identifier from which to take the entity part.
|
||||
* @param rhs The identifier from which to take the version part.
|
||||
* @return A properly constructed identifier.
|
||||
*/
|
||||
[[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept {
|
||||
constexpr auto mask = (version_mask << length);
|
||||
return value_type{(lhs & entity_mask) | (rhs & mask)};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Entity traits.
|
||||
* @tparam Type Type of identifier.
|
||||
*/
|
||||
template<typename Type>
|
||||
struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> {
|
||||
/*! @brief Base type. */
|
||||
using base_type = basic_entt_traits<internal::entt_traits<Type>>;
|
||||
/*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */
|
||||
static constexpr std::size_t page_size = ENTT_SPARSE_PAGE;
|
||||
};
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_integral
|
||||
* @tparam Entity The value type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept {
|
||||
return entt_traits<Entity>::to_integral(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_entity
|
||||
* @tparam Entity The value type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept {
|
||||
return entt_traits<Entity>::to_entity(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @copydoc entt_traits<Entity>::to_version
|
||||
* @tparam Entity The value type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr typename entt_traits<Entity>::version_type to_version(const Entity value) noexcept {
|
||||
return entt_traits<Entity>::to_version(value);
|
||||
}
|
||||
|
||||
/*! @brief Null object for all identifiers. */
|
||||
struct null_t {
|
||||
/**
|
||||
* @brief Converts the null object to identifiers of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @return The null representation for the given type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr operator Entity() const noexcept {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two null objects.
|
||||
* @param other A null object.
|
||||
* @return True in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two null objects.
|
||||
* @param other A null object.
|
||||
* @return False in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
return traits_type::to_entity(entity) == traits_type::to_entity(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
|
||||
return !(entity == *this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares a null object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param 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) 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) noexcept {
|
||||
return !(other == entity);
|
||||
}
|
||||
|
||||
/*! @brief Tombstone object for all identifiers. */
|
||||
struct tombstone_t {
|
||||
/**
|
||||
* @brief Converts the tombstone object to identifiers of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @return The tombstone representation for the given type.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr operator Entity() const noexcept {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two tombstone objects.
|
||||
* @param other A tombstone object.
|
||||
* @return True in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two tombstone objects.
|
||||
* @param other A tombstone object.
|
||||
* @return False in all cases.
|
||||
*/
|
||||
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
|
||||
using traits_type = entt_traits<Entity>;
|
||||
return traits_type::to_version(entity) == traits_type::to_version(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
|
||||
return !(entity == *this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A tombstone object yet to be converted.
|
||||
* @return False if the two elements differ, true otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator==(const Entity entity, const tombstone_t other) noexcept {
|
||||
return other.operator==(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares a tombstone object and an identifier of any type.
|
||||
* @tparam Entity Type of identifier.
|
||||
* @param entity Identifier with which to compare.
|
||||
* @param other A tombstone object yet to be converted.
|
||||
* @return True if the two elements differ, false otherwise.
|
||||
*/
|
||||
template<typename Entity>
|
||||
[[nodiscard]] constexpr bool operator!=(const Entity entity, const tombstone_t other) noexcept {
|
||||
return !(other == entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compile-time constant for null entities.
|
||||
*
|
||||
* There exist implicit conversions from this variable to identifiers of any
|
||||
* allowed type. Similarly, there exist comparison 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 comparison operators between the
|
||||
* tombstone entity and any other identifier.
|
||||
*/
|
||||
inline constexpr tombstone_t tombstone{};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
257
src/entt/entity/fwd.hpp
Normal file
257
src/entt/entity/fwd.hpp
Normal file
@@ -0,0 +1,257 @@
|
||||
#ifndef ENTT_ENTITY_FWD_HPP
|
||||
#define ENTT_ENTITY_FWD_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @brief Default entity identifier. */
|
||||
enum class entity : id_type {};
|
||||
|
||||
/*! @brief Storage deletion policy. */
|
||||
enum class deletion_policy : std::uint8_t {
|
||||
/*! @brief Swap-and-pop deletion policy. */
|
||||
swap_and_pop = 0u,
|
||||
/*! @brief In-place deletion policy. */
|
||||
in_place = 1u
|
||||
};
|
||||
|
||||
template<typename Entity = entity, typename = std::allocator<Entity>>
|
||||
class basic_sparse_set;
|
||||
|
||||
template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
|
||||
class basic_storage;
|
||||
|
||||
template<typename Type>
|
||||
class sigh_mixin;
|
||||
|
||||
/**
|
||||
* @brief Provides a common way to define storage types.
|
||||
* @tparam Type Storage value type.
|
||||
* @tparam Entity A valid entity type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
|
||||
struct storage_type {
|
||||
/*! @brief Type-to-storage conversion result. */
|
||||
using type = sigh_mixin<basic_storage<Type, Entity, Allocator>>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using storage_type_t = typename storage_type<Args...>::type;
|
||||
|
||||
/**
|
||||
* Type-to-storage conversion utility that preserves constness.
|
||||
* @tparam Type Storage value type, eventually const.
|
||||
* @tparam Entity A valid entity type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
|
||||
struct storage_for {
|
||||
/*! @brief Type-to-storage conversion result. */
|
||||
using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper type.
|
||||
* @tparam Args Arguments to forward.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using storage_for_t = typename storage_for<Args...>::type;
|
||||
|
||||
template<typename Entity = entity, typename = std::allocator<Entity>>
|
||||
class basic_registry;
|
||||
|
||||
template<typename, typename, typename = void>
|
||||
class basic_view;
|
||||
|
||||
template<typename Type, typename = std::allocator<Type *>>
|
||||
class basic_runtime_view;
|
||||
|
||||
template<typename, typename, typename>
|
||||
class basic_group;
|
||||
|
||||
template<typename, typename Mask = std::uint32_t, typename = std::allocator<Mask>>
|
||||
class basic_observer;
|
||||
|
||||
template<typename>
|
||||
class basic_organizer;
|
||||
|
||||
template<typename, typename...>
|
||||
struct basic_handle;
|
||||
|
||||
template<typename>
|
||||
class basic_snapshot;
|
||||
|
||||
template<typename>
|
||||
class basic_snapshot_loader;
|
||||
|
||||
template<typename>
|
||||
class basic_continuous_loader;
|
||||
|
||||
/**
|
||||
* @brief Alias for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
struct exclude_t final: type_list<Type...> {
|
||||
/*! @brief Default constructor. */
|
||||
explicit constexpr exclude_t() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Variable template for exclusion lists.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
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 final: type_list<Type...> {
|
||||
/*! @brief Default constructor. */
|
||||
explicit constexpr get_t() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Variable template for lists of observed components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
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 final: type_list<Type...> {
|
||||
/*! @brief Default constructor. */
|
||||
explicit constexpr owned_t() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Variable template for lists of owned components.
|
||||
* @tparam Type List of types.
|
||||
*/
|
||||
template<typename... Type>
|
||||
inline constexpr owned_t<Type...> owned{};
|
||||
|
||||
/**
|
||||
* @brief Applies a given _function_ to a get list and generate a new list.
|
||||
* @tparam Type Types provided by the get list.
|
||||
* @tparam Op Unary operation as template class with a type member named `type`.
|
||||
*/
|
||||
template<typename... Type, template<typename...> class Op>
|
||||
struct type_list_transform<get_t<Type...>, Op> {
|
||||
/*! @brief Resulting get list after applying the transform function. */
|
||||
using type = get_t<typename Op<Type>::type...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Applies a given _function_ to an exclude list and generate a new list.
|
||||
* @tparam Type Types provided by the exclude list.
|
||||
* @tparam Op Unary operation as template class with a type member named `type`.
|
||||
*/
|
||||
template<typename... Type, template<typename...> class Op>
|
||||
struct type_list_transform<exclude_t<Type...>, Op> {
|
||||
/*! @brief Resulting exclude list after applying the transform function. */
|
||||
using type = exclude_t<typename Op<Type>::type...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Applies a given _function_ to an owned list and generate a new list.
|
||||
* @tparam Type Types provided by the owned list.
|
||||
* @tparam Op Unary operation as template class with a type member named `type`.
|
||||
*/
|
||||
template<typename... Type, template<typename...> class Op>
|
||||
struct type_list_transform<owned_t<Type...>, Op> {
|
||||
/*! @brief Resulting owned list after applying the transform function. */
|
||||
using type = owned_t<typename Op<Type>::type...>;
|
||||
};
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using sparse_set = basic_sparse_set<>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Type Type of objects assigned to the entities.
|
||||
*/
|
||||
template<typename Type>
|
||||
using storage = basic_storage<Type>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using registry = basic_registry<>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using observer = basic_observer<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using organizer = basic_organizer<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using handle = basic_handle<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using const_handle = basic_handle<const registry>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using handle_view = basic_handle<registry, Args...>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Args Other template parameters.
|
||||
*/
|
||||
template<typename... Args>
|
||||
using const_handle_view = basic_handle<const registry, Args...>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot = basic_snapshot<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using snapshot_loader = basic_snapshot_loader<registry>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using continuous_loader = basic_continuous_loader<registry>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Get Types of storage iterated by the view.
|
||||
* @tparam Exclude Types of storage used to filter the view.
|
||||
*/
|
||||
template<typename Get, typename Exclude = exclude_t<>>
|
||||
using view = basic_view<type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using runtime_view = basic_runtime_view<sparse_set>;
|
||||
|
||||
/*! @brief Alias declaration for the most common use case. */
|
||||
using const_runtime_view = basic_runtime_view<const sparse_set>;
|
||||
|
||||
/**
|
||||
* @brief Alias declaration for the most common use case.
|
||||
* @tparam Owned Types of storage _owned_ by the group.
|
||||
* @tparam Get Types of storage _observed_ by the group.
|
||||
* @tparam Exclude Types of storage used to filter the group.
|
||||
*/
|
||||
template<typename Owned, typename Get, typename Exclude>
|
||||
using group = basic_group<type_list_transform_t<Owned, storage_for>, type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
1084
src/entt/entity/group.hpp
Normal file
1084
src/entt/entity/group.hpp
Normal file
File diff suppressed because it is too large
Load Diff
384
src/entt/entity/handle.hpp
Normal file
384
src/entt/entity/handle.hpp
Normal file
@@ -0,0 +1,384 @@
|
||||
#ifndef ENTT_ENTITY_HANDLE_HPP
|
||||
#define ENTT_ENTITY_HANDLE_HPP
|
||||
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../core/iterator.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename It>
|
||||
class handle_storage_iterator final {
|
||||
template<typename Other>
|
||||
friend class handle_storage_iterator;
|
||||
|
||||
using underlying_type = std::remove_reference_t<typename It::value_type::second_type>;
|
||||
using entity_type = typename underlying_type::entity_type;
|
||||
|
||||
public:
|
||||
using value_type = typename std::iterator_traits<It>::value_type;
|
||||
using pointer = input_iterator_pointer<value_type>;
|
||||
using reference = value_type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
constexpr handle_storage_iterator() noexcept
|
||||
: entt{null},
|
||||
it{},
|
||||
last{} {}
|
||||
|
||||
constexpr handle_storage_iterator(entity_type value, It from, It to) noexcept
|
||||
: entt{value},
|
||||
it{from},
|
||||
last{to} {
|
||||
while(it != last && !it->second.contains(entt)) {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr handle_storage_iterator &operator++() noexcept {
|
||||
while(++it != last && !it->second.contains(entt)) {}
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr handle_storage_iterator operator++(int) noexcept {
|
||||
handle_storage_iterator orig = *this;
|
||||
return ++(*this), orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr reference operator*() const noexcept {
|
||||
return *it;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr pointer operator->() const noexcept {
|
||||
return operator*();
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
friend constexpr bool operator==(const handle_storage_iterator<ILhs> &, const handle_storage_iterator<IRhs> &) noexcept;
|
||||
|
||||
private:
|
||||
entity_type entt;
|
||||
It it;
|
||||
It last;
|
||||
};
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator==(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
|
||||
return lhs.it == rhs.it;
|
||||
}
|
||||
|
||||
template<typename ILhs, typename IRhs>
|
||||
[[nodiscard]] constexpr bool operator!=(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Non-owning handle to an entity.
|
||||
*
|
||||
* Tiny wrapper around a registry and an entity.
|
||||
*
|
||||
* @tparam Registry Basic registry type.
|
||||
* @tparam Scope Types to which to restrict the scope of a handle.
|
||||
*/
|
||||
template<typename Registry, typename... Scope>
|
||||
struct basic_handle {
|
||||
/*! @brief Type of registry accepted by the handle. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
/*! @brief Underlying version type. */
|
||||
using version_type = typename registry_type::version_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = typename registry_type::size_type;
|
||||
|
||||
/*! @brief Constructs an invalid handle. */
|
||||
basic_handle() noexcept
|
||||
: reg{},
|
||||
entt{null} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a handle from a given registry and entity.
|
||||
* @param ref An instance of the registry class.
|
||||
* @param value A valid identifier.
|
||||
*/
|
||||
basic_handle(registry_type &ref, entity_type value) noexcept
|
||||
: reg{&ref},
|
||||
entt{value} {}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterable object to use to _visit_ a handle.
|
||||
*
|
||||
* The iterable object returns a pair that contains the name and a reference
|
||||
* to the current storage.<br/>
|
||||
* Returned storage are those that contain the entity associated with the
|
||||
* handle.
|
||||
*
|
||||
* @return An iterable object to use to _visit_ the handle.
|
||||
*/
|
||||
[[nodiscard]] auto storage() const noexcept {
|
||||
auto iterable = reg->storage();
|
||||
using iterator_type = internal::handle_storage_iterator<typename decltype(iterable)::iterator>;
|
||||
return iterable_adaptor{iterator_type{entt, iterable.begin(), iterable.end()}, iterator_type{entt, iterable.end(), iterable.end()}};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs a const handle from a non-const one.
|
||||
* @tparam Other A valid entity type.
|
||||
* @tparam Args Scope of the handle to construct.
|
||||
* @return A const handle referring to the same registry and the same
|
||||
* entity.
|
||||
*/
|
||||
template<typename Other, typename... Args>
|
||||
operator basic_handle<Other, Args...>() const noexcept {
|
||||
static_assert(std::is_same_v<Other, Registry> || std::is_same_v<std::remove_const_t<Other>, Registry>, "Invalid conversion between different handles");
|
||||
static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v<type_list<Scope...>, Args>))), "Invalid conversion between different handles");
|
||||
|
||||
return reg ? basic_handle<Other, Args...>{*reg, entt} : basic_handle<Other, Args...>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Converts a handle to its underlying entity.
|
||||
* @return The contained identifier.
|
||||
*/
|
||||
[[nodiscard]] operator entity_type() const noexcept {
|
||||
return entity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle refers to non-null registry pointer and entity.
|
||||
* @return True if the handle refers to non-null registry and entity, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] explicit operator bool() const noexcept {
|
||||
return reg && reg->valid(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle refers to a valid entity or not.
|
||||
* @return True if the handle refers to a valid entity, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool valid() const {
|
||||
return reg->valid(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a pointer to the underlying registry, if any.
|
||||
* @return A pointer to the underlying registry, if any.
|
||||
*/
|
||||
[[nodiscard]] registry_type *registry() const noexcept {
|
||||
return reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the entity associated with a handle.
|
||||
* @return The entity associated with the handle.
|
||||
*/
|
||||
[[nodiscard]] entity_type entity() const noexcept {
|
||||
return entt;
|
||||
}
|
||||
|
||||
/*! @brief Destroys the entity associated with a handle. */
|
||||
void destroy() {
|
||||
reg->destroy(std::exchange(entt, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destroys the entity associated with a handle.
|
||||
* @param version A desired version upon destruction.
|
||||
*/
|
||||
void destroy(const version_type version) {
|
||||
reg->destroy(std::exchange(entt, null), version);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns the given component to a handle.
|
||||
* @tparam Component Type of component to create.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return A reference to the newly created component.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template emplace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns or replaces the given component for a handle.
|
||||
* @tparam Component Type of component to assign or replace.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return A reference to the newly created component.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) emplace_or_replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template emplace_or_replace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Patches the given component for a handle.
|
||||
* @tparam Component Type of component to patch.
|
||||
* @tparam Func Types of the function objects to invoke.
|
||||
* @param func Valid function objects.
|
||||
* @return A reference to the patched component.
|
||||
*/
|
||||
template<typename Component, typename... Func>
|
||||
decltype(auto) patch(Func &&...func) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template patch<Component>(entt, std::forward<Func>(func)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Replaces the given component for a handle.
|
||||
* @tparam Component Type of component to replace.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return A reference to the component being replaced.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
decltype(auto) replace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template replace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes the given components from a handle.
|
||||
* @tparam Component Types of components to remove.
|
||||
* @return The number of components actually removed.
|
||||
*/
|
||||
template<typename... Component>
|
||||
size_type remove() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
|
||||
return reg->template remove<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erases the given components from a handle.
|
||||
* @tparam Component Types of components to erase.
|
||||
*/
|
||||
template<typename... Component>
|
||||
void erase() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
|
||||
reg->template erase<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle has all the given components.
|
||||
* @tparam Component Components for which to perform the check.
|
||||
* @return True if the handle has all the components, false otherwise.
|
||||
*/
|
||||
template<typename... Component>
|
||||
[[nodiscard]] decltype(auto) all_of() const {
|
||||
return reg->template all_of<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle has at least one of the given components.
|
||||
* @tparam Component Components for which to perform the check.
|
||||
* @return True if the handle has at least one of the given components,
|
||||
* false otherwise.
|
||||
*/
|
||||
template<typename... Component>
|
||||
[[nodiscard]] decltype(auto) any_of() const {
|
||||
return reg->template any_of<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns references to the given components for a handle.
|
||||
* @tparam Component Types of components to get.
|
||||
* @return References to the components owned by the handle.
|
||||
*/
|
||||
template<typename... Component>
|
||||
[[nodiscard]] decltype(auto) get() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
|
||||
return reg->template get<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the given component for a handle.
|
||||
* @tparam Component Type of component to get.
|
||||
* @tparam Args Types of arguments to use to construct the component.
|
||||
* @param args Parameters to use to initialize the component.
|
||||
* @return Reference to the component owned by the handle.
|
||||
*/
|
||||
template<typename Component, typename... Args>
|
||||
[[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const {
|
||||
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
|
||||
return reg->template get_or_emplace<Component>(entt, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns pointers to the given components for a handle.
|
||||
* @tparam Component Types of components to get.
|
||||
* @return Pointers to the components owned by the handle.
|
||||
*/
|
||||
template<typename... Component>
|
||||
[[nodiscard]] auto try_get() const {
|
||||
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
|
||||
return reg->template try_get<Component...>(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a handle has components assigned.
|
||||
* @return True if the handle has no components assigned, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool orphan() const {
|
||||
return reg->orphan(entt);
|
||||
}
|
||||
|
||||
private:
|
||||
registry_type *reg;
|
||||
entity_type entt;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compares two handles.
|
||||
* @tparam Args Scope of the first handle.
|
||||
* @tparam Other Scope of the second handle.
|
||||
* @param lhs A valid handle.
|
||||
* @param rhs A valid handle.
|
||||
* @return True if both handles refer to the same registry and the same
|
||||
* entity, false otherwise.
|
||||
*/
|
||||
template<typename... Args, typename... Other>
|
||||
[[nodiscard]] bool operator==(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
|
||||
return lhs.registry() == rhs.registry() && lhs.entity() == rhs.entity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compares two handles.
|
||||
* @tparam Args Scope of the first handle.
|
||||
* @tparam Other Scope of the second handle.
|
||||
* @param lhs A valid handle.
|
||||
* @param rhs A valid handle.
|
||||
* @return False if both handles refer to the same registry and the same
|
||||
* entity, true otherwise.
|
||||
*/
|
||||
template<typename... Args, typename... Other>
|
||||
[[nodiscard]] bool operator!=(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
258
src/entt/entity/helper.hpp
Normal file
258
src/entt/entity/helper.hpp
Normal file
@@ -0,0 +1,258 @@
|
||||
#ifndef ENTT_ENTITY_HELPER_HPP
|
||||
#define ENTT_ENTITY_HELPER_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../core/fwd.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../signal/delegate.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "group.hpp"
|
||||
#include "view.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Converts a registry to a view.
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Registry>
|
||||
class as_view {
|
||||
template<typename... Get, typename... Exclude>
|
||||
auto dispatch(get_t<Get...>, exclude_t<Exclude...>) const {
|
||||
return reg.template view<constness_as_t<typename Get::value_type, Get>...>(exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{});
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Type of registry to convert. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs a converter for a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
as_view(registry_type &source) noexcept
|
||||
: reg{source} {}
|
||||
|
||||
/**
|
||||
* @brief Conversion function from a registry to a view.
|
||||
* @tparam Get Type of storage used to construct the view.
|
||||
* @tparam Exclude Types of storage used to filter the view.
|
||||
* @return A newly created view.
|
||||
*/
|
||||
template<typename Get, typename Exclude>
|
||||
operator basic_view<Get, Exclude>() const {
|
||||
return dispatch(Get{}, Exclude{});
|
||||
}
|
||||
|
||||
private:
|
||||
registry_type ®
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Converts a registry to a group.
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Registry>
|
||||
class as_group {
|
||||
template<typename... Owned, typename... Get, typename... Exclude>
|
||||
auto dispatch(owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>) const {
|
||||
if constexpr(std::is_const_v<registry_type>) {
|
||||
return reg.template group_if_exists<typename Owned::value_type...>(get_t<typename Get::value_type...>{}, exclude_t<typename Exclude::value_type...>{});
|
||||
} else {
|
||||
return reg.template group<constness_as_t<typename Owned::value_type, Owned>...>(get_t<constness_as_t<typename Get::value_type, Get>...>{}, exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{});
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Type of registry to convert. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
|
||||
/**
|
||||
* @brief Constructs a converter for a given registry.
|
||||
* @param source A valid reference to a registry.
|
||||
*/
|
||||
as_group(registry_type &source) noexcept
|
||||
: reg{source} {}
|
||||
|
||||
/**
|
||||
* @brief Conversion function from a registry to a group.
|
||||
* @tparam Owned Types of _owned_ by the group.
|
||||
* @tparam Get Types of storage _observed_ by the group.
|
||||
* @tparam Exclude Types of storage used to filter the group.
|
||||
* @return A newly created group.
|
||||
*/
|
||||
template<typename Owned, typename Get, typename Exclude>
|
||||
operator basic_group<Owned, Get, Exclude>() const {
|
||||
return dispatch(Owned{}, Get{}, Exclude{});
|
||||
}
|
||||
|
||||
private:
|
||||
registry_type ®
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper to create a listener that directly invokes a member function.
|
||||
* @tparam Member Member function to invoke on a component of the given type.
|
||||
* @tparam Registry Basic registry type.
|
||||
* @param reg A registry that contains the given entity and its components.
|
||||
* @param entt Entity from which to get the component.
|
||||
*/
|
||||
template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, Member>>>
|
||||
void invoke(Registry ®, const typename Registry::entity_type entt) {
|
||||
static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
|
||||
delegate<void(Registry &, const typename Registry::entity_type)> func;
|
||||
func.template connect<Member>(reg.template get<member_class_t<decltype(Member)>>(entt));
|
||||
func(reg, entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the entity associated with a given component.
|
||||
*
|
||||
* @warning
|
||||
* Currently, this function only works correctly with the default pool as it
|
||||
* makes assumptions about how the components are laid out.
|
||||
*
|
||||
* @tparam Registry Basic registry type.
|
||||
* @tparam Component Type of component.
|
||||
* @param reg A registry that contains the given entity and its components.
|
||||
* @param instance A valid component instance.
|
||||
* @return The entity associated with the given component.
|
||||
*/
|
||||
template<typename Registry, typename Component>
|
||||
typename Registry::entity_type to_entity(const Registry ®, const Component &instance) {
|
||||
if(const auto *storage = reg.template storage<Component>(); storage) {
|
||||
constexpr auto page_size = std::remove_const_t<std::remove_pointer_t<decltype(storage)>>::traits_type::page_size;
|
||||
const typename Registry::common_type &base = *storage;
|
||||
const auto *addr = std::addressof(instance);
|
||||
|
||||
for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) {
|
||||
if(const auto dist = (addr - std::addressof(storage->get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(page_size)) {
|
||||
return *(it + dist);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/*! @brief Primary template isn't defined on purpose. */
|
||||
template<typename...>
|
||||
struct sigh_helper;
|
||||
|
||||
/**
|
||||
* @brief Signal connection helper for registries.
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Registry>
|
||||
struct sigh_helper<Registry> {
|
||||
/*! @brief Registry type. */
|
||||
using registry_type = Registry;
|
||||
|
||||
/**
|
||||
* @brief Constructs a helper for a given registry.
|
||||
* @param ref A valid reference to a registry.
|
||||
*/
|
||||
sigh_helper(registry_type &ref)
|
||||
: bucket{&ref} {}
|
||||
|
||||
/**
|
||||
* @brief Binds a properly initialized helper to a given signal type.
|
||||
* @tparam Type Type of signal to bind the helper to.
|
||||
* @param id Optional name for the underlying storage to use.
|
||||
* @return A helper for a given registry and signal type.
|
||||
*/
|
||||
template<typename Type>
|
||||
auto with(const id_type id = type_hash<Type>::value()) noexcept {
|
||||
return sigh_helper<registry_type, Type>{*bucket, id};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the underlying registry.
|
||||
* @return A reference to the underlying registry.
|
||||
*/
|
||||
[[nodiscard]] registry_type ®istry() noexcept {
|
||||
return *bucket;
|
||||
}
|
||||
|
||||
private:
|
||||
registry_type *bucket;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Signal connection helper for registries.
|
||||
* @tparam Registry Basic registry type.
|
||||
* @tparam Type Type of signal to connect listeners to.
|
||||
*/
|
||||
template<typename Registry, typename Type>
|
||||
struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
|
||||
/*! @brief Registry type. */
|
||||
using registry_type = Registry;
|
||||
|
||||
/**
|
||||
* @brief Constructs a helper for a given registry.
|
||||
* @param ref A valid reference to a registry.
|
||||
* @param id Optional name for the underlying storage to use.
|
||||
*/
|
||||
sigh_helper(registry_type &ref, const id_type id = type_hash<Type>::value())
|
||||
: sigh_helper<Registry>{ref},
|
||||
name{id} {}
|
||||
|
||||
/**
|
||||
* @brief Forwards the call to `on_construct` on the underlying storage.
|
||||
* @tparam Candidate Function or member to connect.
|
||||
* @tparam Args Type of class or type of payload, if any.
|
||||
* @param args A valid object that fits the purpose, if any.
|
||||
* @return This helper.
|
||||
*/
|
||||
template<auto Candidate, typename... Args>
|
||||
auto on_construct(Args &&...args) {
|
||||
this->registry().template on_construct<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forwards the call to `on_update` on the underlying storage.
|
||||
* @tparam Candidate Function or member to connect.
|
||||
* @tparam Args Type of class or type of payload, if any.
|
||||
* @param args A valid object that fits the purpose, if any.
|
||||
* @return This helper.
|
||||
*/
|
||||
template<auto Candidate, typename... Args>
|
||||
auto on_update(Args &&...args) {
|
||||
this->registry().template on_update<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forwards the call to `on_destroy` on the underlying storage.
|
||||
* @tparam Candidate Function or member to connect.
|
||||
* @tparam Args Type of class or type of payload, if any.
|
||||
* @param args A valid object that fits the purpose, if any.
|
||||
* @return This helper.
|
||||
*/
|
||||
template<auto Candidate, typename... Args>
|
||||
auto on_destroy(Args &&...args) {
|
||||
this->registry().template on_destroy<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
id_type name;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Deduction guide.
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Registry>
|
||||
sigh_helper(Registry &) -> sigh_helper<Registry>;
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
293
src/entt/entity/mixin.hpp
Normal file
293
src/entt/entity/mixin.hpp
Normal file
@@ -0,0 +1,293 @@
|
||||
#ifndef ENTT_ENTITY_MIXIN_HPP
|
||||
#define ENTT_ENTITY_MIXIN_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../config/config.h"
|
||||
#include "../core/any.hpp"
|
||||
#include "../signal/sigh.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @brief Mixin type used to add signal support to storage types.
|
||||
*
|
||||
* The function type of a listener is equivalent to:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(basic_registry<entity_type> &, entity_type);
|
||||
* @endcode
|
||||
*
|
||||
* This applies to all signals made available.
|
||||
*
|
||||
* @tparam Type The type of the underlying storage.
|
||||
*/
|
||||
template<typename Type>
|
||||
class sigh_mixin final: public Type {
|
||||
using underlying_type = Type;
|
||||
using basic_registry_type = basic_registry<typename underlying_type::entity_type, typename underlying_type::base_type::allocator_type>;
|
||||
using sigh_type = sigh<void(basic_registry_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
|
||||
using underlying_iterator = typename underlying_type::base_type::basic_iterator;
|
||||
|
||||
basic_registry_type &owner_or_assert() const noexcept {
|
||||
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
|
||||
return *owner;
|
||||
}
|
||||
|
||||
void pop(underlying_iterator first, underlying_iterator last) final {
|
||||
if(auto ® = owner_or_assert(); destruction.empty()) {
|
||||
underlying_type::pop(first, last);
|
||||
} else {
|
||||
for(; first != last; ++first) {
|
||||
const auto entt = *first;
|
||||
destruction.publish(reg, entt);
|
||||
const auto it = underlying_type::find(entt);
|
||||
underlying_type::pop(it, it + 1u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pop_all() final {
|
||||
if(auto ® = owner_or_assert(); !destruction.empty()) {
|
||||
for(auto pos = underlying_type::each().begin().base().index(); !(pos < 0); --pos) {
|
||||
if constexpr(underlying_type::traits_type::in_place_delete) {
|
||||
if(const auto entt = underlying_type::operator[](static_cast<typename underlying_type::size_type>(pos)); entt != tombstone) {
|
||||
destruction.publish(reg, entt);
|
||||
}
|
||||
} else {
|
||||
destruction.publish(reg, underlying_type::operator[](static_cast<typename underlying_type::size_type>(pos)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
underlying_type::pop_all();
|
||||
}
|
||||
|
||||
underlying_iterator try_emplace(const typename underlying_type::entity_type entt, const bool force_back, const void *value) final {
|
||||
const auto it = underlying_type::try_emplace(entt, force_back, value);
|
||||
|
||||
if(auto ® = owner_or_assert(); it != underlying_type::base_type::end()) {
|
||||
construction.publish(reg, *it);
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = typename underlying_type::allocator_type;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename underlying_type::entity_type;
|
||||
/*! @brief Expected registry type. */
|
||||
using registry_type = basic_registry_type;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
sigh_mixin()
|
||||
: sigh_mixin{allocator_type{}} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty storage with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit sigh_mixin(const allocator_type &allocator)
|
||||
: underlying_type{allocator},
|
||||
owner{},
|
||||
construction{allocator},
|
||||
destruction{allocator},
|
||||
update{allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param other The instance to move from.
|
||||
*/
|
||||
sigh_mixin(sigh_mixin &&other) noexcept
|
||||
: underlying_type{std::move(other)},
|
||||
owner{other.owner},
|
||||
construction{std::move(other.construction)},
|
||||
destruction{std::move(other.destruction)},
|
||||
update{std::move(other.update)} {}
|
||||
|
||||
/**
|
||||
* @brief Allocator-extended move constructor.
|
||||
* @param other The instance to move from.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
sigh_mixin(sigh_mixin &&other, const allocator_type &allocator) noexcept
|
||||
: underlying_type{std::move(other), allocator},
|
||||
owner{other.owner},
|
||||
construction{std::move(other.construction), allocator},
|
||||
destruction{std::move(other.destruction), allocator},
|
||||
update{std::move(other.update), allocator} {}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param other The instance to move from.
|
||||
* @return This storage.
|
||||
*/
|
||||
sigh_mixin &operator=(sigh_mixin &&other) noexcept {
|
||||
underlying_type::operator=(std::move(other));
|
||||
owner = other.owner;
|
||||
construction = std::move(other.construction);
|
||||
destruction = std::move(other.destruction);
|
||||
update = std::move(other.update);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Exchanges the contents with those of a given storage.
|
||||
* @param other Storage to exchange the content with.
|
||||
*/
|
||||
void swap(sigh_mixin &other) {
|
||||
using std::swap;
|
||||
underlying_type::swap(other);
|
||||
swap(owner, other.owner);
|
||||
swap(construction, other.construction);
|
||||
swap(destruction, other.destruction);
|
||||
swap(update, other.update);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object.
|
||||
*
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever a new instance is created and assigned to an entity.<br/>
|
||||
* Listeners are invoked after the object has been assigned to the entity.
|
||||
*
|
||||
* @sa sink
|
||||
*
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
[[nodiscard]] auto on_construct() noexcept {
|
||||
return sink{construction};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object.
|
||||
*
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever an instance is explicitly updated.<br/>
|
||||
* Listeners are invoked after the object has been updated.
|
||||
*
|
||||
* @sa sink
|
||||
*
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
[[nodiscard]] auto on_update() noexcept {
|
||||
return sink{update};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a sink object.
|
||||
*
|
||||
* The sink returned by this function can be used to receive notifications
|
||||
* whenever an instance is removed from an entity and thus destroyed.<br/>
|
||||
* Listeners are invoked before the object has been removed from the entity.
|
||||
*
|
||||
* @sa sink
|
||||
*
|
||||
* @return A temporary sink object.
|
||||
*/
|
||||
[[nodiscard]] auto on_destroy() noexcept {
|
||||
return sink{destruction};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Emplace elements into a storage.
|
||||
*
|
||||
* The behavior of this operation depends on the underlying storage type
|
||||
* (for example, components vs entities).<br/>
|
||||
* Refer to the specific documentation for more details.
|
||||
*
|
||||
* @return A return value as returned by the underlying storage.
|
||||
*/
|
||||
auto emplace() {
|
||||
const auto entt = underlying_type::emplace();
|
||||
construction.publish(owner_or_assert(), entt);
|
||||
return entt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Emplace elements into a storage.
|
||||
*
|
||||
* The behavior of this operation depends on the underlying storage type
|
||||
* (for example, components vs entities).<br/>
|
||||
* Refer to the specific documentation for more details.
|
||||
*
|
||||
* @tparam Args Types of arguments to forward to the underlying storage.
|
||||
* @param hint A valid identifier.
|
||||
* @param args Parameters to forward to the underlying storage.
|
||||
* @return A return value as returned by the underlying storage.
|
||||
*/
|
||||
template<typename... Args>
|
||||
decltype(auto) emplace(const entity_type hint, Args &&...args) {
|
||||
if constexpr(std::is_same_v<typename underlying_type::value_type, typename underlying_type::entity_type>) {
|
||||
const auto entt = underlying_type::emplace(hint, std::forward<Args>(args)...);
|
||||
construction.publish(owner_or_assert(), entt);
|
||||
return entt;
|
||||
} else {
|
||||
underlying_type::emplace(hint, std::forward<Args>(args)...);
|
||||
construction.publish(owner_or_assert(), hint);
|
||||
return this->get(hint);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Patches the given instance for an entity.
|
||||
* @tparam Func Types of the function objects to invoke.
|
||||
* @param entt A valid identifier.
|
||||
* @param func Valid function objects.
|
||||
* @return A reference to the patched instance.
|
||||
*/
|
||||
template<typename... Func>
|
||||
decltype(auto) patch(const entity_type entt, Func &&...func) {
|
||||
underlying_type::patch(entt, std::forward<Func>(func)...);
|
||||
update.publish(owner_or_assert(), entt);
|
||||
return this->get(entt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Emplace elements into a storage.
|
||||
*
|
||||
* The behavior of this operation depends on the underlying storage type
|
||||
* (for example, components vs entities).<br/>
|
||||
* Refer to the specific documentation for more details.
|
||||
*
|
||||
* @tparam It Iterator type (as required by the underlying storage type).
|
||||
* @tparam Args Types of arguments to forward to the underlying storage.
|
||||
* @param first An iterator to the first element of the range.
|
||||
* @param last An iterator past the last element of the range.
|
||||
* @param args Parameters to use to forward to the underlying storage.
|
||||
*/
|
||||
template<typename It, typename... Args>
|
||||
void insert(It first, It last, Args &&...args) {
|
||||
underlying_type::insert(first, last, std::forward<Args>(args)...);
|
||||
|
||||
if(auto ® = owner_or_assert(); !construction.empty()) {
|
||||
for(; first != last; ++first) {
|
||||
construction.publish(reg, *first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Forwards variables to derived classes, if any.
|
||||
* @param value A variable wrapped in an opaque container.
|
||||
*/
|
||||
void bind(any value) noexcept final {
|
||||
auto *reg = any_cast<basic_registry_type>(&value);
|
||||
owner = reg ? reg : owner;
|
||||
underlying_type::bind(std::move(value));
|
||||
}
|
||||
|
||||
private:
|
||||
basic_registry_type *owner;
|
||||
sigh_type construction;
|
||||
sigh_type destruction;
|
||||
sigh_type update;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
436
src/entt/entity/observer.hpp
Normal file
436
src/entt/entity/observer.hpp
Normal file
@@ -0,0 +1,436 @@
|
||||
#ifndef ENTT_ENTITY_OBSERVER_HPP
|
||||
#define ENTT_ENTITY_OBSERVER_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../signal/delegate.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "storage.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @brief Grouping matcher. */
|
||||
template<typename...>
|
||||
struct matcher {};
|
||||
|
||||
/**
|
||||
* @brief Collector.
|
||||
*
|
||||
* Primary template isn't defined on purpose. All the specializations give a
|
||||
* compile-time error, but for a few reasonable cases.
|
||||
*/
|
||||
template<typename...>
|
||||
struct basic_collector;
|
||||
|
||||
/**
|
||||
* @brief Collector.
|
||||
*
|
||||
* A collector contains a set of rules (literally, matchers) to use to track
|
||||
* entities.<br/>
|
||||
* Its main purpose is to generate a descriptor that allows an observer to know
|
||||
* how to connect to a registry.
|
||||
*/
|
||||
template<>
|
||||
struct basic_collector<> {
|
||||
/**
|
||||
* @brief Adds a grouping matcher to the collector.
|
||||
* @tparam AllOf Types of components tracked by the matcher.
|
||||
* @tparam NoneOf Types of components used to filter out entities.
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename... AllOf, typename... NoneOf>
|
||||
static constexpr auto group(exclude_t<NoneOf...> = exclude_t{}) noexcept {
|
||||
return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an observing matcher to the collector.
|
||||
* @tparam AnyOf Type of component for which changes should be detected.
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename AnyOf>
|
||||
static constexpr auto update() noexcept {
|
||||
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>>{};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Collector.
|
||||
* @copydetails basic_collector<>
|
||||
* @tparam Reject Untracked types used to filter out entities.
|
||||
* @tparam Require Untracked types required by the matcher.
|
||||
* @tparam Rule Specific details of the current matcher.
|
||||
* @tparam Other Other matchers.
|
||||
*/
|
||||
template<typename... Reject, typename... Require, typename... Rule, typename... Other>
|
||||
struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule...>, Other...> {
|
||||
/*! @brief Current matcher. */
|
||||
using current_type = matcher<type_list<Reject...>, type_list<Require...>, Rule...>;
|
||||
|
||||
/**
|
||||
* @brief Adds a grouping matcher to the collector.
|
||||
* @tparam AllOf Types of components tracked by the matcher.
|
||||
* @tparam NoneOf Types of components used to filter out entities.
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename... AllOf, typename... NoneOf>
|
||||
static constexpr auto group(exclude_t<NoneOf...> = exclude_t{}) noexcept {
|
||||
return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>, current_type, Other...>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an observing matcher to the collector.
|
||||
* @tparam AnyOf Type of component for which changes should be detected.
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename AnyOf>
|
||||
static constexpr auto update() noexcept {
|
||||
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>, current_type, Other...>{};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the filter of the last added matcher.
|
||||
* @tparam AllOf Types of components required by the matcher.
|
||||
* @tparam NoneOf Types of components used to filter out entities.
|
||||
* @return The updated collector.
|
||||
*/
|
||||
template<typename... AllOf, typename... NoneOf>
|
||||
static constexpr auto where(exclude_t<NoneOf...> = exclude_t{}) noexcept {
|
||||
using extended_type = matcher<type_list<Reject..., NoneOf...>, type_list<Require..., AllOf...>, Rule...>;
|
||||
return basic_collector<extended_type, Other...>{};
|
||||
}
|
||||
};
|
||||
|
||||
/*! @brief Variable template used to ease the definition of collectors. */
|
||||
inline constexpr basic_collector<> collector{};
|
||||
|
||||
/**
|
||||
* @brief Observer.
|
||||
*
|
||||
* An observer returns all the entities and only the entities that fit the
|
||||
* requirements of at least one matcher. Moreover, it's guaranteed that the
|
||||
* entity list is tightly packed in memory for fast iterations.<br/>
|
||||
* In general, observers don't stay true to the order of any set of components.
|
||||
*
|
||||
* Observers work mainly with two types of matchers, provided through a
|
||||
* collector:
|
||||
*
|
||||
* * Observing matcher: an observer will return at least all the living entities
|
||||
* for which one or more of the given components have been updated and not yet
|
||||
* destroyed.
|
||||
* * Grouping matcher: an observer will return at least all the living entities
|
||||
* that would have entered the given group if it existed and that would have
|
||||
* not yet left it.
|
||||
*
|
||||
* If an entity respects the requirements of multiple matchers, it will be
|
||||
* returned once and only once by the observer in any case.
|
||||
*
|
||||
* Matchers support also filtering by means of a _where_ clause that accepts
|
||||
* both a list of types and an exclusion list.<br/>
|
||||
* Whenever a matcher finds that an entity matches its requirements, the
|
||||
* condition of the filter is verified before to register the entity itself.
|
||||
* Moreover, a registered entity isn't returned by the observer if the condition
|
||||
* set by the filter is broken in the meantime.
|
||||
*
|
||||
* @b Important
|
||||
*
|
||||
* Iterators aren't invalidated if:
|
||||
*
|
||||
* * New instances of the given components are created and assigned to entities.
|
||||
* * The entity currently pointed is modified (as an example, if one of the
|
||||
* given components is removed from the entity to which the iterator points).
|
||||
* * The entity currently pointed is destroyed.
|
||||
*
|
||||
* In all the other cases, modifying the pools of the given components in any
|
||||
* way invalidates all the iterators.
|
||||
*
|
||||
* @warning
|
||||
* Lifetime of an observer doesn't necessarily have to overcome that of the
|
||||
* registry to which it is connected. However, the observer must be disconnected
|
||||
* from the registry before being destroyed to avoid crashes due to dangling
|
||||
* pointers.
|
||||
*
|
||||
* @tparam Registry Basic registry type.
|
||||
* @tparam Mask Mask type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Registry, typename Mask, typename Allocator>
|
||||
class basic_observer: private basic_storage<Mask, typename Registry::entity_type, Allocator> {
|
||||
using base_type = basic_storage<Mask, typename Registry::entity_type, Allocator>;
|
||||
|
||||
template<typename>
|
||||
struct matcher_handler;
|
||||
|
||||
template<typename... Reject, typename... Require, typename AnyOf>
|
||||
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
|
||||
template<std::size_t Index>
|
||||
static void maybe_valid_if(basic_observer &obs, Registry ®, const typename Registry::entity_type entt) {
|
||||
if(reg.template all_of<Require...>(entt) && !reg.template any_of<Reject...>(entt)) {
|
||||
if(!obs.contains(entt)) {
|
||||
obs.emplace(entt);
|
||||
}
|
||||
|
||||
obs.get(entt) |= (1 << Index);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) {
|
||||
if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) {
|
||||
obs.erase(entt);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void connect(basic_observer &obs, Registry ®) {
|
||||
(reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
|
||||
(reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
|
||||
reg.template on_update<AnyOf>().template connect<&maybe_valid_if<Index>>(obs);
|
||||
reg.template on_destroy<AnyOf>().template connect<&discard_if<Index>>(obs);
|
||||
}
|
||||
|
||||
static void disconnect(basic_observer &obs, Registry ®) {
|
||||
(reg.template on_destroy<Require>().disconnect(&obs), ...);
|
||||
(reg.template on_construct<Reject>().disconnect(&obs), ...);
|
||||
reg.template on_update<AnyOf>().disconnect(&obs);
|
||||
reg.template on_destroy<AnyOf>().disconnect(&obs);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
|
||||
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> {
|
||||
template<std::size_t Index, typename... Ignore>
|
||||
static void maybe_valid_if(basic_observer &obs, Registry ®, const typename Registry::entity_type entt) {
|
||||
auto condition = [®, entt]() {
|
||||
if constexpr(sizeof...(Ignore) == 0) {
|
||||
return reg.template all_of<AllOf..., Require...>(entt) && !reg.template any_of<NoneOf..., Reject...>(entt);
|
||||
} else {
|
||||
return reg.template all_of<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !reg.template any_of<NoneOf>(entt)) && ...) && !reg.template any_of<Reject...>(entt);
|
||||
}
|
||||
};
|
||||
|
||||
if(condition()) {
|
||||
if(!obs.contains(entt)) {
|
||||
obs.emplace(entt);
|
||||
}
|
||||
|
||||
obs.get(entt) |= (1 << Index);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) {
|
||||
if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) {
|
||||
obs.erase(entt);
|
||||
}
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void connect(basic_observer &obs, Registry ®) {
|
||||
(reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
|
||||
(reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
|
||||
(reg.template on_construct<AllOf>().template connect<&maybe_valid_if<Index>>(obs), ...);
|
||||
(reg.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index, NoneOf>>(obs), ...);
|
||||
(reg.template on_destroy<AllOf>().template connect<&discard_if<Index>>(obs), ...);
|
||||
(reg.template on_construct<NoneOf>().template connect<&discard_if<Index>>(obs), ...);
|
||||
}
|
||||
|
||||
static void disconnect(basic_observer &obs, Registry ®) {
|
||||
(reg.template on_destroy<Require>().disconnect(&obs), ...);
|
||||
(reg.template on_construct<Reject>().disconnect(&obs), ...);
|
||||
(reg.template on_construct<AllOf>().disconnect(&obs), ...);
|
||||
(reg.template on_destroy<NoneOf>().disconnect(&obs), ...);
|
||||
(reg.template on_destroy<AllOf>().disconnect(&obs), ...);
|
||||
(reg.template on_construct<NoneOf>().disconnect(&obs), ...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Matcher>
|
||||
static void disconnect(Registry ®, basic_observer &obs) {
|
||||
(matcher_handler<Matcher>::disconnect(obs, reg), ...);
|
||||
}
|
||||
|
||||
template<typename... Matcher, std::size_t... Index>
|
||||
void connect(Registry ®, std::index_sequence<Index...>) {
|
||||
static_assert(sizeof...(Matcher) < std::numeric_limits<typename base_type::value_type>::digits, "Too many matchers");
|
||||
(matcher_handler<Matcher>::template connect<Index>(*this, reg), ...);
|
||||
release.template connect<&basic_observer::disconnect<Matcher...>>(reg);
|
||||
}
|
||||
|
||||
public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Random access iterator type. */
|
||||
using iterator = typename registry_type::common_type::iterator;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_observer()
|
||||
: basic_observer{allocator_type{}} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs an empty storage with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit basic_observer(const allocator_type &allocator)
|
||||
: base_type{allocator},
|
||||
release{} {}
|
||||
|
||||
/*! @brief Default copy constructor, deleted on purpose. */
|
||||
basic_observer(const basic_observer &) = delete;
|
||||
|
||||
/*! @brief Default move constructor, deleted on purpose. */
|
||||
basic_observer(basic_observer &&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Creates an observer and connects it to a given registry.
|
||||
* @tparam Matcher Types of matchers to use to initialize the observer.
|
||||
* @param reg A valid reference to a registry.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
template<typename... Matcher>
|
||||
basic_observer(registry_type ®, basic_collector<Matcher...>, const allocator_type &allocator = allocator_type{})
|
||||
: basic_observer{allocator} {
|
||||
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator, deleted on purpose.
|
||||
* @return This observer.
|
||||
*/
|
||||
basic_observer &operator=(const basic_observer &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator, deleted on purpose.
|
||||
* @return This observer.
|
||||
*/
|
||||
basic_observer &operator=(basic_observer &&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Connects an observer to a given registry.
|
||||
* @tparam Matcher Types of matchers to use to initialize the observer.
|
||||
* @param reg A valid reference to a registry.
|
||||
*/
|
||||
template<typename... Matcher>
|
||||
void connect(registry_type ®, basic_collector<Matcher...>) {
|
||||
disconnect();
|
||||
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
|
||||
base_type::clear();
|
||||
}
|
||||
|
||||
/*! @brief Disconnects an observer from the registry it keeps track of. */
|
||||
void disconnect() {
|
||||
if(release) {
|
||||
release(*this);
|
||||
release.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in an observer.
|
||||
* @return Number of elements.
|
||||
*/
|
||||
[[nodiscard]] size_type size() const noexcept {
|
||||
return base_type::size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks whether an observer is empty.
|
||||
* @return True if the observer is empty, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept {
|
||||
return base_type::empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Direct access to the list of entities of the observer.
|
||||
*
|
||||
* The returned pointer is such that range `[data(), data() + size())` is
|
||||
* always a valid range, even if the container is empty.
|
||||
*
|
||||
* @note
|
||||
* Entities are in the reverse order as returned by the `begin`/`end`
|
||||
* iterators.
|
||||
*
|
||||
* @return A pointer to the array of entities.
|
||||
*/
|
||||
[[nodiscard]] const entity_type *data() const noexcept {
|
||||
return base_type::data();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator to the first entity of the observer.
|
||||
*
|
||||
* If the observer is empty, the returned iterator will be equal to `end()`.
|
||||
*
|
||||
* @return An iterator to the first entity of the observer.
|
||||
*/
|
||||
[[nodiscard]] iterator begin() const noexcept {
|
||||
return base_type::base_type::begin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns an iterator that is past the last entity of the observer.
|
||||
* @return An iterator to the entity following the last entity of the
|
||||
* observer.
|
||||
*/
|
||||
[[nodiscard]] iterator end() const noexcept {
|
||||
return base_type::base_type::end();
|
||||
}
|
||||
|
||||
/*! @brief Clears the underlying container. */
|
||||
void clear() noexcept {
|
||||
base_type::clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates entities and applies the given function object to them.
|
||||
*
|
||||
* The function object is invoked for each entity.<br/>
|
||||
* The signature of the function must be equivalent to the following form:
|
||||
*
|
||||
* @code{.cpp}
|
||||
* void(const entity_type);
|
||||
* @endcode
|
||||
*
|
||||
* @tparam Func Type of the function object to invoke.
|
||||
* @param func A valid function object.
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) const {
|
||||
for(const auto entity: *this) {
|
||||
func(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Iterates entities and applies the given function object to them,
|
||||
* then clears the observer.
|
||||
*
|
||||
* @sa each
|
||||
*
|
||||
* @tparam Func Type of the function object to invoke.
|
||||
* @param func A valid function object.
|
||||
*/
|
||||
template<typename Func>
|
||||
void each(Func func) {
|
||||
std::as_const(*this).each(std::move(func));
|
||||
clear();
|
||||
}
|
||||
|
||||
private:
|
||||
delegate<void(basic_observer &)> release;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
412
src/entt/entity/organizer.hpp
Normal file
412
src/entt/entity/organizer.hpp
Normal file
@@ -0,0 +1,412 @@
|
||||
#ifndef ENTT_ENTITY_ORGANIZER_HPP
|
||||
#define ENTT_ENTITY_ORGANIZER_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "../core/type_info.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../core/utility.hpp"
|
||||
#include "../graph/adjacency_matrix.hpp"
|
||||
#include "../graph/flow.hpp"
|
||||
#include "fwd.hpp"
|
||||
#include "helper.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/**
|
||||
* @cond TURN_OFF_DOXYGEN
|
||||
* Internal details not to be documented.
|
||||
*/
|
||||
|
||||
namespace internal {
|
||||
|
||||
template<typename>
|
||||
struct is_view: std::false_type {};
|
||||
|
||||
template<typename... Args>
|
||||
struct is_view<basic_view<Args...>>: std::true_type {};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool is_view_v = is_view<Type>::value;
|
||||
|
||||
template<typename Type, typename Override>
|
||||
struct unpack_type {
|
||||
using ro = std::conditional_t<
|
||||
type_list_contains_v<Override, const Type> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
|
||||
type_list<std::remove_const_t<Type>>,
|
||||
type_list<>>;
|
||||
|
||||
using rw = std::conditional_t<
|
||||
type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, const Type>),
|
||||
type_list<Type>,
|
||||
type_list<>>;
|
||||
};
|
||||
|
||||
template<typename... Args, typename... Override>
|
||||
struct unpack_type<basic_registry<Args...>, type_list<Override...>> {
|
||||
using ro = type_list<>;
|
||||
using rw = type_list<>;
|
||||
};
|
||||
|
||||
template<typename... Args, typename... Override>
|
||||
struct unpack_type<const basic_registry<Args...>, type_list<Override...>>
|
||||
: unpack_type<basic_registry<Args...>, type_list<Override...>> {};
|
||||
|
||||
template<typename... Get, typename... Exclude, typename... Override>
|
||||
struct unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {
|
||||
using ro = type_list_cat_t<type_list<typename Exclude::value_type...>, typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::ro...>;
|
||||
using rw = type_list_cat_t<typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::rw...>;
|
||||
};
|
||||
|
||||
template<typename... Get, typename... Exclude, typename... Override>
|
||||
struct unpack_type<const basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>>
|
||||
: unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {};
|
||||
|
||||
template<typename, typename>
|
||||
struct resource_traits;
|
||||
|
||||
template<typename... Args, typename... Req>
|
||||
struct resource_traits<type_list<Args...>, type_list<Req...>> {
|
||||
using args = type_list<std::remove_const_t<Args>...>;
|
||||
using ro = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::ro..., typename unpack_type<Req, type_list<>>::ro...>;
|
||||
using rw = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::rw..., typename unpack_type<Req, type_list<>>::rw...>;
|
||||
};
|
||||
|
||||
template<typename... Req, typename Ret, typename... Args>
|
||||
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(Args...));
|
||||
|
||||
template<typename... Req, typename Ret, typename Type, typename... Args>
|
||||
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, Args...));
|
||||
|
||||
template<typename... Req, typename Ret, typename Class, typename... Args>
|
||||
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...));
|
||||
|
||||
template<typename... Req, typename Ret, typename Class, typename... Args>
|
||||
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Internal details not to be documented.
|
||||
* @endcond
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Utility class for creating a static task graph.
|
||||
*
|
||||
* This class offers minimal support (but sufficient in many cases) for creating
|
||||
* an execution graph from functions and their requirements on resources.<br/>
|
||||
* Note that the resulting tasks aren't executed in any case. This isn't the
|
||||
* goal of the tool. Instead, they are returned to the user in the form of a
|
||||
* graph that allows for safe execution.
|
||||
*
|
||||
* @tparam Registry Basic registry type.
|
||||
*/
|
||||
template<typename Registry>
|
||||
class basic_organizer final {
|
||||
using callback_type = void(const void *, Registry &);
|
||||
using prepare_type = void(Registry &);
|
||||
using dependency_type = std::size_t(const bool, const type_info **, const std::size_t);
|
||||
|
||||
struct vertex_data final {
|
||||
std::size_t ro_count{};
|
||||
std::size_t rw_count{};
|
||||
const char *name{};
|
||||
const void *payload{};
|
||||
callback_type *callback{};
|
||||
dependency_type *dependency;
|
||||
prepare_type *prepare{};
|
||||
const type_info *info{};
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
[[nodiscard]] static decltype(auto) extract(Registry ®) {
|
||||
if constexpr(std::is_same_v<Type, Registry>) {
|
||||
return reg;
|
||||
} else if constexpr(internal::is_view_v<Type>) {
|
||||
return static_cast<Type>(as_view{reg});
|
||||
} else {
|
||||
return reg.ctx().template emplace<std::remove_reference_t<Type>>();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
[[nodiscard]] static auto to_args(Registry ®, type_list<Args...>) {
|
||||
return std::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
|
||||
}
|
||||
|
||||
template<typename... Type>
|
||||
static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const std::size_t count) {
|
||||
if constexpr(sizeof...(Type) == 0u) {
|
||||
return {};
|
||||
} else {
|
||||
const type_info *info[sizeof...(Type)]{&type_id<Type>()...};
|
||||
const auto length = count < sizeof...(Type) ? count : sizeof...(Type);
|
||||
|
||||
for(std::size_t pos{}; pos < length; ++pos) {
|
||||
buffer[pos] = info[pos];
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename... RO, typename... RW>
|
||||
void track_dependencies(std::size_t index, const bool requires_registry, type_list<RO...>, type_list<RW...>) {
|
||||
builder.bind(static_cast<id_type>(index));
|
||||
builder.set(type_hash<Registry>::value(), requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u));
|
||||
(builder.ro(type_hash<RO>::value()), ...);
|
||||
(builder.rw(type_hash<RW>::value()), ...);
|
||||
}
|
||||
|
||||
public:
|
||||
/*! Basic registry type. */
|
||||
using registry_type = Registry;
|
||||
/*! @brief Underlying entity identifier. */
|
||||
using entity_type = typename registry_type::entity_type;
|
||||
/*! @brief Unsigned integer type. */
|
||||
using size_type = std::size_t;
|
||||
/*! @brief Raw task function type. */
|
||||
using function_type = callback_type;
|
||||
|
||||
/*! @brief Vertex type of a task graph defined as an adjacency list. */
|
||||
struct vertex {
|
||||
/**
|
||||
* @brief Constructs a vertex of the task graph.
|
||||
* @param vtype True if the vertex is a top-level one, false otherwise.
|
||||
* @param data The data associated with the vertex.
|
||||
* @param edges The indices of the children in the adjacency list.
|
||||
*/
|
||||
vertex(const bool vtype, vertex_data data, std::vector<std::size_t> edges)
|
||||
: is_top_level{vtype},
|
||||
node{std::move(data)},
|
||||
reachable{std::move(edges)} {}
|
||||
|
||||
/**
|
||||
* @brief Fills a buffer with the type info objects for the writable
|
||||
* resources of a vertex.
|
||||
* @param buffer A buffer pre-allocated by the user.
|
||||
* @param length The length of the user-supplied buffer.
|
||||
* @return The number of type info objects written to the buffer.
|
||||
*/
|
||||
size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept {
|
||||
return node.dependency(false, buffer, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fills a buffer with the type info objects for the read-only
|
||||
* resources of a vertex.
|
||||
* @param buffer A buffer pre-allocated by the user.
|
||||
* @param length The length of the user-supplied buffer.
|
||||
* @return The number of type info objects written to the buffer.
|
||||
*/
|
||||
size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept {
|
||||
return node.dependency(true, buffer, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of read-only resources of a vertex.
|
||||
* @return The number of read-only resources of the vertex.
|
||||
*/
|
||||
size_type ro_count() const noexcept {
|
||||
return node.ro_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of writable resources of a vertex.
|
||||
* @return The number of writable resources of the vertex.
|
||||
*/
|
||||
size_type rw_count() const noexcept {
|
||||
return node.rw_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a vertex is also a top-level one.
|
||||
* @return True if the vertex is a top-level one, false otherwise.
|
||||
*/
|
||||
bool top_level() const noexcept {
|
||||
return is_top_level;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a type info object associated with a vertex.
|
||||
* @return A properly initialized type info object.
|
||||
*/
|
||||
const type_info &info() const noexcept {
|
||||
return *node.info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a user defined name associated with a vertex, if any.
|
||||
* @return The user defined name associated with the vertex, if any.
|
||||
*/
|
||||
const char *name() const noexcept {
|
||||
return node.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the function associated with a vertex.
|
||||
* @return The function associated with the vertex.
|
||||
*/
|
||||
function_type *callback() const noexcept {
|
||||
return node.callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the payload associated with a vertex, if any.
|
||||
* @return The payload associated with the vertex, if any.
|
||||
*/
|
||||
const void *data() const noexcept {
|
||||
return node.payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the list of nodes reachable from a given vertex.
|
||||
* @return The list of nodes reachable from the vertex.
|
||||
*/
|
||||
const std::vector<std::size_t> &children() const noexcept {
|
||||
return reachable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Prepares a registry and assures that all required resources
|
||||
* are properly instantiated before using them.
|
||||
* @param reg A valid registry.
|
||||
*/
|
||||
void prepare(registry_type ®) const {
|
||||
node.prepare ? node.prepare(reg) : void();
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_top_level;
|
||||
vertex_data node;
|
||||
std::vector<std::size_t> reachable;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Adds a free function to the task list.
|
||||
* @tparam Candidate Function to add to the task list.
|
||||
* @tparam Req Additional requirements and/or override resource access mode.
|
||||
* @param name Optional name to associate with the task.
|
||||
*/
|
||||
template<auto Candidate, typename... Req>
|
||||
void emplace(const char *name = nullptr) {
|
||||
using resource_type = decltype(internal::free_function_to_resource_traits<Req...>(Candidate));
|
||||
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
|
||||
|
||||
callback_type *callback = +[](const void *, registry_type ®) {
|
||||
std::apply(Candidate, to_args(reg, typename resource_type::args{}));
|
||||
};
|
||||
|
||||
vertex_data vdata{
|
||||
resource_type::ro::size,
|
||||
resource_type::rw::size,
|
||||
name,
|
||||
nullptr,
|
||||
callback,
|
||||
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
+[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); },
|
||||
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
|
||||
|
||||
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
vertices.push_back(std::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a free function with payload or a member function with an
|
||||
* instance to the task list.
|
||||
* @tparam Candidate Function or member to add to the task list.
|
||||
* @tparam Req Additional requirements and/or override resource access mode.
|
||||
* @tparam Type Type of class or type of payload.
|
||||
* @param value_or_instance A valid object that fits the purpose.
|
||||
* @param name Optional name to associate with the task.
|
||||
*/
|
||||
template<auto Candidate, typename... Req, typename Type>
|
||||
void emplace(Type &value_or_instance, const char *name = nullptr) {
|
||||
using resource_type = decltype(internal::constrained_function_to_resource_traits<Req...>(Candidate));
|
||||
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
|
||||
|
||||
callback_type *callback = +[](const void *payload, registry_type ®) {
|
||||
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
|
||||
std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
|
||||
};
|
||||
|
||||
vertex_data vdata{
|
||||
resource_type::ro::size,
|
||||
resource_type::rw::size,
|
||||
name,
|
||||
&value_or_instance,
|
||||
callback,
|
||||
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
+[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); },
|
||||
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
|
||||
|
||||
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
vertices.push_back(std::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an user defined function with optional payload to the task
|
||||
* list.
|
||||
* @tparam Req Additional requirements and/or override resource access mode.
|
||||
* @param func Function to add to the task list.
|
||||
* @param payload User defined arbitrary data.
|
||||
* @param name Optional name to associate with the task.
|
||||
*/
|
||||
template<typename... Req>
|
||||
void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) {
|
||||
using resource_type = internal::resource_traits<type_list<>, type_list<Req...>>;
|
||||
track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
|
||||
|
||||
vertex_data vdata{
|
||||
resource_type::ro::size,
|
||||
resource_type::rw::size,
|
||||
name,
|
||||
payload,
|
||||
func,
|
||||
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
|
||||
nullptr,
|
||||
&type_id<void>()};
|
||||
|
||||
vertices.push_back(std::move(vdata));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generates a task graph for the current content.
|
||||
* @return The adjacency list of the task graph.
|
||||
*/
|
||||
std::vector<vertex> graph() {
|
||||
std::vector<vertex> adjacency_list{};
|
||||
adjacency_list.reserve(vertices.size());
|
||||
auto adjacency_matrix = builder.graph();
|
||||
|
||||
for(auto curr: adjacency_matrix.vertices()) {
|
||||
const auto iterable = adjacency_matrix.in_edges(curr);
|
||||
std::vector<std::size_t> reachable{};
|
||||
|
||||
for(auto &&edge: adjacency_matrix.out_edges(curr)) {
|
||||
reachable.push_back(edge.second);
|
||||
}
|
||||
|
||||
adjacency_list.emplace_back(iterable.cbegin() == iterable.cend(), vertices[curr], std::move(reachable));
|
||||
}
|
||||
|
||||
return adjacency_list;
|
||||
}
|
||||
|
||||
/*! @brief Erases all elements from a container. */
|
||||
void clear() {
|
||||
builder.clear();
|
||||
vertices.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<vertex_data> vertices;
|
||||
flow builder;
|
||||
};
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user