Compare commits

..

658 Commits

Author SHA1 Message Date
Michele Caini
7821307565 update single include file 2024-04-10 08:52:08 +02:00
Michele Caini
27efd6fdf4 snapshot: suppress a warning by clang 2024-04-10 08:29:17 +02:00
Michele Caini
4dc3f650e8 snapshot: full support to stable types - close #1118 2024-04-10 08:29:14 +02:00
Michele Caini
d5a2e353cd sigh_mixin: avoid using weak ranges twice - close #1123 2024-04-10 08:29:10 +02:00
Michele Caini
3fd8b84d04 now working on version v3.13.2 2024-04-10 08:28:47 +02:00
Michele Caini
2909e7ab1f update single include file 2024-02-02 10:09:52 +01:00
Ezekiel Warren
60703f6845 build: don't install include/BUILD.bazel (#1107) 2024-01-22 09:55:58 +01:00
Michele Caini
062c95fc11 test: avoid warnings due to unused variables 2024-01-19 14:35:45 +01:00
Michele Caini
15ce55bc60 group: avoid swapping observed types - close #1100 2024-01-19 14:23:02 +01:00
Michele Caini
2d3fa3e51a snapshot: refine the check in the constructor of the loader class - close #1106 2024-01-19 09:22:58 +01:00
Michele Caini
7f49768739 now working on version v3.13.1 2024-01-19 08:52:00 +01:00
Michele Caini
fedcb920ce update single include file 2024-01-16 15:55:41 +01:00
Michele Caini
6e0c2baf9d test: drop a bunch of NOLINT 2024-01-15 14:26:23 +01:00
Michele Caini
20aa62c584 test: drop a bunch of NOLINT 2024-01-15 14:26:19 +01:00
Michele Caini
9fbd167bd0 test: make all compilers happy again 2024-01-15 10:04:14 +01:00
Michele Caini
2562bf76f6 test: drop a bunch of NOLINT 2024-01-15 09:26:51 +01:00
Michele Caini
b5ac3c5f41 test: drop a bunch of NOLINT 2024-01-15 09:26:46 +01:00
Michele Caini
7af8d015bc test: drop a bunch of NOLINT 2024-01-12 16:11:20 +01:00
Michele Caini
f01fe06b7a test: drop a bunch of NOLINT 2024-01-12 16:11:16 +01:00
Michele Caini
5618fd9549 test: drop a bunch of NOLINT 2024-01-12 11:34:38 +01:00
Michele Caini
76397ad2e6 test: drop a bunch of NOLINT 2024-01-12 11:34:30 +01:00
Michele Caini
6ca1bca26c test: drop a bunch of NOLINT 2024-01-12 11:34:21 +01:00
Michele Caini
b0b5b2ec4d test: drop a bunch of NOLINT 2024-01-12 10:35:32 +01:00
Michele Caini
1c460130a5 test: drop a bunch of NOLINT 2024-01-12 10:35:10 +01:00
Michele Caini
31b2a2129c test: drop a bunch of NOLINT 2024-01-12 10:34:41 +01:00
Michele Caini
f3a6fdbc02 test: linter utilities 2024-01-12 10:34:11 +01:00
Michele Caini
f6232603c4 test: minor changes 2024-01-12 10:33:50 +01:00
Michele Caini
15d63ec358 test: drop a bunch of NOLINT 2024-01-11 14:11:43 +01:00
Michele Caini
9800bfa680 test: drop a bunch of NOLINT 2024-01-11 14:11:31 +01:00
Michele Caini
6b91bbab28 test: drop a bunch of NOLINT 2024-01-11 14:11:13 +01:00
Michele Caini
b7e929b0cc test: drop a bunch of NOLINT 2024-01-11 14:11:01 +01:00
Michele Caini
f38ab24b7a test: drop a bunch of NOLINT 2024-01-11 14:10:47 +01:00
Michele Caini
b698e53131 test: drop a bunch of NOLINT 2024-01-11 14:10:39 +01:00
Michele Caini
346165e4f9 test: drop a bunch of NOLINT 2024-01-11 14:10:26 +01:00
Michele Caini
9708727269 test: drop a bunch of NOLINT 2024-01-11 14:09:51 +01:00
Michele Caini
0f6e1d8aef test: drop a bunch of NOLINT 2024-01-10 17:44:34 +01:00
Michele Caini
51932b4459 linter: cleanup clang-tidy config 2024-01-10 17:35:51 +01:00
Michele Caini
2b092c2fce test: prepare to cleanup clang-tidy config and track things to review in future 2024-01-10 17:35:27 +01:00
Michele Caini
b152c63dd6 test: suppress linter warnings on reinterpret_cast 2024-01-09 19:28:46 +01:00
Michele Caini
f920a84ac0 test: suppress non-const global variable warnings by the linter 2024-01-09 16:26:34 +01:00
Michele Caini
4e9cc9773d *: updated TODO 2024-01-09 16:25:53 +01:00
Michele Caini
4d32c1ba58 test: avoid non-const global variables 2024-01-09 12:38:01 +01:00
Michele Caini
2776f9bad9 test: avoid using C-style arrays 2024-01-09 11:36:19 +01:00
Michele Caini
fc381b72d3 test: minor changes 2024-01-09 11:36:11 +01:00
Michele Caini
a77a223223 test: avoid using C-style arrays 2024-01-09 11:35:51 +01:00
Michele Caini
b249fa252d *: updated TODO 2024-01-09 10:33:36 +01:00
Michele Caini
b32b8002d3 test: drop unused variable 2024-01-09 10:33:22 +01:00
Michele Caini
8177f8934c test: reintroduce meaningful checks behind a NOLINT directive 2024-01-09 10:32:40 +01:00
Michele Caini
ac4c38a10a test: reintroduce meaningful checks behind a NOLINT directive 2024-01-09 10:31:19 +01:00
Michele Caini
854dedfda0 test: reintroduce meaningful checks behind a NOLINT directive 2024-01-09 10:29:50 +01:00
Michele Caini
52f8e6db30 test: improve code coverage on deprecated function 2024-01-08 15:23:49 +01:00
Michele Caini
140d0dab6a test: drop unnecessary checks 2024-01-08 15:08:29 +01:00
Michele Caini
1ff2db8aa2 test: drop unnecessary checks 2024-01-08 14:25:03 +01:00
Michele Caini
34f700fcca test: suppress linter false warnings 2024-01-08 14:18:36 +01:00
Michele Caini
8c53e0514e test: avoid unnecessary NOLINT 2024-01-08 13:18:15 +01:00
Michele Caini
b6cea84910 test: avoid using ASSERT_NO_FATAL_FAILURE improperly 2024-01-08 12:42:13 +01:00
Michele Caini
f4d9a7729f test: drop unnecessary checks 2024-01-08 12:09:20 +01:00
Michele Caini
47ab69f394 test: drop unnecessary NOLINT 2024-01-08 11:43:57 +01:00
Michele Caini
aab9277d8d build: temporary workaround to a GH issue with C++20 2024-01-08 10:32:53 +01:00
Michele Caini
6d21fdcc78 *: updated TODO 2024-01-08 08:52:49 +01:00
Michele Caini
1d9f771af3 test: avoid using deprecated functions 2024-01-01 17:11:09 +01:00
Michele Caini
18330eb330 test: avoid using deprecated functions 2024-01-01 16:59:10 +01:00
Michele Caini
6f38fdaea6 *: updated TODO 2024-01-01 16:40:27 +01:00
Michele Caini
bd75e33694 test: refine linter directives 2024-01-01 16:40:20 +01:00
Michele Caini
010f0b9402 storage: avoid using base_type::at internally 2024-01-01 16:39:51 +01:00
Michele Caini
776c541d1c saprse_set: deprecate .at as ambiguous 2024-01-01 16:39:33 +01:00
Michele Caini
f20abd5767 test: suppress linter warnings on deprecated functions 2024-01-01 16:02:53 +01:00
Michele Caini
8cb0c8802d *: updated TODO 2024-01-01 15:46:19 +01:00
Michele Caini
a4a0abdbd6 view: avoid forcing non-integral entity types 2024-01-01 15:46:07 +01:00
Michele Caini
4bd0f26a26 doc: a few links 2024-01-01 10:55:41 +01:00
Michele Caini
5ea8f0382b test: NOLINT review 2023-12-23 18:01:35 +01:00
Michele Caini
8beaea89f2 test: comment expected NOLINT for deprecated feature 2023-12-23 17:49:43 +01:00
Michele Caini
433fca98a3 test: minor changes (code coverage purposes) 2023-12-23 17:49:04 +01:00
Michele Caini
24aac47ce5 test: delete unused functions (code coverage purposes) 2023-12-23 15:45:32 +01:00
Michele Caini
d5518c63e9 test: avoid non-private member variables in classes (linter) 2023-12-22 16:34:24 +01:00
Michele Caini
4a06c41a33 test: minor changes 2023-12-22 14:42:05 +01:00
Michele Caini
4d63ac5c88 *: updated TODO 2023-12-22 14:31:00 +01:00
Michele Caini
6e31855717 build: work-in-progress clang-tidy config 2023-12-22 14:30:46 +01:00
Michele Caini
76e668034c test: special member functions warnings (linter) 2023-12-22 14:30:17 +01:00
Michele Caini
28424709d5 sparse_set: refine assure_at_least to better support non-enum identifiers 2023-12-22 14:30:02 +01:00
Michele Caini
fc3df2b0ac test: special member functions warnings (linter) 2023-12-22 14:29:33 +01:00
Michele Caini
27698a2a0a test: use default member init as needed 2023-12-21 10:21:08 +01:00
Michele Caini
9b7aa49adc test: use equals default as needed 2023-12-21 09:45:31 +01:00
Michele Caini
8022cf4200 test: avoid confusable identifiers 2023-12-21 08:59:26 +01:00
Michele Caini
bd06d384e0 test: try to make all compilers happy again 2023-12-21 08:22:01 +01:00
Michele Caini
17913a7a14 test: avoid uninitialized variables 2023-12-20 17:30:19 +01:00
Michele Caini
ef914bad8c test: avoid static global functions 2023-12-20 14:04:20 +01:00
Michele Caini
867656f549 test: use transparent functors 2023-12-20 10:34:54 +01:00
Michele Caini
6e665b27bf test: handle linter warning on string literals 2023-12-20 10:08:13 +01:00
Michele Caini
f34dbcd7d8 test: handle linter warning due to unnecessary copy 2023-12-20 09:49:16 +01:00
Michele Caini
6b608f51fb test: avoid moving trivially copyable types 2023-12-20 09:19:19 +01:00
Michele Caini
cbf853fa75 test: comment expected NOLINT for deprecated feature 2023-12-20 09:16:22 +01:00
Michele Caini
14450df1ee test: more by the linter (work in progress) 2023-12-19 18:59:40 +01:00
Michele Caini
27a46a97a6 test: linter related stuff 2023-12-19 18:58:47 +01:00
Michele Caini
d2344e8e62 hashed_string: linter related stuff 2023-12-19 11:51:29 +01:00
Michele Caini
4b5a6cd2c6 test: minor changes 2023-12-19 11:25:53 +01:00
Michele Caini
f3ce121be3 test: try to make all compilers happy at once 2023-12-19 11:21:10 +01:00
Michele Caini
eef8b42c77 test: make gcc happy again 2023-12-19 11:13:10 +01:00
Michele Caini
03551c242c *: updated TODO 2023-12-19 11:06:48 +01:00
Michele Caini
f5a8feb47f meta: linter related stuff 2023-12-19 11:06:24 +01:00
Michele Caini
3208281d94 test: [[nodiscard]], const-correctness and other linter related stuff 2023-12-19 11:06:08 +01:00
Michele Caini
2271fb8c0f *: updated TODO 2023-12-19 11:05:51 +01:00
Michele Caini
feb0bb02ae test: minor changes 2023-12-19 11:05:23 +01:00
Michele Caini
6c99ca50e7 test: minor changes 2023-12-19 11:05:08 +01:00
Michele Caini
cadcd9ce43 test: [[nodiscard]], const-correctness and other linter related stuff 2023-12-19 11:04:55 +01:00
Michele Caini
0bf1817b9a test: const-correctness and other linter related stuff 2023-12-19 11:04:21 +01:00
Michele Caini
cd887237b8 test: const-correctness and other linter related stuff 2023-12-19 11:04:07 +01:00
Michele Caini
218cb02492 test: [[nodiscard]] as needed 2023-12-19 11:03:47 +01:00
Michele Caini
5a2be7d6eb test: [[nodiscard]] and other linter related stuff 2023-12-19 11:03:25 +01:00
Michele Caini
c6f3a5408e test: [[nodiscard]], const-correctness and other linter related stuff 2023-12-19 10:58:43 +01:00
Michele Caini
b6d0921177 registry: use sort_as rather than pack 2023-12-19 10:53:19 +01:00
Michele Caini
6ac7a02172 test: const-correctness and other linter related stuff 2023-12-19 10:23:45 +01:00
Michele Caini
a35612a4f8 test: const-correctness and other linter related stuff 2023-12-19 10:23:11 +01:00
Michele Caini
4d9ff926b6 test: [[nodiscard]], const-correctness and other linter related stuff 2023-12-18 17:48:16 +01:00
Michele Caini
636749eff3 test: const correctness 2023-12-18 14:34:01 +01:00
Michele Caini
685467acba test: claenup (and use static_assert as needed) 2023-12-18 14:33:48 +01:00
Michele Caini
9605af3f54 test: const correctness 2023-12-18 14:33:01 +01:00
Michele Caini
a3db63342d test: minor changes 2023-12-18 14:32:48 +01:00
Michele Caini
57ec8d9ca3 test: const correctness 2023-12-18 14:32:33 +01:00
Michele Caini
f11d93ab25 test: const correctness (and [[nodiscard]] as needed) 2023-12-18 14:32:18 +01:00
Michele Caini
b3489857ad test: const correctness (and [[nodiscard]] as needed) 2023-12-18 14:32:06 +01:00
Michele Caini
205e21e313 doc: minor changes 2023-12-18 14:13:05 +01:00
Michele Caini
cd59efab8f test: const-correctness (and [[nodiscard]] as needed) 2023-12-18 14:00:28 +01:00
Michele Caini
72304e6781 test: const-correctness (and [[maybe_unused] as needed) 2023-12-18 14:00:04 +01:00
Michele Caini
bdd213009c test: const-correctness 2023-12-18 13:59:34 +01:00
Michele Caini
5f576667d3 doc: cleanup 2023-12-18 12:24:00 +01:00
Michele Caini
1ec2f3eeb8 type_traits: avoid redefining type again and again 2023-12-18 10:02:48 +01:00
Michele Caini
b1a5b4b982 test: cleanup 2023-12-17 12:52:39 +01:00
Michele Caini
9e4f40fee6 test: minor changes 2023-12-15 16:46:27 +01:00
Michele Caini
fa0add3c02 test: avoid using a moved from vector 2023-12-15 16:46:00 +01:00
Michele Caini
937ed81fa2 dispatcher: [[nodiscard]] 2023-12-15 16:38:46 +01:00
Michele Caini
daa83a1885 registry: avoid shadow warnings with gcc 2023-12-15 12:13:49 +01:00
Michele Caini
eb290d8bd4 *: updated TODO 2023-12-15 11:59:12 +01:00
Michele Caini
dad6061cbb view: minor changes 2023-12-15 11:49:54 +01:00
Michele Caini
07777c78aa view: back to the plain pointer model for internal functions 2023-12-15 11:40:59 +01:00
Michele Caini
7a12dc6533 view: refine internal functions 2023-12-15 11:29:25 +01:00
Michele Caini
80c8c76fdb view: use more explicit types on internal functions 2023-12-15 09:00:09 +01:00
Michele Caini
1931ade325 view: drop check set as a whole 2023-12-15 08:54:28 +01:00
Michele Caini
2e264dffb3 view: index-based view iterator (no check set required) 2023-12-15 08:54:18 +01:00
Michele Caini
09197a91a0 view: prepare to drop check set 2023-12-15 08:42:30 +01:00
Michele Caini
70053f9301 core: minimize compilation cost of type_list_unique 2023-12-15 08:15:45 +01:00
Michele Caini
91a193141f view: proper ctors for multi type base view 2023-12-14 14:47:50 +01:00
Michele Caini
5d8a1e3ee1 view: proper ctors for single type base view 2023-12-14 14:47:39 +01:00
Michele Caini
9c85cd8d55 view: prepare to optimize further view definitions 2023-12-14 09:42:04 +01:00
Ezekiel Warren
1fb1027036 build system: use env var for bazel version in CI (#1098) 2023-12-14 09:16:11 +01:00
Michele Caini
bdea65d500 build: updated action versions 2023-12-13 12:35:54 +01:00
Michele Caini
88f65c8d5d doc: updated README file 2023-12-13 12:35:26 +01:00
Samuel Dowling
8355f12398 doc: add conan badge to README (#1096) 2023-12-13 12:22:28 +01:00
Michele Caini
f3120f7e7d view: drop duplicated function 2023-12-13 12:00:20 +01:00
Mojert
a74b1b8220 doc: include FetchContent as needed (#1097) 2023-12-13 11:57:28 +01:00
Michele Caini
b81e40e07e signal: doc review 2023-12-12 14:15:07 +01:00
Michele Caini
e4df106417 resource: doc review 2023-12-12 14:15:02 +01:00
Michele Caini
d0a16cd852 process: doc review 2023-12-12 14:14:53 +01:00
Michele Caini
b274d49b3f platform: doc review 2023-12-12 14:14:48 +01:00
Michele Caini
3d9651b783 meta: doc review 2023-12-12 14:14:42 +01:00
Michele Caini
dfd7cb90d0 graph: doc review 2023-12-12 14:14:36 +01:00
Michele Caini
c33bee892d entity: doc review 2023-12-12 14:14:30 +01:00
Michele Caini
a986f68e45 core: doc review 2023-12-12 14:14:20 +01:00
Michele Caini
c0f1a691f9 container: doc review 2023-12-12 14:14:12 +01:00
Michele Caini
711e82b688 view: suppress doc warning 2023-12-12 14:14:01 +01:00
Michele Caini
5190db0222 registry: explicit iterable and const_iterable types 2023-12-11 12:14:41 +01:00
Michele Caini
b00830d382 registry: refine ::assure (const and non-const) 2023-12-11 12:09:16 +01:00
Michele Caini
cd24c0aac5 view: use a name that doesn't drive me crazy when I search for it 2023-12-07 16:56:03 +01:00
Michele Caini
a927d6db07 view: use the right len for the check array 2023-12-06 10:01:47 +01:00
Michele Caini
294a606cf9 *: updated TODO 2023-12-06 09:13:04 +01:00
Michele Caini
735db1e6af view: shared implementation for common views 2023-12-06 09:12:57 +01:00
Michele Caini
3ec5e81d81 view: backward compat/coverage purposes 2023-12-05 17:08:16 +01:00
Michele Caini
4664d0601f view: explicit trivial return types 2023-12-05 15:02:25 +01:00
Michele Caini
43fcc94682 view: minor changes 2023-12-05 15:01:12 +01:00
Michele Caini
4cdff43781 view: shared implementation for storage views 2023-12-05 15:00:14 +01:00
Michele Caini
9d23522086 *: updated TODO 2023-12-05 14:46:19 +01:00
Michele Caini
feed10c9f6 view: avoid calculating the check set again and again 2023-12-04 08:54:37 +01:00
Michele Caini
9732092c0f view: improved validity check 2023-12-03 23:23:22 +01:00
Michele Caini
aa46b2504c *: updated TODO 2023-12-01 15:53:58 +01:00
Michele Caini
c3e36e7148 build: prepare for tools 2023-12-01 15:24:37 +01:00
Michele Caini
c912b85f6e test: reserved bits example - see #888 2023-12-01 15:24:27 +01:00
Michele Caini
4f700f90ec natvis: update snippets for storage/sparse set 2023-12-01 09:01:12 +01:00
Michele Caini
f2c417435c test: another couple of changes to make all compilers happy :) 2023-11-30 15:19:51 +01:00
Michele Caini
48c374be2a test: try to make all compilers happy again 2023-11-30 15:16:57 +01:00
Michele Caini
4cb4553796 *: updated TODO 2023-11-30 15:13:34 +01:00
Michele Caini
3db20d0aa5 entity: fully support reserved bits on identifiers 2023-11-30 15:13:15 +01:00
Michele Caini
9e62e1dab6 sparse_set: ::contains uses the right version mask 2023-11-30 15:12:47 +01:00
Michele Caini
42529d0ab2 doc: minor changes 2023-11-30 11:42:18 +01:00
Michele Caini
637d6bbabc natvis: drop unused intrinsic 2023-11-29 17:30:40 +01:00
Michele Caini
f8eba58e19 test: avoid using registry if not needed 2023-11-29 16:13:48 +01:00
Michele Caini
d58c5766bc test: use template keyword with dependent template name 2023-11-29 13:06:41 +01:00
Michele Caini
5b2c136a7c entity: avoid unnecessary operations 2023-11-29 12:59:39 +01:00
Michele Caini
8c532fb377 test: more on entity traits 2023-11-28 16:56:08 +01:00
Michele Caini
c5552d85c3 *: updated TODO 2023-11-28 08:04:28 +01:00
Michele Caini
d5c162e6a0 test: more on view 2023-11-28 08:04:08 +01:00
Michele Caini
95b73d94f7 storage: minor changes 2023-11-28 08:03:53 +01:00
Michele Caini
9f80b14f88 meta: avoid duplicating data in meta containers 2023-11-27 15:13:59 +01:00
Michele Caini
1a6565d5f9 meta: review meta containers' begin/end functions 2023-11-27 15:13:29 +01:00
Michele Caini
9c60708203 meta: drop unnecessary remove_reference_t 2023-11-27 08:25:11 +01:00
Michele Caini
e0cac58500 meta: avoid indirections due to any in meta containers 2023-11-27 08:18:33 +01:00
Michele Caini
60e2557c45 meta_range_iterator: iterator_concept 2023-11-26 10:17:42 +01:00
Michele Caini
228066c1f6 cache: iterator_concept 2023-11-26 10:17:26 +01:00
Michele Caini
0744937811 adjacency_matrix: iterator_concept 2023-11-26 10:17:18 +01:00
Michele Caini
a383c0c0a5 storage: iterator_concept 2023-11-26 10:17:01 +01:00
Michele Caini
b6da31d933 registry: iterator_concept 2023-11-26 10:16:52 +01:00
Michele Caini
5985531d9e handle: iterator_concept 2023-11-26 10:16:42 +01:00
Michele Caini
847099932d group: iterator_concept 2023-11-26 10:16:33 +01:00
Michele Caini
d43416102b dense_map: iterator_concept 2023-11-26 10:16:20 +01:00
Michele Caini
9e73c3c44a meta: iterator_concept 2023-11-26 10:16:03 +01:00
Michele Caini
d152153547 view: iterator_concept - close #1090 2023-11-23 18:01:44 +01:00
Michele Caini
5016dd8bb0 test: try to make gcc happy again 2023-11-23 15:21:34 +01:00
Michele Caini
a3fdc96b0d container: minor changes 2023-11-23 14:58:21 +01:00
Michele Caini
b5fbe50fa1 doc: updated FAQs - close #1063 2023-11-23 14:34:11 +01:00
Michele Caini
e9039ece28 meta: drop [[maybe_unused]] 2023-11-22 15:48:07 +01:00
Michele Caini
60e8763fe8 *: updated TODO 2023-11-22 10:15:47 +01:00
Michele Caini
e3475c026c mixin: make sigh mixin work with custom registry types - close #1079 2023-11-22 10:15:17 +01:00
Michele Caini
24c95e493f meta: internal changes to make things easier to maintain and evolve 2023-11-21 14:35:40 +01:00
Michele Caini
8ce80145de test: minor changes 2023-11-20 16:47:26 +01:00
Michele Caini
838d0e5f76 doc: updated README 2023-11-20 16:46:44 +01:00
Michele Caini
7fecbf7e03 doc: minor changes 2023-11-17 16:26:45 +01:00
Michele Caini
e04f2bdb24 *: coding style 2023-11-17 16:26:21 +01:00
Michele Caini
c26a24e713 test: static-less throwing allocator 2023-11-17 15:51:08 +01:00
Michele Caini
c785260783 test: continue the internal rework 2023-11-17 09:06:28 +01:00
Michele Caini
8372292841 flow: correctly forward allocator to members 2023-11-16 18:13:52 +01:00
Michele Caini
2ce6317c9a test: code coverage for scheduler class 2023-11-16 11:03:56 +01:00
Michele Caini
16d43d2975 scheduler: allocator-aware implementation 2023-11-16 11:03:36 +01:00
Michele Caini
d7d8752a84 test: minor changes 2023-11-16 11:02:04 +01:00
Michele Caini
339df18c06 dispatcher: minor changes 2023-11-15 17:29:20 +01:00
Michele Caini
757eb5f10c scheduler: prepare to support allocators 2023-11-15 17:29:03 +01:00
Michele Caini
580f1edb91 *: updated TODO 2023-11-15 10:11:13 +01:00
Michele Caini
6e03ca088e doc: updated scheduler doc 2023-11-15 10:10:16 +01:00
Michele Caini
c75a4804da test: minor changes 2023-11-15 10:06:12 +01:00
Michele Caini
3487196d0d scheduler: redesign basic scheduler 2023-11-15 10:06:02 +01:00
Michele Caini
adbcc8dca9 process: minor changes 2023-11-15 10:04:46 +01:00
Michele Caini
8b79ee586a test: suppress conversion warnings 2023-11-14 14:27:20 +01:00
Michele Caini
abfd8e035c test: minor changes to utility class 2023-11-14 14:26:36 +01:00
Michele Caini
9bad12064c scheduler: avoid handling ::next in the update function 2023-11-14 08:54:19 +01:00
Michele Caini
a5608bf7bb process: prepare to redesign scheduler 2023-11-14 08:53:27 +01:00
Michele Caini
b84a4bed29 test: minor changes 2023-11-13 10:52:26 +01:00
Michele Caini
94582777e8 test: minor changes 2023-11-13 10:52:10 +01:00
Michele Caini
c2b5be0836 test: minor changes 2023-11-13 10:51:50 +01:00
Michele Caini
8e13ede4d5 test: simplify/cleanup throwing_type 2023-11-13 09:10:00 +01:00
Michele Caini
857d70528d test: minor changes 2023-11-10 15:23:58 +01:00
Michele Caini
b16e4c1ec7 doc: minor changes 2023-11-10 12:43:46 +01:00
Michele Caini
b8b41b3ac7 meta: minor changes for code readability 2023-11-10 12:02:05 +01:00
Michele Caini
f13dcae6d3 test: make toolset v141 happy again 2023-11-10 11:53:28 +01:00
Michele Caini
1724e8cfeb test: internal rework 2023-11-10 10:28:12 +01:00
Michele Caini
e53601e860 view: avoid taking decisions on page_size 2023-11-10 10:27:36 +01:00
Michele Caini
5e8544cfc6 storage: void returned value type for storage entity 2023-11-10 10:25:47 +01:00
Michele Caini
dc184c10e2 snapshot: avoid using page_size directly 2023-11-09 15:37:22 +01:00
Michele Caini
f89e8560a3 doc: nth_argument[_t] 2023-11-09 14:50:51 +01:00
Michele Caini
f4a54cc0da type_traits: type based nth_argument[_t] 2023-11-09 14:50:00 +01:00
Michele Caini
6aa4c770e6 test: use shared custom_entity type 2023-11-08 12:38:36 +01:00
Michele Caini
afe942ef2e test: use shared custom_entity type 2023-11-08 12:38:16 +01:00
Michele Caini
9b4c920d1f test: shared custom_entity type 2023-11-08 12:37:54 +01:00
Michele Caini
00d0ff2e45 registry: use the right type within assure - close #1088 2023-11-08 10:15:07 +01:00
Michele Caini
3f5b6a1693 test: sigh mixin ::pop_all 2023-11-08 09:44:05 +01:00
Michele Caini
d98821e976 doc: add EnTT Editor to links.md :) 2023-11-07 13:53:39 +01:00
Michele Caini
223c8ab9b9 doc: add robotfindskitten to links.md :) 2023-11-07 13:53:22 +01:00
Michele Caini
76a6a22527 test: minor changes 2023-11-07 08:58:40 +01:00
Michele Caini
ee7e025680 test: increase coverage for handle class 2023-11-07 08:58:23 +01:00
Michele Caini
68125c4187 test: scoped include 2023-11-06 15:38:42 +01:00
Michele Caini
fd1abc952f test: iwyu docet 2023-11-06 14:46:24 +01:00
Michele Caini
5c04c872c5 test: iwyu docet 2023-11-06 14:46:00 +01:00
Michele Caini
8405a78bd8 test: use plain integral counter to test sigh mixin 2023-11-06 14:45:32 +01:00
Michele Caini
0e4f5a6870 test: use shared empty type 2023-11-06 08:55:32 +01:00
Michele Caini
a4f2ba1ab8 test: use shared empty type 2023-11-06 08:52:21 +01:00
Michele Caini
3c8ddbb0a5 test: use shared empty type 2023-11-06 08:52:05 +01:00
Michele Caini
1dbe025d36 test: use shared empty type 2023-11-06 08:51:56 +01:00
Michele Caini
16d55c9f59 test: use shared empty type 2023-11-06 08:51:46 +01:00
Michele Caini
f3bd033bf6 test: use shared empty type 2023-11-06 08:51:03 +01:00
Michele Caini
ba87e22af0 test: use shared empty type 2023-11-06 08:50:48 +01:00
Michele Caini
9d2bbac695 test: use shared empty type 2023-11-06 08:50:20 +01:00
Michele Caini
5e0f4e6ef0 test: use shared empty type 2023-11-06 08:50:00 +01:00
Michele Caini
9a362b39bf test: shared empty type 2023-11-06 08:49:37 +01:00
Michele Caini
fb624bab50 test: minor changes 2023-11-05 19:56:29 +01:00
Michele Caini
e0661a55f6 iwyu: analyzer docet :) 2023-11-05 17:12:53 +01:00
Michele Caini
1773cc9eb5 iwyu: comments/sections 2023-11-04 12:48:12 +01:00
Michele Caini
dd7c8f2ad6 iwyu: disambiguate . 2023-11-04 12:47:55 +01:00
Michele Caini
592ff17c5f test: cleanup 2023-11-03 14:46:04 +01:00
Michele Caini
6d6d83afdb test: use shared non_movable type 2023-11-03 12:51:48 +01:00
Michele Caini
134640411a test: use shared non_movable type 2023-11-03 12:49:11 +01:00
Michele Caini
6e1a5c0353 test: shared non_movable type 2023-11-03 12:48:40 +01:00
Michele Caini
b1a884f898 test: typo 2023-11-03 12:46:19 +01:00
Michele Caini
1717b3683c test: use shared non_comparable type 2023-11-03 12:45:51 +01:00
Michele Caini
a00f9e5f77 test: use shared non_comparable type 2023-11-03 12:44:47 +01:00
Michele Caini
e210c31bf2 test: use shared non_comparable type 2023-11-03 12:43:58 +01:00
Michele Caini
93094740b2 test: shared non_comparable type 2023-11-03 12:43:18 +01:00
Michele Caini
8ee3c333fb test: updated tests for allocate_unique 2023-11-03 12:18:59 +01:00
Michele Caini
302b246475 test: static-less shared throwing_type 2023-11-03 12:04:48 +01:00
Michele Caini
90b9186fd6 test: prepare to get rid of static variables in the shared types 2023-11-03 11:57:00 +01:00
Michele Caini
29e2f13e1e test: prepare to get rid of static variables in the shared types 2023-11-03 11:56:44 +01:00
Michele Caini
3d9da1dbce test: refine throwing_type (prepare to get rid of static variables) 2023-11-03 11:52:00 +01:00
Michele Caini
62a13526c9 registry: try_get should not create storage 2023-11-03 09:36:29 +01:00
Michele Caini
4dcc0e8666 test: reduce the tests for aggregate types to what is needed 2023-11-02 16:57:55 +01:00
Michele Caini
7e98afe6fe test: small cleanup 2023-11-02 15:58:30 +01:00
Michele Caini
e835bfbec7 test: use unique_ptr as move-only type 2023-11-02 15:06:04 +01:00
Michele Caini
577ff97980 test: use shared aggregate type 2023-11-02 15:05:36 +01:00
Michele Caini
76516e0320 test: cleanup 2023-11-02 15:05:16 +01:00
Michele Caini
385155f043 test: use shared aggregate type 2023-11-02 15:04:57 +01:00
Michele Caini
29b2552cf2 test: use shared aggregate type 2023-11-02 15:04:46 +01:00
Michele Caini
ee1e1a4cd5 test: shared aggregate type 2023-11-02 15:04:20 +01:00
Michele Caini
a0c85add5b test: use shared boxed_int type 2023-11-02 08:32:14 +01:00
Michele Caini
94472a6782 test: use shared boxed_int type 2023-11-02 08:30:45 +01:00
Michele Caini
cdc47832ef test: use shared boxed_int type 2023-11-02 08:30:04 +01:00
Michele Caini
acae98324b test: shared boxed_int type 2023-11-02 08:29:37 +01:00
Michele Caini
4786178705 test: increase code coverage (const overload) 2023-11-01 22:51:35 +01:00
Michele Caini
2e375a4482 test: drop unused header 2023-11-01 22:51:07 +01:00
Michele Caini
e58735a6fd test: use shared transparent_equal_to type 2023-11-01 22:50:56 +01:00
Michele Caini
0f1fff7ac8 test: use shared transparent_equal_to type 2023-11-01 22:50:49 +01:00
Michele Caini
0ef43f5d57 test: shared transparent_equal_to type 2023-11-01 22:50:37 +01:00
Michele Caini
7a2c5753c5 type_traits: try to please older compilers too 2023-10-31 15:41:24 +01:00
Michele Caini
2a3ae06d85 type_traits: thanks msvc for accepting invalid code, love it 2023-10-31 14:31:00 +01:00
Michele Caini
f009d99e5e type_traits: further improve and cleanup is_equality_comparable 2023-10-31 14:26:32 +01:00
Michele Caini
206d2f623d type_traits: further refine is_equality_comparable[_v] to avoid specializations 2023-10-31 14:08:38 +01:00
Michele Caini
273035ff49 type_traits: improve is_equality_comparable[_v] 2023-10-31 14:02:34 +01:00
Michele Caini
3540fbab74 test: sigh mixin test review (in progress) 2023-10-31 09:23:59 +01:00
Michele Caini
4983d40358 test: use shared non default constructible type 2023-10-31 09:18:57 +01:00
Michele Caini
fd970971af test: use shared non default constructible type 2023-10-31 09:18:51 +01:00
Michele Caini
c8a0701597 test: use shared non default constructible type 2023-10-31 09:18:36 +01:00
Michele Caini
ad99c4eb14 test: shared non default constructible type 2023-10-31 09:18:13 +01:00
Michele Caini
67d7b0080e test: use shared pointer stable type 2023-10-31 09:10:58 +01:00
Michele Caini
2bf66e5b42 test: use shared pointer stable type 2023-10-31 09:10:39 +01:00
Michele Caini
88d0b5a17d test: use shared pointer stable type 2023-10-31 09:10:15 +01:00
Michele Caini
c042e3d985 test: use shared pointer stable type 2023-10-31 09:10:01 +01:00
Michele Caini
2defe1c2c4 test: use shared pointer stable type 2023-10-31 09:09:37 +01:00
Michele Caini
0bc946b333 test: shared pointer stable type 2023-10-31 09:09:20 +01:00
Michele Caini
98dd0fbad7 test: start sigh mixin test review 2023-10-30 13:58:17 +01:00
Michele Caini
4bb37f7e25 test: drop unnecessary test 2023-10-30 13:54:27 +01:00
Michele Caini
23703f5c01 test: iwyu docet :) 2023-10-30 13:51:30 +01:00
Michele Caini
215a22f425 test: avoid shadow warnings 2023-10-30 12:24:16 +01:00
Michele Caini
e742fe7bf9 test: minor changes 2023-10-29 22:59:41 +01:00
Michele Caini
57d1754bc8 test: cleanup 2023-10-29 22:56:38 +01:00
Michele Caini
b95bb9bedb test: minor changes 2023-10-29 22:51:23 +01:00
Michele Caini
39f6349878 mixin: use if constexpr as it should be 2023-10-29 22:27:49 +01:00
Michele Caini
678131429b test: minor changes 2023-10-29 16:36:43 +01:00
Michele Caini
bb70e8b14e view: drop filter_as_tuple 2023-10-27 18:30:33 +02:00
Michele Caini
b9c86b3f99 view: further reduce instantiations due to filters 2023-10-27 18:29:57 +02:00
MiloWang
0ec50842a7 doc: update unreal.md (#1085) 2023-10-27 18:29:06 +02:00
Michele Caini
a678133e47 view: try to also please gcc 2023-10-26 14:28:36 +02:00
Michele Caini
b0a5f4f3e8 natvis: updated snippet for basic_view 2023-10-26 12:46:51 +02:00
Michele Caini
642f4e70b5 view: view_pack review to cleanup single type views 2023-10-26 12:44:48 +02:00
Michele Caini
efd03711cc config: provide coverage for user defined ENTT_ID_TYPE in the std namespace 2023-10-25 17:01:56 +02:00
Michele Caini
4c067ee13d meta: suppress warnings due to implicit conversions - see #394 2023-10-25 16:51:28 +02:00
Michele Caini
5cb7fc2610 test: missing include 2023-10-25 14:17:43 +02:00
Michele Caini
05ba05393c test: storage entity and sorting functions 2023-10-25 08:25:03 +02:00
Michele Caini
2206d3f921 test: drop extra ; 2023-10-24 11:20:54 +02:00
Michele Caini
1f7f613800 sparse_set: use scoped iterators within ::sort 2023-10-24 11:11:11 +02:00
Michele Caini
8d92440451 natvis: temporary workaround to print views correctly 2023-10-24 09:09:54 +02:00
Michele Caini
5fca9d4c94 nativs: basic_storage::length is no longer a thing in any case 2023-10-23 17:36:08 +02:00
Michele Caini
663353cbdb view: avoid multiple instantiations of fully_initialized 2023-10-23 17:05:40 +02:00
Michele Caini
8550a9f159 test: sort/sort_n/sort_as for storage no instance 2023-10-23 11:34:47 +02:00
Michele Caini
f01dbd68f3 test: cleanup 2023-10-23 11:33:50 +02:00
Michele Caini
5913829e21 test: minor changes 2023-10-23 08:55:51 +02:00
Michele Caini
c201a44f1a test: more about storage no instance 2023-10-23 08:54:31 +02:00
Michele Caini
382be6c4e1 *: updated TODO 2023-10-20 12:24:06 +02:00
Michele Caini
aad20ed035 storage: deprecate ::pack, use ::sort_as instead 2023-10-20 12:23:43 +02:00
Michele Caini
c24adea40f test: minor changes 2023-10-20 12:23:28 +02:00
Michele Caini
223e2376b6 test: suppress warnings due to shadow variables 2023-10-19 16:23:44 +02:00
Michele Caini
0ce65cec6b test: suppress warnings due to unused type aliases 2023-10-19 16:22:12 +02:00
Michele Caini
7ddef2586c group: iterator based sort_as 2023-10-19 14:34:38 +02:00
Michele Caini
4d9f137980 test: use iterator based sort_as in the storage tests 2023-10-19 14:34:14 +02:00
Michele Caini
03aabbfa07 registry: use iterator based sort_as 2023-10-18 11:49:42 +02:00
Michele Caini
fe0d412b98 sparse_set: iterator based sort_as as it should be 2023-10-18 11:13:07 +02:00
LiterallyVoid
826eb7ed65 doc: fix typo in Sorting section (#1080) 2023-10-18 10:32:24 +02:00
Michele Caini
2dc121e3df meta: correctly initialize all members of meta container wrappers 2023-10-17 15:20:56 +02:00
Michele Caini
75bff4d67f meta: expose basic_meta_sequence_container_traits::fixed_size 2023-10-17 14:20:11 +02:00
Michele Caini
9d33ae86be helper: storage-based to_entity function 2023-10-17 14:09:04 +02:00
Michele Caini
173c4e1c78 test: make toolset v141 happy again 2023-10-13 19:33:43 +02:00
Michele Caini
2d0b451ed0 test: storage 2023-10-13 18:48:59 +02:00
Michele Caini
35f2dbad09 *: updated TODO 2023-10-12 14:58:15 +02:00
Michele Caini
872fc4751b build: updated bazel files 2023-10-12 14:57:42 +02:00
Michele Caini
504959850c test: more on storage optimization 2023-10-12 14:55:56 +02:00
Michele Caini
2466c7123e test: storage entity 2023-10-11 08:15:00 +02:00
Michele Caini
0f9b4f1b6c test: more on storage no instance 2023-10-10 16:29:29 +02:00
Michele Caini
38f63135a8 test: split storage utilities 2023-10-10 08:38:02 +02:00
Michele Caini
b0ad2ddbe7 test: another attempt to get around an issue of msvc 2023-10-09 15:57:40 +02:00
Michele Caini
94b3944003 test: try to get around an issue of msvc 2023-10-09 15:26:39 +02:00
Michele Caini
aa1bfebc46 test: split storage tests for better management and to avoid issues with the CI 2023-10-09 14:45:59 +02:00
Michele Caini
62dd41f0a1 test: minor changes 2023-10-09 12:35:24 +02:00
Michele Caini
bb54e2542c test: typed test empty/void for storage optimization (to fully cover void version) 2023-10-09 12:35:05 +02:00
Michele Caini
639191af23 build: set test timeout once for all workflows 2023-10-06 15:26:22 +02:00
Michele Caini
4670a939bf workflow: increase test timeout to avoid failures when the CI is particularly slow 2023-10-06 15:18:35 +02:00
Michele Caini
391dcf9639 test: further reduce the number of ASSERT_DEATH to please GH CI :) 2023-10-06 15:04:18 +02:00
Michele Caini
7378abdedb test: further reduce ASSERT_DEATH cost on sparse set tests 2023-10-06 11:28:42 +02:00
Michele Caini
43c5c2dd0d test: suppress another warning by clang-cl 2023-10-06 11:12:33 +02:00
Michele Caini
ffa0a7f276 test: suppress a warning from clang-cl 2023-10-06 11:08:39 +02:00
Michele Caini
592147a499 test: drop unused aliases 2023-10-06 11:08:08 +02:00
Michele Caini
02e2532e17 test: drop a bunch of useless ASSERT_DEATH since they are very expensive on the CI 2023-10-06 11:00:12 +02:00
Michele Caini
4891c8fcd2 test: reduce the scope of the sparse set tests to something meaningful 2023-10-06 10:38:37 +02:00
Michele Caini
ae20db416f test: avoid testing entt::entity like types more than once with the sparse set 2023-10-06 10:30:26 +02:00
Michele Caini
283ad71283 mixin: suppress warning due to constepxr expression 2023-10-06 10:27:04 +02:00
Michele Caini
25bbc4e053 test: suppress warnings due to unused variables 2023-10-06 10:22:48 +02:00
Michele Caini
913d313098 sparse_set: cast null to the right entity type before using it 2023-10-06 10:04:36 +02:00
Michele Caini
7efbafb8b4 test: test different entity types to show off a wip-only failure in the sparse set after recent rework 2023-10-06 10:04:06 +02:00
Michele Caini
3500757c97 test: typed parametrized sparse set tests 2023-10-06 10:02:47 +02:00
Michele Caini
c4c6ba7620 meta: use is_void_v as needed 2023-10-05 14:18:21 +02:00
Michele Caini
c53eaf939d storage: use is_void_v as needed 2023-10-05 14:18:09 +02:00
Michele Caini
d5613e8c65 registry: use is_void_v as needed 2023-10-05 14:17:58 +02:00
Michele Caini
7fada722e7 type_traits: use is_void_v as needed 2023-10-05 14:17:46 +02:00
Michele Caini
66ee7bab32 any: use is_void_v as needed 2023-10-05 14:17:35 +02:00
Michele Caini
8848040203 meta: meta_sequence_container::resize support to non default constructible types (close #1072) 2023-10-05 12:38:14 +02:00
Michele Caini
33ef814a76 meta: minor changes 2023-10-05 11:08:52 +02:00
Michele Caini
06e032bc6d test: prepare for new meta container tests 2023-10-05 10:38:03 +02:00
Michele Caini
25e844fadd test: minor changes 2023-10-05 10:02:56 +02:00
Michele Caini
08474c671b test: drop unused type 2023-10-05 09:46:29 +02:00
Michele Caini
8f94041ea2 doc: typo 2023-10-05 09:43:31 +02:00
Michele Caini
08fc2b3a4a test: still reworking storage tests, empty types are done 2023-10-04 18:58:04 +02:00
Michele Caini
37aec0ab84 view: use type members as needed 2023-10-04 09:06:21 +02:00
Michele Caini
61ad570ecc storage: use type members as needed 2023-10-04 09:06:13 +02:00
Michele Caini
90e158e519 group: use type members as needed 2023-10-04 09:06:05 +02:00
Michele Caini
97d49b4bf3 test: rework storage tests (work in progress) 2023-10-03 14:49:43 +02:00
Michele Caini
4c3a35bc95 storage: make get_allocator work with void type 2023-10-03 14:49:04 +02:00
Michele Caini
244b5d56ff test: add required include 2023-10-02 12:08:26 +02:00
Michele Caini
755cb0f4e0 test: merge storage and storage entity tests, prepare for storage tests rework 2023-10-02 11:50:08 +02:00
Michele Caini
7b2b402d37 *: updated TODO 2023-10-02 11:49:31 +02:00
Michele Caini
41481548b8 test: finish to rework sparse set tests to cover all policies 2023-10-02 11:49:13 +02:00
Michele Caini
f2411a1db7 sparse_set: do not invoke compact automatically when sorting 2023-10-02 11:48:34 +02:00
Michele Caini
073cbae9d5 test: still working on sparse set to fully cover all policies 2023-09-29 17:29:57 +02:00
Michele Caini
db8e22196d test: make test local functions static 2023-09-29 10:16:28 +02:00
Michele Caini
8a68fea16e test: sparse set tests (work in progress) 2023-09-29 10:00:18 +02:00
Michele Caini
6501ca9b3c doc: more links (engine + YT series) 2023-09-29 09:59:45 +02:00
Michele Caini
0c7c6c58c0 test: suppress warning due to unused alias 2023-09-29 09:46:49 +02:00
Michele Caini
f3f0ba6955 test: TEST[_P] -> ENTT_DEBUG_TEST[_P] 2023-09-29 09:46:29 +02:00
Michele Caini
52da5cf894 test: help the coverage tool who goes crazy sometimes 2023-09-29 09:45:10 +02:00
Michele Caini
2878e096e6 test: keep working on sparse set tests (work in progress) 2023-09-28 09:37:55 +02:00
Michele Caini
4f3ef4818a test: review sparse set (work in progress) 2023-09-27 09:48:33 +02:00
Michele Caini
ffc0c5f2d3 *: updated TODO 2023-09-27 09:47:49 +02:00
Michele Caini
9d97c83909 view: use scoped iterators with ::contains 2023-09-26 14:32:02 +02:00
Michele Caini
6a21e29397 view: use scoped iterators with ::back 2023-09-26 14:31:42 +02:00
Michele Caini
8fdc24097e view: begin/end return scoped iterators as needed 2023-09-26 08:45:52 +02:00
Michele Caini
4e7368f79a storage: entity storage no longer has component traits exposed 2023-09-25 14:26:10 +02:00
Michele Caini
1e1dee88b7 registry: avoid warnings due to unused variables 2023-09-25 08:50:16 +02:00
Michele Caini
91e4ff6a08 storage: internal changes 2023-09-22 18:31:28 +02:00
Michele Caini
4be9aac7a6 storage: use scoped iterators in entity storage 2023-09-22 18:30:31 +02:00
Michele Caini
af059b5e21 mixin: rework pop_all to make it work without component traits 2023-09-22 18:27:48 +02:00
Michele Caini
fdb1978f89 component: cleanup 2023-09-22 17:35:33 +02:00
Michele Caini
8332e59c62 sparse_set: minor changes 2023-09-22 16:15:27 +02:00
Michele Caini
20cc263502 view: use scoped iterators as in the ::each function 2023-09-22 07:57:33 +02:00
Michele Caini
361d4ec4dd sparse_set: scoped iterator 2023-09-21 17:58:24 +02:00
Michele Caini
11f8ba5a8f *: updated TODO 2023-09-21 17:57:04 +02:00
Michele Caini
c3bf842f9f sparse_set: const correctness 2023-09-21 17:35:05 +02:00
Michele Caini
33b598289b meta: help the code coverage tool 2023-09-20 14:51:14 +02:00
Michele Caini
cfc7f99405 meta: avoid dead code warnings 2023-09-20 12:35:01 +02:00
Michele Caini
1d79550f3c *: updated TODO 2023-09-20 12:23:40 +02:00
Michele Caini
db5ecd2c96 meta: further reduce size of symbols 2023-09-20 12:22:18 +02:00
Michele Caini
1280367a35 test: cleanup 2023-09-19 09:27:01 +02:00
Michele Caini
14706c8f9a test: cleanup 2023-09-18 14:38:16 +02:00
Michele Caini
b821df4279 *: update TODO 2023-09-18 14:08:26 +02:00
Michele Caini
07ff28d9dc sparse_set/storage: put swap_or_move check into the base class 2023-09-18 14:07:59 +02:00
Michele Caini
d15fd2a8b7 test: ENTT_DEBUG_TEST_P 2023-09-18 14:07:14 +02:00
Michele Caini
6e4381934a storage: improve asserts 2023-09-14 23:47:50 +02:00
Michele Caini
46ccded145 *: in_use -> free_list 2023-09-14 23:34:59 +02:00
Ezekiel Warren
01453b67fc build system: add bzlmod support + tests (#1057) 2023-09-14 08:48:17 +02:00
Michele Caini
7ec739b5c7 view: drop specialization for single type views with exclusion list 2023-09-13 13:00:01 +02:00
Michele Caini
fd8279ee90 *: cleanup TODO 2023-09-12 08:54:47 +02:00
Michele Caini
a6fea6727b sparse_set/storage: improve emplace(N) with non-sequential entities 2023-09-12 08:54:38 +02:00
Michele Caini
e561e8cbdd storage: deprecate in_use 2023-09-12 08:47:34 +02:00
Michele Caini
8d39f89aff sparse_set: added free_list(N) for swap_only sets 2023-09-12 08:46:57 +02:00
Michele Caini
05644a742f *: updated TODO 2023-09-11 12:47:57 +02:00
Michele Caini
f0f7fcf5b7 test: a few more checks for the sparse set class 2023-09-11 12:47:48 +02:00
Michele Caini
16bb54c524 sparse_set/storage: move swap_only policy towards the base 2023-09-11 10:51:29 +02:00
Michele Caini
70c3eaab80 natvis: add free_list to the sparse set snippet 2023-09-08 11:17:06 +02:00
Michele Caini
104fb0f06c doc: update to reflect last changes (close #1061) 2023-09-08 11:12:33 +02:00
Michele Caini
d93f96f48f test: use the right values for the free_list to avoid regressions 2023-09-07 18:22:20 +02:00
Michele Caini
8731eb91f4 sparse_set: split swap_at for internal uses 2023-09-07 10:41:12 +02:00
Michele Caini
a987609b2a sparse_set: make ::free_list [[nodiscard]] 2023-09-06 15:13:16 +02:00
Michele Caini
40793e9485 sparse_set: minor changes 2023-09-06 14:59:56 +02:00
Michele Caini
874587a591 sparse_set: swap_only pop function 2023-09-06 08:37:31 +02:00
Michele Caini
59a401fbe2 *: updated TODO 2023-09-06 08:37:00 +02:00
Michele Caini
9c797ead28 sparse_set: extra (temporary) check 2023-09-05 15:05:15 +02:00
Michele Caini
b6bb7c1a84 sparse_set: clear policy_to_head 2023-09-05 15:05:04 +02:00
Michele Caini
995f7e8e19 sparse_set: review pop_all 2023-09-05 14:37:14 +02:00
Michele Caini
9732f0547d sparse_set/storage: drop length in favor of a temporary function to make the transition easier 2023-09-05 14:36:33 +02:00
Michele Caini
9c9a71af74 sparse_set: update/set head properly accordingly with the policy 2023-09-05 10:00:03 +02:00
Michele Caini
be09b3a40a entity: update doc 2023-09-05 09:58:52 +02:00
Michele Caini
d79d08ef11 sparse_set: use the underlying entity type for the head of the free list 2023-09-04 17:37:40 +02:00
Michele Caini
c7377cbbbf sparse_set: strip the version from the head of the free list 2023-09-04 17:33:24 +02:00
Michele Caini
bbcc88217a sparse_set: make ::pop_all work property in managed swap_only mode 2023-09-04 12:40:33 +02:00
Michele Caini
c2838b4861 sparse_set: ::free_list function (for later uses) 2023-09-01 14:26:02 +02:00
Michele Caini
19c256d9a4 sparse_set: prepare to make swap_only a proper deletion policy managed at sparse set level 2023-09-01 09:26:42 +02:00
Michele Caini
7b08533a76 *: updated TODO 2023-08-31 11:28:15 +02:00
Michele Caini
baf0057628 sparse_set: drop swap_at as it ought to be 2023-08-31 11:28:15 +02:00
Michele Caini
99bf93dce6 storage: stop using swap_at, prepare to make swap_only a proper sparse set policy 2023-08-31 11:28:15 +02:00
Michele Caini
776ec96565 sparse_set: minor changes 2023-08-31 11:28:15 +02:00
Michele Caini
d03c444eae sparse_set: prepare to offer the free_list value to the user 2023-08-31 11:28:15 +02:00
Michele Caini
de6678c47a sparse_set: refine ::sort_n to work with upcoming changes 2023-08-31 11:28:15 +02:00
Michele Caini
b780198526 sparse_set: make ::compact work only with the right deletion policies 2023-08-31 11:28:15 +02:00
Michele Caini
27f1e9e476 sparse_set: refine ::contiguous to work fine with upcoming changes 2023-08-31 11:28:15 +02:00
Michele Caini
a9de9da75b sparse_set: prepare to drop swap_at 2023-08-31 11:28:15 +02:00
Michele Caini
4f0a119279 sparse_set: swap-only mode for easy identification 2023-08-31 11:28:15 +02:00
Michele Caini
9d3b4b8d78 meta: suppress warnings due to unused variables 2023-08-31 11:28:07 +02:00
Michele Caini
9a59de939e meta: deprecate ::key_only 2023-08-31 11:27:48 +02:00
Michele Caini
c5a2d00395 meta: deprecate (again) ::owner 2023-08-31 11:27:43 +02:00
Michele Caini
36c2087269 any: deprecate (again) ::owner 2023-08-31 11:27:39 +02:00
Michele Caini
7178970524 meta: make basic_meta_[sequence|associative]_container_traits public with doc 2023-08-21 12:30:13 +02:00
Michele Caini
d76fa92be3 meta: use the right return type for meta assoc container ::erase function 2023-08-21 11:30:37 +02:00
Michele Caini
e942348211 meta: [[nodiscard]] as it ought to be 2023-08-21 09:48:17 +02:00
Michele Caini
3e12f4f55f *: updated TODO 2023-08-19 17:36:29 +02:00
Michele Caini
4ed51d3fd8 meta: back to the multi-function model because it's easier to partially customize it 2023-08-19 17:35:51 +02:00
Michele Caini
c9a5fda400 meta: allow for a smoother transition before dropping meta_associative_container::key_only 2023-08-19 16:22:59 +02:00
Michele Caini
45d4bd0cf5 meta: allow for a smoother transition before deprecating ::owner 2023-08-19 16:15:48 +02:00
Michele Caini
aafa8a9b0b any: allow for a smoother transition before deprecating ::owner 2023-08-19 16:15:38 +02:00
Michele Caini
b1e47fc7d4 snpashot: review/cleanup orphans but keep it in place 2023-08-19 16:07:26 +02:00
Michele Caini
b87b8cf272 *: updated TODO 2023-08-19 16:07:26 +02:00
Michele Caini
e797fadaff meta: further review meta container vtables 2023-08-19 16:07:26 +02:00
Michele Caini
316b5b9992 meta: split begin/cbegin and end/cend for meta assoc containers, review vtable 2023-08-19 16:07:26 +02:00
Michele Caini
5aeae3a452 meta: split begin/cbegin and end/cend for meta seq containers, review vtable 2023-08-19 16:07:26 +02:00
Michele Caini
3f4f976396 *: updated TODO 2023-08-19 16:07:26 +02:00
Michele Caini
7cd83ced17 meta: split insert/erase for meta containers to simplify the cleanup/improvement 2023-08-19 16:07:26 +02:00
Michele Caini
f832a8f97c meta: static_cast only vtable for meta associative containers 2023-08-19 16:07:26 +02:00
Michele Caini
256eb727a5 meta: const correctness 2023-08-19 16:07:26 +02:00
Michele Caini
3ae6613445 meta: further reduce vtable size for meta associative containers 2023-08-19 16:07:26 +02:00
Michele Caini
5979dd2e15 meta: further reduce the size of meta_any vtables for non-container non-pointer-like types 2023-08-19 16:07:26 +02:00
Michele Caini
b203a31039 meta: I probably went a little too far :) 2023-08-19 16:07:26 +02:00
Michele Caini
1f99b49617 meta:
* drop any from meta containers rebind
* further reduce the size of the meta any vtable for containers
2023-08-19 16:07:26 +02:00
Michele Caini
efbf5e3111 meta:
* further reduce the size of the meta_any vtable
* drop meta_any operation enum
2023-08-19 16:07:26 +02:00
Michele Caini
b52fe64628 *: updated TODO 2023-08-19 16:07:26 +02:00
Michele Caini
0d3511c05f meta: further refine meta_any vtable 2023-08-19 16:07:26 +02:00
Michele Caini
ace3da4173 meta: refine meta_any vtable, prepare to drop any from meta container rebind 2023-08-19 16:07:26 +02:00
Michele Caini
f65a21f88c meta: minor changes 2023-08-19 16:07:26 +02:00
DonutVikingChap
47aeeabc51 *: fix C++20 global module fragment inclusion (#1047) 2023-08-19 16:07:26 +02:00
Michele Caini
049860b884 meta: decouple container operations for coverage purposes and share them properly 2023-08-19 16:07:26 +02:00
Michele Caini
b7d23e1aec meta: suppress comma warnings (close #1044) 2023-08-19 16:07:26 +02:00
Michele Caini
f1f33a3ac7 build: enable -Wcomma on clang (see #1044) 2023-08-19 16:07:26 +02:00
Michele Caini
607e6d96a4 meta: share look_for function to reduce duplication 2023-08-19 16:07:26 +02:00
Michele Caini
d8551ead86 sparse_set: prepare for yet another option 2023-08-19 16:07:26 +02:00
Michele Caini
29510716bb meta: drop friendship between meta_any and meta_type 2023-08-19 16:07:26 +02:00
Michele Caini
735e0af91a meta: try_convert to replace/merge can_convert and allow_cast 2023-08-19 16:07:26 +02:00
Michele Caini
2666982645 meta: drop constexpr from meta iterators since it drives gcc crazy 2023-08-19 16:07:25 +02:00
Michele Caini
768c8de48c doc: cleanup 2023-08-19 16:07:25 +02:00
Michele Caini
ce6a04ae5a meta: avoid passing contexts to meta containers' vtables 2023-08-19 16:07:25 +02:00
Michele Caini
f8012d5055 meta: avoid shadow warnings 2023-08-19 16:07:25 +02:00
Michele Caini
966efd2397 doc: minor changes 2023-08-19 16:07:25 +02:00
Michele Caini
9344798fa1 doc: update the give me everything section (close #1043) 2023-08-19 16:07:25 +02:00
skypjack
95643b6a56 meta: drop unnecessary move 2023-08-19 16:07:25 +02:00
skypjack
6b2c88e542 meta: cleanup 2023-08-19 16:07:25 +02:00
skypjack
0df38df1c6 *: updated TODO 2023-08-19 16:07:25 +02:00
skypjack
73dd3dcc26 meta: add meta_type::can_convert (close #1028) 2023-08-19 16:07:25 +02:00
skypjack
1e65fede6c test: minor changes 2023-08-19 16:07:25 +02:00
skypjack
b3c0d91eb3 meta: drop redundant assert 2023-08-19 16:07:25 +02:00
skypjack
eaa93d287e meta: meta_type::can_cast (see #1028) 2023-08-19 16:07:25 +02:00
skypjack
4517ae22e5 test: cleanup 2023-08-19 16:07:25 +02:00
skypjack
f4537ad272 *: updated TODO 2023-08-19 16:07:25 +02:00
skypjack
c425199239 meta: make basic meta container traits publicly available 2023-08-19 16:07:25 +02:00
skypjack
e15894872d meta: slightly improved meta_any::allow_cast 2023-08-19 16:07:25 +02:00
skypjack
54a15d7b51 doc: minor changes 2023-08-19 16:07:25 +02:00
skypjack
b1b6470cc2 doc: drop unused comments 2023-08-19 16:07:25 +02:00
skypjack
3a89263e73 doc: cleanup 2023-08-19 16:07:25 +02:00
skypjack
533b755b11 doc: minor changes 2023-08-19 16:07:25 +02:00
skypjack
c5d94545b5 *: updated TODO 2023-08-19 16:07:25 +02:00
skypjack
2ae3e52f76 meta: merge meta container operation enums 2023-08-19 16:07:25 +02:00
skypjack
f20b9e3875 meta: drop useless key_only func on meta assoc containers 2023-08-19 16:07:25 +02:00
skypjack
a1ca352818 meta: exploit vtable params for meta containers 2023-08-19 16:07:25 +02:00
skypjack
6b96e2f2a9 meta: make the non-consteness of the value-or-container explicit in the meta container vtable 2023-08-19 16:07:25 +02:00
skypjack
b1b4c67b75 meta: drop meta op cbegin/cend, use unused param value to pass constness around 2023-08-19 16:07:25 +02:00
skypjack
f775d3be67 meta: drop meta op cfind, use unused param value to pass constness around 2023-08-19 16:07:25 +02:00
skypjack
09f7814503 meta: drop redundant function in the meta associative container 2023-08-19 16:07:25 +02:00
skypjack
745c5384bb *: updated TODO 2023-08-19 16:07:25 +02:00
skypjack
5ff2b97f67 meta: fake vtable for meta associative containers 2023-08-19 16:07:25 +02:00
skypjack
44f30dc01c meta: fake vtable for meta sequence containers 2023-08-19 16:07:25 +02:00
skypjack
4b307cb2b2 doc: updated meta container doc (::reserve) 2023-08-19 16:07:25 +02:00
skypjack
378d98096d meta: meta containers support to ::reserve 2023-08-19 16:07:25 +02:00
skypjack
2b12d29a2f meta: minor changes 2023-08-19 16:07:25 +02:00
skypjack
7382a68505 *: updated TODO 2023-08-19 16:07:25 +02:00
skypjack
e10d2cb37e test: avoid shadow warnings 2023-08-19 16:07:25 +02:00
skypjack
c4e7a62ac3 meta: update meta seq container ::clear 2023-08-19 16:07:25 +02:00
skypjack
f354378fec *: updated TODO 2023-08-19 16:07:25 +02:00
Michele Caini
c638cb38b9 test: avoid shadow warnings 2023-08-19 16:07:25 +02:00
Michele Caini
d255ecf0f9 *: updated TODO 2023-08-19 16:07:25 +02:00
Michele Caini
4ea691118c view: specialization for single type views with exclusion lists - close #1032 2023-08-19 16:07:25 +02:00
Michele Caini
bfd962cda2 doc: minor changes 2023-08-19 16:07:25 +02:00
Michele Caini
719c233e77 doc: avoid warnings and errors by doxygen 2023-08-19 16:07:25 +02:00
Michele Caini
bd78235b28 doc: update doxy.in to doxygen 1.9.7 2023-08-19 16:07:25 +02:00
Michele Caini
aa292ed113 doc: drop typo 2023-08-19 16:07:25 +02:00
Michele Caini
b99d789543 test: yet another failing test to fix #1032 and avoid regressions 2023-08-19 16:07:25 +02:00
Michele Caini
5ef58cce5d test: failing test to fix #1032 and avoid regressions 2023-08-19 16:07:25 +02:00
Michele Caini
31c3868bc8 test: name consistency 2023-08-19 16:07:25 +02:00
Michele Caini
071a97becb test: review benchmark file 2023-08-19 16:07:25 +02:00
Michele Caini
1df40ada5c test: view ::use and ::refresh 2023-08-19 16:07:25 +02:00
Michele Caini
a12b99ad49 test: drop useless call to view::use 2023-08-19 16:07:25 +02:00
Michele Caini
e1d84d0b92 test: drop useless call to refresh 2023-08-19 16:07:25 +02:00
Michele Caini
fb47ef66da view: internal changes 2023-08-19 16:07:24 +02:00
Michele Caini
9621348ad0 view: internal changes (prepare to additional specialization) 2023-08-19 16:07:24 +02:00
Michele Caini
560e1429f1 test: yet another non-failing test for the storage entity 2023-08-19 16:07:24 +02:00
Michele Caini
18a945e7d6 test: prepare to fix #1032 and avoid regressions 2023-08-19 16:07:24 +02:00
Michele Caini
16548fc3a1 test: a few more 2023-08-19 16:07:24 +02:00
Michele Caini
4272d954ea test: cleanup 2023-08-19 16:07:24 +02:00
Michele Caini
77b5907a9f snapshot: code coverage 2023-08-19 16:07:24 +02:00
Michele Caini
acae0533bc view: drop unnecessary data member from single type views 2023-08-19 16:07:24 +02:00
Michele Caini
a5e259c19b view: minor changes 2023-08-19 16:07:24 +02:00
Michele Caini
12865f318e links: add saurian sorcery :) 2023-08-19 16:07:24 +02:00
pokutnev
51704ee7ce container: workaround for the max() ambiguity with MAX macro (#1034) 2023-08-19 16:07:18 +02:00
Michele Caini
ad6f4a3dd8 meta: further reduce symbol size of meta assoc container iterator 2023-08-19 16:07:11 +02:00
Michele Caini
70ffa25c4c meta: further reduce symbol size of meta seq container iterator 2023-08-19 16:07:05 +02:00
Michele Caini
4aef168a50 view: minor changes 2023-08-19 16:06:12 +02:00
Michele Caini
40fe70f15f meta: further reduce symbol size of meta assoc container iterator vtable 2023-08-19 16:05:37 +02:00
Michele Caini
812351cfdb meta: further reduce symbol size of meta seq container iterator vtable 2023-08-19 16:05:30 +02:00
Michele Caini
518e1abb26 meta: revert changes to meta container iterators, I strongly prefer this version actually 2023-08-19 16:05:24 +02:00
Michele Caini
9db64d3389 meta: avoid invoking .data() more than once 2023-08-19 16:05:18 +02:00
Michele Caini
2ad1a44432 meta: reduce symbol size of meta assoc traits ::insert_or_erase function 2023-08-19 16:04:50 +02:00
Michele Caini
3047c73952 meta: reduce symbol size of meta assoc traits ::iter function 2023-08-19 16:04:44 +02:00
Michele Caini
c8f5b1afa6 meta: reduce symbol size of meta assoc traits ::clear function 2023-08-19 16:04:40 +02:00
Michele Caini
54be0c2d9c meta: reduce symbol size of meta assoc traits ::find function 2023-08-19 16:04:26 +02:00
Michele Caini
b5b4991ae6 meta: reduce symbol size of meta assoc traits ::size function 2023-08-19 16:04:15 +02:00
Michele Caini
3273c75057 *: updated TODO 2023-08-19 16:04:09 +02:00
Michele Caini
f60f0cf279 meta: reduce symbol size of meta seq traits ::insert_or_erase function 2023-08-19 16:04:01 +02:00
Michele Caini
9e7881ee08 meta: reduce symbol size of meta seq traits ::iter function 2023-08-19 16:03:52 +02:00
Michele Caini
9d45825947 meta: minor changes 2023-08-19 16:02:27 +02:00
Michele Caini
c993388e5c meta_any:
* introduce meta_any_policy
* deprecate ::owner member
* add ::policy member
2023-08-19 16:02:20 +02:00
Michele Caini
b45cf33eef any:
* introduce any_policy
* deprecate ::owner member
* add ::policy member
2023-08-19 16:02:14 +02:00
Michele Caini
de376a0b25 meta: reduce symbol size of meta seq traits ::size function 2023-08-19 16:00:05 +02:00
Michele Caini
c659fad434 meta: make meta seq ::clear forward to ::resize 2023-08-19 16:00:05 +02:00
Michele Caini
5e7e4a4b11 meta: further reduce symbol size of meta seq traits ::size function 2023-08-19 16:00:05 +02:00
Michele Caini
7efbc3f72d meta: reduce symbol size of meta seq traits ::resize function 2023-08-19 16:00:05 +02:00
Michele Caini
8c93171303 doc: cleanup 2023-08-19 16:00:05 +02:00
Michele Caini
d8f314df25 registry: use the "right" allocator 2023-08-19 16:00:05 +02:00
Michele Caini
be0872e71e meta: internal changes 2023-08-19 16:00:05 +02:00
Michele Caini
3b95cbd697 doc: cleanup 2023-08-19 16:00:05 +02:00
Michele Caini
5ef07da451 view: further reduce instantiations 2023-08-19 16:00:05 +02:00
Michele Caini
5d98fc06c2 view: let's trust the compiler and assume that it's good enough to optimize this :) 2023-08-19 16:00:05 +02:00
Michele Caini
7f531e5e2d view: further reduce instantiations 2023-08-19 16:00:05 +02:00
Michele Caini
542a700f2c view: further reduce instantiations and symbols 2023-08-19 16:00:05 +02:00
Michele Caini
f3eaa1f74a view: reduce instantiations due to none_of 2023-08-19 16:00:05 +02:00
Michele Caini
06680c64eb doc: dense set 2023-08-19 16:00:05 +02:00
Michele Caini
4b1a19677a dense_set: reverse iterators 2023-08-19 16:00:05 +02:00
Michele Caini
5792f43185 *: updated TODO 2023-08-19 16:00:05 +02:00
Michele Caini
e89298eb52 doc: add Minecraft Legends to links 2023-08-19 16:00:05 +02:00
Michele Caini
22fada19ec build: minor changes 2023-08-19 16:00:05 +02:00
Michele Caini
ef7fa8ae0f build: make the debug build suitable for SizeBench 2023-08-19 16:00:05 +02:00
Michele Caini
72fa115160 update single include file to v3.12.2 2023-08-19 16:00:05 +02:00
Michele Caini
3665cf11f3 meta: additional assert to avoid mistakes with meta containers 2023-08-19 16:00:05 +02:00
Michele Caini
9b5910547f meta: check type when assigning a meta container 2023-08-19 16:00:05 +02:00
Michele Caini
04bcb51c73 registry: make ::valid backward compatible 2023-08-19 16:00:05 +02:00
Michele Caini
774049c75e build: update iwyu version 2023-08-19 16:00:05 +02:00
Michele Caini
b8e52934ea build: update cereal version 2023-08-19 16:00:05 +02:00
Michele Caini
5047aeacb5 doc: add hellbound :) 2023-08-19 16:00:05 +02:00
Michele Caini
6594da85f1 snapshot: try to suppress a warning from older versions of gcc 2023-08-19 16:00:05 +02:00
Michele Caini
f532807d62 update single include file to v3.12.1 2023-08-19 16:00:05 +02:00
Michele Caini
ffdc7893fe registry: drop ::assign (deprecated function) 2023-08-19 16:00:05 +02:00
Michele Caini
25a401042a registry: drop ::release (deprecated function) 2023-08-19 16:00:05 +02:00
Michele Caini
22914d4687 registry: drop ::release (deprecated function) 2023-08-19 16:00:05 +02:00
Michele Caini
7970a24359 registry: drop ::release (deprecated function) 2023-08-19 16:00:04 +02:00
Michele Caini
8bbc113258 registry: drop ::released (deprecated function) 2023-08-19 16:00:04 +02:00
Michele Caini
10c13e8fbe snapshot: reintroduce support to storage listeners 2023-08-19 15:59:57 +02:00
Michele Caini
0fec57e76d registry: drop ::data (deprecated function) 2023-06-17 22:42:55 +02:00
Michele Caini
e72bf9acb1 registry: drop ::each (deprecated function) 2023-06-16 17:35:06 +02:00
Michele Caini
fc4287e9e1 doc: typo 2023-06-16 15:59:59 +02:00
Michele Caini
5f184ed655 registry: drop ::capacity (deprecated function) 2023-06-16 11:25:07 +02:00
Michele Caini
abad59f0ce registry: drop ::reserve (deprecated function) 2023-06-16 11:23:45 +02:00
Michele Caini
cd3474e5b5 registry: drop ::alive (deprecated function) 2023-06-16 11:21:59 +02:00
Michele Caini
57d8072901 registry: drop ::empty (deprecated function) 2023-06-16 11:18:10 +02:00
Michele Caini
d7d0ba498c registry: drop ::size (deprecated function) 2023-06-15 16:42:55 +02:00
Michele Caini
169fcdc323 snapshot: drop deprecated methods (and fix tests accordingly) 2023-06-15 14:16:18 +02:00
Michele Caini
a8a19b0c4d test: meta include review (thanks iwyu) 2023-06-14 15:38:58 +02:00
Michele Caini
a669b84e6a test: lib/meta include review (thanks iwyu) 2023-06-14 15:38:58 +02:00
Michele Caini
c5e764750b test: example include review (thanks iwyu) 2023-06-14 15:38:57 +02:00
Michele Caini
7d2b7974fb test: resource include review (thanks iwyu) 2023-06-14 15:38:57 +02:00
Michele Caini
ee955f7bef test: entity include review (thanks iwyu) 2023-06-14 15:38:57 +02:00
Michele Caini
ad370d35c2 test: config include review (thanks iwyu) 2023-06-14 15:38:57 +02:00
Michele Caini
6a76afc061 process: add missing include 2023-06-14 15:38:57 +02:00
Michele Caini
c67f659041 iwyu: updated imp file 2023-06-14 15:38:57 +02:00
Michele Caini
dc5eea48ae now working on version 3.13 2023-06-14 15:38:42 +02:00
188 changed files with 19869 additions and 17104 deletions

1
.bazelignore Normal file
View File

@@ -0,0 +1 @@
test

1
.bazeliskrc Normal file
View File

@@ -0,0 +1 @@
USE_BAZEL_VERSION=6.x

17
.bazelrc Normal file
View File

@@ -0,0 +1,17 @@
common --enable_bzlmod
build --enable_platform_specific_config
build --incompatible_use_platforms_repo_for_constraints
build --incompatible_enable_cc_toolchain_resolution
build --enable_runfiles
build --incompatible_strict_action_env
# required for googletest
build:linux --cxxopt=-std=c++17
build:macos --cxxopt=-std=c++17
common:ci --announce_rc
common:ci --verbose_failures
common:ci --keep_going
test:ci --test_output=errors
try-import %workspace%/user.bazelrc

26
.clang-tidy Normal file
View File

@@ -0,0 +1,26 @@
Checks: >
bugprone-*,
concurrency-*,
cppcoreguidelines-*,
misc-*,
-misc-no-recursion,
modernize-*,
-modernize-use-trailing-return-type,
performance-*,
portability-*,
readibility-*
CheckOptions:
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: true
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
value: true
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctionsWhenCopyIsDeleted
value: true
- key: misc-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic
value: true
- key: misc-non-private-member-variables-in-classes.IgnorePublicMemberVariables
value: true
- key: cppcoreguidelines-avoid-magic-numbers.IgnorePowersOf2IntegerValues
value: true
- key: cppcoreguidelines-avoid-magic-numbers.IgnoreAllFloatingPointValues
value: true

View File

@@ -12,14 +12,14 @@ jobs:
timeout-minutes: 30
env:
IWYU: 0.19
LLVM: 15
IWYU: "0.20"
LLVM: "16"
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install llvm/clang
# see: https://apt.llvm.org/
run: |

View File

@@ -0,0 +1,20 @@
name: Bazel Release
on:
release:
types: [published]
jobs:
# A release archive is required for bzlmod
# See: https://blog.bazel.build/2023/02/15/github-archive-checksum.html
bazel-release-archive:
runs-on: ubuntu-latest
continue-on-error: true
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- run: git archive $GITHUB_REF -o "entt-${GITHUB_REF:10}.tar.gz"
- run: gh release upload ${GITHUB_REF:10} "entt-${GITHUB_REF:10}.tar.gz"
env:
GH_TOKEN: ${{ github.token }}

20
.github/workflows/bazel.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: bazel
on: [push, pull_request]
jobs:
test:
strategy:
matrix:
os:
- ubuntu-latest
- windows-latest
- macos-latest
runs-on: ${{ matrix.os }}
continue-on-error: true
steps:
- uses: actions/checkout@v4
- run: bazelisk test --config=ci ...
working-directory: test
env:
USE_BAZEL_VERSION: 6.x

View File

@@ -55,7 +55,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Install compiler
run: |
sudo apt update
@@ -71,7 +71,7 @@ jobs:
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4
windows:
timeout-minutes: 15
@@ -90,7 +90,7 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Compile tests
working-directory: build
run: |
@@ -100,14 +100,14 @@ jobs:
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4
macos:
timeout-minutes: 15
runs-on: macOS-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Compile tests
working-directory: build
run: |
@@ -117,7 +117,7 @@ jobs:
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4
extra:
timeout-minutes: 15
@@ -131,7 +131,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Compile tests
working-directory: build
run: |
@@ -141,4 +141,4 @@ jobs:
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4

View File

@@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Compile tests
working-directory: build
env:
@@ -22,7 +22,7 @@ jobs:
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4
- name: Collect data
working-directory: build
run: |

View File

@@ -16,7 +16,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
# temporary workaround for https://github.com/actions/runner-images/issues/8659
- uses: mjp41/workaround8649@c8550b715ccdc17f89c8d5c28d7a48eeff9c94a8
- name: Compile tests
working-directory: build
env:
@@ -28,4 +30,4 @@ jobs:
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4

2
.gitignore vendored
View File

@@ -11,3 +11,5 @@ cpp.hint
# Bazel
/bazel-*
/test/bazel-*
/user.bazelrc

View File

@@ -1,14 +1,6 @@
_msvc_copts = ["/std:c++17"]
_gcc_copts = ["-std=c++17"]
package(default_visibility = ["//visibility:public"])
cc_library(
alias(
name = "entt",
visibility = ["//visibility:public"],
strip_include_prefix = "src",
hdrs = glob(["src/**/*.h", "src/**/*.hpp"]),
copts = select({
"@bazel_tools//src/conditions:windows": _msvc_copts,
"@bazel_tools//src/conditions:windows_msvc": _msvc_copts,
"//conditions:default": _gcc_copts,
}),
actual = "//src:entt",
)

View File

@@ -1,21 +1,15 @@
#
# EnTT
#
cmake_minimum_required(VERSION 3.15.7)
#
# Read project version
#
set(ENTT_VERSION_REGEX "#define ENTT_VERSION_.*[ \t]+(.+)")
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/src/entt/config/version.h" ENTT_VERSION REGEX ${ENTT_VERSION_REGEX})
list(TRANSFORM ENTT_VERSION REPLACE ${ENTT_VERSION_REGEX} "\\1")
string(JOIN "." ENTT_VERSION ${ENTT_VERSION})
#
# Project configuration
#
project(
EnTT
@@ -34,18 +28,15 @@ message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
message(VERBOSE "* Copyright (c) 2017-2023 Michele Caini <michele.caini@gmail.com>")
message(VERBOSE "*")
#
# CMake stuff
#
list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
#
# Compiler stuff
#
option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." OFF)
option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags if available." OFF)
option(ENTT_USE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF)
if(ENTT_USE_LIBCPP)
if(NOT WIN32)
@@ -65,7 +56,7 @@ if(ENTT_USE_LIBCPP)
endif()
if(NOT ENTT_HAS_LIBCPP)
message(VERBOSE "The option ENTT_USE_LIBCPP is set but libc++ is not available. The flag will not be added to the target.")
message(VERBOSE "The option ENTT_USE_LIBCPP is set but libc++ is not available.")
endif()
endif()
@@ -76,13 +67,19 @@ if(ENTT_USE_SANITIZER)
endif()
if(NOT ENTT_HAS_SANITIZER)
message(VERBOSE "The option ENTT_USE_SANITIZER is set but sanitizer support is not available. The flags will not be added to the target.")
message(VERBOSE "The option ENTT_USE_SANITIZER is set but sanitizer support is not available.")
endif()
endif()
if(ENTT_USE_CLANG_TIDY)
find_program(ENTT_CLANG_TIDY_EXECUTABLE "clang-tidy")
if(NOT ENTT_CLANG_TIDY_EXECUTABLE)
message(VERBOSE "The option ENTT_USE_CLANG_TIDY is set but clang-tidy executable is not available.")
endif()
endif()
#
# Add EnTT target
#
option(ENTT_INCLUDE_HEADERS "Add all EnTT headers to the EnTT target." OFF)
option(ENTT_INCLUDE_NATVIS "Add EnTT natvis files to the EnTT target." OFF)
@@ -216,13 +213,15 @@ if(ENTT_HAS_SANITIZER)
target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
endif()
if(ENTT_CLANG_TIDY_EXECUTABLE)
set(CMAKE_CXX_CLANG_TIDY "${ENTT_CLANG_TIDY_EXECUTABLE};--config-file=${EnTT_SOURCE_DIR}/.clang-tidy;--header-filter=${EnTT_SOURCE_DIR}/src/entt/.*;--extra-arg=/EHsc")
endif()
if(ENTT_HAS_LIBCPP)
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
endif()
#
# Install pkg-config file
#
include(JoinPaths)
@@ -241,9 +240,7 @@ install(
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
#
# Install EnTT
#
include(CMakePackageConfigHelpers)
@@ -285,13 +282,17 @@ install(
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
)
install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(
DIRECTORY src/
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING
PATTERN "*.h"
PATTERN "*.hpp"
)
export(PACKAGE EnTT)
#
# Tests
#
option(ENTT_BUILD_TESTING "Enable building tests." OFF)
@@ -310,9 +311,15 @@ if(ENTT_BUILD_TESTING)
add_subdirectory(test)
endif()
#
# Tools
option(ENTT_BUILD_TOOLS "Enable building tools." OFF)
if(ENTT_BUILD_TOOLS)
add_subdirectory(tools)
endif()
# Documentation
#
option(ENTT_BUILD_DOCS "Enable building with documentation." OFF)

8
MODULE.bazel Normal file
View File

@@ -0,0 +1,8 @@
module(
name = "entt",
version = "3.12.2",
compatibility_level = 3012,
)
bazel_dep(name = "rules_cc", version = "0.0.8")
bazel_dep(name = "bazel_skylib", version = "1.4.2")

View File

@@ -6,11 +6,11 @@
[![Build Status](https://github.com/skypjack/entt/workflows/build/badge.svg)](https://github.com/skypjack/entt/actions)
[![Coverage](https://codecov.io/gh/skypjack/entt/branch/master/graph/badge.svg)](https://codecov.io/gh/skypjack/entt)
[![Try online](https://img.shields.io/badge/try-online-brightgreen)](https://godbolt.org/z/zxW73f)
[![Vcpkg port](https://img.shields.io/vcpkg/v/entt)](https://vcpkg.link/ports/entt)
[![Documentation](https://img.shields.io/badge/docs-doxygen-blue)](https://skypjack.github.io/entt/)
[![Vcpkg port](https://img.shields.io/vcpkg/v/entt)](https://vcpkg.link/ports/entt)
[![Conan Center](https://img.shields.io/conan/v/entt)](https://conan.io/center/recipes/entt)
[![Gitter chat](https://badges.gitter.im/skypjack/entt.png)](https://gitter.im/skypjack/entt)
[![Discord channel](https://img.shields.io/discord/707607951396962417?logo=discord)](https://discord.gg/5BjPWBd)
[![Donate](https://img.shields.io/badge/donate-paypal-blue.svg)](https://www.paypal.me/skypjack)
> `EnTT` has been a dream so far, we haven't found a single bug to date and it's
> super easy to work with
@@ -39,7 +39,8 @@ Don't forget to check the
there.
Do you want to support `EnTT`? Consider becoming a
[**sponsor**](https://github.com/users/skypjack/sponsorship).
[**sponsor**](https://github.com/users/skypjack/sponsorship) or making a
donation via [**PayPal**](https://www.paypal.me/skypjack).<br/>
Many thanks to [these people](https://skypjack.github.io/sponsorship/) and
**special** thanks to:
@@ -51,7 +52,7 @@ Many thanks to [these people](https://skypjack.github.io/sponsorship/) and
* [Introduction](#introduction)
* [Code Example](#code-example)
* [Motivation](#motivation)
* [Performance](#performance)
* [Benchmark](#benchmark)
* [Integration](#integration)
* [Requirements](#requirements)
* [CMake](#cmake)
@@ -175,37 +176,28 @@ Nowadays, `EnTT` is finally what I was looking for: still faster than its
_competitors_, lower memory usage in the average case, a really good API and an
amazing set of features. And even more, of course.
## Performance
## Benchmark
The proposed entity-component system is incredibly fast to iterate entities and
components, this is a fact. Some compilers make a lot of optimizations because
of how `EnTT` works, some others aren't that good. In general, if we consider
real world cases, `EnTT` is somewhere between a bit and much faster than many of
the other solutions around, although I couldn't check them all for obvious
reasons.
For what it's worth, you'll **never** see me trying to make other projects look
bad or offer dubious comparisons just to make this library seem cooler.<br/>
I leave this activity to others, if they enjoy it (and it seems that some people
actually like it). I prefer to make better use of my time.
If you are interested, you can compile the `benchmark` test in release mode (to
enable compiler optimizations, otherwise it would make little sense) by setting
the `ENTT_BUILD_BENCHMARK` option of `CMake` to `ON`, then evaluate yourself
whether you're satisfied with the results or not.
Honestly I got tired of updating the README file whenever there is an
improvement.<br/>
There are already a lot of projects out there that use `EnTT` as a basis for
There are also a lot of projects out there that use `EnTT` as a basis for
comparison (this should already tell you a lot). Many of these benchmarks are
completely wrong, many others are simply incomplete, good at omitting some
information and using the wrong function to compare a given feature. Certainly
there are also good ones but they age quickly if nobody updates them, especially
when the library they are dealing with is actively developed.
The choice to use `EnTT` should be based on its carefully designed API, its
set of features and the general performance, **not** because some single
benchmark shows it to be the fastest tool available.
In the future I'll likely try to get even better performance while still adding
new features, mainly for fun.<br/>
If you want to contribute and/or have suggestions, feel free to make a PR or
open an issue to discuss your idea.
when the library they are dealing with is actively developed.<br/>
Out of all of them, [this](https://github.com/abeimler/ecs_benchmark) seems like
the most up-to-date project and also covers a certain number of libraries. I
can't say exactly whether `EnTT` is used correctly or not. However, even if used
poorly, it should still give the reader an idea of where it's going to operate.
# Integration
@@ -327,6 +319,18 @@ If you spot errors or have suggestions, any contribution is welcome!
[documentation](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-repositories)
for more details.
* [`bzlmod`](https://bazel.build/external/overview#bzlmod), Bazel's external
dependency management system.<br/>
To use the [`entt`](https://registry.bazel.build/modules/entt) module in a
`bazel` project, add the following to your `MODULE.bazel` file:
```starlark
bazel_dep(name = "entt", version = "3.12.2")
```
EnTT will now be available as `@entt` (short for `@entt//:entt`) to be used
in your `cc_*` rule `deps`.
Consider this list a work in progress and help me to make it longer if you like.
## pkg-config

27
TODO
View File

@@ -4,23 +4,28 @@ EXAMPLES
DOC:
* custom storage/view
* examples (and credits) from @alanjfs :)
* update entity doc when the storage based model is in place
* in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
* view: single vs multi type views are no longer a thing actually
* bump entities, reserved bits on identifiers
TODO (high prio):
* check natvis files (periodically :)
TODO:
* resource cache: avoid using shared ptr with loader and the others
* further optimize exclusion lists in multi type views (no existence check)
* further improve the snapshot stuff, ie component functions
* use fixture for storage tests to reduce loc number and duplication as much as possible
* basic_view<...>::reach(...)
* doc: bump entities
WIP:
* further improve meta resolve function by id (bimap)
* get rid of observers, storage based views made them pointless - document alternatives
* exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details)
* process scheduler: reviews, use free lists internally
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
* bring nested groups back in place (see bd34e7f)
* work stealing job system (see #100) + mt scheduler based on const awareness for types
* view: reduce inst due to/improve perf with index-based approach in dispatch_get/pick_and_each/each (single type too, define storage ::at and ::at_as_tuple)
* view: update natvis as needed after the last rework, merge pools/filter in the same array, drop check (?) and turn view into a position
* view: type-only view_iterator (dyn get/excl sizes), type-only basic_common_view (dyn get/excl sizes with pointer to array from derived)
* combine version-mask-vs-version-bits tricks with reserved bits to allow things like enabling/disabling
* basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) uses moved-from packed in assert (same for storage)
* maybe drop begin(v)/end(v) from sparse set and only use scoped begin/end at call sites
* view unchecked_refresh loop is never executed if Get is 1u
* review all // NOLINT + linter workflow + review clang-tidy file
* self contained entity traits to avoid explicit specializations (ie enum constants)
* review assure conflicts check, hash doesn't fit the purpose maybe
* allow to zero-sized versions (with non-regression tests)
* auto type info data from types if present

View File

@@ -1 +0,0 @@
workspace(name = "com_github_skypjack_entt")

1
WORKSPACE.bazel Normal file
View File

@@ -0,0 +1 @@
# SEE MODULE.bazel

0
bazel/BUILD.bazel Normal file
View File

13
bazel/copts.bzl Normal file
View File

@@ -0,0 +1,13 @@
load("@bazel_skylib//lib:selects.bzl", "selects")
COPTS = selects.with_or({
("//conditions:default", "@rules_cc//cc/compiler:clang", "@rules_cc//cc/compiler:gcc", "@rules_cc//cc/compiler:mingw-gcc"): [
"-std=c++17",
"-w",
],
("@rules_cc//cc/compiler:msvc-cl", "@rules_cc//cc/compiler:clang-cl"): [
"/std:c++17",
"/permissive-",
"/w",
],
})

View File

@@ -1,6 +1,6 @@
#
# Doxygen configuration (documentation)
#
include(FetchContent)
FetchContent_Declare(
doxygen-awesome-css

View File

@@ -1,4 +1,4 @@
# Doxyfile 1.9.6
# Doxyfile 1.9.7
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -353,6 +353,17 @@ MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 5
# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to
# generate identifiers for the Markdown headings. Note: Every identifier is
# unique.
# Possible values are: DOXYGEN Use a fixed 'autotoc_md' string followed by a
# sequence number starting at 0. and GITHUB Use the lower case version of title
# with any whitespace replaced by '-' and punctations characters removed..
# The default value is: DOXYGEN.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
MARKDOWN_ID_STYLE = DOXYGEN
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
@@ -477,6 +488,14 @@ LOOKUP_CACHE_SIZE = 0
NUM_PROC_THREADS = 1
# If the TIMESTAMP tag is set different from NO then each generated page will
# contain the date or date and time when the page was generated. Setting this to
# NO can help when comparing the output of multiple runs.
# Possible values are: YES, NO, DATETIME and DATE.
# The default value is: NO.
TIMESTAMP = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@@ -862,7 +881,14 @@ WARN_IF_UNDOC_ENUM_VAL = NO
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves
# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not
# write the warning messages in between other messages but write them at the end
# of a run, in case a WARN_LOGFILE is defined the warning messages will be
# besides being in the defined file also be shown at the end of a run, unless
# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case
# the behavior will remain as with the setting FAIL_ON_WARNINGS.
# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT.
# The default value is: NO.
WARN_AS_ERROR = NO
@@ -990,9 +1016,6 @@ EXCLUDE_PATTERNS =
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# ANamespace::AClass, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS =
@@ -1375,15 +1398,6 @@ HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will
@@ -1533,6 +1547,16 @@ BINARY_TOC = NO
TOC_EXPAND = NO
# The SITEMAP_URL tag is used to specify the full URL of the place where the
# generated documentation will be placed on the server by the user during the
# deployment of the documentation. The generated sitemap is called sitemap.xml
# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL
# is specified no sitemap is generated. For information about the sitemap
# protocol see https://www.sitemaps.org
# This tag requires that the tag GENERATE_HTML is set to YES.
SITEMAP_URL =
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
@@ -2021,9 +2045,16 @@ PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running
# if errors occur, instead of asking the user for help.
# The LATEX_BATCHMODE tag ignals the behavior of LaTeX in case of an error.
# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch
# mode nothing is printed on the terminal, errors are scrolled as if <return> is
# hit at every error; missing files that TeX tries to input or request from
# keyboard input (\read on a not open input stream) cause the job to abort,
# NON_STOP In nonstop mode the diagnostic message will appear on the terminal,
# but there is no possibility of user interaction just like in batch mode,
# SCROLL In scroll mode, TeX will stop only for missing files to input or if
# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at
# each error, asking for user intervention.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -2044,14 +2075,6 @@ LATEX_HIDE_INDICES = NO
LATEX_BIB_STYLE = plain
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_TIMESTAMP = NO
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the
@@ -2217,7 +2240,7 @@ DOCBOOK_OUTPUT = docbook
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures
# the structure of the code including all documentation. Note that this feature
# is still experimental and incomplete at the moment.
# The default value is: NO.
@@ -2388,16 +2411,9 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
# Configuration options related to diagram generator tools
#---------------------------------------------------------------------------
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
DIA_PATH =
# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
@@ -2406,7 +2422,7 @@ HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz (see:
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
# The default value is: NO.
@@ -2459,13 +2475,15 @@ DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
DOT_FONTPATH =
# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a
# graph for each documented class showing the direct and indirect inheritance
# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,
# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set
# to TEXT the direct and indirect inheritance relations will be shown as texts /
# links.
# Possible values are: NO, YES, TEXT and GRAPH.
# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will
# generate a graph for each documented class showing the direct and indirect
# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and
# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case
# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the
# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used.
# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance
# relations will be shown as texts / links.
# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN.
# The default value is: YES.
CLASS_GRAPH = YES
@@ -2606,7 +2624,7 @@ DIR_GRAPH_MAX_DEPTH = 1
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see:
# http://www.graphviz.org/)).
# https://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
@@ -2643,11 +2661,12 @@ DOT_PATH =
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
MSCFILE_DIRS =
DIA_PATH =
# The DIAFILE_DIRS tag can be used to specify one or more directories that
# contain dia files that are included in the documentation (see the \diafile
@@ -2724,3 +2743,19 @@ GENERATE_LEGEND = YES
# The default value is: YES.
DOT_CLEANUP = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will
# use a built-in version of mscgen tool to produce the charts. Alternatively,
# the MSCGEN_TOOL tag can also specify the name an external tool. For instance,
# specifying prog as the value, doxygen will call the tool as prog -T
# <outfile_format> -o <outputfile> <inputfile>. The external tool should support
# output file formats "png", "eps", "svg", and "ismap".
MSCGEN_TOOL =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
MSCFILE_DIRS =

View File

@@ -63,4 +63,5 @@ implicit list within the packed array itself.
The interface is in all respects similar to its counterpart in the standard
library, that is, the `std::unordered_set` class.<br/>
Therefore, there is no need to go into the API description.
However, this type of set also supports reverse iteration and therefore offers
all the functions necessary for the purpose (such as `rbegin` and `rend`).

View File

@@ -773,7 +773,7 @@ A utility to quickly find the n-th argument of a function, member function or
data member (for blind operations on opaque types):
```cpp
using type = entt::nth_argument_t<1u, &clazz::member>;
using type = entt::nth_argument_t<1u, decltype(&clazz::member)>;
```
Disambiguation of overloaded functions is the responsibility of the user, should

View File

@@ -583,7 +583,7 @@ There are two functions that respond to slightly different needs:
* Components are sorted either directly:
```cpp
registry.sort<renderable>([](const auto &lhs, const auto &rhs) {
registry.sort<renderable>([](const renderable &lhs, const renderable &rhs) {
return lhs.z < rhs.z;
});
```
@@ -1372,7 +1372,7 @@ Finally, when the user asks the registry for an iterable object to visit all the
storage elements inside it as follows:
```cpp
for(auto [id, storage]: registry.each()) {
for(auto [id, storage]: registry.storage()) {
// ...
}
```
@@ -1549,7 +1549,7 @@ own API for them. However, there is still no limit to the possibilities of use:
auto &&other = registry.storage<velocity>("other"_hs);
registry.emplace<velocity>(entity);
storage.push(entity);
other.push(entity);
```
Anything that can be done via the registry interface can also be done directly
@@ -1817,7 +1817,10 @@ However, it's possible to _enforce_ iteration of a view by given component order
by means of the `use` function:
```cpp
for(auto entity : registry.view<position, velocity>().use<position>()) {
auto view = registry.view<position, velocity>();
view.use<position>();
for(auto entity: view) {
// ...
}
```
@@ -2105,28 +2108,27 @@ The same concepts apply to groups as well.
Views and groups are narrow windows on the entire list of entities. They work by
filtering entities according to their components.<br/>
In some cases there may be the need to iterate all the entities still in use
regardless of their components. The registry offers a specific member function
to do that:
regardless of their components. This is done by accessing entity storage:
```cpp
registry.each([](auto entity) {
for(auto entity: registry.view<entt::entity>()) {
// ...
});
}
```
As a rule of thumb, consider using a view or a group if the goal is to iterate
entities that have a determinate set of components. These tools are usually much
faster than combining the `each` function with a bunch of custom tests.<br/>
faster than filtering entities with a bunch of custom tests.<br/>
In all the other cases, this is the way to go. For example, it's possible to
combine `each` with the `orphan` member function to clean up orphan entities
combine this view with the `orphan` member function to clean up orphan entities
(that is, entities that are still in use and have no assigned components):
```cpp
registry.each([&registry](auto entity) {
for(auto entity: registry.view<entt::entity>()) {
if(registry.orphan(entity)) {
registry.release(entity);
}
});
}
```
In general, iterating all entities can result in poor performance. It should not

View File

@@ -14,6 +14,7 @@
* [Warning C4003: the min, the max and the macro](#warning-C4003-the-min-the-max-and-the-macro)
* [The standard and the non-copyable types](#the-standard-and-the-non-copyable-types)
* [Which functions trigger which signals](#which-functions-trigger-which-signals)
* [Duplicate storage for the same component](#duplicate-storage-for-the-same-component)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@@ -213,3 +214,28 @@ otherwise the latter is replaced and therefore `on_update` is triggered. As for
the second case, components are removed from their entities and thus freed when
they are recycled. It means that `on_destroyed` is triggered for every component
owned by the entity that is destroyed.
## Duplicate storage for the same component
It's rare but you can see double sometimes, especially when it comes to storage.
This can be caused by a conflict in the hash assigned to the various component
types (one of a kind) or by bugs in your compiler
([more common](https://github.com/skypjack/entt/issues/1063) apparently).<br/>
Regardless of the cause, `EnTT` offers a customization point that also serves as
a solution in this case:
```cpp
template<>
struct entt::type_hash<Type> final {
[[nodiscard]] static constexpr id_type value() noexcept {
return hashed_string::value("Type");
}
[[nodiscard]] constexpr operator id_type() const noexcept {
return value();
}
};
```
Specializing `type_hash` directly bypasses the default implementation offered by
`EnTT`, thus avoiding any possible conflicts or compiler bugs.

View File

@@ -39,6 +39,9 @@ I hope the following lists can grow much more in the future.
* [Minecraft](https://minecraft.net/en-us/attribution/) by
[Mojang](https://mojang.com/): of course, **that** Minecraft, see the
open source attributions page for more details.
* [Minecraft Legends](https://www.minecraft.net/it-it/about-legends) by
[Mojang](https://mojang.com/): an action strategy game where users have to
fight to defend the Overworld.
* [Minecraft Earth](https://www.minecraft.net/en-us/about-earth) by
[Mojang](https://mojang.com/): an augmented reality game for mobile, that
lets users bring Minecraft into the real world.
@@ -124,6 +127,16 @@ I hope the following lists can grow much more in the future.
multi-player arcade shooter game prototype.
* [Confetti Party](https://github.com/hexerei/entt-confetti): C++ sample
application as a starting point using `EnTT` and `SDL2`.
* [Hellbound](https://buas.itch.io/hellbound): a top-down action rogue-like
where to fight colossal demons in procedurally generated levels of hell.
* [Saurian Sorcery](https://github.com/cajallen/spellbook): a tower defense
game where to assemble a tribe of lizards to defend against robot invaders.
* [robotfindskitten](https://github.com/autogalkin/robotfindskitten): a clone
of `robotfindskitten` inside `Notepad.exe`, powered by `EnTT`.
* [Orion](https://github.com/alekskoloch/Orion): Outer-space Research and
Interstellar Observation Network (a space shooter game).
* [EnTT Boids](https://github.com/DanielEliasib/entt_boids): a simple boids
implementation using `EnTT` and `Raylib`.
## Engines and the like:
@@ -200,7 +213,14 @@ I hope the following lists can grow much more in the future.
open-source engine for building 2D & 3D real-time rendering and interactive
contents.
* [Kengine](https://github.com/phisko/kengine): the _Koala engine_ is a game
engine entirely implemented as an entity-component-ystem.
engine entirely implemented as an entity-component-system.
* [Scion2D](https://github.com/dwjclark11/Scion2D): 2D game engine with
[YouTube series](https://www.youtube.com/playlist?list=PL3HUvSWOJR7XRDwVVQqqWO-zyyscb8L-v)
included.
* [EnTT Editor](https://github.com/TheDimin/EnttEditor): an editor for `EnTT`
libary that combines its built-in reflection system with `ImGui`.
* [Era Game Engine](https://github.com/EldarMuradov/EraGameEngine): a modern
ECS-based game engine.
## Articles, videos and blog posts:
@@ -227,6 +247,17 @@ I hope the following lists can grow much more in the future.
- ... And so on.
[Check out](https://www.youtube.com/channel/UCQ-W1KE9EYfdxhL6S4twUNw) the
_Game Engine Series_ by The Cherno for more videos.
* [Game Engine series](https://www.youtube.com/@JADE-iteGames/videos) by
[dwjclark11](https://github.com/dwjclark11) (not just `EnTT` but a lot of
it):
- [Getting into ECS](https://youtu.be/k9CbonLopJU?si=za3Tisyc96_92DWM)
- [Creating ECS Wrapper Classes](https://youtu.be/yetyuMJRdbo?si=PJTkmap4Ysqbzb_M)
- [Runtime Reflection using EnTT meta](https://youtu.be/GrXV5A07GTY?si=fKdWTj9AOhnhtiXq)
- [Adding entt::meta and Sol2 bindings](https://youtu.be/IM55JgxOqFA?si=rsbb4AG_NVh4IUmD)
(with [part two](https://youtu.be/-PTt-b1tzRw?si=zPJ4vEluyheMcNgO) too)
- ... And so on.
[Check it out](https://www.youtube.com/playlist?list=PL3HUvSWOJR7XRDwVVQqqWO-zyyscb8L-v)
for more videos.
* [Warmonger Dynasty devlog series](https://david-delassus.medium.com/list/warmonger-dynasty-devlogs-f64b71f556de)
by [linkdd](https://github.com/linkdd): an interesting walkthrough of
developing a game (also) with EnTT.

View File

@@ -385,6 +385,10 @@ to case. In particular:
true in case of success.<br/>
For example, it's not possible to clear fixed size containers.
* The `reserve` member function allows to increase the capacity of the wrapped
container and returns true in case of success.<br/>
For example, it's not possible to increase capacity of fixed size containers.
* The `begin` and `end` member functions return opaque iterators that is used to
iterate the container directly:
@@ -472,6 +476,10 @@ differences in behavior in the case of key-only containers. In particular:
* The `clear` member function allows to clear the wrapped container and returns
true in case of success.
* The `reserve` member function allows to increase the capacity of the wrapped
container and returns true in case of success.<br/>
For example, it's not possible to increase capacity of standard maps.
* The `begin` and `end` member functions return opaque iterators that are used
to iterate the container directly:

View File

@@ -177,8 +177,8 @@ To attach a process to a scheduler there are mainly two ways:
scheduler.attach([](auto...){ /* ... */ });
```
In both cases, the return value is an opaque object that offers a `then` member
function used to create chains of processes to run sequentially.<br/>
In both cases, the scheduler is returned and its `then` member function can be
used to create chains of processes to run sequentially.<br/>
As a minimal example of use:
```cpp

View File

@@ -14,6 +14,8 @@
## Enable Cpp17
> Skip this part if you are working with UE5, Since UE5 uses cpp17 by default.
As of writing (Unreal Engine v4.25), the default C++ standard of Unreal Engine
is C++14.<br/>
On the other hand, note that `EnTT` requires C++17 to compile. To enable it, in

View File

@@ -1,34 +1,42 @@
[
# gtest only
{ "include": [ "@<gtest/internal/.*>", "private", "<gtest/gtest.h>", "public" ] },
{ "include": [ "@<gtest/gtest-.*>", "private", "<gtest/gtest.h>", "public" ] },
{ "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_map.hpp>", "public" ] },
{ "include": [ "@[\"<].*/container/fwd.hpp[\">]", "private", "<entt/container/dense_set.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/any.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/family.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/hashed_string.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/ident.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/monostate.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_info.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd.hpp[\">]", "private", "<entt/core/type_traits.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/entity.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/group.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/handle.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/helper.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/observer.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/organizer.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/registry.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/runtime_view.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/snapshot.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/sparse_set.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/storage.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd.hpp[\">]", "private", "<entt/entity/view.hpp>", "public" ] },
{ "include": [ "@[\"<].*/meta/fwd.hpp[\">]", "private", "<entt/meta/meta.hpp>", "public" ] },
{ "include": [ "@[\"<].*/poly/fwd.hpp[\">]", "private", "<entt/poly/poly.hpp>", "public" ] },
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/cache.hpp>", "public" ] },
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/loader.hpp>", "public" ] },
{ "include": [ "@[\"<].*/resource/fwd.hpp[\">]", "private", "<entt/resource/resource.hpp>", "public" ] },
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/delegate.hpp>", "public" ] },
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/dispatcher.hpp>", "public" ] },
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/emitter.hpp>", "public" ] },
{ "include": [ "@[\"<].*/signal/fwd.hpp[\">]", "private", "<entt/signal/sigh.hpp>", "public" ] }
# forward files
{ "include": [ "@[\"<].*/container/fwd\\.hpp[\">]", "private", "<entt/container/dense_map.hpp>", "public" ] },
{ "include": [ "@[\"<].*/container/fwd\\.hpp[\">]", "private", "<entt/container/dense_set.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/any.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/family.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/hashed_string.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/ident.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/monostate.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/type_info.hpp>", "public" ] },
{ "include": [ "@[\"<].*/core/fwd\\.hpp[\">]", "private", "<entt/core/type_traits.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/component.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/entity.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/group.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/handle.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/helper.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/observer.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/organizer.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/registry.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/runtime_view.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/snapshot.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/sparse_set.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/storage.hpp>", "public" ] },
{ "include": [ "@[\"<].*/entity/fwd\\.hpp[\">]", "private", "<entt/entity/view.hpp>", "public" ] },
{ "include": [ "@[\"<].*/graph/fwd\\.hpp[\">]", "private", "<entt/graph/adjacency_matrix.hpp>", "public" ] },
{ "include": [ "@[\"<].*/graph/fwd\\.hpp[\">]", "private", "<entt/graph/dot.hpp>", "public" ] },
{ "include": [ "@[\"<].*/graph/fwd\\.hpp[\">]", "private", "<entt/graph/flow.hpp>", "public" ] },
{ "include": [ "@[\"<].*/meta/fwd\\.hpp[\">]", "private", "<entt/meta/meta.hpp>", "public" ] },
{ "include": [ "@[\"<].*/poly/fwd\\.hpp[\">]", "private", "<entt/poly/poly.hpp>", "public" ] },
{ "include": [ "@[\"<].*/process/fwd\\.hpp[\">]", "private", "<entt/process/process.hpp>", "public" ] },
{ "include": [ "@[\"<].*/process/fwd\\.hpp[\">]", "private", "<entt/process/scheduler.hpp>", "public" ] },
{ "include": [ "@[\"<].*/resource/fwd\\.hpp[\">]", "private", "<entt/resource/cache.hpp>", "public" ] },
{ "include": [ "@[\"<].*/resource/fwd\\.hpp[\">]", "private", "<entt/resource/loader.hpp>", "public" ] },
{ "include": [ "@[\"<].*/resource/fwd\\.hpp[\">]", "private", "<entt/resource/resource.hpp>", "public" ] },
{ "include": [ "@[\"<].*/signal/fwd\\.hpp[\">]", "private", "<entt/signal/delegate.hpp>", "public" ] },
{ "include": [ "@[\"<].*/signal/fwd\\.hpp[\">]", "private", "<entt/signal/dispatcher.hpp>", "public" ] },
{ "include": [ "@[\"<].*/signal/fwd\\.hpp[\">]", "private", "<entt/signal/emitter.hpp>", "public" ] },
{ "include": [ "@[\"<].*/signal/fwd\\.hpp[\">]", "private", "<entt/signal/sigh.hpp>", "public" ] }
]

View File

@@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="entt::basic_registry&lt;*&gt;">
<Intrinsic Name="to_entity" Expression="*((traits_type::entity_type *)&amp;entity) &amp; traits_type::entity_mask">
<Parameter Name="entity" Type="traits_type::value_type &amp;"/>
</Intrinsic>
<DisplayString>{{ pools={ pools.size() } }}</DisplayString>
<Expand>
<Item Name="[entities]">entities</Item>
@@ -33,10 +30,12 @@
</Expand>
</Type>
<Type Name="entt::basic_sparse_set&lt;*&gt;">
<Intrinsic Name="cap" Expression="(traits_type::version_mask &lt;&lt; traits_type::length)"/>
<DisplayString>{{ size={ packed.size() }, type={ info->alias,na } }}</DisplayString>
<Expand>
<Item Name="[capacity]" ExcludeView="simple">packed.capacity()</Item>
<Item Name="[policy]">mode,en</Item>
<Item Name="[free_list]">head</Item>
<Synthetic Name="[sparse]">
<DisplayString>{ sparse.size() * traits_type::page_size }</DisplayString>
<Expand>
@@ -50,7 +49,7 @@
<Break Condition="pos == last"/>
<Exec>page = pos / traits_type::page_size</Exec>
<Exec>offset = pos &amp; (traits_type::page_size - 1)</Exec>
<If Condition="sparse[page] &amp;&amp; (*((traits_type::entity_type *)&amp;sparse[page][offset]) &lt; ~traits_type::entity_mask)">
<If Condition="sparse[page] &amp;&amp; (*((traits_type::entity_type *)&amp;sparse[page][offset]) &lt; cap())">
<Item Name="[{ pos }]">*((traits_type::entity_type *)&amp;sparse[page][offset]) &amp; traits_type::entity_mask</Item>
</If>
<Exec>++pos</Exec>
@@ -67,7 +66,7 @@
<Variable Name="last" InitialValue="packed.size()"/>
<Loop>
<Break Condition="pos == last"/>
<If Condition="*((traits_type::entity_type *)&amp;packed[pos]) &lt; ~traits_type::entity_mask">
<If Condition="*((traits_type::entity_type *)&amp;packed[pos]) &lt; cap()">
<Item Name="[{ pos }]">packed[pos]</Item>
</If>
<Exec>++pos</Exec>
@@ -78,11 +77,11 @@
</Expand>
</Type>
<Type Name="entt::basic_storage&lt;*&gt;">
<Intrinsic Name="cap" Expression="(base_type::traits_type::version_mask &lt;&lt; base_type::traits_type::length)"/>
<DisplayString>{{ size={ base_type::packed.size() }, type={ base_type::info->alias,na } }}</DisplayString>
<Expand>
<Item Name="[capacity]" Optional="true" ExcludeView="simple">payload.capacity() * traits_type::page_size</Item>
<Item Name="[page size]" Optional="true" ExcludeView="simple">traits_type::page_size</Item>
<Item Name="[length]" Optional="true" ExcludeView="simple">length</Item>
<Item Name="[base]" ExcludeView="simple">(base_type*)this,nand</Item>
<Item Name="[base]" IncludeView="simple">(base_type*)this,view(simple)nand</Item>
<!-- having SFINAE-like techniques in natvis is priceless :) -->
@@ -91,7 +90,7 @@
<Variable Name="last" InitialValue="base_type::packed.size()"/>
<Loop>
<Break Condition="pos == last"/>
<If Condition="*((base_type::traits_type::entity_type *)&amp;base_type::packed[pos]) &lt; ~base_type::traits_type::entity_mask">
<If Condition="*((base_type::traits_type::entity_type *)&amp;base_type::packed[pos]) &lt; cap()">
<Item Name="[{ pos }:{ base_type::packed[pos] }]">payload[pos / traits_type::page_size][pos &amp; (traits_type::page_size - 1)]</Item>
</If>
<Exec>++pos</Exec>
@@ -100,10 +99,12 @@
</Expand>
</Type>
<Type Name="entt::basic_view&lt;*&gt;">
<DisplayString>{{ size_hint={ view->packed.size() } }}</DisplayString>
<DisplayString Condition="leading != nullptr">{{ size_hint={ leading->packed.size() } }}</DisplayString>
<DisplayString>{{ size_hint=0 }}</DisplayString>
<Expand>
<Item Name="[pools]">pools,na</Item>
<Item Name="[filter]">filter,na</Item>
<Item Name="[pools]" Optional="true">pools,na</Item>
<Item Name="[filter]" Optional="true">filter,na</Item>
<Item Name="[handle]" Condition="leading != nullptr">leading,na</Item>
</Expand>
</Type>
<Type Name="entt::basic_runtime_view&lt;*&gt;">

File diff suppressed because it is too large Load Diff

11
src/BUILD.bazel Normal file
View File

@@ -0,0 +1,11 @@
load("@bazel_skylib//lib:selects.bzl", "selects")
load("//bazel:copts.bzl", "COPTS")
package(default_visibility = ["//:__subpackages__"])
cc_library(
name = "entt",
includes = ["."],
hdrs = glob(["**/*.h", "**/*.hpp"]),
copts = COPTS,
)

View File

@@ -25,6 +25,8 @@
#ifndef ENTT_ID_TYPE
# include <cstdint>
# define ENTT_ID_TYPE std::uint32_t
#else
# include <cstdint> // provides coverage for types in the std namespace
#endif
#ifndef ENTT_SPARSE_PAGE

View File

@@ -4,8 +4,8 @@
#include "macro.h"
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 12
#define ENTT_VERSION_PATCH 1
#define ENTT_VERSION_MINOR 13
#define ENTT_VERSION_PATCH 2
#define ENTT_VERSION \
ENTT_XSTR(ENTT_VERSION_MAJOR) \

View File

@@ -20,11 +20,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Key, typename Type>
@@ -69,6 +65,7 @@ public:
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
constexpr dense_map_iterator() noexcept
: it{} {}
@@ -190,6 +187,7 @@ public:
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
constexpr dense_map_local_iterator() noexcept
: it{},
@@ -241,11 +239,7 @@ template<typename Lhs, typename Rhs>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Associative container for key-value pairs with unique keys.
@@ -989,7 +983,7 @@ public:
sparse.first().resize(sz);
for(auto &&elem: sparse.first()) {
elem = std::numeric_limits<size_type>::max();
elem = (std::numeric_limits<size_type>::max)();
}
for(size_type pos{}, last = size(); pos < last; ++pos) {
@@ -1033,11 +1027,7 @@ private:
} // namespace entt
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace std {
template<typename Key, typename Value, typename Allocator>
@@ -1045,10 +1035,6 @@ struct uses_allocator<entt::internal::dense_map_node<Key, Value>, Allocator>
: std::true_type {};
} // namespace std
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
#endif

View File

@@ -19,11 +19,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename It>
@@ -206,11 +202,7 @@ template<typename Lhs, typename Rhs>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Associative container for unique objects of a given type.
@@ -311,6 +303,10 @@ public:
using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>;
/*! @brief Constant random access iterator type. */
using const_iterator = internal::dense_set_iterator<typename packed_container_type::const_iterator>;
/*! @brief Reverse iterator type. */
using reverse_iterator = std::reverse_iterator<iterator>;
/*! @brief Constant reverse iterator type. */
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
/*! @brief Forward iterator type. */
using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>;
/*! @brief Constant forward iterator type. */
@@ -447,6 +443,46 @@ public:
return packed.first().end();
}
/**
* @brief Returns a reverse iterator to the beginning.
*
* If the array is empty, the returned iterator will be equal to `rend()`.
*
* @return An iterator to the first instance of the reversed internal array.
*/
[[nodiscard]] const_reverse_iterator crbegin() const noexcept {
return std::make_reverse_iterator(cend());
}
/*! @copydoc crbegin */
[[nodiscard]] const_reverse_iterator rbegin() const noexcept {
return crbegin();
}
/*! @copydoc rbegin */
[[nodiscard]] reverse_iterator rbegin() noexcept {
return std::make_reverse_iterator(end());
}
/**
* @brief Returns a reverse iterator to the end.
* @return An iterator to the element following the last instance of the
* reversed internal array.
*/
[[nodiscard]] const_reverse_iterator crend() const noexcept {
return std::make_reverse_iterator(cbegin());
}
/*! @copydoc crend */
[[nodiscard]] const_reverse_iterator rend() const noexcept {
return crend();
}
/*! @copydoc rend */
[[nodiscard]] reverse_iterator rend() noexcept {
return std::make_reverse_iterator(begin());
}
/**
* @brief Checks whether a container is empty.
* @return True if the container is empty, false otherwise.
@@ -842,7 +878,7 @@ public:
sparse.first().resize(sz);
for(auto &&elem: sparse.first()) {
elem = std::numeric_limits<size_type>::max();
elem = (std::numeric_limits<size_type>::max)();
}
for(size_type pos{}, last = size(); pos < last; ++pos) {

View File

@@ -3,6 +3,7 @@
#include <functional>
#include <memory>
#include <utility>
namespace entt {

View File

@@ -13,11 +13,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
enum class any_operation : std::uint8_t {
@@ -30,19 +26,19 @@ enum class any_operation : std::uint8_t {
get
};
} // namespace internal
/*! @endcond */
/*! @brief Possible modes of an any object. */
enum class any_policy : std::uint8_t {
/*! @brief Default mode, the object owns the contained element. */
owner,
/*! @brief Aliasing mode, the object _points_ to a non-const element. */
ref,
/*! @brief Const aliasing mode, the object _points_ to a const element. */
cref
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief A SBO friendly, type-safe container for single values of any type.
* @tparam Len Size of the storage reserved for the small buffer optimization.
@@ -51,7 +47,6 @@ enum class any_policy : std::uint8_t {
template<std::size_t Len, std::size_t Align>
class basic_any {
using operation = internal::any_operation;
using policy = internal::any_policy;
using vtable_type = const void *(const operation, const basic_any &, const void *);
struct storage_type {
@@ -63,11 +58,11 @@ class basic_any {
template<typename Type>
static const void *basic_vtable(const operation op, const basic_any &value, const void *other) {
static_assert(!std::is_same_v<Type, void> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
static_assert(!std::is_void_v<Type> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
const Type *element = nullptr;
if constexpr(in_situ<Type>) {
element = value.owner() ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance);
element = (value.mode == any_policy::owner) ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance);
} else {
element = static_cast<const Type *>(value.instance);
}
@@ -80,7 +75,7 @@ class basic_any {
break;
case operation::move:
if constexpr(in_situ<Type>) {
if(value.owner()) {
if(value.mode == any_policy::owner) {
return new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(element))};
}
}
@@ -129,7 +124,7 @@ class basic_any {
if constexpr(std::is_lvalue_reference_v<Type>) {
static_assert((std::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "Invalid arguments");
mode = std::is_const_v<std::remove_reference_t<Type>> ? policy::cref : policy::ref;
mode = std::is_const_v<std::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
instance = (std::addressof(args), ...);
} else if constexpr(in_situ<std::remove_cv_t<std::remove_reference_t<Type>>>) {
if constexpr(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>)) {
@@ -147,7 +142,7 @@ class basic_any {
}
}
basic_any(const basic_any &other, const policy pol) noexcept
basic_any(const basic_any &other, const any_policy pol) noexcept
: instance{other.data()},
info{other.info},
vtable{other.vtable},
@@ -174,7 +169,7 @@ public:
: instance{},
info{},
vtable{},
mode{policy::owner} {
mode{any_policy::owner} {
initialize<Type>(std::forward<Args>(args)...);
}
@@ -214,7 +209,7 @@ public:
/*! @brief Frees the internal storage, whatever it means. */
~basic_any() {
if(vtable && owner()) {
if(vtable && (mode == any_policy::owner)) {
vtable(operation::destroy, *this, nullptr);
}
}
@@ -295,7 +290,7 @@ public:
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] void *data() noexcept {
return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data());
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data());
}
/**
@@ -304,7 +299,7 @@ public:
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] void *data(const type_info &req) noexcept {
return mode == policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
}
/**
@@ -325,7 +320,7 @@ public:
* @return True in case of success, false otherwise.
*/
bool assign(const basic_any &other) {
if(vtable && mode != policy::cref && *info == *other.info) {
if(vtable && mode != any_policy::cref && *info == *other.info) {
return (vtable(operation::assign, *this, other.data()) != nullptr);
}
@@ -334,7 +329,7 @@ public:
/*! @copydoc assign */
bool assign(basic_any &&other) {
if(vtable && mode != policy::cref && *info == *other.info) {
if(vtable && mode != any_policy::cref && *info == *other.info) {
if(auto *val = other.data(); val) {
return (vtable(operation::transfer, *this, val) != nullptr);
} else {
@@ -347,7 +342,7 @@ public:
/*! @brief Destroys contained object */
void reset() {
if(vtable && owner()) {
if(vtable && (mode == any_policy::owner)) {
vtable(operation::destroy, *this, nullptr);
}
@@ -355,7 +350,7 @@ public:
ENTT_ASSERT((instance = nullptr) == nullptr, "");
info = &type_id<void>();
vtable = nullptr;
mode = policy::owner;
mode = any_policy::owner;
}
/**
@@ -393,20 +388,28 @@ public:
* @return A wrapper that shares a reference to an unmanaged object.
*/
[[nodiscard]] basic_any as_ref() noexcept {
return basic_any{*this, (mode == policy::cref ? policy::cref : policy::ref)};
return basic_any{*this, (mode == any_policy::cref ? any_policy::cref : any_policy::ref)};
}
/*! @copydoc as_ref */
[[nodiscard]] basic_any as_ref() const noexcept {
return basic_any{*this, policy::cref};
return basic_any{*this, any_policy::cref};
}
/**
* @brief Returns true if a wrapper owns its object, false otherwise.
* @return True if the wrapper owns its object, false otherwise.
*/
[[nodiscard]] bool owner() const noexcept {
return (mode == policy::owner);
[[deprecated("use policy() and any_policy instead")]] [[nodiscard]] bool owner() const noexcept {
return (mode == any_policy::owner);
}
/**
* @brief Returns the current mode of an any object.
* @return The current mode of the any object.
*/
[[nodiscard]] any_policy policy() const noexcept {
return mode;
}
private:
@@ -416,7 +419,7 @@ private:
};
const type_info *info;
vtable_type *vtable;
policy mode;
any_policy mode;
};
/**

View File

@@ -9,11 +9,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type, std::size_t, typename = void>
@@ -73,11 +69,7 @@ struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Ty
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief A compressed pair.

View File

@@ -7,11 +7,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename>
@@ -43,11 +39,7 @@ struct basic_hashed_string {
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Zero overhead unique identifier.
@@ -175,7 +167,7 @@ public:
* @return The size of the hashed string.
*/
[[nodiscard]] constexpr size_type size() const noexcept {
return base_type::length;
return base_type::length; // NOLINT
}
/**

View File

@@ -12,7 +12,8 @@
namespace entt {
/**
* @brief Checks whether a value is a power of two or not.
* @brief Checks whether a value is a power of two or not (waiting for C++20 and
* `std::has_single_bit`).
* @param value A value that may or may not be a power of two.
* @return True if the value is a power of two, false otherwise.
*/
@@ -21,7 +22,8 @@ namespace entt {
}
/**
* @brief Computes the smallest power of two greater than or equal to a value.
* @brief Computes the smallest power of two greater than or equal to a value
* (waiting for C++20 and `std::bit_ceil`).
* @param value The value to use.
* @return The smallest power of two greater than or equal to the given value.
*/
@@ -163,11 +165,7 @@ ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) {
return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
}
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type>
@@ -223,11 +221,7 @@ struct uses_allocator_construction<std::pair<Type, Other>> {
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Uses-allocator construction utility (waiting for C++20).

View File

@@ -7,11 +7,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename>
@@ -21,11 +17,7 @@ template<typename... Args>
struct is_tuple_impl<std::tuple<Args...>>: std::true_type {};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Provides the member constant `value` to true if a given type is a

View File

@@ -11,11 +11,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
struct ENTT_API type_index final {
@@ -38,26 +34,26 @@ template<typename Type>
}
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
[[nodiscard]] static constexpr std::string_view type_name(int) noexcept {
[[nodiscard]] constexpr std::string_view type_name(int) noexcept {
constexpr auto value = stripped_type_name<Type>();
return value;
}
template<typename Type>
[[nodiscard]] static std::string_view type_name(char) noexcept {
[[nodiscard]] std::string_view type_name(char) noexcept {
static const auto value = stripped_type_name<Type>();
return value;
}
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
[[nodiscard]] static constexpr id_type type_hash(int) noexcept {
[[nodiscard]] constexpr id_type type_hash(int) noexcept {
constexpr auto stripped = stripped_type_name<Type>();
constexpr auto value = hashed_string::value(stripped.data(), stripped.size());
return value;
}
template<typename Type>
[[nodiscard]] static id_type type_hash(char) noexcept {
[[nodiscard]] id_type type_hash(char) noexcept {
static const auto value = [](const auto stripped) {
return hashed_string::value(stripped.data(), stripped.size());
}(stripped_type_name<Type>());
@@ -65,11 +61,7 @@ template<typename Type>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Type sequential identifier.

View File

@@ -17,7 +17,7 @@ namespace entt {
*/
template<std::size_t N>
struct choice_t
// Unfortunately, doxygen cannot parse such a construct.
// unfortunately, doxygen cannot parse such a construct
: /*! @cond TURN_OFF_DOXYGEN */ choice_t<N - 1> /*! @endcond */
{};
@@ -250,37 +250,40 @@ struct type_list_cat<type_list<Type...>> {
template<typename... List>
using type_list_cat_t = typename type_list_cat<List...>::type;
/*! @brief Primary template isn't defined on purpose. */
template<typename>
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename...>
struct type_list_unique;
template<typename First, typename... Other, typename... Type>
struct type_list_unique<type_list<First, Other...>, Type...>
: std::conditional_t<(std::is_same_v<First, Type> || ...), type_list_unique<type_list<Other...>, Type...>, type_list_unique<type_list<Other...>, Type..., First>> {};
template<typename... Type>
struct type_list_unique<type_list<>, Type...> {
using type = type_list<Type...>;
};
} // namespace internal
/*! @endcond */
/**
* @brief Removes duplicates types from a type list.
* @tparam Type One of the types provided by the given type list.
* @tparam Other The other types provided by the given type list.
* @tparam List Type list.
*/
template<typename Type, typename... Other>
struct type_list_unique<type_list<Type, Other...>> {
template<typename List>
struct type_list_unique {
/*! @brief A type list without duplicate types. */
using type = std::conditional_t<
(std::is_same_v<Type, Other> || ...),
typename type_list_unique<type_list<Other...>>::type,
type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>>;
};
/*! @brief Removes duplicates types from a type list. */
template<>
struct type_list_unique<type_list<>> {
/*! @brief A type list without duplicate types. */
using type = type_list<>;
using type = typename internal::type_list_unique<List>::type;
};
/**
* @brief Helper type.
* @tparam Type A type list.
* @tparam List Type list.
*/
template<typename Type>
using type_list_unique_t = typename type_list_unique<Type>::type;
template<typename List>
using type_list_unique_t = typename type_list_unique<List>::type;
/**
* @brief Provides the member constant `value` to true if a type list contains a
@@ -675,11 +678,7 @@ inline constexpr bool is_complete_v = is_complete<Type>::value;
template<typename Type, typename = void>
struct is_iterator: std::false_type {};
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename, typename = void>
@@ -689,15 +688,11 @@ template<typename Type>
struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/*! @copydoc is_iterator */
template<typename Type>
struct is_iterator<Type, std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_pointer_t<Type>>, void>>>
struct is_iterator<Type, std::enable_if_t<!std::is_void_v<std::remove_cv_t<std::remove_pointer_t<Type>>>>>
: internal::has_iterator_category<Type> {};
/**
@@ -742,19 +737,7 @@ struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::tr
template<typename Type>
inline constexpr bool is_transparent_v = is_transparent<Type>::value;
/**
* @brief Provides the member constant `value` to true if a given type is
* equality comparable, false otherwise.
* @tparam Type The type to test.
*/
template<typename Type, typename = void>
struct is_equality_comparable: std::false_type {};
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename, typename = void>
@@ -763,51 +746,69 @@ struct has_tuple_size_value: std::false_type {};
template<typename Type>
struct has_tuple_size_value<Type, std::void_t<decltype(std::tuple_size<const Type>::value)>>: std::true_type {};
template<typename, typename = void>
struct has_value_type: std::false_type {};
template<typename Type>
struct has_value_type<Type, std::void_t<typename Type::value_type>>: std::true_type {};
template<typename>
[[nodiscard]] constexpr bool dispatch_is_equality_comparable();
template<typename Type, std::size_t... Index>
[[nodiscard]] constexpr bool unpack_maybe_equality_comparable(std::index_sequence<Index...>) {
return (is_equality_comparable<std::tuple_element_t<Index, Type>>::value && ...);
return (dispatch_is_equality_comparable<std::tuple_element_t<Index, Type>>() && ...);
}
template<typename>
[[nodiscard]] constexpr bool maybe_equality_comparable(choice_t<0>) {
[[nodiscard]] constexpr bool maybe_equality_comparable(char) {
return false;
}
template<typename Type>
[[nodiscard]] constexpr auto maybe_equality_comparable(int) -> decltype(std::declval<Type>() == std::declval<Type>()) {
return true;
}
template<typename Type>
[[nodiscard]] constexpr auto maybe_equality_comparable(choice_t<1>) -> decltype(std::declval<typename Type::value_type>(), bool{}) {
if constexpr(is_iterator_v<Type>) {
return true;
} else if constexpr(std::is_same_v<typename Type::value_type, Type>) {
return maybe_equality_comparable<Type>(choice<0>);
[[nodiscard]] constexpr bool dispatch_is_equality_comparable() {
if constexpr(std::is_array_v<Type>) {
return false;
} else if constexpr(is_iterator_v<Type>) {
return maybe_equality_comparable<Type>(0);
} else if constexpr(has_value_type<Type>::value) {
if constexpr(std::is_same_v<typename Type::value_type, Type>) {
return maybe_equality_comparable<Type>(0);
} else if constexpr(dispatch_is_equality_comparable<typename Type::value_type>()) {
return maybe_equality_comparable<Type>(0);
} else {
return false;
}
} else if constexpr(is_complete_v<std::tuple_size<std::remove_cv_t<Type>>>) {
if constexpr(has_tuple_size_value<Type>::value) {
return maybe_equality_comparable<Type>(0) && unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
} else {
return maybe_equality_comparable<Type>(0);
}
} else {
return is_equality_comparable<typename Type::value_type>::value;
}
}
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<is_complete_v<std::tuple_size<std::remove_cv_t<Type>>>, bool> maybe_equality_comparable(choice_t<2>) {
if constexpr(has_tuple_size_value<Type>::value) {
return unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
} else {
return maybe_equality_comparable<Type>(choice<1>);
return maybe_equality_comparable<Type>(0);
}
}
} // namespace internal
/*! @endcond */
/**
* Internal details not to be documented.
* @endcond
* @brief Provides the member constant `value` to true if a given type is
* equality comparable, false otherwise.
* @tparam Type The type to test.
*/
template<typename Type>
struct is_equality_comparable: std::bool_constant<internal::dispatch_is_equality_comparable<Type>()> {};
/*! @copydoc is_equality_comparable */
template<typename Type>
struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>>
: std::bool_constant<internal::maybe_equality_comparable<Type>(choice<2>)> {};
/*! @copydoc is_equality_comparable */
template<typename Type, auto N>
struct is_equality_comparable<Type[N]>: std::false_type {};
struct is_equality_comparable<const Type>: is_equality_comparable<Type> {};
/**
* @brief Helper variable template.
@@ -874,9 +875,9 @@ using member_class_t = typename member_class<Member>::type;
/**
* @brief Extracts the n-th argument of a given function or member function.
* @tparam Index The index of the argument to extract.
* @tparam Candidate A valid function, member function or data member.
* @tparam Candidate A valid function, member function or data member type.
*/
template<std::size_t Index, auto Candidate>
template<std::size_t Index, typename Candidate>
class nth_argument {
template<typename Ret, typename... Args>
static constexpr type_list<Args...> pick_up(Ret (*)(Args...));
@@ -892,15 +893,15 @@ class nth_argument {
public:
/*! @brief N-th argument of the given function or member function. */
using type = type_list_element_t<Index, decltype(pick_up(Candidate))>;
using type = type_list_element_t<Index, decltype(pick_up(std::declval<Candidate>()))>;
};
/**
* @brief Helper type.
* @tparam Index The index of the argument to extract.
* @tparam Candidate A valid function, member function or data member.
* @tparam Candidate A valid function, member function or data member type.
*/
template<std::size_t Index, auto Candidate>
template<std::size_t Index, typename Candidate>
using nth_argument_t = typename nth_argument<Index, Candidate>::type;
} // namespace entt

View File

@@ -8,11 +8,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type, typename = void>
@@ -32,15 +28,11 @@ template<>
struct page_size<void>: std::integral_constant<std::size_t, 0u> {};
template<typename Type>
struct page_size<Type, std::enable_if_t<std::is_convertible_v<decltype(Type::page_size), std::size_t>>>
struct page_size<Type, std::void_t<decltype(Type::page_size)>>
: std::integral_constant<std::size_t, Type::page_size> {};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Common way to access various properties of components.

View File

@@ -9,16 +9,12 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
// waiting for C++20 (and std::popcount)
// waiting for C++20 and std::popcount
template<typename Type>
static constexpr int popcount(Type value) noexcept {
constexpr int popcount(Type value) noexcept {
return value ? (int(value & 1) + popcount(value >> 1)) : 0;
}
@@ -60,11 +56,7 @@ struct entt_traits<std::uint64_t> {
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Common basic entity traits implementation.
@@ -114,7 +106,7 @@ public:
* @return The integral representation of the version part.
*/
[[nodiscard]] static constexpr version_type to_version(const value_type value) noexcept {
return static_cast<version_type>(to_integral(value) >> length);
return (static_cast<version_type>(to_integral(value) >> length) & version_mask);
}
/**
@@ -124,7 +116,7 @@ public:
*/
[[nodiscard]] static constexpr value_type next(const value_type value) noexcept {
const auto vers = to_version(value) + 1;
return construct(to_entity(value), static_cast<version_type>(vers + (vers == version_mask)));
return construct(to_integral(value), static_cast<version_type>(vers + (vers == version_mask)));
}
/**
@@ -138,7 +130,7 @@ public:
* @return A properly constructed identifier.
*/
[[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) noexcept {
return value_type{(entity & entity_mask) | (static_cast<entity_type>(version) << length)};
return value_type{(entity & entity_mask) | (static_cast<entity_type>(version & version_mask) << length)};
}
/**
@@ -152,8 +144,7 @@ public:
* @return A properly constructed identifier.
*/
[[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept {
constexpr auto mask = (version_mask << length);
return value_type{(lhs & entity_mask) | (rhs & mask)};
return value_type{(lhs & entity_mask) | (rhs & (version_mask << length))};
}
};
@@ -170,8 +161,10 @@ struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> {
};
/**
* @copydoc entt_traits<Entity>::to_integral
* @brief Converts an entity to its underlying type.
* @tparam Entity The value type.
* @param value The value to convert.
* @return The integral representation of the given value.
*/
template<typename Entity>
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept {
@@ -179,8 +172,10 @@ template<typename Entity>
}
/**
* @copydoc entt_traits<Entity>::to_entity
* @brief Returns the entity part once converted to the underlying type.
* @tparam Entity The value type.
* @param value The value to convert.
* @return The integral representation of the entity part.
*/
template<typename Entity>
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept {
@@ -188,8 +183,10 @@ template<typename Entity>
}
/**
* @copydoc entt_traits<Entity>::to_version
* @brief Returns the version part once converted to the underlying type.
* @tparam Entity The value type.
* @param value The value to convert.
* @return The integral representation of the version part.
*/
template<typename Entity>
[[nodiscard]] constexpr typename entt_traits<Entity>::version_type to_version(const Entity value) noexcept {

View File

@@ -17,7 +17,9 @@ enum class deletion_policy : std::uint8_t {
/*! @brief Swap-and-pop deletion policy. */
swap_and_pop = 0u,
/*! @brief In-place deletion policy. */
in_place = 1u
in_place = 1u,
/*! @brief Swap-only deletion policy. */
swap_only = 2u
};
template<typename Entity = entity, typename = std::allocator<Entity>>
@@ -26,46 +28,8 @@ class basic_sparse_set;
template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
class basic_storage;
template<typename Type>
class sigh_mixin;
/**
* @brief Provides a common way to define storage types.
* @tparam Type Storage value type.
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
struct storage_type {
/*! @brief Type-to-storage conversion result. */
using type = sigh_mixin<basic_storage<Type, Entity, Allocator>>;
};
/**
* @brief Helper type.
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using storage_type_t = typename storage_type<Args...>::type;
/**
* Type-to-storage conversion utility that preserves constness.
* @tparam Type Storage value type, eventually const.
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
struct storage_for {
/*! @brief Type-to-storage conversion result. */
using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
};
/**
* @brief Helper type.
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using storage_for_t = typename storage_for<Args...>::type;
template<typename, typename>
class basic_sigh_mixin;
template<typename Entity = entity, typename = std::allocator<Entity>>
class basic_registry;
@@ -97,6 +61,67 @@ class basic_snapshot_loader;
template<typename>
class basic_continuous_loader;
/*! @brief Alias declaration for the most common use case. */
using sparse_set = basic_sparse_set<>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Type Type of objects assigned to the entities.
*/
template<typename Type>
using storage = basic_storage<Type>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Type Underlying storage type.
*/
template<typename Type>
using sigh_mixin = basic_sigh_mixin<Type, basic_registry<typename Type::entity_type, typename Type::base_type::allocator_type>>;
/*! @brief Alias declaration for the most common use case. */
using registry = basic_registry<>;
/*! @brief Alias declaration for the most common use case. */
using observer = basic_observer<registry>;
/*! @brief Alias declaration for the most common use case. */
using organizer = basic_organizer<registry>;
/*! @brief Alias declaration for the most common use case. */
using handle = basic_handle<registry>;
/*! @brief Alias declaration for the most common use case. */
using const_handle = basic_handle<const registry>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using handle_view = basic_handle<registry, Args...>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using const_handle_view = basic_handle<const registry, Args...>;
/*! @brief Alias declaration for the most common use case. */
using snapshot = basic_snapshot<registry>;
/*! @brief Alias declaration for the most common use case. */
using snapshot_loader = basic_snapshot_loader<registry>;
/*! @brief Alias declaration for the most common use case. */
using continuous_loader = basic_continuous_loader<registry>;
/*! @brief Alias declaration for the most common use case. */
using runtime_view = basic_runtime_view<sparse_set>;
/*! @brief Alias declaration for the most common use case. */
using const_runtime_view = basic_runtime_view<const sparse_set>;
/**
* @brief Alias for exclusion lists.
* @tparam Type List of types.
@@ -181,53 +206,43 @@ struct type_list_transform<owned_t<Type...>, Op> {
using type = owned_t<typename Op<Type>::type...>;
};
/*! @brief Alias declaration for the most common use case. */
using sparse_set = basic_sparse_set<>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Type Type of objects assigned to the entities.
* @brief Provides a common way to define storage types.
* @tparam Type Storage value type.
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type>
using storage = basic_storage<Type>;
/*! @brief Alias declaration for the most common use case. */
using registry = basic_registry<>;
/*! @brief Alias declaration for the most common use case. */
using observer = basic_observer<registry>;
/*! @brief Alias declaration for the most common use case. */
using organizer = basic_organizer<registry>;
/*! @brief Alias declaration for the most common use case. */
using handle = basic_handle<registry>;
/*! @brief Alias declaration for the most common use case. */
using const_handle = basic_handle<const registry>;
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<Type>, typename = void>
struct storage_type {
/*! @brief Type-to-storage conversion result. */
using type = sigh_mixin<basic_storage<Type, Entity, Allocator>>;
};
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
* @brief Helper type.
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using handle_view = basic_handle<registry, Args...>;
using storage_type_t = typename storage_type<Args...>::type;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
* Type-to-storage conversion utility that preserves constness.
* @tparam Type Storage value type, eventually const.
* @tparam Entity A valid entity type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Entity = entity, typename Allocator = std::allocator<std::remove_const_t<Type>>>
struct storage_for {
/*! @brief Type-to-storage conversion result. */
using type = constness_as_t<storage_type_t<std::remove_const_t<Type>, Entity, Allocator>, Type>;
};
/**
* @brief Helper type.
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using const_handle_view = basic_handle<const registry, Args...>;
/*! @brief Alias declaration for the most common use case. */
using snapshot = basic_snapshot<registry>;
/*! @brief Alias declaration for the most common use case. */
using snapshot_loader = basic_snapshot_loader<registry>;
/*! @brief Alias declaration for the most common use case. */
using continuous_loader = basic_continuous_loader<registry>;
using storage_for_t = typename storage_for<Args...>::type;
/**
* @brief Alias declaration for the most common use case.
@@ -237,12 +252,6 @@ using continuous_loader = basic_continuous_loader<registry>;
template<typename Get, typename Exclude = exclude_t<>>
using view = basic_view<type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
/*! @brief Alias declaration for the most common use case. */
using runtime_view = basic_runtime_view<sparse_set>;
/*! @brief Alias declaration for the most common use case. */
using const_runtime_view = basic_runtime_view<const sparse_set>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Owned Types of storage _owned_ by the group.

View File

@@ -16,11 +16,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename, typename, typename>
@@ -44,12 +40,13 @@ public:
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
constexpr extended_group_iterator()
: it{},
pools{} {}
extended_group_iterator(It from, const std::tuple<Owned *..., Get *...> &cpools)
extended_group_iterator(iterator_type from, const std::tuple<Owned *..., Get *...> &cpools)
: it{from},
pools{cpools} {}
@@ -112,27 +109,28 @@ class group_handler<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> fin
using base_type = std::common_type_t<typename Owned::base_type..., typename Get::base_type..., typename Exclude::base_type...>;
using entity_type = typename base_type::entity_type;
void swap_elements(const std::size_t pos, const entity_type entt) {
std::apply([pos, entt](auto *...cpool) { (cpool->swap_elements(cpool->data()[pos], entt), ...); }, pools);
template<std::size_t... Index>
void swap_elements(const std::size_t pos, const entity_type entt, std::index_sequence<Index...>) {
(std::get<Index>(pools)->swap_elements(std::get<Index>(pools)->data()[pos], entt), ...);
}
void push_on_construct(const entity_type entt) {
if(std::apply([entt, len = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < len) && (other->contains(entt) && ...); }, pools)
&& std::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) {
swap_elements(len++, entt);
swap_elements(len++, entt, std::index_sequence_for<Owned...>{});
}
}
void push_on_destroy(const entity_type entt) {
if(std::apply([entt, len = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < len) && (other->contains(entt) && ...); }, pools)
&& std::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) {
swap_elements(len++, entt);
swap_elements(len++, entt, std::index_sequence_for<Owned...>{});
}
}
void remove_if(const entity_type entt) {
if(std::get<0>(pools)->contains(entt) && (std::get<0>(pools)->index(entt) < len)) {
swap_elements(--len, entt);
swap_elements(--len, entt, std::index_sequence_for<Owned...>{});
}
}
@@ -166,13 +164,11 @@ public:
return len;
}
template<typename Type>
Type pools_as() const noexcept {
auto pools_as_tuple() const noexcept {
return pools;
}
template<typename Type>
Type filter_as() const noexcept {
auto filter_as_tuple() const noexcept {
return filter;
}
@@ -234,13 +230,11 @@ public:
return elem;
}
template<typename Type>
Type pools_as() const noexcept {
auto pools_as_tuple() const noexcept {
return pools;
}
template<typename Type>
Type filter_as() const noexcept {
auto filter_as_tuple() const noexcept {
return filter;
}
@@ -251,11 +245,7 @@ private:
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Group.
@@ -298,12 +288,12 @@ class basic_group<owned_t<>, get_t<Get...>, exclude_t<Exclude...>> {
auto pools() const noexcept {
using return_type = std::tuple<Get *...>;
return descriptor ? descriptor->template pools_as<return_type>() : return_type{};
return descriptor ? descriptor->pools_as_tuple() : return_type{};
}
auto filter() const noexcept {
using return_type = std::tuple<Exclude *...>;
return descriptor ? descriptor->template filter_as<return_type>() : return_type{};
return descriptor ? descriptor->filter_as_tuple() : return_type{};
}
public:
@@ -498,11 +488,6 @@ public:
/**
* @brief Returns the components assigned to the given entity.
*
* @warning
* Attempting to use an entity that doesn't belong to the group results in
* undefined behavior.
*
* @tparam Type Type of the component to get.
* @tparam Other Other types of components to get.
* @param entt A valid identifier.
@@ -515,11 +500,6 @@ public:
/**
* @brief Returns the components assigned to the given entity.
*
* @warning
* Attempting to use an entity that doesn't belong to the groups results in
* undefined behavior.
*
* @tparam Index Indexes of the components to get.
* @param entt A valid identifier.
* @return The components assigned to the entity.
@@ -660,17 +640,28 @@ public:
}
/**
* @brief Sort the shared pool of entities according to a given storage.
* @brief Sort entities according to their order in a range.
*
* The shared pool of entities and thus its order is affected by the changes
* to each and every pool that it tracks.
*
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
template<typename It>
void sort_as(It first, It last) const {
if(*this) {
descriptor->handle().sort_as(first, last);
}
}
/**
* @brief Sort entities according to their order in a range.
* @param other The storage to use to impose the order.
*/
void sort_as(const common_type &other) const {
if(*this) {
descriptor->handle().sort_as(other);
}
[[deprecated("use iterator based sort_as instead")]] void sort_as(const common_type &other) const {
sort_as(other.begin(), other.end());
}
private:
@@ -718,12 +709,12 @@ class basic_group<owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>> {
auto pools() const noexcept {
using return_type = std::tuple<Owned *..., Get *...>;
return descriptor ? descriptor->template pools_as<return_type>() : return_type{};
return descriptor ? descriptor->pools_as_tuple() : return_type{};
}
auto filter() const noexcept {
using return_type = std::tuple<Exclude *...>;
return descriptor ? descriptor->template filter_as<return_type>() : return_type{};
return descriptor ? descriptor->filter_as_tuple() : return_type{};
}
public:
@@ -903,11 +894,6 @@ public:
/**
* @brief Returns the components assigned to the given entity.
*
* @warning
* Attempting to use an entity that doesn't belong to the group results in
* undefined behavior.
*
* @tparam Type Type of the component to get.
* @tparam Other Other types of components to get.
* @param entt A valid identifier.
@@ -920,11 +906,6 @@ public:
/**
* @brief Returns the components assigned to the given entity.
*
* @warning
* Attempting to use an entity that doesn't belong to the groups results in
* undefined behavior.
*
* @tparam Index Indexes of the components to get.
* @param entt A valid identifier.
* @return The components assigned to the entity.

View File

@@ -12,11 +12,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename It>
@@ -33,6 +29,7 @@ public:
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
constexpr handle_storage_iterator() noexcept
: entt{null},
@@ -86,11 +83,7 @@ template<typename ILhs, typename IRhs>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Non-owning handle to an entity.

View File

@@ -9,6 +9,7 @@
#include "../signal/delegate.hpp"
#include "fwd.hpp"
#include "group.hpp"
#include "storage.hpp"
#include "view.hpp"
namespace entt {
@@ -103,7 +104,7 @@ private:
* @param reg A registry that contains the given entity and its components.
* @param entt Entity from which to get the component.
*/
template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, Member>>>
template<auto Member, typename Registry = std::decay_t<nth_argument_t<0u, decltype(Member)>>>
void invoke(Registry &reg, const typename Registry::entity_type entt) {
static_assert(std::is_member_function_pointer_v<decltype(Member)>, "Invalid pointer to non-static member function");
delegate<void(Registry &, const typename Registry::entity_type)> func;
@@ -115,27 +116,41 @@ void invoke(Registry &reg, const typename Registry::entity_type entt) {
* @brief Returns the entity associated with a given component.
*
* @warning
* Currently, this function only works correctly with the default pool as it
* Currently, this function only works correctly with the default storage as it
* makes assumptions about how the components are laid out.
*
* @tparam Registry Basic registry type.
* @tparam Args Storage type template parameters.
* @param storage A storage that contains the given component.
* @param instance A valid component instance.
* @return The entity associated with the given component.
*/
template<typename... Args>
auto to_entity(const basic_storage<Args...> &storage, const typename basic_storage<Args...>::value_type &instance) -> typename basic_storage<Args...>::entity_type {
constexpr auto page_size = basic_storage<Args...>::traits_type::page_size;
const typename basic_storage<Args...>::base_type &base = storage;
const auto *addr = std::addressof(instance);
for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) {
if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(page_size)) {
return *(it + dist);
}
}
return null;
}
/**
* @copybrief to_entity
* @tparam Args Registry type template parameters.
* @tparam Component Type of component.
* @param reg A registry that contains the given entity and its components.
* @param instance A valid component instance.
* @return The entity associated with the given component.
*/
template<typename Registry, typename Component>
typename Registry::entity_type to_entity(const Registry &reg, const Component &instance) {
template<typename... Args, typename Component>
[[deprecated("use storage based to_entity instead")]] typename basic_registry<Args...>::entity_type to_entity(const basic_registry<Args...> &reg, const Component &instance) {
if(const auto *storage = reg.template storage<Component>(); storage) {
constexpr auto page_size = std::remove_const_t<std::remove_pointer_t<decltype(storage)>>::traits_type::page_size;
const typename Registry::common_type &base = *storage;
const auto *addr = std::addressof(instance);
for(auto it = base.rbegin(), last = base.rend(); it < last; it += page_size) {
if(const auto dist = (addr - std::addressof(storage->get(*it))); dist >= 0 && dist < static_cast<decltype(dist)>(page_size)) {
return *(it + dist);
}
}
return to_entity(*storage, instance);
}
return null;

View File

@@ -22,18 +22,23 @@ namespace entt {
*
* This applies to all signals made available.
*
* @tparam Type The type of the underlying storage.
* @tparam Type Underlying storage type.
* @tparam Registry Basic registry type.
*/
template<typename Type>
class sigh_mixin final: public Type {
template<typename Type, typename Registry>
class basic_sigh_mixin final: public Type {
using underlying_type = Type;
using owner_type = Registry;
using basic_registry_type = basic_registry<typename underlying_type::entity_type, typename underlying_type::base_type::allocator_type>;
using sigh_type = sigh<void(basic_registry_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
using sigh_type = sigh<void(owner_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
using underlying_iterator = typename underlying_type::base_type::basic_iterator;
basic_registry_type &owner_or_assert() const noexcept {
static_assert(std::is_base_of_v<basic_registry_type, owner_type>, "Invalid registry type");
owner_type &owner_or_assert() const noexcept {
ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry");
return *owner;
return static_cast<owner_type &>(*owner);
}
void pop(underlying_iterator first, underlying_iterator last) final {
@@ -51,13 +56,17 @@ class sigh_mixin final: public Type {
void pop_all() final {
if(auto &reg = owner_or_assert(); !destruction.empty()) {
for(auto pos = underlying_type::each().begin().base().index(); !(pos < 0); --pos) {
if constexpr(underlying_type::traits_type::in_place_delete) {
if(const auto entt = underlying_type::operator[](static_cast<typename underlying_type::size_type>(pos)); entt != tombstone) {
destruction.publish(reg, entt);
}
for(auto it = underlying_type::base_type::begin(0), last = underlying_type::base_type::end(0); it != last; ++it) {
if constexpr(std::is_same_v<typename underlying_type::value_type, typename underlying_type::entity_type>) {
destruction.publish(reg, *it);
} else {
destruction.publish(reg, underlying_type::operator[](static_cast<typename underlying_type::size_type>(pos)));
if constexpr(underlying_type::traits_type::in_place_delete) {
if(const auto entt = *it; entt != tombstone) {
destruction.publish(reg, entt);
}
} else {
destruction.publish(reg, *it);
}
}
}
}
@@ -81,17 +90,17 @@ public:
/*! @brief Underlying entity identifier. */
using entity_type = typename underlying_type::entity_type;
/*! @brief Expected registry type. */
using registry_type = basic_registry_type;
using registry_type = owner_type;
/*! @brief Default constructor. */
sigh_mixin()
: sigh_mixin{allocator_type{}} {}
basic_sigh_mixin()
: basic_sigh_mixin{allocator_type{}} {}
/**
* @brief Constructs an empty storage with a given allocator.
* @param allocator The allocator to use.
*/
explicit sigh_mixin(const allocator_type &allocator)
explicit basic_sigh_mixin(const allocator_type &allocator)
: underlying_type{allocator},
owner{},
construction{allocator},
@@ -102,7 +111,7 @@ public:
* @brief Move constructor.
* @param other The instance to move from.
*/
sigh_mixin(sigh_mixin &&other) noexcept
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
: underlying_type{std::move(other)},
owner{other.owner},
construction{std::move(other.construction)},
@@ -114,7 +123,7 @@ public:
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
sigh_mixin(sigh_mixin &&other, const allocator_type &allocator) noexcept
basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator) noexcept
: underlying_type{std::move(other), allocator},
owner{other.owner},
construction{std::move(other.construction), allocator},
@@ -126,7 +135,7 @@ public:
* @param other The instance to move from.
* @return This storage.
*/
sigh_mixin &operator=(sigh_mixin &&other) noexcept {
basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept {
underlying_type::operator=(std::move(other));
owner = other.owner;
construction = std::move(other.construction);
@@ -139,7 +148,7 @@ public:
* @brief Exchanges the contents with those of a given storage.
* @param other Storage to exchange the content with.
*/
void swap(sigh_mixin &other) {
void swap(basic_sigh_mixin &other) {
using std::swap;
underlying_type::swap(other);
swap(owner, other.owner);
@@ -262,11 +271,12 @@ public:
*/
template<typename It, typename... Args>
void insert(It first, It last, Args &&...args) {
auto from = underlying_type::size();
underlying_type::insert(first, last, std::forward<Args>(args)...);
if(auto &reg = owner_or_assert(); !construction.empty()) {
for(; first != last; ++first) {
construction.publish(reg, *first);
for(const auto to = underlying_type::size(); from != to; ++from) {
construction.publish(reg, underlying_type::operator[](from));
}
}
}

View File

@@ -15,11 +15,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename>
@@ -87,11 +83,7 @@ template<typename... Req, typename Ret, typename Class, typename... Args>
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const);
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Utility class for creating a static task graph.

View File

@@ -30,11 +30,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename It>
@@ -50,6 +46,7 @@ public:
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
constexpr registry_storage_iterator() noexcept
: it{} {}
@@ -225,11 +222,7 @@ private:
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Fast and reliable entity-component system.
@@ -249,17 +242,18 @@ class basic_registry {
template<typename Type>
[[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
if constexpr(std::is_same_v<Type, entity_type>) {
return entities;
} else {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
auto &cpool = pools[id];
if(!cpool) {
using storage_type = storage_for_type<Type>;
using alloc_type = typename storage_type::allocator_type;
if constexpr(std::is_same_v<Type, void> && !std::is_constructible_v<alloc_type, allocator_type>) {
if constexpr(std::is_void_v<Type> && !std::is_constructible_v<alloc_type, allocator_type>) {
// std::allocator<void> has no cross constructors (waiting for C++20)
cpool = std::allocate_shared<storage_type>(get_allocator(), alloc_type{});
} else {
@@ -276,11 +270,11 @@ class basic_registry {
template<typename Type>
[[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash<Type>::value()) const {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
if constexpr(std::is_same_v<Type, entity_type>) {
return &entities;
} else {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Non-decayed types not allowed");
if(const auto it = pools.find(id); it != pools.cend()) {
ENTT_ASSERT(it->second->type() == type_id<Type>(), "Unexpected type");
return static_cast<const storage_for_type<Type> *>(it->second.get());
@@ -313,6 +307,10 @@ public:
using common_type = base_type;
/*! @brief Context type. */
using context = internal::registry_context<allocator_type>;
/*! @brief Iterable registry type. */
using iterable = iterable_adaptor<internal::registry_storage_iterator<typename pool_container_type::iterator>>;
/*! @brief Constant iterable registry type. */
using const_iterable = iterable_adaptor<internal::registry_storage_iterator<typename pool_container_type::const_iterator>>;
/**
* @copybrief storage_for
@@ -395,7 +393,7 @@ public:
* @return The associated allocator.
*/
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
return pools.get_allocator();
return entities.get_allocator();
}
/**
@@ -406,12 +404,12 @@ public:
*
* @return An iterable object to use to _visit_ the registry.
*/
[[nodiscard]] auto storage() noexcept {
[[nodiscard]] iterable storage() noexcept {
return iterable_adaptor{internal::registry_storage_iterator{pools.begin()}, internal::registry_storage_iterator{pools.end()}};
}
/*! @copydoc storage */
[[nodiscard]] auto storage() const noexcept {
[[nodiscard]] const_iterable storage() const noexcept {
return iterable_adaptor{internal::registry_storage_iterator{pools.cbegin()}, internal::registry_storage_iterator{pools.cend()}};
}
@@ -456,78 +454,13 @@ public:
return assure<Type>(id);
}
/**
* @brief Returns the number of entities created so far.
* @return Number of entities created so far.
*/
[[deprecated("use .storage<Entity>().size() instead")]] [[nodiscard]] size_type size() const noexcept {
return entities.size();
}
/**
* @brief Returns the number of entities still in use.
* @return Number of entities still in use.
*/
[[deprecated("use .storage<Entity>().in_use() instead")]] [[nodiscard]] size_type alive() const {
return entities.in_use();
}
/**
* @brief Increases the capacity (number of entities) of the registry.
* @param cap Desired capacity.
*/
[[deprecated("use .storage<Entity>().reserve(cap) instead")]] void reserve(const size_type cap) {
entities.reserve(cap);
}
/**
* @brief Returns the number of entities that a registry has currently
* allocated space for.
* @return Capacity of the registry.
*/
[[deprecated("use .storage<Entity>().capacity() instead")]] [[nodiscard]] size_type capacity() const noexcept {
return entities.capacity();
}
/**
* @brief Checks whether the registry is empty (no entities still in use).
* @return True if the registry is empty, false otherwise.
*/
[[deprecated("use .storage<Entity>().in_use() instead")]] [[nodiscard]] bool empty() const {
return !alive();
}
/**
* @brief Direct access to the list of entities of a registry.
*
* The returned pointer is such that range `[data(), data() + size())` is
* always a valid range, even if the registry is empty.
*
* @warning
* This list contains both valid and destroyed entities and isn't suitable
* for direct use.
*
* @return A pointer to the array of entities.
*/
[[deprecated("use .storage<Entity>().data() instead")]] [[nodiscard]] const entity_type *data() const noexcept {
return entities.data();
}
/**
* @brief Returns the number of released entities.
* @return The number of released entities.
*/
[[deprecated("use .storage<Entity>().size() and .storage<Entity>().in_use() instead")]] [[nodiscard]] size_type released() const noexcept {
return (entities.size() - entities.in_use());
}
/**
* @brief Checks if an identifier refers to a valid entity.
* @param entt An identifier, either valid or not.
* @return True if the identifier is valid, false otherwise.
*/
[[nodiscard]] bool valid(const entity_type entt) const {
return entities.contains(entt);
return entities.contains(entt) && (entities.index(entt) < entities.free_list());
}
/**
@@ -575,74 +508,6 @@ public:
entities.insert(std::move(first), std::move(last));
}
/**
* @brief Assigns identifiers to an empty registry.
*
* This function is intended for use in conjunction with `data`, `size` and
* `released`.<br/>
* Don't try to inject ranges of randomly generated entities nor the _wrong_
* head for the list of destroyed entities. There is no guarantee that a
* registry will continue to work properly in this case.
*
* @warning
* There must be no entities still alive for this to work properly.
*
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
* @param destroyed The number of released entities.
*/
template<typename It>
[[deprecated("use .storage<Entity>().push(first, last) and .storage<Entity>().in_use(len) instead")]] void assign(It first, It last, const size_type destroyed) {
ENTT_ASSERT(!entities.in_use(), "Non-empty registry");
entities.push(first, last);
entities.in_use(entities.size() - destroyed);
}
/**
* @brief Releases an identifier.
*
* The version is updated and the identifier can be recycled at any time.
*
* @param entt A valid identifier.
* @return The version of the recycled entity.
*/
[[deprecated("use .orphan(entt) and .storage<Entity>().erase(entt) instead")]] version_type release(const entity_type entt) {
ENTT_ASSERT(orphan(entt), "Non-orphan entity");
entities.erase(entt);
return entities.current(entt);
}
/**
* @brief Releases an identifier.
*
* The suggested version or the valid version closest to the suggested one
* is used instead of the implicitly generated version.
*
* @param entt A valid identifier.
* @param version A desired version upon destruction.
* @return The version actually assigned to the entity.
*/
[[deprecated("use .orphan(entt), then .storage<Entity>().erase(entt)/.bump(next) instead")]] version_type release(const entity_type entt, const version_type version) {
ENTT_ASSERT(orphan(entt), "Non-orphan entity");
entities.erase(entt);
const auto elem = traits_type::construct(traits_type::to_entity(entt), version);
return entities.bump((elem == tombstone) ? traits_type::next(elem) : elem);
}
/**
* @brief Releases all identifiers in a range.
*
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
template<typename It>
[[deprecated("use .orphan(entt) and .storage<Entity>().erase(first, last) instead")]] void release(It first, It last) {
ENTT_ASSERT(std::all_of(first, last, [this](const auto entt) { return orphan(entt); }), "Non-orphan entity");
entities.erase(std::move(first), std::move(last));
}
/**
* @brief Destroys an entity and releases its identifier.
*
@@ -691,11 +556,13 @@ public:
*/
template<typename It>
void destroy(It first, It last) {
const auto from = entities.each().cbegin().base();
const auto to = from + entities.pack(first, last);
entities.sort_as(first, last);
for(size_type pos = pools.size(); pos; --pos) {
pools.begin()[pos - 1u].second->remove(from, to);
const auto from = entities.cbegin(0);
const auto to = from + std::distance(first, last);
for(auto &&curr: pools) {
curr.second->remove(from, to);
}
entities.erase(from, to);
@@ -963,7 +830,7 @@ public:
* @return True if the entity is part of all the storage, false otherwise.
*/
template<typename... Type>
[[nodiscard]] bool all_of(const entity_type entt) const {
[[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const {
if constexpr(sizeof...(Type) == 1u) {
auto *cpool = assure<std::remove_const_t<Type>...>();
return cpool && cpool->contains(entt);
@@ -980,7 +847,7 @@ public:
* otherwise.
*/
template<typename... Type>
[[nodiscard]] bool any_of(const entity_type entt) const {
[[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const {
return (all_of<Type>(entt) || ...);
}
@@ -1062,8 +929,7 @@ public:
template<typename... Type>
[[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) {
if constexpr(sizeof...(Type) == 1u) {
auto &cpool = assure<std::remove_const_t<Type>...>();
return (static_cast<Type *>(cpool.contains(entt) ? std::addressof(cpool.get(entt)) : nullptr), ...);
return (const_cast<Type *>(std::as_const(*this).template try_get<Type>(entt)), ...);
} else {
return std::make_tuple(try_get<Type>(entt)...);
}
@@ -1080,34 +946,13 @@ public:
pools.begin()[pos - 1u].second->clear();
}
const auto iterable = entities.each();
entities.erase(iterable.begin().base(), iterable.end().base());
const auto elem = entities.each();
entities.erase(elem.begin().base(), elem.end().base());
} else {
(assure<Type>().clear(), ...);
}
}
/**
* @brief Iterates all the entities that are still in use.
*
* The signature of the function should be equivalent to the following:
*
* @code{.cpp}
* void(const Entity);
* @endcode
*
* It's not defined whether entities created during iteration are returned.
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
[[deprecated("use .storage<Entity>().each() instead")]] void each(Func func) const {
for(auto [entt]: entities.each()) {
func(entt);
}
}
/**
* @brief Checks if an entity has components assigned.
* @param entt A valid identifier.
@@ -1330,7 +1175,8 @@ public:
template<typename To, typename From>
void sort() {
ENTT_ASSERT(!owned<To>(), "Cannot sort owned storage");
assure<To>().sort_as(assure<From>());
const base_type &cpool = assure<From>();
assure<To>().sort_as(cpool.begin(), cpool.end());
}
/**

View File

@@ -11,11 +11,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Set>
@@ -95,11 +91,7 @@ private:
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Generic runtime view.

View File

@@ -16,30 +16,22 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Registry>
void orphans(Registry &registry) {
auto view = registry.template view<typename Registry::entity_type>();
auto &storage = registry.template storage<typename Registry::entity_type>();
for(auto entt: view) {
for(auto entt: storage) {
if(registry.orphan(entt)) {
view.storage()->erase(entt);
storage.erase(entt);
}
}
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Utility class to create snapshots from a registry.
@@ -89,11 +81,22 @@ public:
archive(static_cast<typename traits_type::entity_type>(storage->size()));
if constexpr(std::is_same_v<Type, entity_type>) {
archive(static_cast<typename traits_type::entity_type>(storage->in_use()));
archive(static_cast<typename traits_type::entity_type>(storage->free_list()));
for(auto first = storage->data(), last = first + storage->size(); first != last; ++first) {
archive(*first);
}
} else if constexpr(component_traits<Type>::in_place_delete) {
const typename registry_type::common_type &base = *storage;
for(auto it = base.rbegin(), last = base.rend(); it != last; ++it) {
if(const auto entt = *it; entt == tombstone) {
archive(static_cast<entity_type>(null));
} else {
archive(entt);
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
}
}
} else {
for(auto elem: storage->reach()) {
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, elem);
@@ -140,45 +143,6 @@ public:
return *this;
}
/**
* @brief Serializes all identifiers, including those to be recycled.
* @tparam Archive Type of output archive.
* @param archive A valid reference to an output archive.
* @return An object of this type to continue creating the snapshot.
*/
template<typename Archive>
[[deprecated("use .get<Entity>(archive) instead")]] const basic_snapshot &entities(Archive &archive) const {
return get<entity_type>(archive);
}
/**
* @brief Serializes all elements of a type with associated identifiers.
* @tparam Component Types of components to serialize.
* @tparam Archive Type of output archive.
* @param archive A valid reference to an output archive.
* @return An object of this type to continue creating the snapshot.
*/
template<typename... Component, typename Archive>
[[deprecated("use .get<Type>(archive) instead")]] const basic_snapshot &component(Archive &archive) const {
return (get<Component>(archive), ...);
}
/**
* @brief Serializes all elements of a type with associated identifiers for
* the entities in a range.
* @tparam Component Types of components to serialize.
* @tparam Archive Type of output archive.
* @tparam It Type of input iterator.
* @param archive A valid reference to an output archive.
* @param first An iterator to the first element of the range to serialize.
* @param last An iterator past the last element of the range to serialize.
* @return An object of this type to continue creating the snapshot.
*/
template<typename... Component, typename Archive, typename It>
[[deprecated("use .get<Type>(archive, first, last) instead")]] const basic_snapshot &component(Archive &archive, It first, It last) const {
return (get<Component>(archive, first, last), ...);
}
private:
const registry_type *reg;
};
@@ -211,7 +175,7 @@ public:
basic_snapshot_loader(registry_type &source) noexcept
: reg{&source} {
// restoring a snapshot as a whole requires a clean registry
ENTT_ASSERT(reg->empty(), "Registry must be empty");
ENTT_ASSERT(reg->template storage<entity_type>().free_list() == 0u, "Registry must be empty");
}
/*! @brief Default move constructor. */
@@ -229,24 +193,24 @@ public:
* @return A valid loader to continue restoring data.
*/
template<typename Type, typename Archive>
basic_snapshot_loader &get([[maybe_unused]] Archive &archive, const id_type id = type_hash<Type>::value()) {
basic_snapshot_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
auto &storage = reg->template storage<Type>(id);
typename traits_type::entity_type length{};
archive(length);
if constexpr(std::is_same_v<Type, entity_type>) {
typename traits_type::entity_type in_use{};
typename traits_type::entity_type count{};
storage.reserve(length);
archive(in_use);
archive(count);
for(entity_type entity = null; length; --length) {
archive(entity);
storage.emplace(entity);
}
storage.in_use(in_use);
storage.free_list(count);
} else {
auto &other = reg->template storage<entity_type>();
entity_type entt{null};
@@ -256,7 +220,7 @@ public:
const auto entity = other.contains(entt) ? entt : other.emplace(entt);
ENTT_ASSERT(entity == entt, "Entity not available for use");
if constexpr(Registry::template storage_for_type<Type>::traits_type::page_size == 0u) {
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
storage.emplace(entity);
} else {
Type elem{};
@@ -270,33 +234,6 @@ public:
return *this;
}
/**
* @brief Restores all identifiers, including those to be recycled.
* @tparam Archive Type of input archive.
* @param archive A valid reference to an input archive.
* @return A valid loader to continue restoring data.
*/
template<typename Archive>
[[deprecated("use .get<Entity>(archive) instead")]] basic_snapshot_loader &entities(Archive &archive) {
return get<entity_type>(archive);
}
/**
* @brief Restores all elements of a type with associated identifiers.
*
* The template parameter list must be exactly the same used during
* serialization.
*
* @tparam Component Type of component to restore.
* @tparam Archive Type of input archive.
* @param archive A valid reference to an input archive.
* @return A valid loader to continue restoring data.
*/
template<typename... Component, typename Archive>
[[deprecated("use .get<Type>(archive) instead")]] basic_snapshot_loader &component(Archive &archive) {
return (get<Component>(archive), ...);
}
/**
* @brief Destroys those entities that have no components.
*
@@ -427,7 +364,7 @@ public:
* @return A valid loader to continue restoring data.
*/
template<typename Type, typename Archive>
basic_continuous_loader &get([[maybe_unused]] Archive &archive, const id_type id = type_hash<Type>::value()) {
basic_continuous_loader &get(Archive &archive, const id_type id = type_hash<Type>::value()) {
auto &storage = reg->template storage<Type>(id);
typename traits_type::entity_type length{};
entity_type entt{null};
@@ -465,7 +402,7 @@ public:
if(archive(entt); entt != null) {
restore(entt);
if constexpr(Registry::template storage_for_type<Type>::traits_type::page_size == 0u) {
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
storage.emplace(map(entt));
} else {
Type elem{};
@@ -479,79 +416,6 @@ public:
return *this;
}
/**
* @brief Restores all identifiers, including those to be recycled.
*
* It creates local counterparts for remote elements as needed.
*
* @tparam Archive Type of input archive.
* @param archive A valid reference to an input archive.
* @return A non-const reference to this loader.
*/
template<typename Archive>
[[deprecated("use .get<Entity>(archive) instead")]] basic_continuous_loader &entities(Archive &archive) {
return get<entity_type>(archive);
}
/**
* @brief Serializes all elements of a type with associated identifiers.
*
* It creates local counterparts for remote elements as needed.<br/>
* Members are either data members of type entity_type or containers of
* entities. In both cases, a loader visits them and replaces entities with
* their local counterpart.
*
* @tparam Component Type of component to restore.
* @tparam Archive Type of input archive.
* @tparam Member Types of members to update with their local counterparts.
* @param archive A valid reference to an input archive.
* @param member Members to update with their local counterparts.
* @return A non-const reference to this loader.
*/
template<typename... Component, typename Archive, typename... Member, typename... Clazz>
[[deprecated("use .component<Type>(archive, members...) instead")]] basic_continuous_loader &component(Archive &archive, Member Clazz::*...member) {
([&](auto &storage) {
for(auto &&ref: remloc) {
storage.remove(ref.second.second);
}
typename traits_type::entity_type length{};
entity_type entt{null};
archive(length);
while(length--) {
if(archive(entt); entt != null) {
restore(entt);
if constexpr(std::remove_reference_t<decltype(storage)>::traits_type::page_size == 0u) {
storage.emplace(map(entt));
} else {
typename std::remove_reference_t<decltype(storage)>::value_type elem{};
archive(elem);
(update(elem, member), ...);
storage.emplace(map(entt), std::move(elem));
}
}
}
}(reg->template storage<Component>()),
...);
return *this;
}
/**
* @brief Helps to purge entities that no longer have a counterpart.
*
* Users should invoke this member function after restoring each snapshot,
* unless they know exactly what they are doing.
*
* @return A non-const reference to this loader.
*/
[[deprecated("use .get<Entity>(archive) instead")]] basic_continuous_loader &shrink() {
return *this;
}
/**
* @brief Destroys those entities that have no components.
*

View File

@@ -17,11 +17,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Container>
@@ -137,11 +133,7 @@ template<typename Container>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Basic sparse set implementation.
@@ -168,6 +160,7 @@ class basic_sparse_set {
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
using sparse_container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
using packed_container_type = std::vector<Entity, Allocator>;
using underlying_type = typename entt_traits<Entity>::entity_type;
[[nodiscard]] auto sparse_ptr(const Entity entt) const {
const auto pos = static_cast<size_type>(traits_type::to_entity(entt));
@@ -194,14 +187,13 @@ class basic_sparse_set {
}
if(!sparse[page]) {
constexpr entity_type init = null;
auto page_allocator{packed.get_allocator()};
sparse[page] = alloc_traits::allocate(page_allocator, traits_type::page_size);
std::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, null);
std::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init);
}
auto &elem = sparse[page][fast_mod(pos, traits_type::page_size)];
ENTT_ASSERT(elem == null, "Slot not available");
return elem;
return sparse[page][fast_mod(pos, traits_type::page_size)];
}
void release_sparse_pages() {
@@ -216,31 +208,42 @@ class basic_sparse_set {
}
}
void swap_at(const std::size_t from, const std::size_t to) {
auto &lhs = packed[from];
auto &rhs = packed[to];
sparse_ref(lhs) = traits_type::combine(static_cast<typename traits_type::entity_type>(to), traits_type::to_integral(lhs));
sparse_ref(rhs) = traits_type::combine(static_cast<typename traits_type::entity_type>(from), traits_type::to_integral(rhs));
std::swap(lhs, rhs);
}
underlying_type policy_to_head() {
return traits_type::entity_mask * (mode != deletion_policy::swap_only);
}
private:
virtual const void *get_at(const std::size_t) const {
return nullptr;
}
virtual void swap_or_move(const std::size_t, const std::size_t) {}
virtual void swap_or_move([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) {
ENTT_ASSERT((mode != deletion_policy::swap_only) || (((lhs < free_list()) + (rhs < free_list())) != 1u), "Cross swapping is not supported");
}
protected:
/*! @brief Random access iterator type. */
using basic_iterator = internal::sparse_set_iterator<packed_container_type>;
/**
* @brief Swaps two items at specific locations.
* @param lhs A position to move from.
* @param rhs The other position to move from.
* @brief Erases an entity from a sparse set.
* @param it An iterator to the element to pop.
*/
void swap_at(const std::size_t lhs, const std::size_t rhs) {
const auto entity = static_cast<typename traits_type::entity_type>(lhs);
const auto other = static_cast<typename traits_type::entity_type>(rhs);
sparse_ref(packed[lhs]) = traits_type::combine(other, traits_type::to_integral(packed[lhs]));
sparse_ref(packed[rhs]) = traits_type::combine(entity, traits_type::to_integral(packed[rhs]));
using std::swap;
swap(packed[lhs], packed[rhs]);
void swap_only(const basic_iterator it) {
ENTT_ASSERT(mode == deletion_policy::swap_only, "Deletion policy mismatch");
const auto pos = static_cast<underlying_type>(index(*it));
bump(traits_type::next(*it));
swap_at(pos, static_cast<size_type>(head -= (pos < head)));
}
/**
@@ -248,7 +251,7 @@ protected:
* @param it An iterator to the element to pop.
*/
void swap_and_pop(const basic_iterator it) {
ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatched");
ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatch");
auto &self = sparse_ref(*it);
const auto entt = traits_type::to_entity(self);
sparse_ref(packed.back()) = traits_type::combine(entt, traits_type::to_integral(packed.back()));
@@ -265,9 +268,9 @@ protected:
* @param it An iterator to the element to pop.
*/
void in_place_pop(const basic_iterator it) {
ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatched");
ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatch");
const auto entt = traits_type::to_entity(std::exchange(sparse_ref(*it), null));
packed[static_cast<size_type>(entt)] = std::exchange(free_list, traits_type::combine(entt, tombstone));
packed[static_cast<size_type>(entt)] = traits_type::combine(std::exchange(head, entt), tombstone);
}
protected:
@@ -277,31 +280,47 @@ protected:
* @param last An iterator past the last element of the range of entities.
*/
virtual void pop(basic_iterator first, basic_iterator last) {
if(mode == deletion_policy::swap_and_pop) {
switch(mode) {
case deletion_policy::swap_and_pop:
for(; first != last; ++first) {
swap_and_pop(first);
}
} else {
break;
case deletion_policy::in_place:
for(; first != last; ++first) {
in_place_pop(first);
}
break;
case deletion_policy::swap_only:
for(; first != last; ++first) {
swap_only(first);
}
break;
}
}
/*! @brief Erases all entities of a sparse set. */
virtual void pop_all() {
if(const auto prev = std::exchange(free_list, tombstone); prev == null) {
switch(mode) {
case deletion_policy::in_place:
if(head != traits_type::to_entity(null)) {
for(auto first = begin(); !(first.index() < 0); ++first) {
if(*first != tombstone) {
sparse_ref(*first) = null;
}
}
break;
}
[[fallthrough]];
case deletion_policy::swap_only:
case deletion_policy::swap_and_pop:
for(auto first = begin(); !(first.index() < 0); ++first) {
sparse_ref(*first) = null;
}
} else {
for(auto first = begin(); !(first.index() < 0); ++first) {
if(*first != tombstone) {
sparse_ref(*first) = null;
}
}
break;
}
head = policy_to_head();
packed.clear();
}
@@ -312,18 +331,42 @@ protected:
* @return Iterator pointing to the emplaced element.
*/
virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) {
ENTT_ASSERT(!contains(entt), "Set already contains entity");
auto &elem = assure_at_least(entt);
auto pos = size();
if(auto &elem = assure_at_least(entt); free_list == null || force_back) {
switch(mode) {
case deletion_policy::in_place:
if(head != traits_type::to_entity(null) && !force_back) {
pos = static_cast<size_type>(head);
ENTT_ASSERT(elem == null, "Slot not available");
elem = traits_type::combine(head, traits_type::to_integral(entt));
head = traits_type::to_entity(std::exchange(packed[pos], entt));
break;
}
[[fallthrough]];
case deletion_policy::swap_and_pop:
packed.push_back(entt);
ENTT_ASSERT(elem == null, "Slot not available");
elem = traits_type::combine(static_cast<typename traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
return begin();
} else {
const auto pos = static_cast<size_type>(traits_type::to_entity(free_list));
elem = traits_type::combine(traits_type::to_integral(free_list), traits_type::to_integral(entt));
free_list = std::exchange(packed[pos], entt);
return --(end() - pos);
break;
case deletion_policy::swap_only:
if(elem == null) {
packed.push_back(entt);
elem = traits_type::combine(static_cast<typename traits_type::entity_type>(packed.size() - 1u), traits_type::to_integral(entt));
} else {
ENTT_ASSERT(!(traits_type::to_entity(elem) < head), "Slot not available");
bump(entt);
}
if(force_back) {
pos = static_cast<size_type>(head++);
swap_at(static_cast<size_type>(traits_type::to_entity(elem)), pos);
}
break;
}
return --(end() - pos);
}
public:
@@ -378,8 +421,8 @@ public:
: sparse{allocator},
packed{allocator},
info{&elem},
free_list{tombstone},
mode{pol} {}
mode{pol},
head{policy_to_head()} {}
/**
* @brief Move constructor.
@@ -389,8 +432,8 @@ public:
: sparse{std::move(other.sparse)},
packed{std::move(other.packed)},
info{other.info},
free_list{std::exchange(other.free_list, tombstone)},
mode{other.mode} {}
mode{other.mode},
head{std::exchange(other.head, policy_to_head())} {}
/**
* @brief Allocator-extended move constructor.
@@ -401,8 +444,8 @@ public:
: sparse{std::move(other.sparse), allocator},
packed{std::move(other.packed), allocator},
info{other.info},
free_list{std::exchange(other.free_list, tombstone)},
mode{other.mode} {
mode{other.mode},
head{std::exchange(other.head, policy_to_head())} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.get_allocator() == other.packed.get_allocator(), "Copying a sparse set is not allowed");
}
@@ -423,8 +466,8 @@ public:
sparse = std::move(other.sparse);
packed = std::move(other.packed);
info = other.info;
free_list = std::exchange(other.free_list, tombstone);
mode = other.mode;
head = std::exchange(other.head, policy_to_head());
return *this;
}
@@ -437,8 +480,8 @@ public:
swap(sparse, other.sparse);
swap(packed, other.packed);
swap(info, other.info);
swap(free_list, other.free_list);
swap(mode, other.mode);
swap(head, other.head);
}
/**
@@ -457,6 +500,23 @@ public:
return mode;
}
/**
* @brief Returns the head of the free list, if any.
* @return The head of the free list.
*/
[[nodiscard]] size_type free_list() const noexcept {
return static_cast<size_type>(head);
}
/**
* @brief Sets the head of the free list, if possible.
* @param len The value to use as the new head of the free list.
*/
void free_list(const size_type len) noexcept {
ENTT_ASSERT((mode == deletion_policy::swap_only) && !(len > packed.size()), "Invalid value");
head = static_cast<underlying_type>(len);
}
/**
* @brief Increases the capacity of a sparse set.
*
@@ -524,7 +584,7 @@ public:
* @return True if the sparse set is fully packed, false otherwise.
*/
[[nodiscard]] bool contiguous() const noexcept {
return (free_list == null);
return (mode != deletion_policy::in_place) || (head == traits_type::to_entity(null));
}
/**
@@ -543,7 +603,7 @@ public:
*
* @return An iterator to the first entity of the sparse set.
*/
[[nodiscard]] const_iterator begin() const noexcept {
[[nodiscard]] iterator begin() const noexcept {
const auto pos = static_cast<typename iterator::difference_type>(packed.size());
return iterator{packed, pos};
}
@@ -576,7 +636,7 @@ public:
* @return An iterator to the first entity of the reversed internal packed
* array.
*/
[[nodiscard]] const_reverse_iterator rbegin() const noexcept {
[[nodiscard]] reverse_iterator rbegin() const noexcept {
return std::make_reverse_iterator(end());
}
@@ -599,13 +659,53 @@ public:
return rend();
}
/*! @copydoc begin Useful only in case of swap-only policy. */
[[nodiscard]] iterator begin(int) const noexcept {
return (mode == deletion_policy::swap_only) ? (end() - static_cast<typename iterator::difference_type>(head)) : begin();
}
/*! @copydoc cbegin Useful only in case of swap-only policy. */
[[nodiscard]] const_iterator cbegin(int) const noexcept {
return begin(0);
}
/*! @copydoc end Useful only in case of swap-only policy. */
[[nodiscard]] iterator end(int) const noexcept {
return end();
}
/*! @copydoc cend Useful only in case of swap-only policy. */
[[nodiscard]] const_iterator cend(int) const noexcept {
return end(0);
}
/*! @copydoc rbegin Useful only in case of swap-only policy. */
[[nodiscard]] reverse_iterator rbegin(int) const noexcept {
return std::make_reverse_iterator(end(0));
}
/*! @copydoc rbegin Useful only in case of swap-only policy. */
[[nodiscard]] const_reverse_iterator crbegin(int) const noexcept {
return rbegin(0);
}
/*! @copydoc rbegin Useful only in case of swap-only policy. */
[[nodiscard]] reverse_iterator rend(int) const noexcept {
return std::make_reverse_iterator(begin(0));
}
/*! @copydoc rbegin Useful only in case of swap-only policy. */
[[nodiscard]] const_reverse_iterator crend(int) const noexcept {
return rend(0);
}
/**
* @brief Finds an entity.
* @param entt A valid identifier.
* @return An iterator to the given entity if it's found, past the end
* iterator otherwise.
*/
[[nodiscard]] iterator find(const entity_type entt) const noexcept {
[[nodiscard]] const_iterator find(const entity_type entt) const noexcept {
return contains(entt) ? to_iterator(entt) : end();
}
@@ -616,9 +716,10 @@ public:
*/
[[nodiscard]] bool contains(const entity_type entt) const noexcept {
const auto elem = sparse_ptr(entt);
constexpr auto cap = traits_type::to_entity(null);
constexpr auto cap = traits_type::entity_mask;
constexpr auto mask = traits_type::to_integral(null) & ~cap;
// testing versions permits to avoid accessing the packed array
return elem && (((~cap & traits_type::to_integral(entt)) ^ traits_type::to_integral(*elem)) < cap);
return elem && (((mask & traits_type::to_integral(entt)) ^ traits_type::to_integral(*elem)) < cap);
}
/**
@@ -653,7 +754,7 @@ public:
* @param pos The position for which to return the entity.
* @return The entity at specified location if any, a null entity otherwise.
*/
[[nodiscard]] entity_type at(const size_type pos) const noexcept {
[[deprecated("use .begin()[pos] instead")]] [[nodiscard]] entity_type at(const size_type pos) const noexcept {
return pos < packed.size() ? packed[pos] : null;
}
@@ -699,7 +800,7 @@ public:
* `end()` iterator otherwise.
*/
iterator push(const entity_type entt, const void *elem = nullptr) {
return try_emplace(entt, false, elem);
return try_emplace(entt, (mode == deletion_policy::swap_only), elem);
}
/**
@@ -822,25 +923,26 @@ public:
/*! @brief Removes all tombstones from a sparse set. */
void compact() {
size_type from = packed.size();
for(; from && packed[from - 1u] == tombstone; --from) {}
if(mode == deletion_policy::in_place) {
size_type from = packed.size();
for(; from && packed[from - 1u] == tombstone; --from) {}
underlying_type pos = std::exchange(head, traits_type::entity_mask);
for(auto *it = &free_list; *it != null && from; it = std::addressof(packed[traits_type::to_entity(*it)])) {
if(const size_type to = traits_type::to_entity(*it); to < from) {
--from;
swap_or_move(from, to);
while(pos != traits_type::to_entity(null)) {
if(const auto to = static_cast<size_type>(std::exchange(pos, traits_type::to_entity(packed[pos]))); to < from) {
--from;
swap_or_move(from, to);
packed[to] = std::exchange(packed[from], tombstone);
const auto entity = static_cast<typename traits_type::entity_type>(to);
sparse_ref(packed[to]) = traits_type::combine(entity, traits_type::to_integral(packed[to]));
packed[to] = packed[from];
const auto entity = static_cast<typename traits_type::entity_type>(to);
sparse_ref(packed[to]) = traits_type::combine(entity, traits_type::to_integral(packed[to]));
*it = traits_type::combine(static_cast<typename traits_type::entity_type>(from), tombstone);
for(; from && packed[from - 1u] == tombstone; --from) {}
for(; from && packed[from - 1u] == tombstone; --from) {}
}
}
}
free_list = tombstone;
packed.resize(from);
packed.erase(packed.begin() + from, packed.end());
}
}
/**
@@ -897,8 +999,8 @@ public:
*/
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) {
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == traits_type::to_entity(null)), "Sorting with tombstones not allowed");
ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements");
ENTT_ASSERT(free_list == null, "Partial sorting with tombstones is not supported");
algo(packed.rend() - length, packed.rend(), std::move(compare), std::forward<Args>(args)...);
@@ -932,28 +1034,27 @@ public:
*/
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&...args) {
compact();
sort_n(packed.size(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
sort_n(static_cast<size_type>(end(0) - begin(0)), std::move(compare), std::move(algo), std::forward<Args>(args)...);
}
/**
* @brief Sort entities according to their order in another sparse set.
* @brief Sort entities according to their order in a range.
*
* Entities that are part of both the sparse sets are ordered internally
* according to the order they have in `other`.<br/>
* All the other entities goes to the end of the list and there are no
* Entities that are part of both the sparse set and the range are ordered
* internally according to the order they have in the range.<br/>
* All other entities goes to the end of the sparse set and there are no
* guarantees on their order.
*
* @param other The sparse sets that imposes the order of the entities.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
void sort_as(const basic_sparse_set &other) {
compact();
template<typename It>
void sort_as(It first, It last) {
ENTT_ASSERT((mode != deletion_policy::in_place) || (head == traits_type::to_entity(null)), "Sorting with tombstones not allowed");
const auto to = other.end();
auto from = other.begin();
for(auto it = begin(); it.index() && from != to; ++from) {
if(const auto curr = *from; contains(curr)) {
for(auto it = begin(0); it.index() && first != last; ++first) {
if(const auto curr = *first; contains(curr)) {
if(const auto entt = *it; entt != curr) {
// basic no-leak guarantee (with invalid state) if swapping throws
swap_elements(entt, curr);
@@ -964,12 +1065,20 @@ public:
}
}
/**
* @copybrief sort_as
* @param other The sparse sets that imposes the order of the entities.
*/
[[deprecated("use iterator based sort_as instead")]] void sort_as(const basic_sparse_set &other) {
sort_as(other.begin(), other.end());
}
/*! @brief Clears a sparse set. */
void clear() {
pop_all();
// sanity check to avoid subtle issues due to storage classes
ENTT_ASSERT((compact(), size()) == 0u, "Non-empty set");
free_list = tombstone;
head = policy_to_head();
packed.clear();
}
@@ -988,8 +1097,8 @@ private:
sparse_container_type sparse;
packed_container_type packed;
const type_info *info;
entity_type free_list;
deletion_policy mode;
underlying_type head;
};
} // namespace entt

View File

@@ -19,11 +19,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Container, std::size_t Size>
@@ -161,11 +157,12 @@ public:
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
constexpr extended_storage_iterator()
: it{} {}
constexpr extended_storage_iterator(It base, Other... other)
constexpr extended_storage_iterator(iterator_type base, Other... other)
: it{base, other...} {}
template<typename... Args, typename = std::enable_if_t<(!std::is_same_v<Other, Args> && ...) && (std::is_constructible_v<Other, Args> && ...)>>
@@ -211,11 +208,7 @@ template<typename... Lhs, typename... Rhs>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Basic storage implementation.
@@ -240,8 +233,6 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
using underlying_iterator = typename underlying_type::basic_iterator;
static constexpr bool is_pinned_type_v = !(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>);
[[nodiscard]] auto &element_at(const std::size_t pos) const {
return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)];
}
@@ -290,7 +281,7 @@ class basic_storage: public basic_sparse_set<Entity, typename std::allocator_tra
for(auto pos = sz, length = base_type::size(); pos < length; ++pos) {
if constexpr(traits_type::in_place_delete) {
if(base_type::at(pos) != tombstone) {
if(base_type::data()[pos] != tombstone) {
alloc_traits::destroy(allocator, std::addressof(element_at(pos)));
}
} else {
@@ -311,6 +302,7 @@ private:
}
void swap_or_move([[maybe_unused]] const std::size_t from, [[maybe_unused]] const std::size_t to) override {
static constexpr bool is_pinned_type_v = !(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>);
// use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy
ENTT_ASSERT((from + 1u) && !is_pinned_type_v, "Pinned type");
@@ -841,7 +833,12 @@ public:
* @return The associated allocator.
*/
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
return allocator_type{base_type::get_allocator()};
// std::allocator<void> has no cross constructors (waiting for C++20)
if constexpr(std::is_void_v<value_type> && !std::is_constructible_v<allocator_type, typename base_type::allocator_type>) {
return allocator_type{};
} else {
return allocator_type{base_type::get_allocator()};
}
}
/**
@@ -958,42 +955,13 @@ class basic_storage<Entity, Entity, Allocator>
static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>, "Invalid value type");
using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
using underlying_iterator = typename underlying_type::basic_iterator;
using local_traits_type = entt_traits<Entity>;
auto entity_at(const std::size_t pos) const noexcept {
ENTT_ASSERT(pos < local_traits_type::to_entity(null), "Invalid element");
return local_traits_type::combine(static_cast<typename local_traits_type::entity_type>(pos), {});
}
private:
void swap_or_move([[maybe_unused]] const std::size_t lhs, [[maybe_unused]] const std::size_t rhs) override {
ENTT_ASSERT(((lhs < length) + (rhs < length)) != 1u, "Cross swapping is not supported");
ENTT_ASSERT(pos < underlying_type::traits_type::to_entity(null), "Invalid element");
return underlying_type::traits_type::combine(static_cast<typename underlying_type::traits_type::entity_type>(pos), {});
}
protected:
/**
* @brief Erases entities from a storage.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
void pop(underlying_iterator first, underlying_iterator last) override {
for(; first != last; ++first) {
if(const auto pos = base_type::index(*first); pos < length) {
base_type::bump(local_traits_type::next(*first));
if(pos != --length) {
base_type::swap_at(pos, length);
}
}
}
}
/*! @brief Erases all entities of a sparse set. */
void pop_all() override {
length = 0u;
base_type::pop_all();
}
/**
* @brief Assigns an entity to a storage.
* @param hint A valid identifier.
@@ -1008,8 +976,6 @@ public:
using base_type = basic_sparse_set<Entity, Allocator>;
/*! @brief Type of the objects assigned to entities. */
using value_type = Entity;
/*! @brief Component traits. */
using traits_type = component_traits<value_type>;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
@@ -1035,16 +1001,14 @@ public:
* @param allocator The allocator to use.
*/
explicit basic_storage(const allocator_type &allocator)
: base_type{type_id<value_type>(), deletion_policy::swap_and_pop, allocator},
length{} {}
: base_type{type_id<void>(), deletion_policy::swap_only, allocator} {}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_storage(basic_storage &&other) noexcept
: base_type{std::move(other)},
length{std::exchange(other.length, size_type{})} {}
: base_type{std::move(other)} {}
/**
* @brief Allocator-extended move constructor.
@@ -1052,8 +1016,7 @@ public:
* @param allocator The allocator to use.
*/
basic_storage(basic_storage &&other, const allocator_type &allocator) noexcept
: base_type{std::move(other), allocator},
length{std::exchange(other.length, size_type{})} {}
: base_type{std::move(other), allocator} {}
/**
* @brief Move assignment operator.
@@ -1062,7 +1025,6 @@ public:
*/
basic_storage &operator=(basic_storage &&other) noexcept {
base_type::operator=(std::move(other));
length = std::exchange(other.length, size_type{});
return *this;
}
@@ -1076,7 +1038,7 @@ public:
* @param entt A valid identifier.
*/
void get([[maybe_unused]] const entity_type entt) const noexcept {
ENTT_ASSERT(base_type::index(entt) < length, "The requested entity is not a live one");
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
}
/**
@@ -1090,30 +1052,18 @@ public:
* @return Returns an empty tuple.
*/
[[nodiscard]] std::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept {
ENTT_ASSERT(base_type::index(entt) < length, "The requested entity is not a live one");
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
return std::tuple{};
}
/**
* @brief Exchanges the contents with those of a given storage.
* @param other Storage to exchange the content with.
*/
void swap(basic_storage &other) {
using std::swap;
base_type::swap(other);
swap(length, other.length);
}
/**
* @brief Creates a new identifier or recycles a destroyed one.
* @return A valid identifier.
*/
entity_type emplace() {
if(length == base_type::size()) {
return *base_type::try_emplace(entity_at(length++), true);
}
return base_type::operator[](length++);
const auto len = base_type::free_list();
const auto entt = (len == base_type::size()) ? entity_at(len) : base_type::data()[len];
return *base_type::try_emplace(entt, true);
}
/**
@@ -1128,23 +1078,20 @@ public:
entity_type emplace(const entity_type hint) {
if(hint == null || hint == tombstone) {
return emplace();
} else if(const auto curr = local_traits_type::construct(local_traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone) {
const auto pos = static_cast<size_type>(local_traits_type::to_entity(hint));
} else if(const auto curr = underlying_type::traits_type::construct(underlying_type::traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone) {
const auto pos = static_cast<size_type>(underlying_type::traits_type::to_entity(hint));
const auto entt = *base_type::try_emplace(hint, true);
while(!(pos < base_type::size())) {
base_type::try_emplace(entity_at(base_type::size()), true);
base_type::try_emplace(entity_at(base_type::size() - 1u), false);
}
base_type::swap_at(pos, length++);
} else if(const auto idx = base_type::index(curr); idx < length) {
return entt;
} else if(const auto idx = base_type::index(curr); idx < base_type::free_list()) {
return emplace();
} else {
base_type::swap_at(idx, length++);
return *base_type::try_emplace(hint, true);
}
base_type::bump(hint);
return hint;
}
/**
@@ -1155,7 +1102,7 @@ public:
*/
template<typename... Func>
void patch([[maybe_unused]] const entity_type entt, Func &&...func) {
ENTT_ASSERT(base_type::contains(entt), "Storage does not contain entity");
ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one");
(std::forward<Func>(func)(), ...);
}
@@ -1167,12 +1114,12 @@ public:
*/
template<typename It>
void insert(It first, It last) {
for(const auto sz = base_type::size(); first != last && length != sz; ++first, ++length) {
*first = base_type::operator[](length);
for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) {
*first = *base_type::try_emplace(base_type::data()[base_type::free_list()], true);
}
for(; first != last; ++first) {
*first = *base_type::try_emplace(entity_at(length++), true);
*first = *base_type::try_emplace(entity_at(base_type::free_list()), true);
}
}
@@ -1184,33 +1131,25 @@ public:
* @return The number of elements within the newly created range.
*/
template<typename It>
size_type pack(It first, It last) {
size_type len = length;
for(; first != last; ++first, --len) {
const auto pos = base_type::index(*first);
ENTT_ASSERT(pos < length, "Invalid element");
base_type::swap_at(pos, static_cast<size_type>(len - 1u));
}
return (length - len);
[[deprecated("use sort_as instead")]] size_type pack(It first, It last) {
base_type::sort_as(first, last);
return static_cast<size_type>(std::distance(first, last));
}
/**
* @brief Returns the number of elements considered still in use.
* @return The number of elements considered still in use.
*/
[[nodiscard]] size_type in_use() const noexcept {
return length;
[[deprecated("use free_list() instead")]] [[nodiscard]] size_type in_use() const noexcept {
return base_type::free_list();
}
/**
* @brief Sets the number of elements considered still in use.
* @param len The number of elements considered still in use.
*/
void in_use(const size_type len) noexcept {
ENTT_ASSERT(!(len > base_type::size()), "Invalid length");
length = len;
[[deprecated("use free_list(len) instead")]] void in_use(const size_type len) noexcept {
base_type::free_list(len);
}
/**
@@ -1221,12 +1160,12 @@ public:
* @return An iterable object to use to _visit_ the storage.
*/
[[nodiscard]] iterable each() noexcept {
return {internal::extended_storage_iterator{base_type::end() - length}, internal::extended_storage_iterator{base_type::end()}};
return {internal::extended_storage_iterator{base_type::begin(0)}, internal::extended_storage_iterator{base_type::end(0)}};
}
/*! @copydoc each */
[[nodiscard]] const_iterable each() const noexcept {
return {internal::extended_storage_iterator{base_type::cend() - length}, internal::extended_storage_iterator{base_type::cend()}};
return {internal::extended_storage_iterator{base_type::cbegin(0)}, internal::extended_storage_iterator{base_type::cend(0)}};
}
/**
@@ -1237,16 +1176,13 @@ public:
* @return A reverse iterable object to use to _visit_ the storage.
*/
[[nodiscard]] reverse_iterable reach() noexcept {
return {internal::extended_storage_iterator{base_type::rbegin()}, internal::extended_storage_iterator{base_type::rbegin() + length}};
return {internal::extended_storage_iterator{base_type::rbegin()}, internal::extended_storage_iterator{base_type::rend(0)}};
}
/*! @copydoc reach */
[[nodiscard]] const_reverse_iterable reach() const noexcept {
return {internal::extended_storage_iterator{base_type::crbegin()}, internal::extended_storage_iterator{base_type::crbegin() + length}};
return {internal::extended_storage_iterator{base_type::crbegin()}, internal::extended_storage_iterator{base_type::crend(0)}};
}
private:
size_type length;
};
} // namespace entt

File diff suppressed because it is too large Load Diff

View File

@@ -13,11 +13,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename It>
@@ -30,6 +26,7 @@ public:
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
constexpr edge_iterator() noexcept
: it{},
@@ -87,11 +84,7 @@ template<typename Container>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Basic implementation of a directed adjacency matrix.

View File

@@ -134,8 +134,8 @@ public:
*/
explicit basic_flow(const allocator_type &allocator)
: index{0u, allocator},
vertices{},
deps{},
vertices{allocator},
deps{allocator},
sync_on{} {}
/*! @brief Default copy constructor. */

View File

@@ -19,145 +19,284 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename, typename = void>
struct is_dynamic_sequence_container: std::false_type {};
struct fixed_size_sequence_container: std::true_type {};
template<typename Type>
struct is_dynamic_sequence_container<Type, std::void_t<decltype(&Type::clear)>>: std::true_type {};
struct fixed_size_sequence_container<Type, std::void_t<decltype(&Type::clear)>>: std::false_type {};
template<typename Type>
inline constexpr bool fixed_size_sequence_container_v = fixed_size_sequence_container<Type>::value;
template<typename, typename = void>
struct is_key_only_meta_associative_container: std::true_type {};
struct key_only_associative_container: std::true_type {};
template<typename Type>
struct is_key_only_meta_associative_container<Type, std::void_t<typename Type::mapped_type>>: std::false_type {};
struct key_only_associative_container<Type, std::void_t<typename Type::mapped_type>>: std::false_type {};
template<typename Type>
struct basic_meta_sequence_container_traits {
using iterator = meta_sequence_container::iterator;
using size_type = std::size_t;
inline constexpr bool key_only_associative_container_v = key_only_associative_container<Type>::value;
[[nodiscard]] static size_type size(const any &container) noexcept {
return any_cast<const Type &>(container).size();
}
[[nodiscard]] static bool resize([[maybe_unused]] any &container, [[maybe_unused]] size_type sz) {
if constexpr(is_dynamic_sequence_container<Type>::value) {
if(auto *const cont = any_cast<Type>(&container); cont) {
cont->resize(sz);
return true;
}
}
return false;
}
[[nodiscard]] static iterator iter(const meta_ctx &ctx, any &container, const bool as_end) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return iterator{ctx, as_end ? cont->end() : cont->begin()};
}
const Type &as_const = any_cast<const Type &>(container);
return iterator{ctx, as_end ? as_const.end() : as_const.begin()};
}
[[nodiscard]] static iterator insert_or_erase([[maybe_unused]] const meta_ctx &ctx, [[maybe_unused]] any &container, [[maybe_unused]] const any &handle, [[maybe_unused]] meta_any &value) {
if constexpr(is_dynamic_sequence_container<Type>::value) {
if(auto *const cont = any_cast<Type>(&container); cont) {
typename Type::const_iterator it{};
if(auto *non_const = any_cast<typename Type::iterator>(&handle); non_const) {
it = *non_const;
} else {
it = any_cast<const typename Type::const_iterator &>(handle);
}
if(value) {
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
if(value.allow_cast<typename Type::const_reference>() || value.allow_cast<typename Type::value_type>()) {
const auto *element = value.try_cast<std::remove_reference_t<typename Type::const_reference>>();
return iterator{ctx, cont->insert(it, element ? *element : value.cast<typename Type::value_type>())};
}
} else {
return iterator{ctx, cont->erase(it)};
}
}
}
return iterator{};
}
};
template<typename, typename = void>
struct reserve_aware_container: std::false_type {};
template<typename Type>
struct basic_meta_associative_container_traits {
using iterator = meta_associative_container::iterator;
using size_type = std::size_t;
struct reserve_aware_container<Type, std::void_t<decltype(&Type::reserve)>>: std::true_type {};
static constexpr auto key_only = is_key_only_meta_associative_container<Type>::value;
[[nodiscard]] static size_type size(const any &container) noexcept {
return any_cast<const Type &>(container).size();
}
[[nodiscard]] static bool clear(any &container) {
if(auto *const cont = any_cast<Type>(&container); cont) {
cont->clear();
return true;
}
return false;
}
[[nodiscard]] static iterator iter(const meta_ctx &ctx, any &container, const bool as_end) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return iterator{ctx, std::bool_constant<key_only>{}, as_end ? cont->end() : cont->begin()};
}
const auto &as_const = any_cast<const Type &>(container);
return iterator{ctx, std::bool_constant<key_only>{}, as_end ? as_const.end() : as_const.begin()};
}
[[nodiscard]] static size_type insert_or_erase(any &container, meta_any &key, meta_any &value) {
if(auto *const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
if(value) {
if constexpr(key_only) {
return cont->insert(key.cast<const typename Type::key_type &>()).second;
} else {
return value.allow_cast<const typename Type::mapped_type &>() && cont->emplace(key.cast<const typename Type::key_type &>(), value.cast<const typename Type::mapped_type &>()).second;
}
} else {
return cont->erase(key.cast<const typename Type::key_type &>());
}
}
return 0u;
}
[[nodiscard]] static iterator find(const meta_ctx &ctx, any &container, meta_any &key) {
if(key.allow_cast<const typename Type::key_type &>()) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return iterator{ctx, std::bool_constant<key_only>{}, cont->find(key.cast<const typename Type::key_type &>())};
}
return iterator{ctx, std::bool_constant<key_only>{}, any_cast<const Type &>(container).find(key.cast<const typename Type::key_type &>())};
}
return iterator{};
}
};
template<typename Type>
inline constexpr bool reserve_aware_container_v = reserve_aware_container<Type>::value;
} // namespace internal
/*! @endcond */
/**
* Internal details not to be documented.
* @endcond
* @brief General purpose implementation of meta sequence container traits.
* @tparam Type Type of underlying sequence container.
*/
template<typename Type>
struct basic_meta_sequence_container_traits {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
/*! @brief True in case of key-only containers, false otherwise. */
static constexpr bool fixed_size = internal::fixed_size_sequence_container_v<Type>;
/*! @brief Unsigned integer type. */
using size_type = typename meta_sequence_container::size_type;
/*! @brief Meta iterator type. */
using iterator = typename meta_sequence_container::iterator;
/**
* @brief Returns the number of elements in a container.
* @param container Opaque pointer to a container of the given type.
* @return Number of elements.
*/
[[nodiscard]] static size_type size(const void *container) {
return static_cast<const Type *>(container)->size();
}
/**
* @brief Clears a container.
* @param container Opaque pointer to a container of the given type.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear([[maybe_unused]] void *container) {
if constexpr(fixed_size) {
return false;
} else {
static_cast<Type *>(container)->clear();
return true;
}
}
/**
* @brief Increases the capacity of a container.
* @param container Opaque pointer to a container of the given type.
* @param sz Desired capacity.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(internal::reserve_aware_container_v<Type>) {
static_cast<Type *>(container)->reserve(sz);
return true;
} else {
return false;
}
}
/**
* @brief Resizes a container.
* @param container Opaque pointer to a container of the given type.
* @param sz The new number of elements.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(fixed_size || !std::is_default_constructible_v<typename Type::value_type>) {
return false;
} else {
static_cast<Type *>(container)->resize(sz);
return true;
}
}
/**
* @brief Returns a possibly const iterator to the beginning.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @return An iterator to the first element of the container.
*/
static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
return container ? iterator{area, static_cast<Type *>(container)->begin()}
: iterator{area, static_cast<const Type *>(as_const)->begin()};
}
/**
* @brief Returns a possibly const iterator to the end.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @return An iterator that is past the last element of the container.
*/
static iterator end(const meta_ctx &area, void *container, const void *as_const) {
return container ? iterator{area, static_cast<Type *>(container)->end()}
: iterator{area, static_cast<const Type *>(as_const)->end()};
}
/**
* @brief Assigns one element to a container and constructs its object from
* a given opaque instance.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param value Optional opaque instance of the object to construct (as
* value type).
* @param cref Optional opaque instance of the object to construct (as
* decayed const reference type).
* @param it Iterator before which the element will be inserted.
* @return A possibly invalid iterator to the inserted element.
*/
[[nodiscard]] static iterator insert(const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const void *value, [[maybe_unused]] const void *cref, [[maybe_unused]] const iterator &it) {
if constexpr(fixed_size) {
return iterator{area};
} else {
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
return {area, static_cast<Type *>(container)->insert(
non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()),
value ? *static_cast<const typename Type::value_type *>(value) : *static_cast<const std::remove_reference_t<typename Type::const_reference> *>(cref))};
}
}
/**
* @brief Erases an element from a container.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param it An opaque iterator to the element to erase.
* @return A possibly invalid iterator following the last removed element.
*/
[[nodiscard]] static iterator erase(const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) {
if constexpr(fixed_size) {
return iterator{area};
} else {
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
return {area, static_cast<Type *>(container)->erase(non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()))};
}
}
};
/**
* @brief General purpose implementation of meta associative container traits.
* @tparam Type Type of underlying associative container.
*/
template<typename Type>
struct basic_meta_associative_container_traits {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
/*! @brief True in case of key-only containers, false otherwise. */
static constexpr bool key_only = internal::key_only_associative_container_v<Type>;
/*! @brief Unsigned integer type. */
using size_type = typename meta_associative_container::size_type;
/*! @brief Meta iterator type. */
using iterator = typename meta_associative_container::iterator;
/**
* @brief Returns the number of elements in a container.
* @param container Opaque pointer to a container of the given type.
* @return Number of elements.
*/
[[nodiscard]] static size_type size(const void *container) {
return static_cast<const Type *>(container)->size();
}
/**
* @brief Clears a container.
* @param container Opaque pointer to a container of the given type.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear(void *container) {
static_cast<Type *>(container)->clear();
return true;
}
/**
* @brief Increases the capacity of a container.
* @param container Opaque pointer to a container of the given type.
* @param sz Desired capacity.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(internal::reserve_aware_container_v<Type>) {
static_cast<Type *>(container)->reserve(sz);
return true;
} else {
return false;
}
}
/**
* @brief Returns a possibly const iterator to the beginning.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @return An iterator to the first element of the container.
*/
static iterator begin(const meta_ctx &area, void *container, const void *as_const) {
return container ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->begin()}
: iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->begin()};
}
/**
* @brief Returns a possibly const iterator to the end.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @return An iterator that is past the last element of the container.
*/
static iterator end(const meta_ctx &area, void *container, const void *as_const) {
return container ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->end()}
: iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->end()};
}
/**
* @brief Inserts an element into a container, if the key does not exist.
* @param container Opaque pointer to a container of the given type.
* @param key An opaque key value of an element to insert.
* @param value Optional opaque value to insert (key-value containers).
* @return True if the insertion took place, false otherwise.
*/
[[nodiscard]] static bool insert(void *container, const void *key, [[maybe_unused]] const void *value) {
if constexpr(key_only) {
return static_cast<Type *>(container)->insert(*static_cast<const typename Type::key_type *>(key)).second;
} else {
return static_cast<Type *>(container)->emplace(*static_cast<const typename Type::key_type *>(key), *static_cast<const typename Type::mapped_type *>(value)).second;
}
}
/**
* @brief Removes an element from a container.
* @param container Opaque pointer to a container of the given type.
* @param key An opaque key value of an element to remove.
* @return Number of elements removed (either 0 or 1).
*/
[[nodiscard]] static size_type erase(void *container, const void *key) {
return static_cast<Type *>(container)->erase(*static_cast<const typename Type::key_type *>(key));
}
/**
* @brief Finds an element with a given key.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @param key Opaque key value of an element to search for.
* @return An iterator to the element with the given key, if any.
*/
static iterator find(const meta_ctx &area, void *container, const void *as_const, const void *key) {
return container ? iterator{area, std::bool_constant<key_only>{}, static_cast<Type *>(container)->find(*static_cast<const typename Type::key_type *>(key))}
: iterator{area, std::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->find(*static_cast<const typename Type::key_type *>(key))};
}
};
/**
* @brief Meta sequence container traits for `std::vector`s of any type.
@@ -165,7 +304,7 @@ struct basic_meta_associative_container_traits {
*/
template<typename... Args>
struct meta_sequence_container_traits<std::vector<Args...>>
: internal::basic_meta_sequence_container_traits<std::vector<Args...>> {};
: basic_meta_sequence_container_traits<std::vector<Args...>> {};
/**
* @brief Meta sequence container traits for `std::array`s of any type.
@@ -174,7 +313,7 @@ struct meta_sequence_container_traits<std::vector<Args...>>
*/
template<typename Type, auto N>
struct meta_sequence_container_traits<std::array<Type, N>>
: internal::basic_meta_sequence_container_traits<std::array<Type, N>> {};
: basic_meta_sequence_container_traits<std::array<Type, N>> {};
/**
* @brief Meta sequence container traits for `std::list`s of any type.
@@ -182,7 +321,7 @@ struct meta_sequence_container_traits<std::array<Type, N>>
*/
template<typename... Args>
struct meta_sequence_container_traits<std::list<Args...>>
: internal::basic_meta_sequence_container_traits<std::list<Args...>> {};
: basic_meta_sequence_container_traits<std::list<Args...>> {};
/**
* @brief Meta sequence container traits for `std::deque`s of any type.
@@ -190,7 +329,7 @@ struct meta_sequence_container_traits<std::list<Args...>>
*/
template<typename... Args>
struct meta_sequence_container_traits<std::deque<Args...>>
: internal::basic_meta_sequence_container_traits<std::deque<Args...>> {};
: basic_meta_sequence_container_traits<std::deque<Args...>> {};
/**
* @brief Meta associative container traits for `std::map`s of any type.
@@ -198,7 +337,7 @@ struct meta_sequence_container_traits<std::deque<Args...>>
*/
template<typename... Args>
struct meta_associative_container_traits<std::map<Args...>>
: internal::basic_meta_associative_container_traits<std::map<Args...>> {};
: basic_meta_associative_container_traits<std::map<Args...>> {};
/**
* @brief Meta associative container traits for `std::unordered_map`s of any
@@ -207,7 +346,7 @@ struct meta_associative_container_traits<std::map<Args...>>
*/
template<typename... Args>
struct meta_associative_container_traits<std::unordered_map<Args...>>
: internal::basic_meta_associative_container_traits<std::unordered_map<Args...>> {};
: basic_meta_associative_container_traits<std::unordered_map<Args...>> {};
/**
* @brief Meta associative container traits for `std::set`s of any type.
@@ -215,7 +354,7 @@ struct meta_associative_container_traits<std::unordered_map<Args...>>
*/
template<typename... Args>
struct meta_associative_container_traits<std::set<Args...>>
: internal::basic_meta_associative_container_traits<std::set<Args...>> {};
: basic_meta_associative_container_traits<std::set<Args...>> {};
/**
* @brief Meta associative container traits for `std::unordered_set`s of any
@@ -224,7 +363,7 @@ struct meta_associative_container_traits<std::set<Args...>>
*/
template<typename... Args>
struct meta_associative_container_traits<std::unordered_set<Args...>>
: internal::basic_meta_associative_container_traits<std::unordered_set<Args...>> {};
: basic_meta_associative_container_traits<std::unordered_set<Args...>> {};
/**
* @brief Meta associative container traits for `dense_map`s of any type.
@@ -232,7 +371,7 @@ struct meta_associative_container_traits<std::unordered_set<Args...>>
*/
template<typename... Args>
struct meta_associative_container_traits<dense_map<Args...>>
: internal::basic_meta_associative_container_traits<dense_map<Args...>> {};
: basic_meta_associative_container_traits<dense_map<Args...>> {};
/**
* @brief Meta associative container traits for `dense_set`s of any type.
@@ -240,7 +379,7 @@ struct meta_associative_container_traits<dense_map<Args...>>
*/
template<typename... Args>
struct meta_associative_container_traits<dense_set<Args...>>
: internal::basic_meta_associative_container_traits<dense_set<Args...>> {};
: basic_meta_associative_container_traits<dense_set<Args...>> {};
} // namespace entt

View File

@@ -9,11 +9,7 @@ namespace entt {
class meta_ctx;
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
struct meta_type_node;
@@ -21,16 +17,12 @@ struct meta_type_node;
struct meta_context {
dense_map<id_type, meta_type_node, identity> value{};
[[nodiscard]] static inline meta_context &from(meta_ctx &ctx);
[[nodiscard]] static inline const meta_context &from(const meta_ctx &ctx);
[[nodiscard]] inline static meta_context &from(meta_ctx &ctx);
[[nodiscard]] inline static const meta_context &from(const meta_ctx &ctx);
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/*! @brief Disambiguation tag for constructors and the like. */
class meta_ctx_arg_t final {};
@@ -40,15 +32,11 @@ inline constexpr meta_ctx_arg_t meta_ctx_arg{};
/*! @brief Opaque meta context type. */
class meta_ctx: private internal::meta_context {
/*! @brief Attorney idiom like model to access the base class. */
// attorney idiom like model to access the base class
friend struct internal::meta_context;
};
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
[[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) {
return ctx;
}
@@ -56,11 +44,7 @@ class meta_ctx: private internal::meta_context {
[[nodiscard]] inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) {
return ctx;
}
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
} // namespace entt

View File

@@ -22,11 +22,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
[[nodiscard]] inline decltype(auto) owner(meta_ctx &ctx, const type_info &info) {
@@ -57,11 +53,7 @@ inline meta_func_node &meta_extend(internal::meta_type_node &parent, const id_ty
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Basic meta factory to be used for reflection purposes.
@@ -115,7 +107,7 @@ public:
/**
* @brief Assigns a custom unique identifier to a meta type.
* @param id A custom unique identifier.
* @return An extended meta factory for the given type.
* @return A meta factory for the given type.
*/
auto type(const id_type id) noexcept {
auto &&elem = internal::owner(*ctx, *info);
@@ -192,7 +184,7 @@ public:
*
* @tparam Candidate The actual function to use as a constructor.
* @tparam Policy Optional policy (no policy set by default).
* @return An extended meta factory for the parent type.
* @return A meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_is_t>
auto ctor() noexcept {
@@ -212,7 +204,7 @@ public:
* type that can be invoked with parameters whose types are those given.
*
* @tparam Args Types of arguments to use to construct an instance.
* @return An extended meta factory for the parent type.
* @return A meta factory for the parent type.
*/
template<typename... Args>
auto ctor() noexcept {
@@ -264,7 +256,7 @@ public:
* @tparam Data The actual variable to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
* @return A meta factory for the parent type.
*/
template<auto Data, typename Policy = as_is_t>
auto data(const id_type id) noexcept {
@@ -329,7 +321,7 @@ public:
* @tparam Getter The actual function to use as a getter.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
* @return A meta factory for the parent type.
*/
template<auto Setter, auto Getter, typename Policy = as_is_t>
auto data(const id_type id) noexcept {
@@ -386,7 +378,7 @@ public:
* @tparam Getter The actual getter function.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
* @return A meta factory for the parent type.
*/
template<typename Setter, auto Getter, typename Policy = as_is_t>
auto data(const id_type id) noexcept {
@@ -405,7 +397,7 @@ public:
* @tparam Candidate The actual function to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
* @return A meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_is_t>
auto func(const id_type id) noexcept {
@@ -434,7 +426,7 @@ public:
* @tparam Value Optional type of the property value.
* @param id Property key.
* @param value Optional property value.
* @return An extended meta factory for the given type.
* @return A meta factory for the parent type.
*/
template<typename... Value>
meta_factory prop(id_type id, [[maybe_unused]] Value &&...value) {

View File

@@ -36,11 +36,15 @@ public:
/*! @brief Meta iterator type. */
using iterator = meta_iterator;
/*! @brief Default constructor. */
meta_sequence_container() noexcept
: meta_sequence_container{locator<meta_ctx>::value_or()} {}
/**
* @brief Context aware constructor.
* @param area The context from which to search for meta types.
*/
meta_sequence_container(const meta_ctx &area = locator<meta_ctx>::value_or()) noexcept
meta_sequence_container(const meta_ctx &area) noexcept
: ctx{&area} {}
/**
@@ -49,19 +53,26 @@ public:
* @param instance The container to wrap.
*/
template<typename Type>
void rebind(any instance) noexcept {
void rebind(Type &instance) noexcept {
value_type_node = &internal::resolve<typename Type::value_type>;
size_fn = &meta_sequence_container_traits<Type>::size;
resize_fn = &meta_sequence_container_traits<Type>::resize;
iter_fn = &meta_sequence_container_traits<Type>::iter;
insert_or_erase_fn = &meta_sequence_container_traits<Type>::insert_or_erase;
storage = std::move(instance);
const_reference_node = &internal::resolve<std::remove_const_t<std::remove_reference_t<typename Type::const_reference>>>;
size_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::size;
clear_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::clear;
reserve_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::reserve;
resize_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::resize;
begin_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::begin;
end_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::end;
insert_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::insert;
erase_fn = meta_sequence_container_traits<std::remove_const_t<Type>>::erase;
const_only = std::is_const_v<Type>;
data = &instance;
}
[[nodiscard]] inline meta_type value_type() const noexcept;
[[nodiscard]] inline size_type size() const noexcept;
inline bool resize(const size_type);
inline bool clear();
inline bool reserve(const size_type);
[[nodiscard]] inline iterator begin();
[[nodiscard]] inline iterator end();
inline iterator insert(iterator, meta_any);
@@ -72,11 +83,17 @@ public:
private:
const meta_ctx *ctx{};
internal::meta_type_node (*value_type_node)(const internal::meta_context &){};
size_type (*size_fn)(const any &) noexcept {};
bool (*resize_fn)(any &, size_type){};
iterator (*iter_fn)(const meta_ctx &, any &, const bool){};
iterator (*insert_or_erase_fn)(const meta_ctx &, any &, const any &, meta_any &){};
any storage{};
internal::meta_type_node (*const_reference_node)(const internal::meta_context &){};
size_type (*size_fn)(const void *){};
bool (*clear_fn)(void *){};
bool (*reserve_fn)(void *, const size_type){};
bool (*resize_fn)(void *, const size_type){};
iterator (*begin_fn)(const meta_ctx &, void *, const void *){};
iterator (*end_fn)(const meta_ctx &, void *, const void *){};
iterator (*insert_fn)(const meta_ctx &, void *, const void *, const void *, const iterator &){};
iterator (*erase_fn)(const meta_ctx &, void *, const iterator &){};
const void *data{};
bool const_only{};
};
/*! @brief Proxy object for associative containers. */
@@ -89,11 +106,15 @@ public:
/*! @brief Meta iterator type. */
using iterator = meta_iterator;
/*! @brief Default constructor. */
meta_associative_container() noexcept
: meta_associative_container{locator<meta_ctx>::value_or()} {}
/**
* @brief Context aware constructor.
* @param area The context from which to search for meta types.
*/
meta_associative_container(const meta_ctx &area = locator<meta_ctx>::value_or()) noexcept
meta_associative_container(const meta_ctx &area) noexcept
: ctx{&area} {}
/**
@@ -102,20 +123,24 @@ public:
* @param instance The container to wrap.
*/
template<typename Type>
void rebind(any instance) noexcept {
if constexpr(!meta_associative_container_traits<Type>::key_only) {
void rebind(Type &instance) noexcept {
key_type_node = &internal::resolve<typename Type::key_type>;
value_type_node = &internal::resolve<typename Type::value_type>;
if constexpr(!meta_associative_container_traits<std::remove_const_t<Type>>::key_only) {
mapped_type_node = &internal::resolve<typename Type::mapped_type>;
}
key_only_container = meta_associative_container_traits<Type>::key_only;
key_type_node = &internal::resolve<typename Type::key_type>;
value_type_node = &internal::resolve<typename Type::value_type>;
size_fn = &meta_associative_container_traits<Type>::size;
clear_fn = &meta_associative_container_traits<Type>::clear;
iter_fn = &meta_associative_container_traits<Type>::iter;
insert_or_erase_fn = &meta_associative_container_traits<Type>::insert_or_erase;
find_fn = &meta_associative_container_traits<Type>::find;
storage = std::move(instance);
size_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::size;
clear_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::clear;
reserve_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::reserve;
begin_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::begin;
end_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::end;
insert_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::insert;
erase_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::erase;
find_fn = &meta_associative_container_traits<std::remove_const_t<Type>>::find;
const_only = std::is_const_v<Type>;
data = &instance;
}
[[nodiscard]] inline bool key_only() const noexcept;
@@ -124,9 +149,9 @@ public:
[[nodiscard]] inline meta_type value_type() const noexcept;
[[nodiscard]] inline size_type size() const noexcept;
inline bool clear();
inline bool reserve(const size_type);
[[nodiscard]] inline iterator begin();
[[nodiscard]] inline iterator end();
inline bool insert(meta_any);
inline bool insert(meta_any, meta_any);
inline size_type erase(meta_any);
[[nodiscard]] inline iterator find(meta_any);
@@ -134,67 +159,63 @@ public:
private:
const meta_ctx *ctx{};
bool key_only_container{};
internal::meta_type_node (*key_type_node)(const internal::meta_context &){};
internal::meta_type_node (*mapped_type_node)(const internal::meta_context &){};
internal::meta_type_node (*value_type_node)(const internal::meta_context &){};
size_type (*size_fn)(const any &) noexcept {};
bool (*clear_fn)(any &){};
iterator (*iter_fn)(const meta_ctx &, any &, const bool){};
size_type (*insert_or_erase_fn)(any &, meta_any &, meta_any &){};
iterator (*find_fn)(const meta_ctx &, any &, meta_any &){};
any storage{};
size_type (*size_fn)(const void *){};
bool (*clear_fn)(void *){};
bool (*reserve_fn)(void *, const size_type){};
iterator (*begin_fn)(const meta_ctx &, void *, const void *){};
iterator (*end_fn)(const meta_ctx &, void *, const void *){};
bool (*insert_fn)(void *, const void *, const void *){};
size_type (*erase_fn)(void *, const void *){};
iterator (*find_fn)(const meta_ctx &, void *, const void *, const void *){};
const void *data{};
bool const_only{};
};
/*! @brief Possible modes of a meta any object. */
using meta_any_policy = any_policy;
/*! @brief Opaque wrapper for values of any type. */
class meta_any {
enum class operation : std::uint8_t {
deref,
seq,
assoc
};
using vtable_type = void(const operation, const any &, void *);
using vtable_type = void(const internal::meta_traits op, const bool, const void *, void *);
template<typename Type>
static void basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const any &value, [[maybe_unused]] void *other) {
static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
static std::enable_if_t<std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>> basic_vtable([[maybe_unused]] const internal::meta_traits req, [[maybe_unused]] const bool const_only, [[maybe_unused]] const void *value, [[maybe_unused]] void *other) {
if constexpr(is_meta_pointer_like_v<Type>) {
if(req == internal::meta_traits::is_meta_pointer_like) {
if constexpr(std::is_function_v<typename std::pointer_traits<Type>::element_type>) {
static_cast<meta_any *>(other)->emplace<Type>(*static_cast<const Type *>(value));
} else if constexpr(!std::is_void_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>>) {
using in_place_type = decltype(adl_meta_pointer_like<Type>::dereference(*static_cast<const Type *>(value)));
if constexpr(!std::is_void_v<Type>) {
switch(op) {
case operation::deref:
if constexpr(is_meta_pointer_like_v<Type>) {
if constexpr(std::is_function_v<typename std::pointer_traits<Type>::element_type>) {
static_cast<meta_any *>(other)->emplace<Type>(any_cast<Type>(value));
} else if constexpr(!std::is_same_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>, void>) {
using in_place_type = decltype(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(value)));
if constexpr(std::is_constructible_v<bool, Type>) {
if(const auto &pointer_like = any_cast<const Type &>(value); pointer_like) {
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(pointer_like));
}
} else {
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(any_cast<const Type &>(value)));
if constexpr(std::is_constructible_v<bool, Type>) {
if(const auto &pointer_like = *static_cast<const Type *>(value); pointer_like) {
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(pointer_like));
}
} else {
static_cast<meta_any *>(other)->emplace<in_place_type>(adl_meta_pointer_like<Type>::dereference(*static_cast<const Type *>(value)));
}
}
break;
case operation::seq:
if constexpr(is_complete_v<meta_sequence_container_traits<Type>>) {
static_cast<meta_sequence_container *>(other)->rebind<Type>(std::move(const_cast<any &>(value)));
}
break;
case operation::assoc:
if constexpr(is_complete_v<meta_associative_container_traits<Type>>) {
static_cast<meta_associative_container *>(other)->rebind<Type>(std::move(const_cast<any &>(value)));
}
break;
}
}
if constexpr(is_complete_v<meta_sequence_container_traits<Type>>) {
if(req == internal::meta_traits::is_meta_sequence_container) {
const_only ? static_cast<meta_sequence_container *>(other)->rebind(*static_cast<const Type *>(value)) : static_cast<meta_sequence_container *>(other)->rebind(*static_cast<Type *>(const_cast<void *>(value)));
}
}
if constexpr(is_complete_v<meta_associative_container_traits<Type>>) {
if(req == internal::meta_traits::is_meta_associative_container) {
const_only ? static_cast<meta_associative_container *>(other)->rebind(*static_cast<const Type *>(value)) : static_cast<meta_associative_container *>(other)->rebind(*static_cast<Type *>(const_cast<void *>(value)));
}
}
}
void release() {
if(node.dtor.dtor && owner()) {
if(node.dtor.dtor && (storage.policy() == any_policy::owner)) {
node.dtor.dtor(storage.data());
}
}
@@ -418,10 +439,6 @@ public:
/**
* @brief Tries to cast an instance to a given type.
*
* @warning
* Attempting to perform an invalid cast results is undefined behavior.
*
* @tparam Type Type to which to cast the instance.
* @return A reference to the contained instance.
*/
@@ -456,7 +473,7 @@ public:
*/
[[nodiscard]] bool allow_cast(const meta_type &type) {
if(auto other = std::as_const(*this).allow_cast(type); other) {
if(other.owner()) {
if((other.storage.policy() == any_policy::owner)) {
std::swap(*this, other);
}
@@ -488,7 +505,7 @@ public:
* @return True if there exists a viable conversion, false otherwise.
*/
template<typename Type>
bool allow_cast() {
[[nodiscard]] bool allow_cast() {
auto other = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
return allow_cast(meta_type{*ctx, other}) && (!(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) || storage.data() != nullptr);
}
@@ -521,17 +538,15 @@ public:
* @return A sequence container proxy for the underlying object.
*/
[[nodiscard]] meta_sequence_container as_sequence_container() noexcept {
any detached = storage.as_ref();
meta_sequence_container proxy{*ctx};
vtable(operation::seq, detached, &proxy);
vtable(internal::meta_traits::is_meta_sequence_container, policy() == meta_any_policy::cref, std::as_const(*this).data(), &proxy);
return proxy;
}
/*! @copydoc as_sequence_container */
[[nodiscard]] meta_sequence_container as_sequence_container() const noexcept {
any detached = storage.as_ref();
meta_sequence_container proxy{*ctx};
vtable(operation::seq, detached, &proxy);
vtable(internal::meta_traits::is_meta_sequence_container, true, data(), &proxy);
return proxy;
}
@@ -540,17 +555,15 @@ public:
* @return An associative container proxy for the underlying object.
*/
[[nodiscard]] meta_associative_container as_associative_container() noexcept {
any detached = storage.as_ref();
meta_associative_container proxy{*ctx};
vtable(operation::assoc, detached, &proxy);
vtable(internal::meta_traits::is_meta_associative_container, policy() == meta_any_policy::cref, std::as_const(*this).data(), &proxy);
return proxy;
}
/*! @copydoc as_associative_container */
[[nodiscard]] meta_associative_container as_associative_container() const noexcept {
any detached = storage.as_ref();
meta_associative_container proxy{*ctx};
vtable(operation::assoc, detached, &proxy);
vtable(internal::meta_traits::is_meta_associative_container, true, data(), &proxy);
return proxy;
}
@@ -561,7 +574,7 @@ public:
*/
[[nodiscard]] meta_any operator*() const noexcept {
meta_any ret{meta_ctx_arg, *ctx};
vtable(operation::deref, storage, &ret);
vtable(internal::meta_traits::is_meta_pointer_like, true, storage.data(), &ret);
return ret;
}
@@ -594,8 +607,16 @@ public:
}
/*! @copydoc any::owner */
[[nodiscard]] bool owner() const noexcept {
return storage.owner();
[[deprecated("use policy() and meta_any_policy instead")]] [[nodiscard]] bool owner() const noexcept {
return (storage.policy() == any_policy::owner);
}
/**
* @brief Returns the current mode of a meta any object.
* @return The current mode of the meta any object.
*/
[[nodiscard]] meta_any_policy policy() const noexcept {
return storage.policy();
}
private:
@@ -632,8 +653,7 @@ template<typename Type>
* @brief Opaque pointers to instances of any type.
*
* A handle doesn't perform copies and isn't responsible for the contained
* object. It doesn't prolong the lifetime of the pointed instance.<br/>
* Handles are used to generate references to actual objects when needed.
* object. It doesn't prolong the lifetime of the pointed instance.
*/
struct meta_handle {
/*! Default constructor. */
@@ -993,8 +1013,7 @@ struct meta_func {
* @brief Invokes the underlying function, if possible.
*
* @warning
* The context of the arguments is **not** changed.<br/>
* It's up to the caller to bind them to the right context(s).
* The context of the arguments is **never** changed.
*
* @param instance An opaque instance of the underlying type.
* @param args Parameters to use to invoke the function.
@@ -1014,12 +1033,8 @@ struct meta_func {
*/
template<typename... Args>
meta_any invoke(meta_handle instance, Args &&...args) const {
if constexpr(sizeof...(Args) == 0u) {
return invoke(std::move(instance), static_cast<meta_any *>(nullptr), size_type{});
} else {
meta_any arguments[sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
return invoke(std::move(instance), arguments, sizeof...(Args));
}
meta_any arguments[sizeof...(Args) + !sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
return invoke(std::move(instance), arguments, sizeof...(Args));
}
/*! @copydoc meta_data::prop */
@@ -1239,13 +1254,12 @@ public:
* doesn't refer to a pointer type.
*/
[[nodiscard]] meta_type remove_pointer() const noexcept {
return {*ctx, node.remove_pointer(internal::meta_context::from(*ctx))};
return {*ctx, node.remove_pointer(internal::meta_context::from(*ctx))}; // NOLINT
}
/**
* @brief Checks whether a type is a pointer-like type or not.
* @return True if the underlying type is a pointer-like one, false
* otherwise.
* @return True if the underlying type is pointer-like, false otherwise.
*/
[[nodiscard]] bool is_pointer_like() const noexcept {
return static_cast<bool>(node.traits & internal::meta_traits::is_meta_pointer_like);
@@ -1302,6 +1316,25 @@ public:
return index < template_arity() ? meta_type{*ctx, node.templ.arg(internal::meta_context::from(*ctx), index)} : meta_type{};
}
/**
* @brief Checks if a type supports direct casting to another type.
* @param other The meta type to test for.
* @return True if direct casting is allowed, false otherwise.
*/
[[nodiscard]] bool can_cast(const meta_type &other) const noexcept {
// casting this is UB in all cases but we aren't going to use the resulting pointer, so...
return (internal::try_cast(internal::meta_context::from(*ctx), node, other.node, this) != nullptr);
}
/**
* @brief Checks if a type supports conversion it to another type.
* @param other The meta type to test for.
* @return True if the conversion is allowed, false otherwise.
*/
[[nodiscard]] bool can_convert(const meta_type &other) const noexcept {
return (internal::try_convert(internal::meta_context::from(*ctx), node, other.info(), other.is_arithmetic() || other.is_enum(), nullptr, [](const void *, auto &&...args) { return ((static_cast<void>(args), 1) + ... + 0u); }) != 0u);
}
/**
* @brief Returns a range to visit registered top-level base meta types.
* @return An iterable range to visit registered top-level base meta types.
@@ -1326,19 +1359,8 @@ public:
* @return The registered meta data for the given identifier, if any.
*/
[[nodiscard]] meta_data data(const id_type id) const {
if(node.details) {
if(const auto it = node.details->data.find(id); it != node.details->data.cend()) {
return meta_data{*ctx, it->second};
}
}
for(auto &&curr: base()) {
if(auto elem = curr.second.data(id); elem) {
return elem;
}
}
return meta_data{};
const auto *elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), node, id);
return elem ? meta_data{*ctx, *elem} : meta_data{};
}
/**
@@ -1353,36 +1375,21 @@ public:
/**
* @brief Lookup utility for meta functions (bases are also visited).
*
* In case of overloaded functions, the first one with the required
* identifier is returned.
* In case of overloaded functions, a random one is returned.
*
* @param id Unique identifier.
* @return The registered meta function for the given identifier, if any.
*/
[[nodiscard]] meta_func func(const id_type id) const {
if(node.details) {
if(const auto it = node.details->func.find(id); it != node.details->func.cend()) {
return meta_func{*ctx, it->second};
}
}
for(auto &&curr: base()) {
if(auto elem = curr.second.func(id); elem) {
return elem;
}
}
return meta_func{};
const auto *elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), node, id);
return elem ? meta_func{*ctx, *elem} : meta_func{};
}
/**
* @brief Creates an instance of the underlying type, if possible.
*
* If suitable, the implicitly generated default constructor is used.
*
* @warning
* The context of the arguments is **not** changed.<br/>
* It's up to the caller to bind them to the right context(s).
* The context of the arguments is **never** changed.
*
* @param args Parameters to use to construct the instance.
* @param sz Number of parameters to use to construct the instance.
@@ -1410,12 +1417,8 @@ public:
*/
template<typename... Args>
[[nodiscard]] meta_any construct(Args &&...args) const {
if constexpr(sizeof...(Args) == 0u) {
return construct(static_cast<meta_any *>(nullptr), size_type{});
} else {
meta_any arguments[sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
return construct(arguments, sizeof...(Args));
}
meta_any arguments[sizeof...(Args) + !sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
return construct(arguments, sizeof...(Args));
}
/**
@@ -1436,8 +1439,7 @@ public:
* @brief Invokes a function given an identifier, if possible.
*
* @warning
* The context of the arguments is **not** changed.<br/>
* It's up to the caller to bind them to the right context(s).
* The context of the arguments is **never** changed.
*
* @param id Unique identifier.
* @param instance An opaque instance of the underlying type.
@@ -1465,7 +1467,6 @@ public:
/**
* @copybrief invoke
*
* @param id Unique identifier.
* @tparam Args Types of arguments to use to invoke the function.
* @param instance An opaque instance of the underlying type.
@@ -1474,12 +1475,8 @@ public:
*/
template<typename... Args>
meta_any invoke(const id_type id, meta_handle instance, Args &&...args) const {
if constexpr(sizeof...(Args) == 0u) {
return invoke(id, std::move(instance), static_cast<meta_any *>(nullptr), size_type{});
} else {
meta_any arguments[sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
return invoke(id, std::move(instance), arguments, sizeof...(Args));
}
meta_any arguments[sizeof...(Args) + !sizeof...(Args)]{{*ctx, std::forward<Args>(args)}...};
return invoke(id, std::move(instance), arguments, sizeof...(Args));
}
/**
@@ -1522,19 +1519,8 @@ public:
* @return The registered meta property for the given key, if any.
*/
[[nodiscard]] meta_prop prop(const id_type key) const {
if(node.details) {
if(const auto it = node.details->prop.find(key); it != node.details->prop.cend()) {
return meta_prop{*ctx, it->second};
}
}
for(auto &&curr: base()) {
if(auto elem = curr.second.prop(key); elem) {
return elem;
}
}
return meta_prop{};
const auto *elem = internal::look_for<&internal::meta_type_descriptor::prop>(internal::meta_context::from(*ctx), node, key);
return elem ? meta_prop{*ctx, *elem} : meta_prop{};
}
/**
@@ -1593,39 +1579,27 @@ bool meta_any::set(const id_type id, Type &&value) {
}
[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const {
if(node.info && *node.info == type.info()) {
return as_ref();
}
if(const auto *value = data(); node.details) {
if(auto it = node.details->conv.find(type.info().hash()); it != node.details->conv.cend()) {
return it->second.conv(*ctx, data());
return internal::try_convert(internal::meta_context::from(*ctx), node, type.info(), type.is_arithmetic() || type.is_enum(), data(), [this, &type]([[maybe_unused]] const void *instance, auto &&...args) {
if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, internal::meta_type_node> || ...)) {
return (args.from_void(*ctx, nullptr, instance), ...);
} else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, internal::meta_conv_node> || ...)) {
return (args.conv(*ctx, instance), ...);
} else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<decltype(args)>>, decltype(internal::meta_type_node::conversion_helper)> || ...)) {
// exploits the fact that arithmetic types and enums are also default constructible
auto other = type.construct();
const auto value = (args(nullptr, instance), ...);
other.node.conversion_helper(other.data(), &value);
return other;
} else {
// forwards to force a compile-time error in case of available arguments
return meta_any{meta_ctx_arg, *ctx, std::forward<decltype(args)>(args)...};
}
for(auto &&curr: node.details->base) {
const auto &as_const = curr.second.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.second.cast(value));
if(auto other = as_const.allow_cast(type); other) {
return other;
}
}
}
if(node.conversion_helper && (type.is_arithmetic() || type.is_enum())) {
// exploits the fact that arithmetic types and enums are also default constructible
auto other = type.construct();
ENTT_ASSERT(other.node.conversion_helper, "Conversion helper not found");
const auto value = node.conversion_helper(nullptr, storage.data());
other.node.conversion_helper(other.storage.data(), &value);
return other;
}
return meta_any{meta_ctx_arg, *ctx};
});
}
inline bool meta_any::assign(const meta_any &other) {
auto value = other.allow_cast({*ctx, node});
return value && storage.assign(std::move(value.storage));
return value && storage.assign(value.storage);
}
inline bool meta_any::assign(meta_any &&other) {
@@ -1652,33 +1626,14 @@ inline bool meta_any::assign(meta_any &&other) {
return index < arity() ? node->arg(*ctx, index) : meta_type{};
}
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
class meta_sequence_container::meta_iterator final {
friend class meta_sequence_container;
enum class operation : std::uint8_t {
incr,
deref
};
using vtable_type = void(const operation, const any &, const std::ptrdiff_t, meta_any *);
using vtable_type = void(const void *, const std::ptrdiff_t, meta_any *);
template<typename It>
static void basic_vtable(const operation op, const any &value, const std::ptrdiff_t offset, meta_any *other) {
switch(op) {
case operation::incr: {
auto &it = any_cast<It &>(const_cast<any &>(value));
it = std::next(it, offset);
} break;
case operation::deref: {
const auto &it = any_cast<const It &>(value);
other->emplace<decltype(*it)>(*it);
} break;
}
static void basic_vtable(const void *value, const std::ptrdiff_t offset, meta_any *other) {
const auto &it = *static_cast<const It *>(value);
other ? other->emplace<decltype(*it)>(*it) : std::advance(const_cast<It &>(it), offset);
}
public:
@@ -1687,43 +1642,45 @@ public:
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::bidirectional_iterator_tag;
constexpr meta_iterator() noexcept
: ctx{},
vtable{},
handle{} {}
meta_iterator() noexcept
: meta_iterator{locator<meta_ctx>::value_or()} {}
meta_iterator(const meta_ctx &area) noexcept
: ctx{&area} {}
template<typename It>
explicit meta_iterator(const meta_ctx &area, It iter) noexcept
meta_iterator(const meta_ctx &area, It iter) noexcept
: ctx{&area},
vtable{&basic_vtable<It>},
handle{iter} {}
meta_iterator &operator++() noexcept {
vtable(operation::incr, handle, 1, nullptr);
vtable(handle.data(), 1, nullptr);
return *this;
}
meta_iterator operator++(int value) noexcept {
meta_iterator orig = *this;
vtable(operation::incr, handle, ++value, nullptr);
vtable(handle.data(), ++value, nullptr);
return orig;
}
meta_iterator &operator--() noexcept {
vtable(operation::incr, handle, -1, nullptr);
vtable(handle.data(), -1, nullptr);
return *this;
}
meta_iterator operator--(int value) noexcept {
meta_iterator orig = *this;
vtable(operation::incr, handle, --value, nullptr);
vtable(handle.data(), --value, nullptr);
return orig;
}
[[nodiscard]] reference operator*() const {
reference other{meta_ctx_arg, *ctx};
vtable(operation::deref, handle, 0, &other);
vtable(handle.data(), 0, &other);
return other;
}
@@ -1743,35 +1700,30 @@ public:
return !(*this == other);
}
[[nodiscard]] const any &base() const noexcept {
return handle;
}
private:
const meta_ctx *ctx;
vtable_type *vtable;
any handle;
const meta_ctx *ctx{};
vtable_type *vtable{};
any handle{};
};
class meta_associative_container::meta_iterator final {
enum class operation : std::uint8_t {
incr,
deref
};
using vtable_type = void(const operation, const any &, std::pair<meta_any, meta_any> *);
using vtable_type = void(const void *, std::pair<meta_any, meta_any> *);
template<bool KeyOnly, typename It>
static void basic_vtable(const operation op, const any &value, std::pair<meta_any, meta_any> *other) {
switch(op) {
case operation::incr:
++any_cast<It &>(const_cast<any &>(value));
break;
case operation::deref:
const auto &it = any_cast<const It &>(value);
static void basic_vtable(const void *value, std::pair<meta_any, meta_any> *other) {
if(const auto &it = *static_cast<const It *>(value); other) {
if constexpr(KeyOnly) {
other->first.emplace<decltype(*it)>(*it);
} else {
other->first.emplace<decltype((it->first))>(it->first);
other->second.emplace<decltype((it->second))>(it->second);
}
break;
} else {
++const_cast<It &>(it);
}
}
@@ -1781,31 +1733,34 @@ public:
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
constexpr meta_iterator() noexcept
: ctx{},
vtable{},
handle{} {}
meta_iterator() noexcept
: meta_iterator{locator<meta_ctx>::value_or()} {}
meta_iterator(const meta_ctx &area) noexcept
: ctx{&area} {}
template<bool KeyOnly, typename It>
meta_iterator(const meta_ctx &area, std::integral_constant<bool, KeyOnly>, It iter) noexcept
meta_iterator(const meta_ctx &area, std::bool_constant<KeyOnly>, It iter) noexcept
: ctx{&area},
vtable{&basic_vtable<KeyOnly, It>},
handle{iter} {}
meta_iterator &operator++() noexcept {
vtable(operation::incr, handle, nullptr);
vtable(handle.data(), nullptr);
return *this;
}
meta_iterator operator++(int) noexcept {
meta_iterator orig = *this;
return ++(*this), orig;
vtable(handle.data(), nullptr);
return orig;
}
[[nodiscard]] reference operator*() const {
reference other{{meta_ctx_arg, *ctx}, {meta_ctx_arg, *ctx}};
vtable(operation::deref, handle, &other);
vtable(handle.data(), &other);
return other;
}
@@ -1826,15 +1781,11 @@ public:
}
private:
const meta_ctx *ctx;
vtable_type *vtable;
any handle;
const meta_ctx *ctx{};
vtable_type *vtable{};
any handle{};
};
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Returns the meta value type of a container.
@@ -1849,7 +1800,7 @@ private:
* @return The size of the container.
*/
[[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const noexcept {
return size_fn(storage);
return size_fn(data);
}
/**
@@ -1858,7 +1809,7 @@ private:
* @return True in case of success, false otherwise.
*/
inline bool meta_sequence_container::resize(const size_type sz) {
return resize_fn(storage, sz);
return !const_only && resize_fn(const_cast<void *>(data), sz);
}
/**
@@ -1866,7 +1817,16 @@ inline bool meta_sequence_container::resize(const size_type sz) {
* @return True in case of success, false otherwise.
*/
inline bool meta_sequence_container::clear() {
return resize_fn(storage, 0u);
return !const_only && clear_fn(const_cast<void *>(data));
}
/**
* @brief Reserves storage for at least the given number of elements.
* @param sz The new capacity of the container.
* @return True in case of success, false otherwise.
*/
inline bool meta_sequence_container::reserve(const size_type sz) {
return !const_only && reserve_fn(const_cast<void *>(data), sz);
}
/**
@@ -1874,7 +1834,7 @@ inline bool meta_sequence_container::clear() {
* @return An iterator to the first element of the container.
*/
[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() {
return iter_fn(*ctx, storage, false);
return begin_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
}
/**
@@ -1882,7 +1842,7 @@ inline bool meta_sequence_container::clear() {
* @return An iterator that is past the last element of the container.
*/
[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() {
return iter_fn(*ctx, storage, true);
return end_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
}
/**
@@ -1892,7 +1852,13 @@ inline bool meta_sequence_container::clear() {
* @return A possibly invalid iterator to the inserted element.
*/
inline meta_sequence_container::iterator meta_sequence_container::insert(iterator it, meta_any value) {
return insert_or_erase_fn(*ctx, storage, it.handle, value);
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
if(const auto vtype = value_type_node(internal::meta_context::from(*ctx)); !const_only && (value.allow_cast({*ctx, vtype}) || value.allow_cast({*ctx, const_reference_node(internal::meta_context::from(*ctx))}))) {
const bool is_value_type = (value.type().info() == *vtype.info);
return insert_fn(*ctx, const_cast<void *>(data), is_value_type ? std::as_const(value).data() : nullptr, is_value_type ? nullptr : std::as_const(value).data(), it);
}
return iterator{*ctx};
}
/**
@@ -1901,7 +1867,7 @@ inline meta_sequence_container::iterator meta_sequence_container::insert(iterato
* @return A possibly invalid iterator following the last removed element.
*/
inline meta_sequence_container::iterator meta_sequence_container::erase(iterator it) {
return insert(it, {});
return const_only ? iterator{*ctx} : erase_fn(*ctx, const_cast<void *>(data), it);
}
/**
@@ -1921,15 +1887,15 @@ inline meta_sequence_container::iterator meta_sequence_container::erase(iterator
* @return False if the proxy is invalid, true otherwise.
*/
[[nodiscard]] inline meta_sequence_container::operator bool() const noexcept {
return static_cast<bool>(storage);
return (data != nullptr);
}
/**
* @brief Returns true if a container is also key-only, false otherwise.
* @return True if the associative container is also key-only, false otherwise.
*/
[[nodiscard]] inline bool meta_associative_container::key_only() const noexcept {
return key_only_container;
[[deprecated("use mapped_type() instead")]] [[nodiscard]] inline bool meta_associative_container::key_only() const noexcept {
return (mapped_type_node == nullptr);
}
/**
@@ -1955,42 +1921,39 @@ inline meta_sequence_container::iterator meta_sequence_container::erase(iterator
/*! @copydoc meta_sequence_container::size */
[[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const noexcept {
return size_fn(storage);
return size_fn(data);
}
/*! @copydoc meta_sequence_container::clear */
inline bool meta_associative_container::clear() {
return clear_fn(storage);
return !const_only && clear_fn(const_cast<void *>(data));
}
/*! @copydoc meta_sequence_container::reserve */
inline bool meta_associative_container::reserve(const size_type sz) {
return !const_only && reserve_fn(const_cast<void *>(data), sz);
}
/*! @copydoc meta_sequence_container::begin */
[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() {
return iter_fn(*ctx, storage, false);
return begin_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
}
/*! @copydoc meta_sequence_container::end */
[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() {
return iter_fn(*ctx, storage, true);
return end_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data);
}
/**
* @brief Inserts a key only element into a container.
* @brief Inserts a key-only or key/value element into a container.
* @param key The key of the element to insert.
* @param value The value of the element to insert, if needed.
* @return A bool denoting whether the insertion took place.
*/
inline bool meta_associative_container::insert(meta_any key) {
meta_any value{*ctx, std::in_place_type<void>};
return (insert_or_erase_fn(storage, key, value) != 0u);
}
/**
* @brief Inserts a key/value element into a container.
* @param key The key of the element to insert.
* @param value The value of the element to insert.
* @return A bool denoting whether the insertion took place.
*/
inline bool meta_associative_container::insert(meta_any key, meta_any value) {
return (insert_or_erase_fn(storage, key, value) != 0u);
inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) {
return !const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})
&& (!mapped_type_node || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))}))
&& insert_fn(const_cast<void *>(data), std::as_const(key).data(), std::as_const(value).data());
}
/**
@@ -1999,7 +1962,7 @@ inline bool meta_associative_container::insert(meta_any key, meta_any value) {
* @return A bool denoting whether the removal took place.
*/
inline meta_associative_container::size_type meta_associative_container::erase(meta_any key) {
return insert(std::move(key), meta_any{meta_ctx_arg, *ctx});
return (!const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(const_cast<void *>(data), std::as_const(key).data()) : 0u;
}
/**
@@ -2008,7 +1971,7 @@ inline meta_associative_container::size_type meta_associative_container::erase(m
* @return An iterator to the element with the given key, if any.
*/
[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) {
return find_fn(*ctx, storage, key);
return key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) ? find_fn(*ctx, const_only ? nullptr : const_cast<void *>(data), data, std::as_const(key).data()) : iterator{*ctx};
}
/**
@@ -2016,7 +1979,7 @@ inline meta_associative_container::size_type meta_associative_container::erase(m
* @return False if the proxy is invalid, true otherwise.
*/
[[nodiscard]] inline meta_associative_container::operator bool() const noexcept {
return static_cast<bool>(storage);
return (data != nullptr);
}
} // namespace entt

View File

@@ -22,11 +22,7 @@ class meta_any;
class meta_type;
struct meta_handle;
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
enum class meta_traits : std::uint32_t {
@@ -131,6 +127,23 @@ struct meta_type_node {
std::shared_ptr<meta_type_descriptor> details{};
};
template<auto Member>
auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id) {
if(node.details) {
if(const auto it = (node.details.get()->*Member).find(id); it != (node.details.get()->*Member).cend()) {
return &it->second;
}
for(auto &&curr: node.details->base) {
if(auto *elem = look_for<Member>(context, curr.second.type(context), id); elem) {
return elem;
}
}
}
return static_cast<typename std::remove_reference_t<decltype(node.details.get()->*Member)>::mapped_type *>(nullptr);
}
template<typename Type>
meta_type_node resolve(const meta_context &) noexcept;
@@ -159,6 +172,31 @@ template<typename... Args>
return nullptr;
}
template<typename Func>
[[nodiscard]] inline auto try_convert(const meta_context &context, const meta_type_node &from, const type_info &to, const bool arithmetic_or_enum, const void *instance, Func func) {
if(from.info && *from.info == to) {
return func(instance, from);
}
if(from.details) {
if(auto it = from.details->conv.find(to.hash()); it != from.details->conv.cend()) {
return func(instance, it->second);
}
for(auto &&curr: from.details->base) {
if(auto other = try_convert(context, curr.second.type(context), to, arithmetic_or_enum, curr.second.cast(instance), func); other) {
return other;
}
}
}
if(from.conversion_helper && arithmetic_or_enum) {
return func(instance, from.conversion_helper);
}
return func(instance);
}
[[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
const auto it = context.value.find(info.hash());
return it != context.value.end() ? &it->second : nullptr;
@@ -204,7 +242,7 @@ template<typename Type>
};
}
if constexpr(!std::is_same_v<Type, void> && !std::is_function_v<Type>) {
if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
node.from_void = +[](const meta_ctx &ctx, void *element, const void *as_const) {
if(element) {
return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *static_cast<std::decay_t<Type> *>(element)};
@@ -225,11 +263,7 @@ template<typename Type>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
} // namespace entt

View File

@@ -7,58 +7,34 @@ namespace entt {
/*! @brief Empty class type used to request the _as ref_ policy. */
struct as_ref_t final {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
template<typename Type>
static constexpr bool value = std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>;
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
};
/*! @brief Empty class type used to request the _as cref_ policy. */
struct as_cref_t final {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
template<typename Type>
static constexpr bool value = std::is_reference_v<Type>;
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
};
/*! @brief Empty class type used to request the _as-is_ policy. */
struct as_is_t final {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
template<typename>
static constexpr bool value = true;
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
};
/*! @brief Empty class type used to request the _as void_ policy. */
struct as_void_t final {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
template<typename>
static constexpr bool value = true;
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
};
/**

View File

@@ -10,11 +10,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type, typename It>
@@ -24,6 +20,7 @@ struct meta_range_iterator final {
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
constexpr meta_range_iterator() noexcept
: it{},
@@ -131,11 +128,7 @@ template<typename... Args>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Iterable range to use to iterate all types of meta objects.

View File

@@ -313,16 +313,12 @@ template<typename Type, auto Data, typename Policy = as_is_t>
return meta_getter<Type, Data, Policy>(locator<meta_ctx>::value_or(), std::move(instance));
}
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Policy, typename Candidate, typename... Args>
[[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) {
if constexpr(std::is_same_v<decltype(std::invoke(std::forward<Candidate>(candidate), args...)), void>) {
if constexpr(std::is_void_v<decltype(std::invoke(std::forward<Candidate>(candidate), args...))>) {
std::invoke(std::forward<Candidate>(candidate), args...);
return meta_any{ctx, std::in_place_type<void>};
} else {
@@ -339,7 +335,7 @@ template<typename Type, typename Policy, typename Candidate, std::size_t... Inde
return meta_invoke_with_args<Policy>(ctx, std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
} else if constexpr(std::is_invocable_v<std::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
if(auto *const clazz = instance->try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) { // NOLINT
return meta_invoke_with_args<Policy>(ctx, std::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
} else {
@@ -361,11 +357,7 @@ template<typename Type, typename... Args, std::size_t... Index>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Tries to _invoke_ an object given a list of erased parameters.

View File

@@ -1,11 +1,7 @@
#ifndef ENTT_PLATFORM_ANDROID_NDK_R17_HPP
#define ENTT_PLATFORM_ANDROID_NDK_R17_HPP
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
#ifdef __ANDROID__
# include <android/ndk-version.h>
# if __NDK_MAJOR__ == 17
@@ -58,10 +54,6 @@ using invoke_result_t = typename std::invoke_result<Func, Args...>::type;
# endif
#endif
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
#endif

View File

@@ -190,7 +190,6 @@ decltype(auto) poly_call(Poly &&self, Args &&...args) {
*/
template<typename Concept, std::size_t Len, std::size_t Align>
class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, Len, Align>>> {
/*! @brief A poly base is allowed to snoop into a poly object. */
friend struct poly_base<basic_poly>;
public:

View File

@@ -2,13 +2,14 @@
#define ENTT_PROCESS_FWD_HPP
#include <cstdint>
#include <memory>
namespace entt {
template<typename, typename>
class process;
template<typename = std::uint32_t>
template<typename = std::uint32_t, typename = std::allocator<void>>
class basic_scheduler;
/*! @brief Alias declaration for the most common use case. */

View File

@@ -4,6 +4,7 @@
#include <cstdint>
#include <type_traits>
#include <utility>
#include "fwd.hpp"
namespace entt {
@@ -175,13 +176,13 @@ public:
* The function is idempotent and it does nothing if the process isn't
* alive.
*
* @param immediately Requests an immediate operation.
* @param immediate Requests an immediate operation.
*/
void abort(const bool immediately = false) {
void abort(const bool immediate = false) {
if(alive()) {
current = state::aborted;
if(immediately) {
if(immediate) {
tick({});
}
}

View File

@@ -1,17 +1,56 @@
#ifndef ENTT_PROCESS_SCHEDULER_HPP
#define ENTT_PROCESS_SCHEDULER_HPP
#include <algorithm>
#include <iterator>
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/compressed_pair.hpp"
#include "fwd.hpp"
#include "process.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Delta>
struct basic_process_handler {
virtual ~basic_process_handler() = default;
virtual bool update(const Delta, void *) = 0;
virtual void abort(const bool) = 0;
// std::shared_ptr because of its type erased allocator which is useful here
std::shared_ptr<basic_process_handler> next;
};
template<typename Delta, typename Type>
struct process_handler final: basic_process_handler<Delta> {
template<typename... Args>
process_handler(Args &&...args)
: process{std::forward<Args>(args)...} {}
bool update(const Delta delta, void *data) override {
if(process.tick(delta, data); process.rejected()) {
this->next.reset();
}
return (process.rejected() || process.finished());
}
void abort(const bool immediate) override {
process.abort(immediate);
}
Type process;
};
} // namespace internal
/*! @endcond */
/**
* @brief Cooperative scheduler for processes.
*
@@ -37,95 +76,90 @@ namespace entt {
* @sa process
*
* @tparam Delta Type to use to provide elapsed time.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Delta>
template<typename Delta, typename Allocator>
class basic_scheduler {
struct process_handler {
using instance_type = std::unique_ptr<void, void (*)(void *)>;
using update_fn_type = bool(basic_scheduler &, std::size_t, Delta, void *);
using abort_fn_type = void(basic_scheduler &, std::size_t, bool);
using next_type = std::unique_ptr<process_handler>;
template<typename Type>
using handler_type = internal::process_handler<Delta, Type>;
instance_type instance;
update_fn_type *update;
abort_fn_type *abort;
next_type next;
};
// std::shared_ptr because of its type erased allocator which is useful here
using process_type = std::shared_ptr<internal::basic_process_handler<Delta>>;
struct continuation {
continuation(process_handler *ref) noexcept
: handler{ref} {}
template<typename Proc, typename... Args>
continuation then(Args &&...args) {
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
auto proc = typename process_handler::instance_type{new Proc{std::forward<Args>(args)...}, &basic_scheduler::deleter<Proc>};
handler->next.reset(new process_handler{std::move(proc), &basic_scheduler::update<Proc>, &basic_scheduler::abort<Proc>, nullptr});
handler = handler->next.get();
return *this;
}
template<typename Func>
continuation then(Func &&func) {
return then<process_adaptor<std::decay_t<Func>, Delta>>(std::forward<Func>(func));
}
private:
process_handler *handler;
};
template<typename Proc>
[[nodiscard]] static bool update(basic_scheduler &owner, std::size_t pos, const Delta delta, void *data) {
auto *process = static_cast<Proc *>(owner.handlers[pos].instance.get());
process->tick(delta, data);
if(process->rejected()) {
return true;
} else if(process->finished()) {
if(auto &&handler = owner.handlers[pos]; handler.next) {
handler = std::move(*handler.next);
// forces the process to exit the uninitialized state
return handler.update(owner, pos, {}, nullptr);
}
return true;
}
return false;
}
template<typename Proc>
static void abort(basic_scheduler &owner, std::size_t pos, const bool immediately) {
static_cast<Proc *>(owner.handlers[pos].instance.get())->abort(immediately);
}
template<typename Proc>
static void deleter(void *proc) {
delete static_cast<Proc *>(proc);
}
using alloc_traits = std::allocator_traits<Allocator>;
using container_allocator = typename alloc_traits::template rebind_alloc<process_type>;
using container_type = std::vector<process_type, container_allocator>;
public:
/*! @brief Unsigned integer type. */
using delta_type = Delta;
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Unsigned integer type. */
using delta_type = Delta;
/*! @brief Default constructor. */
basic_scheduler()
: handlers{} {}
: basic_scheduler{allocator_type{}} {}
/*! @brief Default move constructor. */
basic_scheduler(basic_scheduler &&) = default;
/**
* @brief Constructs a scheduler with a given allocator.
* @param allocator The allocator to use.
*/
explicit basic_scheduler(const allocator_type &allocator)
: handlers{allocator, allocator} {}
/*! @brief Default move assignment operator. @return This scheduler. */
basic_scheduler &operator=(basic_scheduler &&) = default;
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_scheduler(basic_scheduler &&other) noexcept
: handlers{std::move(other.handlers)} {}
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
basic_scheduler(basic_scheduler &&other, const allocator_type &allocator) noexcept
: handlers{container_type{std::move(other.handlers.first()), allocator}, allocator} {
ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying a scheduler is not allowed");
}
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This scheduler.
*/
basic_scheduler &operator=(basic_scheduler &&other) noexcept {
ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying a scheduler is not allowed");
handlers = std::move(other.handlers);
return *this;
}
/**
* @brief Exchanges the contents with those of a given scheduler.
* @param other Scheduler to exchange the content with.
*/
void swap(basic_scheduler &other) {
using std::swap;
swap(handlers, other.handlers);
}
/**
* @brief Returns the associated allocator.
* @return The associated allocator.
*/
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
return handlers.second();
}
/**
* @brief Number of processes currently scheduled.
* @return Number of processes currently scheduled.
*/
[[nodiscard]] size_type size() const noexcept {
return handlers.size();
return handlers.first().size();
}
/**
@@ -133,7 +167,7 @@ public:
* @return True if there are scheduled processes, false otherwise.
*/
[[nodiscard]] bool empty() const noexcept {
return handlers.empty();
return handlers.first().empty();
}
/**
@@ -143,15 +177,15 @@ public:
* and never executed again.
*/
void clear() {
handlers.clear();
handlers.first().clear();
}
/**
* @brief Schedules a process for the next tick.
*
* Returned value is an opaque object that can be used to attach a child to
* the given process. The child is automatically scheduled when the process
* terminates and only if the process returns with success.
* Returned value can be used to attach a continuation for the last process.
* The continutation is scheduled automatically when the process terminates
* and only if the process returns with success.
*
* Example of use (pseudocode):
*
@@ -169,16 +203,15 @@ public:
* @tparam Proc Type of process to schedule.
* @tparam Args Types of arguments to use to initialize the process.
* @param args Parameters to use to initialize the process.
* @return An opaque object to use to concatenate processes.
* @return This process scheduler.
*/
template<typename Proc, typename... Args>
auto attach(Args &&...args) {
basic_scheduler &attach(Args &&...args) {
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
auto proc = typename process_handler::instance_type{new Proc{std::forward<Args>(args)...}, &basic_scheduler::deleter<Proc>};
auto &&ref = handlers.emplace_back(process_handler{std::move(proc), &basic_scheduler::update<Proc>, &basic_scheduler::abort<Proc>, nullptr});
auto &ref = handlers.first().emplace_back(std::allocate_shared<handler_type<Proc>>(handlers.second(), std::forward<Args>(args)...));
// forces the process to exit the uninitialized state
ref.update(*this, handlers.size() - 1u, {}, nullptr);
return continuation{&handlers.back()};
ref->update({}, nullptr);
return *this;
}
/**
@@ -207,9 +240,9 @@ public:
* void();
* @endcode
*
* Returned value is an opaque object that can be used to attach a child to
* the given process. The child is automatically scheduled when the process
* terminates and only if the process returns with success.
* Returned value can be used to attach a continuation for the last process.
* The continutation is scheduled automatically when the process terminates
* and only if the process returns with success.
*
* Example of use (pseudocode):
*
@@ -230,14 +263,43 @@ public:
*
* @tparam Func Type of process to schedule.
* @param func Either a lambda or a functor to use as a process.
* @return An opaque object to use to concatenate processes.
* @return This process scheduler.
*/
template<typename Func>
auto attach(Func &&func) {
basic_scheduler &attach(Func &&func) {
using Proc = process_adaptor<std::decay_t<Func>, Delta>;
return attach<Proc>(std::forward<Func>(func));
}
/**
* @brief Sets a process as a continuation of the last scheduled process.
* @tparam Proc Type of process to use as a continuation.
* @tparam Args Types of arguments to use to initialize the process.
* @param args Parameters to use to initialize the process.
* @return This process scheduler.
*/
template<typename Proc, typename... Args>
basic_scheduler &then(Args &&...args) {
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
ENTT_ASSERT(!handlers.first().empty(), "Process not available");
auto *curr = handlers.first().back().get();
for(; curr->next; curr = curr->next.get()) {}
curr->next = std::allocate_shared<handler_type<Proc>>(handlers.second(), std::forward<Args>(args)...);
return *this;
}
/**
* @brief Sets a process as a continuation of the last scheduled process.
* @tparam Func Type of process to use as a continuation.
* @param func Either a lambda or a functor to use as a process.
* @return This process scheduler.
*/
template<typename Func>
basic_scheduler &then(Func &&func) {
using Proc = process_adaptor<std::decay_t<Func>, Delta>;
return then<Proc>(std::forward<Func>(func));
}
/**
* @brief Updates all scheduled processes.
*
@@ -250,12 +312,17 @@ public:
* @param data Optional data.
*/
void update(const delta_type delta, void *data = nullptr) {
for(auto pos = handlers.size(); pos; --pos) {
const auto curr = pos - 1u;
if(const auto dead = handlers[curr].update(*this, curr, delta, data); dead) {
std::swap(handlers[curr], handlers.back());
handlers.pop_back();
for(auto next = handlers.first().size(); next; --next) {
if(const auto pos = next - 1u; handlers.first()[pos]->update(delta, data)) {
// updating might spawn/reallocate, cannot hold refs until here
if(auto &curr = handlers.first()[pos]; curr->next) {
curr = std::move(curr->next);
// forces the process to exit the uninitialized state
curr->update({}, nullptr);
} else {
curr = std::move(handlers.first().back());
handlers.first().pop_back();
}
}
}
}
@@ -268,17 +335,16 @@ public:
* Once a process is fully aborted and thus finished, it's discarded along
* with its child, if any.
*
* @param immediately Requests an immediate operation.
* @param immediate Requests an immediate operation.
*/
void abort(const bool immediately = false) {
for(auto pos = handlers.size(); pos; --pos) {
const auto curr = pos - 1u;
handlers[curr].abort(*this, curr, immediately);
void abort(const bool immediate = false) {
for(auto &&curr: handlers.first()) {
curr->abort(immediate);
}
}
private:
std::vector<process_handler> handlers{};
compressed_pair<container_type, allocator_type> handlers;
};
} // namespace entt

View File

@@ -19,11 +19,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type, typename It>
@@ -37,6 +33,7 @@ public:
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::random_access_iterator_tag;
constexpr resource_cache_iterator() noexcept = default;
@@ -144,11 +141,7 @@ template<typename... Lhs, typename... Rhs>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Basic cache for resources of any type.

View File

@@ -20,7 +20,6 @@ namespace entt {
*/
template<typename Type>
class resource {
/*! @brief Resource handles are friends with each other. */
template<typename>
friend class resource;

View File

@@ -12,11 +12,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Ret, typename... Args>
@@ -43,11 +39,7 @@ template<typename... Class, typename Ret, typename... Args>
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Basic delegate implementation.

View File

@@ -17,11 +17,7 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
struct basic_dispatcher_handler {
@@ -82,7 +78,7 @@ public:
}
}
std::size_t size() const noexcept override {
[[nodiscard]] std::size_t size() const noexcept override {
return events.size();
}
@@ -92,11 +88,7 @@ private:
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Basic dispatcher implementation.
@@ -190,7 +182,6 @@ public:
*/
basic_dispatcher &operator=(basic_dispatcher &&other) noexcept {
ENTT_ASSERT(alloc_traits::is_always_equal::value || pools.second() == other.pools.second(), "Copying a dispatcher is not allowed");
pools = std::move(other.pools);
return *this;
}

View File

@@ -52,7 +52,6 @@ class sigh;
*/
template<typename Ret, typename... Args, typename Allocator>
class sigh<Ret(Args...), Allocator> {
/*! @brief A sink is allowed to modify a signal. */
friend class sink<sigh<Ret(Args...), Allocator>>;
using alloc_traits = std::allocator_traits<Allocator>;
@@ -225,7 +224,6 @@ private:
* the sink that generated it.
*/
class connection {
/*! @brief A sink is allowed to create connection objects. */
template<typename>
friend class sink;

1
test/.bazelrc Normal file
View File

@@ -0,0 +1 @@
import "%workspace%/../.bazelrc"

0
test/BUILD.bazel Normal file
View File

View File

@@ -1,6 +1,4 @@
#
# Tests configuration
#
include(FetchContent)
include(CheckCXXSourceCompiles)
@@ -34,9 +32,16 @@ else()
add_library(GTest::Main ALIAS gtest_main)
target_compile_features(gtest PUBLIC cxx_std_17)
set_target_properties(gtest PROPERTIES CXX_CLANG_TIDY "")
target_compile_features(gtest_main PUBLIC cxx_std_17)
set_target_properties(gtest_main PROPERTIES CXX_CLANG_TIDY "")
target_compile_features(gmock PUBLIC cxx_std_17)
set_target_properties(gmock PROPERTIES CXX_CLANG_TIDY "")
target_compile_features(gmock_main PUBLIC cxx_std_17)
set_target_properties(gmock_main PROPERTIES CXX_CLANG_TIDY "")
endif()
include_directories($<TARGET_PROPERTY:EnTT,INTERFACE_INCLUDE_DIRECTORIES>)
@@ -64,10 +69,20 @@ function(SETUP_TARGET TARGET_NAME)
>
# documentation diagnostic turned on for clang-cl only
$<$<STREQUAL:"${CMAKE_CXX_COMPILER_ID}","Clang">:-Wdocumentation>
# warnings from compilers that think I don't know what I'm doing
$<$<STREQUAL:"${CMAKE_CXX_COMPILER_ID}","Clang">:-Wcomma>
/EHsc /wd4324 /wd4996
$<$<CONFIG:Debug>:/Od>
# disabling INCREMENTAL is required by SizeBench
$<$<CONFIG:Debug>:/Od /INCREMENTAL:NO>
$<$<CONFIG:Release>:/O2>
)
target_link_options(
${TARGET_NAME}
PRIVATE
# disabling INCREMENTAL is required by SizeBench
$<$<CONFIG:Debug>:/INCREMENTAL:NO>
)
else()
target_compile_options(
${TARGET_NAME}
@@ -105,6 +120,7 @@ function(SETUP_BASIC_TEST TEST_NAME TEST_SOURCES)
target_link_libraries(${TEST_NAME} PRIVATE GTest::Main Threads::Threads)
SETUP_TARGET(${TEST_NAME} ${ARGN})
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
set_tests_properties(${TEST_NAME} PROPERTIES TIMEOUT 60)
endfunction()
function(SETUP_LIB_SHARED_TEST TEST_NAME SUB_PATH)
@@ -112,6 +128,7 @@ function(SETUP_LIB_SHARED_TEST TEST_NAME SUB_PATH)
add_library(_${TARGET_NAME} SHARED $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/${SUB_PATH}/lib.cpp)
SETUP_TARGET(_${TARGET_NAME} ENTT_API_EXPORT)
SETUP_BASIC_TEST(lib_${TARGET_NAME} lib/${TEST_NAME}/${SUB_PATH}/main.cpp ENTT_API_IMPORT)
set_target_properties(lib_${TARGET_NAME} PROPERTIES CXX_CLANG_TIDY "")
target_link_libraries(lib_${TARGET_NAME} PRIVATE _${TARGET_NAME})
endfunction()
@@ -120,6 +137,8 @@ function(SETUP_LIB_PLUGIN_TEST TEST_NAME SUB_PATH)
add_library(_${TARGET_NAME} MODULE $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/${SUB_PATH}/plugin.cpp)
SETUP_TARGET(_${TARGET_NAME} ${ARGVN})
SETUP_BASIC_TEST(lib_${TARGET_NAME} lib/${TEST_NAME}/${SUB_PATH}/main.cpp PLUGIN="$<TARGET_FILE:_${TARGET_NAME}>" ${ARGVN})
set_target_properties(_${TARGET_NAME} PROPERTIES CXX_CLANG_TIDY "")
set_target_properties(lib_${TARGET_NAME} PROPERTIES CXX_CLANG_TIDY "")
target_include_directories(_${TARGET_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_include_directories(lib_${TARGET_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_link_libraries(lib_${TARGET_NAME} PRIVATE ${CMAKE_DL_LIBS})
@@ -130,6 +149,7 @@ endfunction()
if(ENTT_BUILD_BENCHMARK)
SETUP_BASIC_TEST(benchmark benchmark/benchmark.cpp)
set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
endif()
# Test example
@@ -137,6 +157,7 @@ endif()
if(ENTT_BUILD_EXAMPLE)
SETUP_BASIC_TEST(custom_identifier example/custom_identifier.cpp)
SETUP_BASIC_TEST(entity_copy example/entity_copy.cpp)
SETUP_BASIC_TEST(reserved_bits example/reserved_bits.cpp)
SETUP_BASIC_TEST(signal_less example/signal_less.cpp)
endif()
@@ -180,7 +201,7 @@ if(ENTT_BUILD_SNAPSHOT)
FetchContent_Declare(
cereal
GIT_REPOSITORY https://github.com/USCiLab/cereal.git
GIT_TAG v1.2.2
GIT_TAG v1.3.2
GIT_SHALLOW 1
)
@@ -192,6 +213,8 @@ if(ENTT_BUILD_SNAPSHOT)
endif()
SETUP_BASIC_TEST(cereal snapshot/snapshot.cpp)
set_target_properties(cereal PROPERTIES CXX_CLANG_TIDY "")
target_include_directories(cereal PRIVATE ${cereal_INCLUDE_DIR})
endif()
@@ -237,6 +260,8 @@ SETUP_BASIC_TEST(snapshot entt/entity/snapshot.cpp)
SETUP_BASIC_TEST(sparse_set entt/entity/sparse_set.cpp)
SETUP_BASIC_TEST(storage entt/entity/storage.cpp)
SETUP_BASIC_TEST(storage_entity entt/entity/storage_entity.cpp)
SETUP_BASIC_TEST(storage_no_instance entt/entity/storage_no_instance.cpp)
SETUP_BASIC_TEST(storage_utility entt/entity/storage_utility.cpp)
SETUP_BASIC_TEST(view entt/entity/view.cpp)
# Test graph

11
test/MODULE.bazel Normal file
View File

@@ -0,0 +1,11 @@
module(name = "entt_test")
bazel_dep(name = "rules_cc", version = "0.0.8")
bazel_dep(name = "bazel_skylib", version = "1.4.2")
bazel_dep(name = "googletest", version = "1.14.0")
bazel_dep(name = "entt")
local_path_override(
module_name = "entt",
path = "..",
)

1
test/WORKSPACE.bazel Normal file
View File

@@ -0,0 +1 @@
# SEE: MODULE.bazel

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
load("@entt//bazel:copts.bzl", "COPTS")
package(default_visibility = ["//:__subpackages__"])
cc_library(
name = "common",
copts = COPTS,
hdrs = glob(["*.h", "*.hpp"]),
)

View File

@@ -0,0 +1,25 @@
#ifndef ENTT_COMMON_AGGREGATE_H
#define ENTT_COMMON_AGGREGATE_H
#include <type_traits>
namespace test {
struct aggregate {
int value{};
};
inline bool operator==(const aggregate &lhs, const aggregate &rhs) {
return lhs.value == rhs.value;
}
inline bool operator<(const aggregate &lhs, const aggregate &rhs) {
return lhs.value < rhs.value;
}
// ensure aggregate-ness :)
static_assert(std::is_aggregate_v<test::aggregate>, "Not an aggregate type");
} // namespace test
#endif

View File

@@ -16,6 +16,11 @@ struct basic_test_allocator: std::allocator<Type> {
using std::allocator<Type>::allocator;
// necessary to avoid a warning by clang-cl :)
basic_test_allocator(const basic_test_allocator &other)
: base{other} {
}
basic_test_allocator &operator=(const basic_test_allocator &other) {
// necessary to avoid call suppression
base::operator=(other);

View File

@@ -0,0 +1,16 @@
#ifndef ENTT_COMMON_BOXED_INT_H
#define ENTT_COMMON_BOXED_INT_H
namespace test {
struct boxed_int {
int value{};
};
inline bool operator==(const boxed_int &lhs, const boxed_int &rhs) {
return lhs.value == rhs.value;
}
} // namespace test
#endif

View File

@@ -5,10 +5,12 @@ namespace test {
#ifdef NDEBUG
# define ENTT_DEBUG_TEST(Case, Test) TEST(Case, DISABLED_##Test)
# define ENTT_DEBUG_TEST_P(Case, Test) TEST_P(Case, DISABLED_##Test)
# define ENTT_DEBUG_TEST_F(Case, Test) TEST_F(Case, DISABLED_##Test)
# define ENTT_DEBUG_TYPED_TEST(Case, Test) TYPED_TEST(Case, DISABLED_##Test)
#else
# define ENTT_DEBUG_TEST(Case, Test) TEST(Case, Test)
# define ENTT_DEBUG_TEST_P(Case, Test) TEST_P(Case, Test)
# define ENTT_DEBUG_TEST_F(Case, Test) TEST_F(Case, Test)
# define ENTT_DEBUG_TYPED_TEST(Case, Test) TYPED_TEST(Case, Test)
#endif

View File

@@ -0,0 +1,12 @@
#ifndef ENTT_COMMON_CUSTOM_ENTITY_H
#define ENTT_COMMON_CUSTOM_ENTITY_H
#include <cstdint>
namespace test {
enum custom_entity : std::uint32_t {};
} // namespace test
#endif

10
test/entt/common/empty.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef ENTT_COMMON_EMPTY_H
#define ENTT_COMMON_EMPTY_H
namespace test {
struct empty {};
} // namespace test
#endif

View File

@@ -0,0 +1,11 @@
#ifndef ENTT_COMMON_LINTER_HPP
#define ENTT_COMMON_LINTER_HPP
namespace test {
template<typename Type>
void is_initialized(Type &) {}
} // namespace test
#endif

View File

@@ -0,0 +1,12 @@
#ifndef ENTT_COMMON_NON_COMPARABLE_H
#define ENTT_COMMON_NON_COMPARABLE_H
namespace test {
struct non_comparable {
bool operator==(const non_comparable &) const = delete;
};
} // namespace test
#endif

View File

@@ -0,0 +1,17 @@
#ifndef ENTT_COMMON_NON_DEFAULT_CONSTRUCTIBLE_H
#define ENTT_COMMON_NON_DEFAULT_CONSTRUCTIBLE_H
namespace test {
struct non_default_constructible {
non_default_constructible() = delete;
non_default_constructible(int v)
: value{v} {}
int value;
};
} // namespace test
#endif

View File

@@ -0,0 +1,20 @@
#ifndef ENTT_COMMON_NON_MOVABLE_H
#define ENTT_COMMON_NON_MOVABLE_H
namespace test {
struct non_movable {
non_movable() = default;
non_movable(const non_movable &) = default;
non_movable(non_movable &&) = delete;
non_movable &operator=(const non_movable &) = default;
non_movable &operator=(non_movable &&) = delete;
int value{};
};
} // namespace test
#endif

View File

@@ -0,0 +1,21 @@
#ifndef ENTT_COMMON_POINTER_STABLE_H
#define ENTT_COMMON_POINTER_STABLE_H
namespace test {
struct pointer_stable {
static constexpr auto in_place_delete = true;
int value{};
};
inline bool operator==(const pointer_stable &lhs, const pointer_stable &rhs) {
return lhs.value == rhs.value;
}
inline bool operator<(const pointer_stable &lhs, const pointer_stable &rhs) {
return lhs.value < rhs.value;
}
} // namespace test
#endif

View File

@@ -2,19 +2,22 @@
#define ENTT_COMMON_THROWING_ALLOCATOR_HPP
#include <cstddef>
#include <limits>
#include <memory>
#include <type_traits>
#include <entt/container/dense_map.hpp>
#include <entt/core/fwd.hpp>
#include <entt/core/type_info.hpp>
namespace test {
struct throwing_allocator_exception {};
template<typename Type>
class throwing_allocator: std::allocator<Type> {
class throwing_allocator {
template<typename Other>
friend class throwing_allocator;
using base = std::allocator<Type>;
struct test_exception {};
public:
using value_type = Type;
using pointer = value_type *;
@@ -23,33 +26,42 @@ public:
using const_void_pointer = const void *;
using propagate_on_container_move_assignment = std::true_type;
using propagate_on_container_swap = std::true_type;
using exception_type = test_exception;
using container_type = entt::dense_map<entt::id_type, std::size_t>;
template<typename Other>
struct rebind {
using other = throwing_allocator<Other>;
};
throwing_allocator() = default;
throwing_allocator()
: allocator{},
config{std::allocate_shared<container_type>(allocator)} {}
template<typename Other>
throwing_allocator(const throwing_allocator<Other> &other)
: base{other} {}
: allocator{other.allocator},
config{other.config} {}
pointer allocate(std::size_t length) {
if(trigger_on_allocate) {
trigger_on_allocate = false;
throw test_exception{};
if(const auto hash = entt::type_id<Type>().hash(); config->contains(hash)) {
if(auto &elem = (*config)[hash]; elem == 0u) {
config->erase(hash);
throw throwing_allocator_exception{};
} else {
--elem;
}
}
trigger_on_allocate = trigger_after_allocate;
trigger_after_allocate = false;
return base::allocate(length);
return allocator.allocate(length);
}
void deallocate(pointer mem, std::size_t length) {
base::deallocate(mem, length);
allocator.deallocate(mem, length);
}
template<typename Other>
void throw_counter(const std::size_t len) {
(*config)[entt::type_id<Other>().hash()] = len;
}
bool operator==(const throwing_allocator<Type> &) const {
@@ -60,8 +72,9 @@ public:
return !(*this == other);
}
static inline bool trigger_on_allocate{};
static inline bool trigger_after_allocate{};
private:
std::allocator<Type> allocator;
std::shared_ptr<container_type> config;
};
} // namespace test

View File

@@ -3,44 +3,40 @@
namespace test {
class throwing_type {
struct test_exception {};
struct throwing_type_exception {};
public:
using exception_type = test_exception;
static constexpr auto moved_from_value = -1;
throwing_type(int value)
: data{value} {}
struct throwing_type {
throwing_type(bool mode)
: trigger{mode} {}
throwing_type(const throwing_type &other)
: data{other.data} {
if(data == trigger_on_value) {
data = moved_from_value;
throw exception_type{};
: trigger{other.trigger} {
if(trigger) {
throw throwing_type_exception{};
}
}
throwing_type &operator=(const throwing_type &other) {
if(other.data == trigger_on_value) {
data = moved_from_value;
throw exception_type{};
}
data = other.data;
trigger = other.trigger;
return *this;
}
operator int() const {
return data;
void throw_on_copy(const bool mode) noexcept {
trigger = mode;
}
static inline int trigger_on_value{};
bool throw_on_copy() const noexcept {
return trigger;
}
private:
int data{};
bool trigger{};
};
inline bool operator==(const throwing_type &lhs, const throwing_type &rhs) {
return lhs.throw_on_copy() == rhs.throw_on_copy();
}
} // namespace test
#endif

Some files were not shown because too many files have changed in this diff Show More