Compare commits

...

2286 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
Michele Caini
cb974bf567 adjacency_matrix: fix in_edges() is off by 1 in some cases (close #1019) 2023-06-13 11:56:56 +02:00
Michele Caini
7b7d82e6f6 doc: snapshot (close #984) 2023-06-12 08:22:13 +02:00
Michele Caini
05c6898fc2 test: self-fixing archive example for snapshot classes 2023-06-12 08:20:32 +02:00
Michele Caini
7ffa459a66 snapshot: drop ::get member template parameter 2023-06-12 08:19:47 +02:00
Michele Caini
93e8e94e60 test: basic continuous loader 2023-06-11 12:52:20 +02:00
Michele Caini
c4e2416621 snapshot: review basic_continuous_loader (and drop shrink) 2023-06-09 09:28:53 +02:00
Michele Caini
9c25419b9a test: more on basic_snapshot_loader 2023-06-09 09:02:42 +02:00
Michele Caini
1879830df1 snapshot: drop pointless assert 2023-06-09 09:01:12 +02:00
Michele Caini
29298c0eb1 test: guarantee code coverage, we'll update the test later on 2023-06-08 10:34:34 +02:00
Michele Caini
247abef1d7 test: rollback for code coverage purposes on the snapshot class 2023-06-08 09:47:40 +02:00
Michele Caini
6994d98d2a test: typo 2023-06-07 17:07:22 +02:00
Michele Caini
9a600ece2d test: snapshot 2023-06-07 15:32:41 +02:00
Michele Caini
f91226ef47 snapshot: share ::orphans implementation (to deprecate in future though) 2023-06-07 09:17:25 +02:00
Michele Caini
e366ffbd30 doc: snapshot 2023-06-07 09:14:14 +02:00
Michele Caini
63b300d39d snapshot: again, dense_map::contains is a thing 2023-06-06 10:18:22 +02:00
Michele Caini
afb70d1570 test: avoid warnings due to unused variables 2023-06-06 10:17:38 +02:00
Michele Caini
49534eec0d snapshot: dense_map::contains is a thing fortunately 2023-06-06 10:14:33 +02:00
Michele Caini
3f1277f7bd snapshot: use the right allocator for the remote-local mapping 2023-06-06 10:10:10 +02:00
Michele Caini
26fad4c385 test: basic snapshot loader 2023-06-06 09:26:34 +02:00
Michele Caini
25b3afacf6 test: basic snapshot 2023-06-06 09:25:56 +02:00
Michele Caini
2d25bbb090 snapshot: check registry type 2023-06-05 16:03:11 +02:00
Michele Caini
0eb834582d snapshot: small cleanup 2023-06-01 14:36:57 +02:00
Michele Caini
124a440527 test: use the new snapshot get functions in the test suite 2023-06-01 10:10:32 +02:00
Michele Caini
5c704636ef test: use the new snapshot get functions in the test suite 2023-06-01 10:10:00 +02:00
Michele Caini
31fd94cc3c snapshot: cleanup to get ready to drop an internal function 2023-05-31 15:16:13 +02:00
Michele Caini
573e43272a snapshot: reduce storage lookups 2023-05-31 15:14:05 +02:00
Michele Caini
1d89434812 snapshot: drop useless function 2023-05-31 15:03:14 +02:00
Michele Caini
e0a1ef7c1b snapshot: check on member type class 2023-05-31 14:44:59 +02:00
Michele Caini
48ac0e0eb4 snapshot: add basic_continuous_loader::get, deprecate ::entities and ::component 2023-05-31 10:04:37 +02:00
Michele Caini
bcb6234d94 snapshot: add basic_snapshot_loader::get, deprecate ::entities and ::component 2023-05-30 15:51:47 +02:00
Michele Caini
f967963264 snapshot: reject entity type in the range-get (now get instead of get_sparse) 2023-05-30 14:23:00 +02:00
Michele Caini
b22c55dd21 doc: typo 2023-05-30 14:21:43 +02:00
Michele Caini
4ff5a536ca snapshot: add basic_snapshot::get, deprecate ::entities and ::component 2023-05-29 14:11:37 +02:00
Michele Caini
fff5f578ac test: avoid using deprecated functions in an example 2023-05-26 15:11:53 +02:00
Michele Caini
0f44c8c923 doc: reflect recent changes 2023-05-26 15:06:34 +02:00
Michele Caini
0b6ad03150 snapshot:
* single element only archive functions required
* avoid iterating elements more than once
2023-05-26 15:00:25 +02:00
Michele Caini
2450b0bc69 test: minor changes (waiting for a rework) 2023-05-26 10:39:54 +02:00
Michele Caini
fc8eebf367 snapshot: use component_traits instead of is_empty_v 2023-05-26 08:49:15 +02:00
Michele Caini
e4f51f2b7f snapshot: avoid multiple lookups of the same storage 2023-05-25 12:04:24 +02:00
Michele Caini
2c2216a89e doc: typo 2023-05-25 11:51:51 +02:00
Michele Caini
cafe851809 snapshot: deprecate multi-type component loading function 2023-05-25 11:50:40 +02:00
Michele Caini
35e338cc99 snapshot: deprecate multi-type component loading function 2023-05-25 11:13:41 +02:00
Michele Caini
8feeaaef7c doc: minor changes 2023-05-25 11:12:51 +02:00
Michele Caini
e7a3c4e370 snapshot: add missing [[deprecate(...)]] 2023-05-24 10:00:38 +02:00
Michele Caini
ea5c558bd4 snapshot: cleanup (waiting for further improvements) 2023-05-24 09:59:46 +02:00
Michele Caini
94f0ed179f snapshot: deprecate multi-type component loading function 2023-05-24 09:54:49 +02:00
Michele Caini
244c359491 snapshot: deprecate multi-type component loading function 2023-05-24 09:47:20 +02:00
Michele Caini
1f24fea21a type_traits: formatting 2023-05-23 14:02:20 +02:00
Michele Caini
8deaa09b24 test: perform static checks at compile-time 2023-05-23 14:00:24 +02:00
Dominic Koepke
85bffb7143 type_traits: std::tuple traits specialization for entt::type_list and entt::value_list (#1011) 2023-05-23 13:56:29 +02:00
Michele Caini
325ca310d3 view: updated ::refresh 2023-05-22 19:10:01 +02:00
Michele Caini
d903e268f0 snapshot: minor changes 2023-05-22 19:03:11 +02:00
Michele Caini
f4b26756c5 snapshot: improved basic_snapshot::component 2023-05-22 18:51:03 +02:00
Michele Caini
fb3a34ee91 *: updated TODO 2023-05-22 18:35:22 +02:00
Michele Caini
6902bb6c41 doc: typo 2023-05-22 17:34:09 +02:00
Michele Caini
379819b2b0 test: cleanup 2023-05-22 16:25:35 +02:00
Michele Caini
59abfbfb5a meta: refine policy check on value types for non-member data 2023-05-19 12:20:21 +02:00
Michele Caini
6e2d871844 registry: avoid casting return types directly to better support empty storage 2023-05-19 12:19:27 +02:00
Michele Caini
57ec3c85cb registry: erase_if (close #977) 2023-05-19 10:44:00 +02:00
Michele Caini
4afdf287f1 doc: minor changes 2023-05-19 10:43:12 +02:00
Michele Caini
2810ac7cb9 registry: suppress a warning on msvc 2023-05-18 14:56:58 +02:00
Michele Caini
e0d27f9bf8 *: updated TODO 2023-05-18 14:06:34 +02:00
Michele Caini
de303c9990 test: reverse-each for storage entity 2023-05-18 14:06:28 +02:00
Michele Caini
1619e780f4 test: reverse each for plain storage classes 2023-05-18 14:06:16 +02:00
Michele Caini
a1e37eca6b storage: reverse-each 2023-05-18 14:06:03 +02:00
Michele Caini
c345e7456c doc: note on reverse iterations 2023-05-17 16:26:15 +02:00
Michele Caini
d166c026f7 snapshot: minor changes 2023-05-17 14:39:54 +02:00
Michele Caini
5e639996d6 doc: minor changes 2023-05-17 10:24:13 +02:00
Michele Caini
dac2ef5a9c doc: typo 2023-05-16 10:56:22 +02:00
Michele Caini
71d7888e81 snapshot: drop redundant check 2023-05-16 10:15:01 +02:00
Michele Caini
84a4df9c49 doc: exclude-only views 2023-05-16 09:55:08 +02:00
Michele Caini
95bc203196 doc: entity lifecycle 2023-05-16 09:49:35 +02:00
Michele Caini
5a9f6d211c doc: cleanup 2023-05-15 16:13:31 +02:00
Michele Caini
a29302faae test: more on entity signals 2023-05-15 08:49:07 +02:00
Michele Caini
75efa72c65 registry: cleanup ::erase 2023-05-15 08:33:26 +02:00
Michele Caini
58a84665b0 registry: cleanup ::remove 2023-05-15 08:33:06 +02:00
Michele Caini
a5263384d9 doc: drop redundant comments 2023-05-13 14:31:30 +02:00
Michele Caini
c0e6759c69 doc: cleanup a little further 2023-05-13 14:22:58 +02:00
Michele Caini
d754f74316 doc: cleanup 2023-05-13 14:06:58 +02:00
Michele Caini
1df5399431 doc: drop pointless tags 2023-05-13 13:57:48 +02:00
Michele Caini
c284e6feed doc: minor changes 2023-05-13 13:29:26 +02:00
Michele Caini
500239758a test: typo 2023-05-12 08:28:24 +02:00
DonutVikingChap
319ecd8084 organizer: fix organizer::vertex::prepare not creating component pools (#1014) 2023-05-12 08:24:23 +02:00
Michele Caini
d7891fabc0 doc: mention named pools support when registering listeners 2023-05-12 08:23:08 +02:00
Michele Caini
e287dd0419 helper: minor changes 2023-05-12 08:22:38 +02:00
Michele Caini
4dee9dde11 registry: named pools support for on_construct/on_update/on_destroy 2023-05-12 08:22:18 +02:00
Michele Caini
9bae6e67bc doc: update connection helper doc 2023-05-11 14:23:15 +02:00
Michele Caini
aa7a7ce25a doc: minor changes 2023-05-11 14:00:53 +02:00
Michele Caini
a969468c57 registry: de-deprecate :) on_construct/on_update/on_destroy 2023-05-11 13:58:52 +02:00
Michele Caini
a1e76fc638 doc: more about entity storage 2023-05-10 11:05:09 +02:00
Michele Caini
d8ed4ca354 registry: refine how entity storage is used internally 2023-05-10 10:47:11 +02:00
Michele Caini
3248e3f91e helper: make sigh_helper work with named pools 2023-05-09 11:09:16 +02:00
Michele Caini
f00687e6f9 doc: updated registry documentation 2023-05-09 10:55:08 +02:00
Michele Caini
5240c6b60a registry: deprecate on_construct/on_update/on_destroy 2023-05-09 10:54:49 +02:00
Michele Caini
67604a88e1 natvis: update registry snippet 2023-05-09 10:49:07 +02:00
Michele Caini
4242dfb8b5 registry: use entity storage directly as much as possible 2023-05-09 10:24:09 +02:00
Michele Caini
f96d8ee832 registry: prepare to split component storage and entity storage 2023-05-09 09:24:25 +02:00
Michele Caini
c147ec37c9 test: try to make gcc happy again 2023-05-09 08:48:22 +02:00
Michele Caini
094ddbba36 meta: avoid shadow warnings 2023-05-09 08:44:24 +02:00
Michele Caini
634630ca2d test: add missing template keywords (thanks msvc for ignoring them) 2023-05-09 08:34:06 +02:00
Michele Caini
d78c26f266 *: updated TODO 2023-05-08 12:45:52 +02:00
Michele Caini
fabc6c9bd7 test: full cross-registry entity-copy example with meta (not strictly required) 2023-05-08 12:45:18 +02:00
Michele Caini
b6e8ddd2ad meta: fight against the small nuances of the language :) 2023-05-08 12:24:43 +02:00
Michele Caini
cf2bbae6e1 mixin: make it simpler to modify the underlying type 2023-05-07 23:38:05 +02:00
Michele Caini
08799616d0 *: updated TODO 2023-05-05 16:19:51 +02:00
Michele Caini
58bebf78d8 meta: reduce symbols and their sizes if possible 2023-05-05 15:53:58 +02:00
Michele Caini
d534fad3ee doc: more about views 2023-05-04 11:35:27 +02:00
Michele Caini
871dc7a401 doc: drop references to storage placeholders 2023-05-04 10:12:35 +02:00
Michele Caini
1fe7c78f7e test: minor changes 2023-05-03 16:22:01 +02:00
Michele Caini
22a65f80fc test: cleanup 2023-05-03 16:11:08 +02:00
Michele Caini
756ea8a388 *: updated TODO 2023-05-03 14:49:43 +02:00
Michele Caini
12186cb401 registry: drop internal static storage variables from ::assure 2023-05-03 14:49:35 +02:00
Michele Caini
aa9ffb9eef registry: const ::storage<T>(...) returns a pointer to possibly null storage 2023-05-03 14:46:40 +02:00
Michele Caini
dcb5aed901 registry: lazily/partially initialize views in the ::view const function 2023-05-02 14:39:06 +02:00
Michele Caini
34f6a747a8 registry: add support for non-existent pools to try_get 2023-05-02 14:37:06 +02:00
Michele Caini
912cb2ad54 snapshot: constness review 2023-05-02 14:30:20 +02:00
Michele Caini
885488b3d6 registry: any_of supports non-existing pools now 2023-04-28 16:28:32 +02:00
Michele Caini
3d3d3ef2d9 registry: all_of supports non-existing pools now 2023-04-28 16:28:13 +02:00
Michele Caini
a7120b3400 registry: coding style 2023-04-28 16:26:56 +02:00
Michele Caini
51915205b0 test: cover stable multi-type model 2023-04-28 16:25:03 +02:00
Michele Caini
4a3ee042ea view: refine ::storage function 2023-04-28 16:24:38 +02:00
Michele Caini
88a1b8d0df view: stable multi-type view ::each(cb) function 2023-04-28 16:24:18 +02:00
Michele Caini
7e18a0f966 view: update ::use function 2023-04-28 16:23:33 +02:00
Michele Caini
c367082ddd view: unchecked_refresh function 2023-04-28 16:22:23 +02:00
Michele Caini
9f94b5306d view: double check on none_of 2023-04-28 16:21:17 +02:00
Michele Caini
44ed10c50b view: stable multi type view ::find/::back/::front functions 2023-04-28 15:55:33 +02:00
Michele Caini
1b22809412 view: stable multi type view ::begin/::end functions 2023-04-28 15:48:09 +02:00
Michele Caini
bdabbaa63d view: stable multi type view ::contains function 2023-04-28 15:47:16 +02:00
Michele Caini
c79c109b77 view: stable multi type view ::size_hint function 2023-04-28 15:44:00 +02:00
Michele Caini
f1a2133820 registry: prepare to remove static storage from const assure 2023-04-28 15:35:15 +02:00
Michele Caini
17dc061490 view: stable single type view ::each(cb) function 2023-04-28 14:20:45 +02:00
Michele Caini
3b8d82330d view: drop unused return 2023-04-28 12:19:45 +02:00
Michele Caini
a20829e700 view: ::handle returns a pointer rather than a reference 2023-04-28 09:42:14 +02:00
Michele Caini
5be2fdc158 view: stable single type view ::each() function 2023-04-27 09:19:57 +02:00
Michele Caini
873b107e69 -: updated TODO 2023-04-27 09:19:27 +02:00
Michele Caini
356bbbe53e view: stable single type view ::find function 2023-04-27 09:11:03 +02:00
Michele Caini
e3ce4e1567 view: stable single type view ::front/::back functions 2023-04-27 09:10:29 +02:00
Michele Caini
e02050c515 view: stable single type view ::rbegin/::rend functions 2023-04-27 09:07:37 +02:00
Michele Caini
26930633f0 view: stable single type view ::begin/::end functions 2023-04-27 08:59:50 +02:00
Michele Caini
b7a485767f view: stable single type view ::contains function 2023-04-26 15:49:21 +02:00
Michele Caini
f54cdccd4f view: stable single type view ::empty function 2023-04-26 15:48:45 +02:00
Michele Caini
41c9a32f31 view: stable single type view ::size function 2023-04-26 15:48:06 +02:00
Michele Caini
736ef35805 view: make operator bool work properly with partially initialized views 2023-04-26 13:10:31 +02:00
Michele Caini
0128cbb4f3 test: minor changes 2023-04-24 18:15:22 +02:00
Michele Caini
ff0a407151 test: prepare test suite for safe invalid views 2023-04-24 18:15:09 +02:00
Michele Caini
34f4403864 view: avoid using storage, further prepare for empty safe views 2023-04-24 17:49:49 +02:00
Michele Caini
b1c78efb6c nativs: updated signal file 2023-04-24 17:31:56 +02:00
Michele Caini
28f03ff9ce meta: add missing checks on factory<...>::data 2023-04-24 09:50:57 +02:00
Michele Caini
a5fe61adbb *: minor changes 2023-04-24 08:35:52 +02:00
Michele Caini
457f5e59ea view: rollback handle() usage and prepare to safe empty views 2023-04-24 08:35:17 +02:00
Michele Caini
422fd284e7 group: refine group ::find function 2023-04-21 15:32:14 +02:00
Michele Caini
6f32225736 view: refine single type view ::find function 2023-04-21 15:28:21 +02:00
Michele Caini
366bbceb02 doc: use doxygen-awesome-css 2023-04-21 09:03:44 +02:00
Michele Caini
7b7f81e08f doc: update reference.md 2023-04-21 08:55:48 +02:00
Michele Caini
cfe955f970 doc: update links.md 2023-04-21 08:55:38 +02:00
Michele Caini
684ddc9de9 doc: minor changes 2023-04-21 08:42:52 +02:00
Michele Caini
f5d38a9aed doc: drop redundant doxy variable 2023-04-21 08:34:23 +02:00
Michele Caini
447e3693f2 doc: updated doxy file (doxygen 1.9.6) 2023-04-21 08:29:25 +02:00
Michele Caini
909490bf63 view: try to make g++ happy again 2023-04-20 14:25:39 +02:00
Michele Caini
d90363e4a4 view: make view pack also work with empty views 2023-04-20 13:48:23 +02:00
Michele Caini
ee5de744c3 view: add missing [[nodiscard]] 2023-04-19 13:51:31 +02:00
Michele Caini
d401c88a04 view: assert on null handles 2023-04-19 11:54:45 +02:00
Michele Caini
80563b9557 view: allow swapping storage elements of a view 2023-04-19 09:29:31 +02:00
Michele Caini
c74900057c sigh_mixin: avoid shadow warnings 2023-04-18 15:22:21 +02:00
Michele Caini
78867d5c9b group: make msvc happy with constness on virtual functions 2023-04-18 15:22:04 +02:00
Michele Caini
d435fc7792 basic_entt_traits: suppress a warning by gcc 2023-04-18 15:21:26 +02:00
Michele Caini
e6f76e0f96 view: try to make VS happy again :) 2023-04-18 14:44:28 +02:00
Michele Caini
1c6b533609 test: minor changes 2023-04-18 13:28:01 +02:00
Michele Caini
5c3d8360c2 view: turn ::use into a self-contained, non-const function 2023-04-18 13:10:01 +02:00
Michele Caini
3882c7d9af view: turn ::refresh into a self contained, non-const function 2023-04-18 13:00:59 +02:00
Michele Caini
15726218bd view: doc 2023-04-18 12:58:04 +02:00
Michele Caini
869bfc82cf test: minor changes 2023-04-17 18:34:53 +02:00
Michele Caini
0eb3d54b21 group: change signature of ::storage to return a (maybe null) pointer rather than a reference 2023-04-17 11:09:10 +02:00
Michele Caini
f83290f762 view: change signature of ::storage to return a (maybe null) pointer rather than a reference 2023-04-17 11:08:55 +02:00
Michele Caini
686a3b9d79 registry: make storage_for_type available to the final user 2023-04-14 12:37:05 +02:00
Michele Caini
4d57d5c327 registry: make ::storage<T> return type explicit 2023-04-14 12:33:41 +02:00
Michele Caini
36c21cf7fa registry: drop redundant traits usage 2023-04-14 12:24:31 +02:00
Michele Caini
7ab10e1936 test: minor changes 2023-04-14 12:03:00 +02:00
Michele Caini
41467d35a4 -: updated TODO 2023-04-14 09:57:42 +02:00
Michele Caini
d351252a12 doc: entity storage 2023-04-14 09:11:42 +02:00
Michele Caini
c6cd4f701c doc: refine storage section 2023-04-13 18:19:31 +02:00
Michele Caini
65889cca44 doc: brief mention of void storage 2023-04-13 14:02:17 +02:00
Michele Caini
f1914fd946 doc: rearrange a few things 2023-04-13 13:46:08 +02:00
Michele Caini
e53af7bef7 registry: minor changes 2023-04-12 15:43:46 +02:00
Michele Caini
b910cd2615 *: updated TODO 2023-04-12 15:16:00 +02:00
Michele Caini
58d331ca0e registry: minor changes 2023-04-12 09:21:47 +02:00
Michele Caini
17f5b0a330 registry: avoid bumping version on destroy if not requested 2023-04-12 09:14:02 +02:00
Michele Caini
de386292bc registry: deprecate ::each 2023-04-12 09:05:38 +02:00
Michele Caini
88bf26a2f8 registry: deprecate ::assign 2023-04-07 18:06:12 +02:00
Michele Caini
3caad4100d mixin: common internal owner_or_assert function 2023-04-07 17:27:32 +02:00
Michele Caini
916203a240 test: stress assert on entity limit 2023-04-07 15:59:22 +02:00
Michele Caini
62f1971f7b test: minor changes 2023-04-07 15:58:48 +02:00
Michele Caini
4fde96357d natvis: updated registry snippet 2023-04-07 09:19:36 +02:00
Michele Caini
c3730b65fb group:
* unified model
* drop group handler's size function (no longer required)
2023-04-07 09:19:22 +02:00
Michele Caini
1ea072cd38 group: back to the unified model for group handlers 2023-04-07 09:17:47 +02:00
Michele Caini
bbe4582ee9 meta: minor changes 2023-04-06 12:40:50 +02:00
Michele Caini
89ab5c328a meta: operator==/!= for meta_func 2023-04-06 12:40:42 +02:00
Michele Caini
3a4672793d meta: operator==/!= for meta_prop 2023-04-06 12:40:12 +02:00
Michele Caini
0a0446f35c meta: operator==/!= for meta_data (close #1002) 2023-04-06 12:39:50 +02:00
Michele Caini
fc58ff74be meta: operator==/!= for meta_handle (see #1002) 2023-04-06 12:39:19 +02:00
Michele Caini
fed6831cdc locator: support to opaque structures (close #956) 2023-04-05 14:20:34 +02:00
Michele Caini
1605c8d9d3 natvis: updated entity file 2023-04-04 11:51:56 +02:00
Michele Caini
d6641c7d8d -: updated TODO file 2023-04-04 09:36:16 +02:00
Michele Caini
5079f38e99 storage: allow on_update signals on entity storage 2023-04-04 09:36:04 +02:00
Michele Caini
1eab2a4a80 meta: fix constness detection for static functions in meta_type::invoke 2023-04-04 09:35:10 +02:00
Michele Caini
c331107651 test: cleanup 2023-04-03 15:30:10 +02:00
Michele Caini
117b0bd675 test: more about storage<...>::patch 2023-04-03 08:56:02 +02:00
Michele Caini
9b4a6f8776 storage: use allocator_traits::destroy rather than destroy_at 2023-04-03 08:41:23 +02:00
Michele Caini
f4e6f2b375 group: suppress shadow warning 2023-03-31 15:51:03 +02:00
Michele Caini
5971fb7aa4 -: updated TODO 2023-03-31 14:00:05 +02:00
Michele Caini
10dfe7e935 sigh: allow disconnecting listeners during iterations (close #986) 2023-03-31 13:59:53 +02:00
Michele Caini
a9208a9565 doc: fixed typo 2023-03-31 11:14:54 +02:00
Michele Caini
1cc5b32cab test: cleanup 2023-03-31 11:14:39 +02:00
Michele Caini
f8a972a3c6 signal: drop sink::before 2023-03-31 09:05:02 +02:00
Michele Caini
5b7cc20027 group: rollback some (no longer required) changes to the owning_group_descriptor 2023-03-30 15:07:51 +02:00
Michele Caini
bd34e7f2c7 group: drop nested groups support, prepare to the large group review and multi storage support 2023-03-30 15:00:32 +02:00
Michele Caini
46fe29c3f6 group: make matching functions virtual for owning groups 2023-03-30 08:48:04 +02:00
Michele Caini
c50e2815c8 group: make owning_group_descriptor depend on the storage base type 2023-03-30 08:43:53 +02:00
Michele Caini
fbfee632d5 group: minor changes 2023-03-29 18:32:19 +02:00
Michele Caini
77c59aabfa group: group_handler::size function for owning groups 2023-03-29 18:26:41 +02:00
Michele Caini
ebb1e8a728 group: single check function for group handlers 2023-03-29 18:26:08 +02:00
Michele Caini
1646217f09 group: make types explicit for the next/prev functions 2023-03-29 17:36:31 +02:00
Michele Caini
645edfb2b8 group: decouple constructing and setting prev/next links 2023-03-29 17:35:53 +02:00
Michele Caini
61f28298c9 group/registry: minor changes 2023-03-29 15:11:05 +02:00
Michele Caini
d19f97bf21 group: use ::handle() if possible 2023-03-29 13:13:07 +02:00
Michele Caini
70c611a84f group: cleanup 2023-03-29 13:12:05 +02:00
Michele Caini
286428c19c group: make common_type base of non-owning group handlers 2023-03-29 13:11:59 +02:00
Michele Caini
6ec719bcfa group: reduce the footprint of non-owning group handlers 2023-03-29 12:54:39 +02:00
Michele Caini
11f9bb2d74 registry: use shared_ptr<void> for non-owning groups (prepare to drop the basic handler dependency) 2023-03-29 12:21:56 +02:00
Michele Caini
5a1ba5ad7d regisrtry: decouple container types for groups 2023-03-29 11:51:20 +02:00
Michele Caini
cf094e7ef5 registry: finally split owning and non-owning groups as it ought to be 2023-03-29 11:50:20 +02:00
Michele Caini
31808bd9a2 sigh: flip the last commit on its head and drop redundant functions rather than merging them 2023-03-27 17:01:14 +02:00
Michele Caini
61a5173a75 sigh: merge a couple of functions 2023-03-27 16:30:16 +02:00
Michele Caini
ed6fe9e657 sigh/sink: refine internal definition 2023-03-27 15:56:35 +02:00
Michele Caini
e30fa85200 doc: cleanup 2023-03-27 15:51:49 +02:00
Michele Caini
ca1069e182 snapshot: avoid allocations if possible 2023-03-27 14:41:46 +02:00
Michele Caini
70f73a0949 snapshot: drop pointless checks 2023-03-27 13:44:03 +02:00
Michele Caini
710fff0e3f entity: make get_t, exclude_t and owned_t constexpr constructible 2023-03-27 11:21:31 +02:00
Michele Caini
660bc5843e entity: turn get_t, exclude_t and owned_t into proper classes (close #998) 2023-03-27 11:15:35 +02:00
Michele Caini
13295a14ee type_traits: v141 toolset workaround for value_list_diff 2023-03-27 11:10:45 +02:00
Michele Caini
9ce07ff617 type_traits: value_list_diff[_t] 2023-03-26 12:46:27 +02:00
Michele Caini
b272e04bab type_traits: value_list_contains[_v] 2023-03-26 12:42:15 +02:00
Michele Caini
28b11912ab test: cleanup 2023-03-26 12:38:50 +02:00
Michele Caini
b9f096d125 type_traits: value_list_unique[_t] 2023-03-26 12:38:09 +02:00
Michele Caini
8c60faa1d0 type_traits: value_list_index[_v] 2023-03-26 12:33:04 +02:00
Michele Caini
1f93ea4eee snapshot: avoid unnecessary lookups 2023-03-24 17:09:09 +01:00
Michele Caini
7ca77e53f6 snapshot: avoid unnecessary lookups 2023-03-24 17:08:01 +01:00
Michele Caini
69397f3658 snapshot: avoid unnecessary lookups 2023-03-24 17:04:23 +01:00
Michele Caini
f907bc066a snapshot: drop redundant checks and avoid unnecessary lookups 2023-03-24 16:48:30 +01:00
Michele Caini
bda52701f5 snapshot: avoid unnecessary lookups 2023-03-24 16:45:41 +01:00
Michele Caini
d26f7684ce snapshot: minor changes 2023-03-24 16:42:24 +01:00
Michele Caini
63d6c2bff6 snapshot: avoid unnecessary lookups 2023-03-24 16:41:26 +01:00
Michele Caini
cc45e73414 snapshot: also avoid using views if not required 2023-03-24 16:37:20 +01:00
Michele Caini
5d092bcb18 snapshot: avoid unnecessary lookups 2023-03-24 16:35:22 +01:00
Michele Caini
295c68841c snapshot: review ::orphans functions 2023-03-24 16:33:40 +01:00
Michele Caini
2664b52559 observer: allocator support 2023-03-24 16:04:52 +01:00
Michele Caini
dd36328331 observer: configurable mask type 2023-03-24 15:56:54 +01:00
Michele Caini
c8c929e4a2 group: use type members properly 2023-03-24 12:16:36 +01:00
Michele Caini
d1ef7bf155 view: use type members properly 2023-03-24 12:16:30 +01:00
Michele Caini
1ab23f17d2 group: early exit on signal races 2023-03-24 11:24:07 +01:00
Michele Caini
a72eb4693b group: minor changes 2023-03-24 11:11:40 +01:00
Michele Caini
67579d062b -: updated TODO 2023-03-23 16:48:48 +01:00
Michele Caini
766a233f37 view: base_type -> common_type 2023-03-23 16:42:13 +01:00
Michele Caini
905671c236 runtime_view: base_type -> common_type 2023-03-23 16:42:06 +01:00
Michele Caini
27c1383e46 group: base_type -> common_type 2023-03-23 16:41:54 +01:00
Michele Caini
029ccc8f75 registry: base_type -> common_type 2023-03-23 16:41:32 +01:00
Michele Caini
cde40d586d group: drop unused using decl 2023-03-23 13:37:40 +01:00
Michele Caini
6a16a8a20b group: auto init for owning groups 2023-03-23 08:52:38 +01:00
Michele Caini
1a12dede6f group: auto init for non-owning groups 2023-03-23 08:36:23 +01:00
Michele Caini
35a78b65ea group: cleanup 2023-03-22 16:42:31 +01:00
Michele Caini
ada19432f6 group: support for index based sort 2023-03-22 13:50:08 +01:00
Michele Caini
4998e90870 doc: minor changes 2023-03-22 13:49:45 +01:00
Michele Caini
471c11c6dc sparse_set: respect -> sort_as (naming is hard, you know) 2023-03-21 14:26:35 +01:00
Michele Caini
3e13e0b59b group: sort/respect -> sort_as (also decoupled from group types) 2023-03-21 14:14:18 +01:00
Michele Caini
53cd105f2e group: reuse pools as much as possible 2023-03-20 10:07:11 +01:00
Michele Caini
24b31c3798 group: reuse pools as much as possible 2023-03-20 10:00:07 +01:00
Michele Caini
def82b534b group: index based get 2023-03-20 08:11:42 +01:00
Michele Caini
a424f4ebf6 view: review get 2023-03-19 16:02:06 +01:00
Michele Caini
b8f0a8d8ec doc: a couple of interesting articles/series (close #994) 2023-03-19 15:31:31 +01:00
Michele Caini
7941226eff group: try to reuse pools when sorting and also please all compilers out there at the same time (aka me figthing ICEs again) 2023-03-18 12:48:52 +01:00
Michele Caini
86bbb2f6bb group: reuse pools when sorting 2023-03-18 12:41:11 +01:00
Michele Caini
3c176f7258 test: suppress warnings due to unused variables 2023-03-18 12:21:13 +01:00
Michele Caini
3642c8a784 registry: drop [[nodiscard]] from ::group (close #991) 2023-03-18 12:17:39 +01:00
Michele Caini
0e80d90a76 group: use storage<idx> as much as possible 2023-03-18 12:14:55 +01:00
Michele Caini
4fdf2dccd4 group: update doc 2023-03-17 16:16:53 +01:00
Michele Caini
f8a997e6c5 group: minor changes 2023-03-17 16:14:16 +01:00
Michele Caini
40f676ed14 test: drop unused include 2023-03-17 12:20:19 +01:00
Michele Caini
5e346748ea test: code coverage for groups and registry 2023-03-17 12:19:23 +01:00
Michele Caini
3ef61fe014 meta: support meta member functions on primitive types 2023-03-17 10:43:08 +01:00
Michele Caini
3885d280d3 test: cleanup 2023-03-17 10:36:10 +01:00
Michele Caini
f41b914197 meta: allow updating values on meta properties 2023-03-17 08:45:58 +01:00
Michele Caini
e0684f6348 registry: cleanup/minor changes 2023-03-17 08:45:00 +01:00
Michele Caini
fb980a78c0 registry: further refine the group function(s) 2023-03-16 15:00:17 +01:00
Michele Caini
c2430ab48d doc: minor changes 2023-03-16 12:25:46 +01:00
Michele Caini
d36d9cb39c registry: further cleanup group functions 2023-03-16 12:25:28 +01:00
Michele Caini
0017c08bb6 group: get pools from handlers 2023-03-16 09:26:47 +01:00
Michele Caini
e737ff7470 group: get filter from handlers 2023-03-15 10:32:59 +01:00
Michele Caini
945dc40937 group: split group handler functions 2023-03-15 09:39:50 +01:00
Michele Caini
7ef0085115 registry: drop group_data 2023-03-14 15:45:13 +01:00
Michele Caini
d2fa68813f registry/group: prepare to get rid of group_data 2023-03-14 15:35:00 +01:00
Michele Caini
f22a09a9a2 group: in-between change to simplify dropping group_data 2023-03-14 15:12:02 +01:00
Michele Caini
b0aba79a56 snapshot: minor changes 2023-03-14 15:10:02 +01:00
Michele Caini
7c23e4a2f6 registry: minor changes 2023-03-14 13:56:06 +01:00
Michele Caini
7fe035ce4b group: move group size from registry group_data to basic_group_handler 2023-03-14 11:38:41 +01:00
Michele Caini
3e7160edad group: minor changes 2023-03-14 11:12:25 +01:00
Michele Caini
aaeb686ec7 group: common base class for group handlers 2023-03-14 11:11:22 +01:00
Michele Caini
3fdf4884d8 group: prepare for group handler common base class 2023-03-14 11:09:35 +01:00
Michele Caini
1b23ff4b91 registry: use common group handler types as keys for the group set 2023-03-14 10:50:02 +01:00
Michele Caini
88dac318e5 group: wrap the len of owning groups to avoid changing it by mistake 2023-03-13 14:47:26 +01:00
Michele Caini
520c2e660d group: make group handlers work with multiple storage of the same type 2023-03-12 19:54:03 +01:00
Michele Caini
f5d0d451b4 group: split pools and filter in the group handlers 2023-03-11 19:23:09 +01:00
Michele Caini
8af6fc0cc4 group: use ::handle internally if possible 2023-03-10 14:41:51 +01:00
Michele Caini
c04b97a313 group: add ::handle function to all group types 2023-03-10 12:46:08 +01:00
Michele Caini
1d85414dc2 doc: drop refs to registry::version (close #992) 2023-03-10 12:23:07 +01:00
Michele Caini
c6533827f0 group: fight with clang format from time to time :) 2023-03-10 10:20:16 +01:00
Michele Caini
b5803451b4 group: make owning groups work with their handlers 2023-03-10 10:17:56 +01:00
Michele Caini
3417d66b2b group: make non-owning groups work with their handlers 2023-03-10 10:05:10 +01:00
Michele Caini
1e61204e80 registry: deduce group handler type from group type 2023-03-10 09:57:23 +01:00
Michele Caini
19c4857ef1 group: cleanup 2023-03-03 11:31:01 +01:00
Michele Caini
66ea94898e registry/group: move group handler to group file as it ought to be 2023-03-03 09:20:10 +01:00
Michele Caini
ced6d21c3e registry: break dependency between registry and group handlers 2023-03-02 10:06:39 +01:00
Michele Caini
429c7c45c7 registry: further cleanup things 2023-03-02 10:03:23 +01:00
Michele Caini
c03b1111aa registry: small cleanup 2023-03-02 09:54:26 +01:00
Michele Caini
ebd7d3acdc registry: storage based model with pools for groups 2023-03-02 09:54:08 +01:00
Michele Caini
5aeec60cfe registry: prepare to switch to storage based group handlers 2023-03-02 09:47:48 +01:00
Michele Caini
620b4f7517 registry: pass handlers to group callbacks 2023-03-02 08:50:25 +01:00
Michele Caini
6d58004c11 registry: minor changes to simplify the implementation slightly 2023-03-02 08:47:23 +01:00
Michele Caini
df6d926dec registry: prepare for a storage based group handler 2023-03-02 08:46:56 +01:00
Michele Caini
e63af24cb5 registry: turn the non-owning group handler in a storage 2023-03-01 18:03:38 +01:00
Michele Caini
068d9f8ae8 registry: discard unused arguments from listeners if possible 2023-03-01 17:50:58 +01:00
Michele Caini
c19c848c46 test: suppress warnings due to unused variables 2023-03-01 12:17:55 +01:00
Michele Caini
0bf0a0a8fa doc: delegate 2023-03-01 12:12:28 +01:00
Michele Caini
743e8678ea delegate: also support functions that skip first elements (on second attempt only) 2023-03-01 12:12:18 +01:00
Michele Caini
a7ad1c06f4 delegate: prepare to support filtering on both sides 2023-02-28 10:46:54 +01:00
Michele Caini
b1af70e70f registry: avoid checking pools in the group handler if possible 2023-02-28 10:23:58 +01:00
Michele Caini
c87c3533ee registry: avoid checking pools in the group handler if possible 2023-02-28 10:08:54 +01:00
Michele Caini
4839a0ee6c registry: cleanup 2023-02-27 16:31:46 +01:00
Michele Caini
a0f0c44e6d registry: minor changes 2023-02-27 16:25:35 +01:00
Michele Caini
74691dc1d9 group: just use meaningful names :) 2023-02-27 16:21:04 +01:00
Michele Caini
e4957badb7 registry: split group handler to further refine group management 2023-02-27 16:17:05 +01:00
Michele Caini
46791c4c3a registry: turn group handler functions into static ones 2023-02-27 16:03:33 +01:00
Michele Caini
56c3917841 registry: prepare to rework groups 2023-02-27 15:59:54 +01:00
Michele Caini
1fb13d3e93 doc: minor changes 2023-02-27 15:32:06 +01:00
Michele Caini
535beb4e2d storage: drop unnecessary use of integral_constant 2023-02-24 16:32:36 +01:00
Michele Caini
2d318b88c9 -: updated TODO 2023-02-24 16:29:35 +01:00
Michele Caini
b7f0b76cef entity/mixin: add missing include 2023-02-24 15:12:49 +01:00
Michele Caini
d30312f516 entity/helper: add missing include, drop unnecessary traits calls 2023-02-24 15:11:19 +01:00
Michele Caini
30772848e6 meta: avoid unnecessary calls to std::move 2023-02-24 15:04:40 +01:00
Nicolas Jakob
eca01a3979 doc: add vcpkg badge and vcpkg.link (#985) 2023-02-24 14:52:06 +01:00
Michele Caini
35ef0b7ac1 core: reduces the number of instantiations a bit 2023-02-23 16:21:49 +01:00
Michele Caini
19ccba3a6c meta: reduces the number of instantiations a bit 2023-02-23 16:21:40 +01:00
Michele Caini
207b7674ae doc: fix typo 2023-02-23 16:04:41 +01:00
Michele Caini
631c55ba92 storage: minor changes/tests 2023-02-22 11:32:15 +01:00
Michele Caini
e7b30fd36d storage: return iterator to elements rather than entities and only if it makes sense 2023-02-22 11:14:30 +01:00
Michele Caini
3e959007b9 storage: ::insert returns an iterator to the range of inserted entities 2023-02-21 10:52:37 +01:00
Michele Caini
07ec4ca230 -: updated TODO 2023-02-21 10:50:42 +01:00
Michele Caini
6e4946b682 storage: uniform interface to simplify mixin implementation 2023-02-20 09:34:11 +01:00
Michele Caini
47ea16f17c test: signals on entity creation/destruction 2023-02-18 11:51:18 +01:00
Michele Caini
722857fc07 test: get rid of pointless template parameters 2023-02-18 11:30:35 +01:00
Michele Caini
2125b38381 test: minor changes 2023-02-17 11:00:50 +01:00
Michele Caini
289de7d57b test: exclude only views 2023-02-17 10:59:36 +01:00
Michele Caini
25ecd8e797 test: minor changes 2023-02-17 10:59:11 +01:00
Michele Caini
319dfdb070 test: filtered registry view 2023-02-17 10:36:07 +01:00
Michele Caini
9dbbcac01e -: updated TODO 2023-02-17 09:09:36 +01:00
Michele Caini
f545c8e058 registry: deprecate ::release 2023-02-17 09:09:28 +01:00
Michele Caini
c68fa6a654 registry: make ::destroy work without ::release (the latter to be deprecated) 2023-02-16 10:00:45 +01:00
Michele Caini
d288ecd70d registry: make ::release use ::bump return value 2023-02-16 09:59:42 +01:00
Michele Caini
312d3aba84 sparse_set: bump returns the version in use (for convenience) 2023-02-16 09:58:07 +01:00
Michele Caini
4d2b2c6de5 registry: use traits_type::next if possible 2023-02-16 09:24:03 +01:00
Michele Caini
80d55a226c test: increase code coverage 2023-02-15 10:15:55 +01:00
Michele Caini
d86a539350 test: suppress warnings due to unused variables 2023-02-15 09:45:34 +01:00
Michele Caini
0f7098d0e0 -: updated TODO 2023-02-15 09:34:25 +01:00
Michele Caini
8c96be1e92 registry: deprecate a bunch of functions because of the entity storage 2023-02-15 09:34:08 +01:00
Michele Caini
37f396bfe3 registry: make entity storage storage as any other 2023-02-14 14:24:20 +01:00
Michele Caini
75894dc401 storage: update traits_type for entity storage 2023-02-13 11:42:30 +01:00
Michele Caini
cdee000ce8 any: rollback a change that turns vs toolset v141 crazy 2023-02-10 11:26:59 +01:00
Michele Caini
54ca62600b dispatcher: refine aggregate check 2023-02-10 10:56:48 +01:00
Michele Caini
6f4280ed59 any: refine aggregate check 2023-02-10 10:56:41 +01:00
Michele Caini
ddf56b78cd storage: backward compatibility on component requirements 2023-02-10 10:56:32 +01:00
Michele Caini
53a854f54f any: just cleanup the code to make it easier to work with 2023-02-10 10:40:48 +01:00
Michele Caini
4896acac7d storage: typo 2023-02-10 10:40:22 +01:00
Michele Caini
e3defeba2a test: suppress warnings due to unused variables 2023-02-10 10:01:39 +01:00
Michele Caini
62079908ce storage: use proper value type for entity storage 2023-02-10 09:37:13 +01:00
Michele Caini
e65a8f2e5f doc: add link to koala engine :) 2023-02-10 08:33:41 +01:00
Michele Caini
9f27fb1e57 registry: further prepare to turn the entity storage into a plain pool 2023-02-09 13:40:41 +01:00
Michele Caini
04d734e76c registry: prepare to turn the entity pool in a plain storage 2023-02-09 12:44:23 +01:00
Michele Caini
df50fa1b59 natvis: cleanup 2023-02-08 16:54:50 +01:00
Michele Caini
051872b8c8 natvis: update registry definition 2023-02-08 16:47:40 +01:00
Michele Caini
57ab9e7be0 registry: avoid using assure if not required 2023-02-07 14:56:56 +01:00
Michele Caini
69d95ba759 test: more bench to stress a little an upcoming feature 2023-02-06 11:27:02 +01:00
Michele Caini
9caf66d7c8 test: cleanup 2023-02-06 11:07:22 +01:00
Michele Caini
74cb0d40c5 test: internal rework 2023-02-06 10:59:10 +01:00
Michele Caini
deac7f34b8 dispatcher: refine aggregate support 2023-02-03 18:40:22 +01:00
Michele Caini
a9883f27c6 storage: refine transparent aggregate support 2023-02-03 18:37:14 +01:00
skypjack
85b1e57d8d sparse_set: drop fast_compact, expect full clear 2023-02-02 18:27:20 +01:00
skypjack
b7d8e01867 storage: make the entity storage perform a full clear rather than a fake one (still viable via erase) 2023-02-02 17:34:11 +01:00
Michele Caini
390a56176f -: updated TODO file 2023-02-01 16:07:17 +01:00
Michele Caini
a1b888cce6 natvis: add optiona storage length item for entity storage 2023-02-01 16:06:56 +01:00
Michele Caini
2107dd6891 natvis: fix already existing errors due to renaming or design changes 2023-02-01 16:06:37 +01:00
Michele Caini
1fca56afef storage: make it easier to refine the natvis file 2023-02-01 16:05:47 +01:00
Michele Caini
c0762a6a5a storage: add get/get_as_tuple to entity storage to make it suitable for use with views 2023-01-31 17:23:42 +01:00
Michele Caini
f48de1bac9 test: stress get/get_as_tuple for empty types 2023-01-31 17:22:07 +01:00
Michele Caini
c7dfce89e5 sigh_mixin: refine pop_all 2023-01-30 19:03:43 +01:00
Michele Caini
822fafcd42 view: uniform implementation to simplify upcoming changes 2023-01-30 16:17:44 +01:00
Michele Caini
1476d4ea9b sparse_set: refine ::respect 2023-01-30 11:26:37 +01:00
Michele Caini
c1c63777e8 -: updated TODO 2023-01-30 10:52:10 +01:00
Michele Caini
2fab25ae89 registry: refine internal check 2023-01-30 10:52:03 +01:00
Michele Caini
75d4491522 -: updated TODO 2023-01-27 09:10:18 +01:00
Michele Caini
c7866fb21b storage: use entt traits next function if possible 2023-01-27 09:10:11 +01:00
Michele Caini
87987bacde entity: added basic_entt_traits::next (with tests) 2023-01-27 09:09:28 +01:00
Michele Caini
bde0219fe6 snapshot: review basic_continuous_loader::entities 2023-01-26 11:54:03 +01:00
Michele Caini
ad64c849b8 storage: suppress warnings 2023-01-26 11:42:19 +01:00
Michele Caini
b808bb83b7 test: suppress warnings 2023-01-26 11:42:11 +01:00
Michele Caini
d0090d35fb snapshot: try to make sizes an opaque value to the caller 2023-01-26 11:30:52 +01:00
Michele Caini
7a1a06a24b sigh_mixin: avoid shadow warnings 2023-01-26 11:13:39 +01:00
Michele Caini
000b17881b -: updated TODO 2023-01-26 09:41:36 +01:00
Michele Caini
068b6ed49b registry: first (almost) backward compatible version with opaque hidden entity storage 2023-01-26 09:41:25 +01:00
Michele Caini
0187fb48aa test: sigh mixin for entity storage types 2023-01-25 11:30:41 +01:00
Michele Caini
35a2b38441 sigh_mixin: also support entity storage types 2023-01-25 11:29:53 +01:00
Michele Caini
4747c9a4c8 registry: extended checks to support swap-only entity storage types 2023-01-24 17:34:46 +01:00
Michele Caini
7be8d83278 registry: make a couple of conditions opaque 2023-01-24 17:08:26 +01:00
Michele Caini
a5d6757d6f registry: prepare to get rid of the vector of entities 2023-01-24 17:06:58 +01:00
Michele Caini
3f09d47c81 storage: remove redundant typename keyword 2023-01-24 16:55:54 +01:00
Michele Caini
9c06d6ba0f registry: use type member names 2023-01-24 16:54:32 +01:00
Michele Caini
b7c819bf48 test: entity storage 2023-01-24 16:46:50 +01:00
Michele Caini
9f31803ba7 storage: swap-only entity storage 2023-01-24 16:46:37 +01:00
Michele Caini
1e7deff9c9 test: drop redundant checks 2023-01-24 10:57:37 +01:00
Michele Caini
04ac15d8d9 test: minor changes 2023-01-24 10:57:25 +01:00
Michele Caini
3762189916 sigh_mixin: make pop_all use narrow view iterators if any 2023-01-23 10:09:56 +01:00
Michele Caini
18d6e466d0 -: [[nodiscard]] as appropriate 2023-01-22 18:16:57 +01:00
Michele Caini
095ecf3142 group: extended_group_iterator::base to return the underlying iterator 2023-01-22 18:16:18 +01:00
Michele Caini
433ed863e5 view: extended_view_iterator::base to return the underlying iterator 2023-01-22 18:08:32 +01:00
Michele Caini
0dba68e754 storage: coding style/minor changes 2023-01-22 18:02:49 +01:00
Michele Caini
1ab2815823 storage: extended_storage_iterator::base to return the underlying iterator 2023-01-22 18:00:28 +01:00
Michele Caini
2af5a725e4 doc:
* updated copyright
* udpated TODO list
2023-01-20 08:50:26 +01:00
Michele Caini
a86bf1332b test: try to make lcov happy 2023-01-18 15:34:49 +01:00
Michele Caini
831054bff1 test: share as much as possible 2023-01-18 10:29:37 +01:00
Michele Caini
f94de1c069 test: rework lib stuff to share common files 2023-01-18 10:17:54 +01:00
Michele Caini
a3d9503a17 test: try to make lcov happy 2023-01-18 08:34:39 +01:00
Michele Caini
3f2b15f9f7 test: try to make lcov happy 2023-01-17 11:42:14 +01:00
Michele Caini
e48817d518 test: try to make lcov happy 2023-01-17 10:57:41 +01:00
Michele Caini
d11cebe30b view: uniform design to also help natvis without having to poke into stl internals 2023-01-17 08:19:34 +01:00
Michele Caini
77a5efb327 natvis: updated to_entity intrinsic 2023-01-17 08:18:21 +01:00
Michele Caini
851006efee -: updated TODO 2023-01-16 16:36:12 +01:00
Michele Caini
6fc6b2fb35 sigh_mixin: further improve ::pop_all 2023-01-16 16:08:11 +01:00
Michele Caini
ed17a2c48b sparse_set: ::contiguous function 2023-01-16 11:07:10 +01:00
Michele Caini
bd00e797a9 sparse_set: further refine pop_all to make it even faster 2023-01-13 12:09:42 +01:00
Michele Caini
e645c4928a -: updated TODO 2023-01-13 12:06:12 +01:00
Michele Caini
a425878e80 sparse_set/storage: clear is backward compatible now 2023-01-12 18:37:33 +01:00
Michele Caini
f3cd9d374d storage: fixed clear_all counter 2023-01-12 15:53:50 +01:00
Michele Caini
b3e93b084e registry: naming convention 2023-01-12 14:45:36 +01:00
Michele Caini
314c189c49 test: minor changes 2023-01-12 08:56:40 +01:00
Michele Caini
2bb2c55662 build: try to make lcov happy again 2023-01-11 18:36:23 +01:00
Michele Caini
d13c126e99 view: avoid name clashes 2023-01-11 18:09:33 +01:00
Michele Caini
9b54ee37a6 flow: propagate allocator to generated graph + internal rework 2023-01-11 17:55:57 +01:00
Michele Caini
e1ead9d3ee build: update coverage workflow 2023-01-11 17:20:58 +01:00
Michele Caini
cf61068dc0 mixin: suppress a warning with gcc11 2023-01-11 16:50:18 +01:00
Michele Caini
82863f8291 test: code coverage for range functionalities 2023-01-11 16:49:52 +01:00
Michele Caini
e4de59827f test: try to make lcov happy 2023-01-11 16:17:02 +01:00
Michele Caini
ccea4c920a memory: code coverage 2023-01-11 15:54:56 +01:00
Michele Caini
89166f0e47 build: refine analyzer workflow 2023-01-11 15:33:00 +01:00
Michele Caini
7a05a16c54 registry: slightly better destroy (yet not quite there though) 2023-01-11 11:54:29 +01:00
Michele Caini
d0854646c7 test: yet another test to stress the upcoming changes 2023-01-11 11:03:04 +01:00
Michele Caini
1e9c9fe5f8 registry: better, faster range-remove + refine range-erase 2023-01-11 10:15:19 +01:00
Michele Caini
80fac8d8e5 test: minor changes 2023-01-11 10:13:47 +01:00
Michele Caini
c774b98389 -: updated TODO 2023-01-11 09:55:57 +01:00
Michele Caini
3fd0403cc9 registry: faster, better range-erase 2023-01-11 09:55:47 +01:00
Michele Caini
6eb3347a3b test: a couple of extra functions to stress the upcoming changes 2023-01-11 09:34:22 +01:00
Michele Caini
89bceaff75 -: updated TODO 2023-01-10 15:51:35 +01:00
Michele Caini
dc25c9c1a2 sparse_set: invoke release_sparse_pages before clearing the sparse array 2023-01-10 15:33:48 +01:00
Michele Caini
e68ba5870c sigh_mixin: add a missing include 2023-01-10 15:01:48 +01:00
Michele Caini
c68cb33751 entity: make deletion_policy publicly available via fwd.hpp 2023-01-10 14:41:13 +01:00
Michele Caini
59f807fd02 sparse_set: suppress warnings due to unused expressions 2023-01-10 14:32:43 +01:00
Michele Caini
232ffebc1e sparse_set: internal clear_all function 2023-01-10 14:22:50 +01:00
Michele Caini
3cea845a0f sparse_set: sparse_set_iterator::data function 2023-01-10 10:53:30 +01:00
Michele Caini
295f3b32e4 registry: a couple of extra move calls here and there 2023-01-10 09:23:28 +01:00
Michele Caini
254da2c3c6 sparse_set: better, faster range remove 2023-01-10 08:43:02 +01:00
Michele Caini
ecd3b8d933 sparse_set: prevent rework errors as much as possible 2023-01-09 18:48:22 +01:00
Michele Caini
c673b9b17c sigh_mixin: slightly improved pop + review insert 2023-01-09 17:45:33 +01:00
Michele Caini
cd28de0d63 test: clear-stable bench 2023-01-09 15:20:19 +01:00
Michele Caini
672f6a7112 test: minor changes 2023-01-09 15:18:06 +01:00
Michele Caini
3b50672b70 storage: restore storage_for/storage_type duality, it turned out to be very useful in practice 2022-12-28 17:56:22 +01:00
Michele Caini
f0613b1c6c sparse_set/storage: minor changes to reuse type members 2022-12-27 12:35:37 +01:00
Michele Caini
2197e160ef -: drop file pushed by mistake :) 2022-12-23 16:58:32 +01:00
Michele Caini
2dccd90166 handle: discard entity on destruction 2022-12-23 16:53:51 +01:00
Michele Caini
2f873f2dd2 -: storage_mixin.hpp -> mixin.hpp (non-storage mixins are also a thing) 2022-12-22 15:12:03 +01:00
Michele Caini
fde1a524ea sparse_set: ::get -> ::value (to avoid hiding from derived classes) 2022-12-22 13:10:57 +01:00
Michele Caini
0558010479 doc: drop references to docsforge + minor changes 2022-12-22 11:40:03 +01:00
Michele Caini
79a054a524 sigh_mixin: scope base_type properly 2022-12-20 15:46:18 +01:00
Michele Caini
d94e443a14 doc: drop outdated section 2022-12-20 15:32:35 +01:00
Michele Caini
3862184e88 sigh_mixin: support self managed storage classes 2022-12-20 15:30:37 +01:00
Michele Caini
f40fa3c2f6 test:
* use range destroy
* avoid compiler optimizations
2022-12-19 16:28:50 +01:00
Michele Caini
01bc93459b test (bench): the new entity storage enables the fast path in all cases 2022-12-19 15:30:30 +01:00
Michele Caini
151bd07391 sparse_set: revert optmized range push, it prevents self-managed storage classes 2022-12-19 08:24:08 +01:00
Michele Caini
935393aae0 sparse_set: better, faster range push 2022-12-16 18:45:51 +01:00
Michele Caini
fbfde43477 snapshot: avoid unused variable warnings 2022-12-16 15:21:56 +01:00
Michele Caini
2ffbe115b7 component_traits: revert entity customization support 2022-12-16 15:14:31 +01:00
Michele Caini
645973eb79 sparse_set: insert -> push 2022-12-15 18:11:19 +01:00
Michele Caini
1332307972 sparse_set: emplace -> push 2022-12-15 14:16:58 +01:00
Michele Caini
b700f5eb5d doc: typo 2022-12-15 12:18:29 +01:00
Michele Caini
e60dbdc521 sparse_set/storage:
* rename swap_at in swap_or_move to capture the real purpose
* define swap_at as a protected function to allow swapping from above
2022-12-15 11:19:44 +01:00
Michele Caini
c66623b330 sigh_mixin: avoid hiding basic_iterator type meber 2022-12-14 12:06:06 +01:00
Michele Caini
62246d8796 storage: avoid hiding basic_iterator type meber 2022-12-14 10:49:32 +01:00
Michele Caini
b35f131309 sparse_set: support swap-only mixins 2022-12-13 17:36:58 +01:00
Michele Caini
3dd82633a3 -: drop storage_mixin.cpp, I forgot to do it a couple of commits ago :) 2022-12-13 15:41:07 +01:00
Michele Caini
00231bf8a7 storage: make swap_at non-final to support checks on derived classes 2022-12-13 15:40:25 +01:00
Michele Caini
58d392e813 -: minor changes 2022-12-13 15:36:49 +01:00
Michele Caini
1d4d99d090 mixin: sigh_storage_mixin -> sigh_mixin 2022-12-13 10:53:07 +01:00
Michele Caini
fe3edf2c83 -: minor changes 2022-12-13 10:50:17 +01:00
Michele Caini
0864ba0429 -: drop useless typename 2022-12-13 10:48:34 +01:00
Michele Caini
3a96980013 build: minor changes 2022-12-12 18:43:44 +01:00
Michele Caini
423f7a555d is_equality_comparable: detect C-style arrays directly 2022-12-12 18:32:07 +01:00
Michele Caini
5db8ad53ac build: update gh workflow 2022-12-12 18:19:51 +01:00
Michele Caini
c2ab357802 view: make also VS toolset v141 happy 2022-12-12 15:42:39 +01:00
Michele Caini
4fb558f143 view: further reduce instantiations 2022-12-12 15:08:37 +01:00
Michele Caini
5762a8a086 view: reuse internal functions if possible 2022-12-12 11:49:47 +01:00
Michele Caini
ed4c675211 sparse_set/storage: drop move_element 2022-12-12 09:38:58 +01:00
Michele Caini
f157898462 config: ENTT_FAIL(msg) -> ENTT_ASSERT(false, msg) 2022-12-07 12:22:35 +01:00
Michele Caini
6d20709e07 storage: minor changes 2022-12-07 10:41:33 +01:00
Michele Caini
a9a9853c01 sigh_storage_mixin: use entity_type from Type 2022-12-06 14:34:16 +01:00
Michele Caini
af14aa4c9e doc: more about signals (sigh_storage_mixin) 2022-12-06 12:01:01 +01:00
Michele Caini
24d6b98817 test: minor changes 2022-12-05 15:29:43 +01:00
Michele Caini
899f4baa63 storage:
* drop storage_for]_t]
* make storage_type[_t] deal with constness
2022-12-05 14:47:32 +01:00
Michele Caini
c1ab7ba025 sigh_storage_mixin: make all virtual member functions final 2022-12-05 09:52:22 +01:00
Michele Caini
9d38f60207 registry: thanks MSVC for accepting invalid C++ code 2022-12-02 11:57:29 +01:00
Michele Caini
0efa25cf61 sigh: cool, I keep doing the same error again and again apparently :) 2022-12-02 11:49:21 +01:00
Michele Caini
6316b60451 registry: make it work with storage<void> also in C++17 2022-12-02 10:56:03 +01:00
Michele Caini
f268fb60a8 entity: avoid breaking changes due to type members renaming 2022-12-01 13:26:22 +01:00
Michele Caini
3520d6915c entity: add base_type 2022-12-01 12:48:26 +01:00
Michele Caini
4da7a84518 entity: make checks work with 64b identifiers :) 2022-12-01 12:26:24 +01:00
Michele Caini
382dfc3bb4 entity: strict check on entity/version masks 2022-12-01 11:17:31 +01:00
Michele Caini
b6dcdc816e entity:
* also expose entity_mask and version mask to the final user
* avoid default args with entt_traits::construct for backward compatibility
2022-12-01 09:22:46 +01:00
Michele Caini
c9d544089a doc: review/cleanup entity.md a bit (done) 2022-11-30 16:17:02 +01:00
Michele Caini
3eb5faeed5 doc: review/cleanup entity.md a bit (work in progress) 2022-11-29 14:40:27 +01:00
Michele Caini
7a328c7edf doc: updated links 2022-11-29 08:21:19 +01:00
Michele Caini
6567aa1951 doc: a note about listeners disconnection (close #958) 2022-11-28 15:40:21 +01:00
Michele Caini
92319f0111 entt_traits: split basic impl, simplify def 2022-11-28 12:48:16 +01:00
Michele Caini
782d86b6e7 entt_traits: value_type -> type (cuz it's not a value type after all) 2022-11-26 18:57:10 +01:00
Michele Caini
c2cae37c1d entity_traits: make page_size type explicit 2022-11-25 18:24:12 +01:00
Michele Caini
1026d26ecb entt_traits: drop reserved value 2022-11-25 11:13:14 +01:00
Michele Caini
7156803dbe test: local non-static constexpr variables 2022-11-25 11:11:54 +01:00
Michele Caini
f54ed54247 helper: local non-static constexpr variables 2022-11-25 11:07:29 +01:00
Michele Caini
f30b50195a algorithm: local non-static constexpr variables 2022-11-25 10:59:47 +01:00
Michele Caini
c90ab9affd sparse_set:
* break dependency on traits_type::reserved
* use a tombstone if all I need is a tombstone
2022-11-25 10:23:43 +01:00
Michele Caini
c2f6ca43f1 doc: graph (close #957) 2022-11-24 09:33:34 +01:00
Michele Caini
3e5e41d88f test: cover some corner cases of the flow class 2022-11-24 09:33:04 +01:00
Michele Caini
9eafc0431d flow: minor changes 2022-11-24 09:31:14 +01:00
Michele Caini
0a82b777b2 component_traits: support specializations based on entity type 2022-11-23 14:53:31 +01:00
Michele Caini
32bcc01a46 component:
* make component_traits treat void properly
* drop ignore_as_empty_v
2022-11-23 12:36:21 +01:00
Michele Caini
9c3fe3546b nativs: entity module 2022-11-23 11:29:48 +01:00
Michele Caini
83f8aed583 helper: use traits_type from storage class directly 2022-11-23 11:28:08 +01:00
Michele Caini
2fd6602740 snapshot: use public registry traits_type member type 2022-11-23 11:11:54 +01:00
Michele Caini
a554d406e7 registry:
* public traits_type member type
* break dependency on component_traits
* use public storage traits_type member type
2022-11-23 11:06:51 +01:00
Michele Caini
5f12f872e6 test: minor changes 2022-11-23 11:04:56 +01:00
Michele Caini
be4eb68a30 helper:
* break dependency on component_traits
* use public storage traits_type member type
2022-11-23 08:58:45 +01:00
Michele Caini
df5284d9e5 view:
* break dependency on component_traits
* use public storage traits_type member type
2022-11-23 08:56:46 +01:00
Michele Caini
0e27d33e7e storage: public traits_type member type 2022-11-23 08:54:56 +01:00
Michele Caini
fe6e6ae738 sparse_set: public traits_type member type 2022-11-23 08:52:54 +01:00
Michele Caini
9d29713eaa entity: naming convention 2022-11-22 15:33:55 +01:00
Michele Caini
270d0277db group: cleanup 2022-11-22 15:33:20 +01:00
Michele Caini
0bd06c8d5d hashed_string: naming convention 2022-11-22 15:32:37 +01:00
Michele Caini
733f215ccf storage: break dependency between component_traits and storage_iterator 2022-11-22 14:53:20 +01:00
Michele Caini
ad01a69fe5 *: renaming/coding style 2022-11-22 14:45:26 +01:00
Michele Caini
dd9c1dade8 sparse_set: no need to differentiate template args for sparse_set_iterator 2022-11-22 14:44:59 +01:00
Michele Caini
b8f70519f6 doc: fixed typo 2022-11-22 14:26:46 +01:00
Michele Caini
9b9d212dde *: coding style 2022-11-22 12:44:31 +01:00
Michele Caini
3fe15969db doc: cleanup 2022-11-22 12:30:51 +01:00
Michele Caini
ec4bf222c6 meta: avoid the +1u trick for 0-sized arrays 2022-11-21 12:48:40 +01:00
Michele Caini
1173908ee4 meta: avoid rebinding when forwarding requests 2022-11-21 12:43:26 +01:00
Michele Caini
2595b8a925 doc: sigh_helper 2022-11-21 10:52:26 +01:00
Michele Caini
f4e2a8c76c sigh_builder: add all missing .template that msvc kindly accepted anyway 2022-11-21 10:38:44 +01:00
Michele Caini
66e1a05652 entity: sigh_helper utility with tests (close #928) 2022-11-21 10:38:42 +01:00
Michele Caini
87283dc41f storage: simplified impl in order to introduce multi-type storage more easily 2022-11-18 14:40:55 +01:00
Michele Caini
a802ebffed storage:
* move storage_type[_t] and storage_for[_t] to fwd.hpp
* no need to include storage.hpp when forward defining views
2022-11-17 17:48:11 +01:00
genar
b84b09421e doc: add Arch ECS to references.md (#954) 2022-11-17 08:45:25 +01:00
Michele Caini
940fd09396 todo: add a note for a (soon to be released) change 2022-11-17 08:42:11 +01:00
Michele Caini
920338be59 doc: add ecsact to links.md (thanks @zaucy for pointing this out) 2022-11-17 08:24:48 +01:00
Michele Caini
bcd1155b77 gh: add more gcc and clang versions 2022-11-16 11:10:13 +01:00
Michele Caini
1dc88109e8 gh: update workflows 2022-11-16 11:03:38 +01:00
Michele Caini
262c1f53c1 cmake: only enable -Wdocumentation for clang-cl 2022-11-16 10:47:03 +01:00
Michele Caini
4af0a3a0d1 doc: cleanup 2022-11-16 10:30:40 +01:00
Michele Caini
be16418289 doc: cleanup 2022-11-16 10:30:35 +01:00
Michele Caini
b54a52fbfe doc: fixed typo 2022-11-16 10:30:18 +01:00
Michele Caini
ae88159952 doc: fixed typo 2022-11-16 10:30:12 +01:00
Michele Caini
62c764f681 doc: fixed typo 2022-11-16 10:29:59 +01:00
Michele Caini
2c48cc10ae cmake: enable documentation diagnostic for clang 2022-11-16 10:23:00 +01:00
Michele Caini
82f2866789 sigh: drop redundant function 2022-11-15 15:40:10 +01:00
Michele Caini
d56e5a269c registry: propagate allocator to context 2022-11-15 14:48:10 +01:00
Michele Caini
1517b29513 doc: document delegate raw access 2022-11-15 08:27:00 +01:00
Michele Caini
bea7b43a1a delegate: target member function 2022-11-15 08:26:44 +01:00
Michele Caini
2f878f8b5a sigh: refine ::collect 2022-11-14 17:47:48 +01:00
Michele Caini
fc68c1b290 view/group: cleanup 2022-11-14 17:13:38 +01:00
Michele Caini
9081c185da meta: minor changes 2022-11-14 14:57:37 +01:00
Michele Caini
7c4493f237 group: make filter storage available 2022-11-14 11:19:22 +01:00
Michele Caini
da4e73ab85 view: make filter storage available 2022-11-14 11:00:57 +01:00
Michele Caini
f3e7f98b48 registry: extra check when moving a registry 2022-11-13 12:36:19 +01:00
Michele Caini
3925fc6124 emitter: extra allocator check when moving 2022-11-13 12:23:32 +01:00
Michele Caini
c639130c1e dispatcher: extra allocator check when moving 2022-11-13 12:21:21 +01:00
Michele Caini
75c3116008 registry: cleanup 2022-11-13 12:01:36 +01:00
Michele Caini
e9e14eb49c meta: [[nodiscard]] 2022-11-13 11:15:50 +01:00
Michele Caini
d1558304f8 any: [[nodiscard]] 2022-11-13 11:15:42 +01:00
Michele Caini
0531b530b1 snapshot: minor changes 2022-11-11 16:37:39 +01:00
Michele Caini
f9d0178dd7 workflow: bump iwyu version 2022-11-11 11:01:04 +01:00
Michele Caini
b66b8d37eb test: suppress warning 2022-11-11 10:59:10 +01:00
Michele Caini
05ef4c29d8 storage: minor changes 2022-11-10 18:47:02 +01:00
Michele Caini
9c3d756692 test: cleanup include directives 2022-11-10 15:56:17 +01:00
Michele Caini
93651e46f5 registry: drop [[deprecated]] functions 2022-11-10 15:05:48 +01:00
Michele Caini
ea901cbfa0 test: code coverage 2022-11-09 12:15:03 +01:00
Michele Caini
d5dc4f43ee doc: meta.md 2022-11-09 12:15:02 +01:00
Michele Caini
498e02f154 doc: core.md 2022-11-09 12:15:02 +01:00
Michele Caini
d0ea8f4f96 cmake: suppress some warnings for clang-cl, it goes a little wrong otherwise 2022-11-09 12:15:02 +01:00
Michele Caini
dec3b7bb39 test: suppress warnings 2022-11-09 12:15:02 +01:00
Michele Caini
10bc8b05ad test: use /W1 with VS (but for toolset v141, too bugged for that) 2022-11-09 12:15:02 +01:00
Michele Caini
ad77b54dce cmake: bump version to get some cool feature/update 2022-11-09 12:15:02 +01:00
Michele Caini
b6724b0283 group: pass filter storage to groups (in-between change for full storage access) 2022-11-09 12:15:02 +01:00
Michele Caini
54270b1038 group: make them easily copyable/movable 2022-11-09 12:15:02 +01:00
Michele Caini
31dc732a74 doc: graph.md 2022-11-09 12:15:02 +01:00
Michele Caini
f0e02d6d39 doc: container.md 2022-11-09 12:15:02 +01:00
Michele Caini
156d6e4ead doc: poly.md 2022-11-09 12:15:02 +01:00
Michele Caini
4375c1c3d6 doc: lib.md 2022-11-09 12:15:02 +01:00
Michele Caini
24a9cd67ee scheduler: forgot to add the fwd file to the previous commit :) 2022-11-09 12:15:02 +01:00
Michele Caini
ba8d522c19 doc: add the worst engine (love the name) to the list of links 2022-11-09 12:15:01 +01:00
Michele Caini
3ae46214a4 doc: review process.md 2022-11-09 12:15:01 +01:00
Michele Caini
5119fe8d7b scheduler: basic type model with default for common cases 2022-11-09 12:15:01 +01:00
Michele Caini
ed0319cdd8 view: avoid shadow warnings 2022-11-09 12:15:01 +01:00
Michele Caini
bc50da6a7c storage: suppress warnings with non copyable nor default constructible types 2022-11-09 12:15:01 +01:00
Michele Caini
52b3b4c249 group: suppress warnings for unused variables in case of empty types 2022-11-09 12:15:01 +01:00
Michele Caini
74bab529d2 test: minor changes 2022-11-09 12:15:01 +01:00
Michele Caini
b1b143917b meta: [[maybe_unused]] variable to avoid warnings with corner cases 2022-11-09 12:15:01 +01:00
Michele Caini
7beb4c85c4 test: suppress a few warnings (entity) 2022-11-09 12:15:01 +01:00
Michele Caini
f3beb5670a test: suppress a few warnings (container) 2022-11-09 12:15:01 +01:00
Michele Caini
446c67b69a test: suppress a few warnings (resource) 2022-11-09 12:15:01 +01:00
Michele Caini
c4507bd172 test: suppress a few warnings (poly) 2022-11-09 12:15:01 +01:00
Michele Caini
61e872bb4e test: suppress a few warnings (meta) 2022-11-09 12:15:01 +01:00
Michele Caini
9f22a3e23a test: suppress a few warnings (memory) 2022-11-09 12:15:00 +01:00
Michele Caini
653dd5cd42 test: suppress a few warnings (tuple) 2022-11-09 12:15:00 +01:00
Michele Caini
bc53ed3be9 test: suppress a few warnings (flow) 2022-11-09 12:15:00 +01:00
Michele Caini
f935bbccee dense_set: suppress warnings due to possible narrowing conversions 2022-11-09 12:15:00 +01:00
Michele Caini
c7d5053536 dense_map: suppress warnings due to possible narrowing conversions 2022-11-09 12:15:00 +01:00
Michele Caini
ea78f1d970 now working on version 3.12 2022-11-09 12:14:10 +01:00
Michele Caini
76298bc26a update single include file 2022-11-09 12:13:00 +01:00
Michele Caini
7c84ce666e sigh: rollback some changes that apparently create issues with (very old) compilers (ie clang 6) 2022-10-26 12:37:46 +02:00
Michele Caini
a02a7c67cb doc: fix typo 2022-10-26 11:53:43 +02:00
Michele Caini
2bb913b898 any: suppress warnings C4706 due to asserts 2022-10-26 10:57:58 +02:00
Michele Caini
94a8bb57dd doc: review resource.md 2022-10-26 10:50:31 +02:00
Michele Caini
f06852b5c2 doc: fixed typos 2022-10-25 14:50:18 +02:00
Michele Caini
fb14d26015 config: refine the ENTT_ASSERT vs ENTT_ASSERT_CONSTEXPR work 2022-10-25 11:05:50 +02:00
Michele Caini
6a53c8eaca doc: review locator.md 2022-10-25 11:04:13 +02:00
Michele Caini
4a98874431 doc: review faq.md 2022-10-25 11:03:59 +02:00
Michele Caini
baf60502c6 doc: review config.md 2022-10-25 11:03:39 +02:00
Michele Caini
2a01b78b32 any: forward/centralize requests internally 2022-10-24 14:38:55 +02:00
Michele Caini
b02e4efe4d doc: updated links (and thanks @Naios for these) 2022-10-24 12:20:20 +02:00
Michele Caini
3c8f6d2831 doc: minor changes 2022-10-24 11:53:23 +02:00
Michele Caini
95b443af16 tuple: is_tuple[_v] implementation 2022-10-24 11:15:34 +02:00
Michele Caini
b54766d2b4 sigh: small cleanup 2022-10-23 11:42:19 +02:00
Michele Caini
25929d6188 doc: ENTT_ASSERT_CONSTEXPR 2022-10-22 19:10:48 +02:00
Michele Caini
4398c962e7 memory:
* use ENTT_ASSERT_CONSTEXPR
* turn the power-of-two toolset into a constexpr one as it ought to be
2022-10-22 19:10:40 +02:00
Michele Caini
fe8919c540 config: introduce ENTT_ASSERT_CONSTEXPR to facilitate extreme customizations 2022-10-22 19:08:13 +02:00
Michele Caini
bdaeef856d delegate: just an extra safe check 2022-10-22 18:56:55 +02:00
Michele Caini
57ad7696be memory: turn the power-of-two/fast_mod toolset into a non-constexpr one 2022-10-21 11:01:18 +02:00
Michele Caini
7c58c83ee0 memory: review propagate_on_container_swap 2022-10-21 10:57:37 +02:00
Michele Caini
dd7aaa30ca organizer: minor changes 2022-10-20 15:34:57 +02:00
Michele Caini
76f95945fc registry: better use of entt:: to avoid ambiguities 2022-10-20 09:36:51 +02:00
Michele Caini
869836ba79 registry: use allocator to allocate_shared groups with uses-allocator policy 2022-10-20 09:10:20 +02:00
Michele Caini
2358552c27 *: internal review of some traits usage 2022-10-19 12:08:41 +02:00
Michele Caini
e22ea5e189 meta: minor changes 2022-10-18 11:03:03 +02:00
Michele Caini
496fefdd01 meta: favor top-level conversion functions over bases lookup 2022-10-18 10:54:31 +02:00
Michele Caini
26f85050c1 any: debug-only check to detect nasty bugs in the client code, if any 2022-10-18 10:53:51 +02:00
Michele Caini
d478b5bc6a test: minor changes to avoid UBs 2022-10-18 10:50:16 +02:00
Michele Caini
c8337e529e natvis: review a bunch of definitions 2022-10-17 09:54:13 +02:00
Michele Caini
f0995297cf emitter: update destructor check on derived type 2022-10-17 09:53:27 +02:00
Michele Caini
b395df0f56 doc: cleanup 2022-10-14 19:05:42 +02:00
Michele Caini
69a6cc6656 meta: better doc, minor changes to propagate the context to the meta handles 2022-10-14 18:52:05 +02:00
Michele Caini
bf73216a76 meta: minor changes 2022-10-14 17:01:54 +02:00
Michele Caini
621860718b meta: rebind elements to the right context upon invocation if possible 2022-10-14 15:40:31 +02:00
Michele Caini
c34c5da277 meta: minor changes 2022-10-14 14:31:55 +02:00
Michele Caini
8dcabba31b meta: clarify utilities behavior with regard to context, instances and arguments 2022-10-14 12:24:25 +02:00
Michele Caini
294064f11f meta: args are always rebinded to the right context (with non-regression tests) 2022-10-14 11:47:27 +02:00
Michele Caini
d125229312 doc: more about the new meta context rework 2022-10-14 11:46:35 +02:00
Michele Caini
11c1e23a91 meta: context aware copy/move ctor for meta_any 2022-10-14 08:49:44 +02:00
Michele Caini
82bc2e1fe4 test: no need to test mixing meta contexts actually, dropped the todo 2022-10-13 13:12:55 +02:00
Michele Caini
92a00f591d test: context aware meta handle 2022-10-13 11:15:48 +02:00
Michele Caini
04716a7fde meta: minor changes 2022-10-13 09:38:22 +02:00
Michele Caini
b6155080b2 test: a few more tests for meta_handle 2022-10-13 09:37:13 +02:00
Michele Caini
0a61de4a09 test: context aware meta_any 2022-10-13 09:33:43 +02:00
Michele Caini
7121da100a test: context aware meta sequence containers 2022-10-13 09:24:20 +02:00
Michele Caini
7bee969ebf test: context aware meta pointers (dereferencing picks the type from the right context) 2022-10-13 09:12:45 +02:00
Michele Caini
4a0a534796 test: context aware forward_as_meta 2022-10-13 09:09:11 +02:00
Michele Caini
a0041d9062 meta: resolve an ambiguity and avoid redundant default ctors (win-win) 2022-10-13 08:59:16 +02:00
Michele Caini
3dd768bb9b meta: context aware meta template 2022-10-12 19:02:30 +02:00
Michele Caini
2a307a681f test: context aware meta prop 2022-10-12 18:30:21 +02:00
Michele Caini
dd1211d021 meta: combine enable_if_t and a meta policy detection utility to avoid API changes 2022-10-12 16:06:25 +02:00
Michele Caini
09a600d68a meta: propagate API changes to the internal functions 2022-10-12 15:36:31 +02:00
Michele Caini
7c25b46513 test: minor changes 2022-10-12 15:14:58 +02:00
Michele Caini
dc42486de8 test: drop redundant using namespace 2022-10-12 14:57:46 +02:00
Michele Caini
36411faf43 test: context aware meta dtor 2022-10-12 14:56:27 +02:00
Michele Caini
a9cd565d65 test: context aware meta conv 2022-10-12 12:49:39 +02:00
Michele Caini
0adbb0ad16 test: context aware meta ctor 2022-10-12 12:43:58 +02:00
Michele Caini
db31f77d63 test: context aware meta func 2022-10-12 12:22:26 +02:00
Michele Caini
c275afef28 test: context aware meta data 2022-10-12 12:16:35 +02:00
Michele Caini
4bad4f3067 test: context aware meta bases 2022-10-12 10:28:41 +02:00
Michele Caini
d2048c037a test: bare minimum tests for meta types from different contexts 2022-10-12 10:04:28 +02:00
Michele Caini
2a39717893 test: add all desired tests for meta context support 2022-10-12 09:59:03 +02:00
Michele Caini
49c2ae0e77 test: context aware meta resolve 2022-10-12 09:58:20 +02:00
Michele Caini
869c18f150 test: prepare to test meta context support 2022-10-12 09:57:58 +02:00
Michele Caini
d79cb5ca98 meta: turn meta_handle into a context aware wrapper 2022-10-11 15:24:23 +02:00
Michele Caini
acc6390312 meta: drop make_meta, unfortunately it doesn't fit well with the context aware design 2022-10-11 14:56:25 +02:00
Michele Caini
2e59fbbccc meta:
* review pending functions to make them context aware if they aren't already
* suppress a meta_associative_container::insert warning (rvalue-to-lvalue binding)
2022-10-11 14:40:16 +02:00
Michele Caini
bec0037797 meta: fully context aware meta_any 2022-10-11 12:20:25 +02:00
Michele Caini
d08c7ddb58 meta: review meta_associative_container::insert/::erase 2022-10-11 12:11:54 +02:00
Michele Caini
696681fefa meta: context aware meta associative container 2022-10-11 11:53:17 +02:00
Michele Caini
5f9faf7a32 meta: context aware meta sequence container 2022-10-11 11:14:22 +02:00
Michele Caini
f160503aaf meta: unroll meta_type::forward_to_bases to return always scoped elements 2022-10-11 11:09:33 +02:00
Michele Caini
b1e9f75a28 meta: meta_type::construct always returns scoped meta_any objects 2022-10-11 11:01:50 +02:00
Michele Caini
91da98353d meta: keep track of the pending changes 2022-10-11 10:28:48 +02:00
Michele Caini
bc86ceb707 meta: drop resolve trampoline function, no longer required 2022-10-10 18:13:59 +02:00
Michele Caini
0baf316e5f meta: add partial support for meta contexts to meta containers 2022-10-10 18:13:20 +02:00
Michele Caini
082605f9d3 meta: prepare meta containers to support context injection 2022-10-10 18:03:30 +02:00
Michele Caini
0fdd7d7a3a meta: meta_any::allow_cast returns a scoped value now 2022-10-10 16:46:43 +02:00
Michele Caini
eee59e6af9 meta: track pending changes as much as possible 2022-10-10 16:46:43 +02:00
Michele Caini
223a8628e3 meta: meta_any::allow_cast propagates the context now 2022-10-10 16:46:42 +02:00
Michele Caini
c0bb603210 meta: meta_any::operator* propagates the context now 2022-10-10 16:46:42 +02:00
Michele Caini
2981d8746a meta: avoid returning contex-less meta_any from meta objects 2022-10-10 16:46:42 +02:00
Michele Caini
c06280894b meta: make internal meta_invoke accept meta contexts and use them properly 2022-10-10 16:46:42 +02:00
Michele Caini
2f2bdcac4d meta:
* make meta_getter use properly meta contexts
* remove the meta context from the argument list of meta setters (not required)
2022-10-10 16:46:42 +02:00
Michele Caini
2739964a1f meta: make meta_dispatch support and use meta contexts 2022-10-10 16:46:42 +02:00
Michele Caini
c3a2a44830 meta: drop useless [[maybe_unused]] 2022-10-10 16:46:42 +02:00
Michele Caini
37a2c3b76c meta: make meta_construct support and use meta contexts 2022-10-10 16:46:42 +02:00
Michele Caini
146a7b2aa3 meta: rollback redundant functions (reduce the number of generated symbols) 2022-10-10 16:46:42 +02:00
Michele Caini
7e093c951f meta:
* use different function names to disambiguate utility calls
* drop base class meta_policy for policies, no longer required
2022-10-10 16:46:42 +02:00
Michele Caini
4901188409 meta: use meta_any context aware constructors if possible 2022-10-10 16:46:42 +02:00
Michele Caini
15d78f80a6 meta: context aware constructors for meta_any 2022-10-10 16:46:42 +02:00
Michele Caini
d61dff45c1 meta: introduce meta_ctx_arg[_t] 2022-10-10 16:46:42 +02:00
Michele Caini
34abddfbbd meta: move the meta context argument to the first slot of the argument lists 2022-10-10 16:46:42 +02:00
Michele Caini
238ebe4e8f meta: try to get around invalid code that msvc accepts happily otherwise 2022-10-10 16:46:42 +02:00
Michele Caini
502accabbc meta: make default_constructor forward the context to the returned element 2022-10-10 16:46:42 +02:00
Michele Caini
9d1df1dae4 meta: make from_void forward the context to the returned element 2022-10-10 16:46:42 +02:00
Michele Caini
a39cfb9e99 meta: always forward the context to meta_type 2022-10-10 16:46:42 +02:00
Michele Caini
27d0e5f55e meta: always forward the context to meta_func 2022-10-10 16:46:42 +02:00
Michele Caini
a0e5d2c495 meta: always forward the context to meta_data 2022-10-10 16:46:42 +02:00
Michele Caini
d2c89d2a40 meta: always forward the context to meta_prop 2022-10-10 16:46:42 +02:00
Michele Caini
54f66c9094 meta: make meta_range_iterator forward the context to the returned elements 2022-10-10 16:46:42 +02:00
Michele Caini
10be00b352 meta: suppress a bunch of shadow warnings 2022-10-10 16:46:42 +02:00
Michele Caini
9032051bf7 meta: review meta_any::try_cast to use the local context 2022-10-10 16:46:42 +02:00
Michele Caini
2d2e4c784e meta: reintroduce as_ref constructor 2022-10-10 16:46:41 +02:00
Michele Caini
0d4674d8e2 meta: refined meta_conv_node definition 2022-10-10 16:46:41 +02:00
Michele Caini
ac06ad35c1 meta: added bare minimum support for contexts to forward_as_meta 2022-10-10 16:46:41 +02:00
Michele Caini
27e492d750 meta: minor changes 2022-10-10 16:46:41 +02:00
Michele Caini
f8281f2a37 meta: add bare minimum support for contexts to meta_any 2022-10-10 16:46:41 +02:00
Michele Caini
9fc717fa6e meta: track pending points for future refinement 2022-10-10 16:46:41 +02:00
Michele Caini
4a0f2f3fe9 meta: drop redundant constructors for meta_any 2022-10-10 16:46:41 +02:00
Michele Caini
ebdd4118fd meta: context aware internal try_cast 2022-10-10 16:46:41 +02:00
Michele Caini
54ae48936f meta: refine includes 2022-10-10 16:46:41 +02:00
Michele Caini
3c9045a3a8 test: avoid using the trampoline resolve function 2022-10-10 16:46:41 +02:00
Michele Caini
f80f179499 meta: small refinement 2022-10-10 16:46:41 +02:00
Michele Caini
69c6ee0675 meta: high level meta types are now context aware 2022-10-10 16:46:41 +02:00
Michele Caini
4e28d96bef meta: remove the last use of the trampoline resolve function from the meta factory 2022-10-10 16:46:41 +02:00
Michele Caini
6552cc4599 meta: refine factory.hpp as it's likely done now 2022-10-10 16:46:41 +02:00
Michele Caini
75b10cfa09 meta: make meta and meta_reset context aware 2022-10-10 16:46:41 +02:00
Michele Caini
dc394f62c6 meta: fully context aware meta factory 2022-10-10 16:46:41 +02:00
Michele Caini
ea6d6662b4 meta: make meta_ctor_node and meta_func_node fully context aware 2022-10-10 16:46:41 +02:00
Michele Caini
de3ecbdd28 meta: make meta_conv_node context aware 2022-10-10 16:46:41 +02:00
Michele Caini
e5c6559836 meta: make meta_data_node fully context aware 2022-10-10 16:46:41 +02:00
Michele Caini
0d422236d6 doc: minor changes 2022-10-10 16:46:41 +02:00
Michele Caini
199b065fe3 meta: make it compile after the last changes as it ought to be 2022-10-10 16:46:41 +02:00
Michele Caini
c46e107107 meta: try to follow my own coding style :) 2022-10-10 16:46:41 +02:00
Michele Caini
a3f66387b2 meta: further refine meta_type_node to make it context aware 2022-10-10 16:46:41 +02:00
Michele Caini
33383bd0c3 meta: try to follow my own naming convention :) 2022-10-10 16:46:41 +02:00
Michele Caini
35b8d95671 meta: make meta_type_node even more context aware 2022-10-10 16:46:40 +02:00
Michele Caini
6e254fb39d meta: make meta_type_node partially context aware 2022-10-10 16:46:40 +02:00
Michele Caini
f50a03dcb4 meta: make meta_ctor_node context aware 2022-10-10 16:46:40 +02:00
Michele Caini
71554b2c19 meta: drop temporary trampoline for meta_arg 2022-10-10 16:46:40 +02:00
Michele Caini
e7762980ec meta: make meta_ctor_node and meta_func_node partially context aware 2022-10-10 16:46:40 +02:00
Michele Caini
c62099969e meta: make meta_data_node partially context aware 2022-10-10 16:46:40 +02:00
Michele Caini
c45ee64800 meta: make meta_arg context aware 2022-10-10 16:46:40 +02:00
Michele Caini
b53c243ef7 meta: refactor context argument as the last one 2022-10-10 16:46:40 +02:00
Michele Caini
9ee084fc40 meta: make meta_template_node context aware 2022-10-10 16:46:40 +02:00
Michele Caini
9c969fb6ac meta: context aware meta_prop_node 2022-10-10 16:46:40 +02:00
Michele Caini
6a8a9c4b31 meta: context aware meta_arg_node function (with internal temporary trampoline) 2022-10-10 16:46:40 +02:00
Michele Caini
bc0233e34b meta: context aware resolve functions (with internal temporary trampoline) 2022-10-10 16:46:40 +02:00
Michele Caini
afd91b4e5a container: suppress a few shadow warnings 2022-10-10 16:46:26 +02:00
Michele Caini
50349dc2af any/meta: work around the bugs of toolset v141 to also make it happy if possible 2022-10-08 19:51:49 +02:00
Michele Caini
4b10981d75 meta: better support to rvalue references for forward_as_meta 2022-10-08 19:00:13 +02:00
Michele Caini
b16cefd534 any: better support to rvalue references for forward_as_any 2022-10-08 19:00:03 +02:00
Michele Caini
46d6625467 dispatcher: minor changes 2022-10-08 17:08:32 +02:00
Michele Caini
a1a8e134d2 doc: mino changes 2022-10-07 12:25:42 +02:00
Michele Caini
0b6bbcc6a3 signal: move connect_arg_t to fwd.hpp 2022-10-07 12:24:11 +02:00
Michele Caini
5fac237153 any: favor delegating constructors if possible 2022-10-07 12:13:17 +02:00
Michele Caini
d2cc1c880c meta: any: favor delegating constructors if possible 2022-10-07 12:09:01 +02:00
Michele Caini
ac18ad5823 any: favor delegating constructors if possible 2022-10-07 12:08:54 +02:00
Michele Caini
9ac5f6d046 meta: simplify container traits definitions 2022-10-06 19:02:32 +02:00
Michele Caini
08adb29d91 registry: also support empty queries to get and try_get (with tests) 2022-10-06 08:36:14 +02:00
Michele Caini
1721d07746 meta: drop useless [[maybe_unused]] 2022-10-06 08:27:38 +02:00
Michele Caini
9401d560b0 any: drop useless [[maybe_unused]] 2022-10-06 08:27:26 +02:00
Michele Caini
7eae8523cb container: drop useless [[maybe_unused]] 2022-10-06 08:27:12 +02:00
Michele Caini
45b5eeeaa0 doc: update doxy file (and required doxygen version) 2022-10-05 18:51:04 +02:00
Michele Caini
12b436e5b8 sigh: small changes to make doxygen happy 2022-10-05 12:20:43 +02:00
Michele Caini
534dc7e7b7 registry: allocate_shared pools to further improve the use of the allocator 2022-10-04 12:30:25 +02:00
Michele Caini
5dfac37dac dispatcher: just a comment for the future me 2022-10-04 12:29:43 +02:00
Michele Caini
f17a4e7f8e locator: just a comment for the future me 2022-10-04 12:29:22 +02:00
Michele Caini
4b586efe66 registry: use the allocator a bit more if possible 2022-10-03 16:04:42 +02:00
Michele Caini
db6dc1e21b sigh: reduce the number of instantiations and the size of the generated symbols 2022-09-30 10:29:47 +02:00
Michele Caini
da11771dab meta: drop using definitions that are pointless/no longer required 2022-09-29 15:48:43 +02:00
Michele Caini
475e3a70b0 meta: minor changes 2022-09-29 09:48:51 +02:00
Michele Caini
5255afc80d meta: drop useless scope 2022-09-28 18:14:12 +02:00
Michele Caini
7a3f59cc5d delegate: drop useless scope 2022-09-28 18:14:04 +02:00
Michele Caini
9470133e33 registry: don't pass the allocator to the fake storage 2022-09-28 12:54:21 +02:00
Michele Caini
5ab0f9e4c0 dispatcher: const assure 2022-09-27 15:08:29 +02:00
Michele Caini
ef91cd5375 registry: rollback some no longer required changes 2022-09-26 15:43:15 +02:00
Michele Caini
cd9553ca10 registry: ::storage(id) returns a pointer rather than an utterly annoying iterator 2022-09-26 15:42:57 +02:00
Michele Caini
8b27a846a6 view: avoid moving the callback with multi-type views 2022-09-23 11:06:30 +02:00
Michele Caini
9d961ad8aa view: minor changes 2022-09-23 11:00:45 +02:00
Michele Caini
0952f3ce03 view: reduce the number of symbols 2022-09-23 10:59:23 +02:00
Michele Caini
ab33111192 view/group: make ::handle [[nodiscard]] 2022-09-22 17:42:38 +02:00
Michele Caini
9a457c5aca registry: prepare to drop static storage within const assure 2022-09-22 17:42:21 +02:00
Michele Caini
4f1c86c52e view: prepare for partially working empty views 2022-09-22 17:42:15 +02:00
Michele Caini
c605e3b5a1 view: prepare for partially working empty views 2022-09-22 17:42:11 +02:00
Michele Caini
5a8c9b8a95 test: ASSERT_NO_THROW -> ASSERT_NO_FATAL_FAILURE 2022-09-22 17:42:01 +02:00
Michele Caini
2b8e9cab18 view: drop useless constexpr branch 2022-09-22 17:41:59 +02:00
Michele Caini
c3dec4b04e view: added ::refresh function to reinitialize the leading pool 2022-09-21 15:42:38 +02:00
Michele Caini
699aa5cd96 meta: rework internal function meta_arg_node 2022-09-21 14:49:54 +02:00
Michele Caini
fea0210b6e meta: support const/non-const overloads of the same function 2022-09-21 13:57:05 +02:00
Michele Caini
cf12765738 registry: pass the allocator to the pools 2022-09-20 16:04:14 +02:00
Michele Caini
17f47fbc92 storage_type[_t]/storage_for[_t]: allocator support 2022-09-20 11:01:58 +02:00
Michele Caini
1e36b6c4b6 registry: strict check on value_type for allocators 2022-09-20 10:25:29 +02:00
Michele Caini
28692fc142 registry: also adjust construction and swap orders 2022-09-19 15:03:51 +02:00
Dominic Koepke
6eff5a88f6 registry: update (and test) member destruction order (#930) 2022-09-19 13:06:37 +02:00
tocic
5742100973 doc: fix typos (#934) 2022-09-19 12:09:30 +02:00
Michele Caini
c52eea7db7 doc: update README ( thanks @Alan-FGR ) 2022-09-16 15:46:20 +02:00
Michele Caini
2f59f5a8fa meta: refine internal::meta_arg_node + code coverage 2022-09-16 10:06:56 +02:00
Michele Caini
e77fe56e8f natvis: meta 2022-09-15 14:09:50 +02:00
Michele Caini
eea1e7b1f8 meta: further reduce the number of instantiations and allocations 2022-09-15 14:09:44 +02:00
Michele Caini
b0fbccdf10 meta: minor changes 2022-09-15 10:20:29 +02:00
Michele Caini
4f3faef153 meta: remove a few pointless moves 2022-09-15 10:08:50 +02:00
Michele Caini
3ae3c82fbb meta: refine meta_construct to make it work with lambdas (+tests) 2022-09-14 16:29:11 +02:00
Michele Caini
1063fbccbe meta: const correctness 2022-09-14 16:26:14 +02:00
Michele Caini
b9e60c679a meta: added meta_function_descriptor_traits to avoid repetition and errors 2022-09-14 09:46:11 +02:00
Michele Caini
88fd79069b locator: minor changes 2022-09-14 09:22:43 +02:00
Michele Caini
ab859f7fa7 meta: review meta_base_node::cast and meta_any::try_cast to reduce their sizes 2022-09-13 15:57:44 +02:00
Michele Caini
cc4d4dfc2b meta: also make vs2017 happy if possible 2022-09-13 12:45:49 +02:00
Michele Caini
bd62e817dc meta: reduce the size of the erased conversion function 2022-09-13 12:33:14 +02:00
Michele Caini
de34a109e1 meta: internal meta_arg_node is back to its old, unsafe version 2022-09-13 12:08:25 +02:00
Michele Caini
e0e45719fa meta: minor changes 2022-09-12 10:59:08 +02:00
Michele Caini
b21b254258 meta: avoid non-standard rvalue-to-lvalue bindings :) 2022-09-12 10:57:04 +02:00
Michele Caini
ca3ef33f46 meta: further reduce the size of the resolve function 2022-09-12 10:46:53 +02:00
Michele Caini
8c4803d906 meta: minor changes 2022-09-12 10:46:52 +02:00
Michele Caini
ffb9e4b0eb meta: shrink function templates a bit 2022-09-12 10:46:49 +02:00
Michele Caini
6010dbc368 meta: pre-instantiate the details section when constructing a factory 2022-09-12 10:46:46 +02:00
Michele Caini
a6343bd152 doc: updated links (close #933) 2022-09-09 14:14:22 +02:00
Michele Caini
9e4a7f48a4 meta: try to also make clang happy 2022-09-09 12:02:57 +02:00
Michele Caini
6ad7424d4a meta: minor changes 2022-09-08 18:02:07 +02:00
Michele Caini
218fa1ba35 meta: share common code if possible 2022-09-08 15:11:09 +02:00
Michele Caini
b45db747a8 meta: review meta_arg[_node] + increase code coverage 2022-09-08 13:29:10 +02:00
Michele Caini
eedecc07fd meta: avoid tricks and whatnot with meta_arg_node 2022-09-08 10:28:49 +02:00
Michele Caini
dcea36de7a meta: try to share common code if possibile 2022-09-07 17:51:11 +02:00
Michele Caini
ed0e3f4435 meta: share common code 2022-09-07 16:17:29 +02:00
Michele Caini
8595e4bd99 meta: review meta containers to further reduce memory usage 2022-09-07 14:58:44 +02:00
Michele Caini
e31b81294d meta: minor changes for consistency 2022-09-07 14:54:34 +02:00
Michele Caini
ac6e9cf2f0 meta: further reduce the number of instantiations 2022-09-07 14:32:15 +02:00
Michele Caini
dac4ae94c0 meta: further reduce the number of instantiations 2022-09-07 12:48:40 +02:00
Michele Caini
b31b585805 natvis: update meta 2022-09-07 11:33:15 +02:00
Michele Caini
1368c56655 meta: avoid storing meta type nodes by reference in the meta factory 2022-09-07 11:32:49 +02:00
Michele Caini
6cab12a14f test: code coverage 2022-09-06 23:42:12 +02:00
Michele Caini
924a09a9c5 meta: minor changes (to suppress warnings) 2022-09-06 23:42:12 +02:00
Michele Caini
e4f6293f42 meta: use the hot/cold model with meta_type_node 2022-09-06 23:42:12 +02:00
Michele Caini
f197b32b02 meta: cleanup 2022-09-06 23:42:12 +02:00
Michele Caini
b80ab36418 meta: use the hot/cold model with meta_func_node 2022-09-06 23:42:12 +02:00
Michele Caini
d5588333f7 meta: use the hot/cold model with meta_data_node 2022-09-06 23:42:12 +02:00
Michele Caini
10755275ea meta: use the hot/cold model with meta_prop_node 2022-09-06 23:42:12 +02:00
Michele Caini
a30cecdf36 meta: use a shared_pointer to void for meta properties 2022-09-06 23:42:12 +02:00
Michele Caini
0068afa06c meta: cleanup 2022-09-06 23:42:12 +02:00
Michele Caini
38597a6499 meta: hot/cold data to allow copies of meta nodes 2022-09-06 23:42:12 +02:00
Michele Caini
65ee240e8e meta: add a test (and a fix) for a corner case of meta_reset 2022-09-06 23:42:12 +02:00
Michele Caini
336bcf4d11 test: minor changes 2022-09-06 23:42:12 +02:00
Michele Caini
ed74a4c213 meta: explicit initialization of all values of a meta object 2022-09-06 23:42:12 +02:00
Michele Caini
3e29617da8 doc: meta 2022-09-06 23:42:11 +02:00
Michele Caini
715b3e450f meta: make meta_factory<...>::type id argument required 2022-09-06 23:42:11 +02:00
Michele Caini
1ab10f3b28 meta: range iterator is an input iterator but models a random access iterator (close #927) 2022-09-06 23:42:11 +02:00
Michele Caini
304d8a80be meta: avoid warnings due to unused variables 2022-09-06 23:42:11 +02:00
Michele Caini
560a3f664e meta: drop meta_func_node::watermark, compare pointers to invoke instead 2022-09-06 23:42:11 +02:00
Michele Caini
41081204f9 tests: minor changes 2022-09-06 23:42:11 +02:00
Michele Caini
b895dfc901 nativs: review meta after the rework 2022-09-06 23:42:11 +02:00
Michele Caini
93a1d65103 meta: meta_type_node is no longer static 2022-09-06 23:42:11 +02:00
Michele Caini
443d53400d meta: decouple meta containers and meta_type_node 2022-09-06 23:42:11 +02:00
Michele Caini
9725582089 meta: use insert_or_assign rather than operator[] 2022-09-06 23:42:11 +02:00
Michele Caini
cd2634a5d4 meta: use lvalue refs to meta any to construct meta handles 2022-09-06 23:42:11 +02:00
Michele Caini
798d1a4f9e meta: add missing template keywords (love you, msvc) 2022-09-06 23:42:11 +02:00
Michele Caini
e13996f68a meta avoid shadow warnings 2022-09-06 23:42:11 +02:00
Michele Caini
1ee077d511 meta: minor internal changes (try to make all compilers happy) 2022-09-06 23:42:11 +02:00
Michele Caini
ccf301c73d test: review/minor changes 2022-09-06 23:42:11 +02:00
Michele Caini
461fe715b7 meta: decouple meta_template_node and meta_type_node 2022-09-06 23:42:11 +02:00
Michele Caini
9549bb4f4d meta: decouple meta_func_node and meta_type_node 2022-09-06 23:42:11 +02:00
Michele Caini
0215722103 meta: decouple meta_data_node and meta_type_node 2022-09-06 23:42:11 +02:00
Michele Caini
7c6606f27e meta: decouple meta_base_node and meta_type_node 2022-09-06 23:42:11 +02:00
Michele Caini
f0b10965fb meta: decouple meta_prop_node and meta_type_node 2022-09-06 23:42:10 +02:00
Michele Caini
53f2bb7701 meta: meta_func_node is no longer static 2022-09-06 23:42:10 +02:00
Michele Caini
945e61d668 meta:
* meta_prop_node is no longer static
* we can attach multiple properties at different times
* meta property keys are of type id_type only
* removed meta_factory::props (use prop instead)
* meta range returns id and meta object pairs now
* removed mera_prop::key (id returned by meta ranges)
2022-09-06 23:42:10 +02:00
Michele Caini
e74c4bb684 meta: improve internal meta_from_void function 2022-09-06 23:42:10 +02:00
Michele Caini
a8eebcb0e2 meta: make meta_range iterators return an id and meta object pair 2022-09-06 23:42:10 +02:00
Michele Caini
1581aa1cf5 meta: meta_ctor_node is no longer static 2022-09-06 23:42:10 +02:00
Michele Caini
839a2cc86d meta: removed meta_data::id 2022-09-06 23:42:10 +02:00
Michele Caini
3062114f0c meta: meta_data_node is no longer static 2022-09-06 23:42:10 +02:00
Michele Caini
ab3abf23ed meta: avoid allocations for meta_template_node 2022-09-06 23:42:10 +02:00
Michele Caini
b5a7812ab4 meta: added meta_dtor_node for consistency 2022-09-06 23:42:10 +02:00
Michele Caini
565de36155 meta: meta_base is no longer static 2022-09-06 23:42:10 +02:00
Michele Caini
c76f078834 meta: prepare for iterator based meta range 2022-09-06 23:42:10 +02:00
Michele Caini
358a9742c5 meta: removed meta_type::base(id_type) because pointless 2022-09-06 23:42:10 +02:00
Michele Caini
7f9e200cfb meta: meta_conv_node is no longer static 2022-09-06 23:42:10 +02:00
Michele Caini
a12710af70 meta: meta_template_node is no longer static 2022-09-06 23:42:10 +02:00
Michele Caini
871234ec76 any: avoid declaring nested types in an union 2022-09-06 23:41:45 +02:00
Michele Caini
0c062cc351 any: refine replacement for std aligned storage (see #919) 2022-09-06 23:09:44 +02:00
Michele Caini
67271e4672 registry: start to introduce the allocator (work in progress) 2022-09-06 09:43:34 +02:00
Michele Caini
2489a95dab registry: don't store the allocator aside anymore 2022-09-06 08:33:10 +02:00
Michele Caini
70b8bd27b8 any/poly: avoid using aligned_storage_t (deprecated - close #919) 2022-09-05 15:32:49 +02:00
Michele Caini
ee88cf16d1 any: avoid using storage_type to compute in_situ 2022-09-05 15:30:29 +02:00
Michele Caini
d83e818517 test: avoid using aligned_storage_t if possible (see #919) 2022-09-02 15:23:47 +02:00
Michele Caini
6462ceb1f5 meta: turn meta_any::operator!= into an in-class method (close #917) 2022-09-02 10:10:10 +02:00
Michele Caini
e2f8ea110a any: turn operator!= into an in-class method 2022-09-02 10:09:02 +02:00
Kyriet
f1acbbedf9 doc: add section about sorting and reverse-iterating views (#918) 2022-08-31 11:29:46 +02:00
Philipp Kurth
8510f535a5 storage: storage_iterator doesn't refer to the right specialization of component_traits (#924) 2022-08-30 12:16:52 +02:00
Michele Caini
9a97a57423 storage: test the proper use of component traits by the storage iterator 2022-08-30 12:13:57 +02:00
Michele Caini
a50cc628ec natvis: drop meta_type_node is_pointer 2022-08-29 14:30:44 +02:00
Michele Caini
dc922c9e4c storage: how the code coverage tool can be hated sometimes :) 2022-08-29 12:35:34 +02:00
Michele Caini
2f2b0cf98a test: minor changes (help the code coverage tool) 2022-08-29 12:11:55 +02:00
Michele Caini
798d5eeb86 storage: minor changes (help the code coverage tool) 2022-08-29 12:04:35 +02:00
Michele Caini
02d8cefcde locator: avoid shadow warnings 2022-08-29 11:48:17 +02:00
Michele Caini
f627593d63 build system: add explicit dependencies for plugin tests 2022-08-29 11:32:16 +02:00
Michele Caini
9aeddc2cb1 locator: lib plugin test 2022-08-29 11:25:37 +02:00
Michele Caini
6650071d24 locator: lib test 2022-08-29 11:08:03 +02:00
Michele Caini
006822c7fc build system: set PIC property for odr target explicitly 2022-08-29 09:48:23 +02:00
Michele Caini
8bed15e469 natvis: update registry snippet 2022-08-28 18:55:58 +02:00
Michele Caini
4200bb9ebb locator: ::handle and extended ::reset 2022-08-27 17:35:42 +02:00
Michele Caini
fdae346aa6 doc: typo (thanks @DNKpp) 2022-08-25 15:07:34 +02:00
Michele Caini
01acb15fab meta: avoid using traits if not needed 2022-08-22 16:58:00 +02:00
Michele Caini
3a6764a685 meta: any and meta_any catchall ctors work the same 2022-08-22 16:56:02 +02:00
Michele Caini
e2e8a575c6 *: minor changes 2022-08-22 16:35:35 +02:00
Michele Caini
7205fb63fa dense_set: minor changes 2022-08-22 16:35:32 +02:00
Michele Caini
c7b59fdc14 entity/*: minor changes 2022-08-22 16:35:28 +02:00
Michele Caini
e9a59bb014 registry: swap 2022-08-11 12:15:49 +02:00
Michele Caini
76ba063f29 registry:
* accept allocator upon construction
* no allocator-extended move ctor due to type erasure (we can't pass it to pools)
2022-08-11 11:40:57 +02:00
Michele Caini
2988a74fe4 registry: prepare allocator support (still an unused parameter) 2022-08-10 11:10:18 +02:00
Michele Caini
72bc9e3973 doc: cleanup 2022-08-10 10:13:12 +02:00
Michele Caini
31fb2bc2c3 group: basic_registry is no longer a friend class 2022-08-10 08:18:52 +02:00
Michele Caini
768f8cd74c storage mixin: prepare for cross registry mixin 2022-08-10 07:59:42 +02:00
Michele Caini
751e044ce2 sigh_storage_mixin: use the allocator as it ought to be 2022-08-10 07:57:00 +02:00
Michele Caini
3406250cf6 iwyu: cleanup 2022-08-09 18:04:38 +02:00
Michele Caini
e510bdf4f2 dot: updated includes 2022-08-09 18:02:43 +02:00
Michele Caini
fccdff05e3 dense_map: equal_range 2022-08-09 09:50:55 +02:00
Michele Caini
e530b3d6f6 dense_set: equal_range 2022-08-09 09:50:52 +02:00
Michele Caini
0f0b70be23 iwyu: use imp file rather than intrusive pragma exports 2022-08-08 10:59:27 +02:00
Michele Caini
e39f235287 test: review includes 2022-08-06 17:36:04 +02:00
Michele Caini
af5acb8d32 test: minor changes 2022-08-05 18:40:17 +02:00
Michele Caini
a2f70cb5e4 emitter: updated includes 2022-08-05 18:38:53 +02:00
Michele Caini
25d10f03bb iwyu: export all fwd includes 2022-08-05 17:47:42 +02:00
Michele Caini
85c1ad060f test: minor changes 2022-08-05 12:28:22 +02:00
Michele Caini
d9b1cc0db3 iwyu: begin/end exports directive for entt.hpp/fwd.hpp (see #777) 2022-08-05 12:28:05 +02:00
Michele Caini
34205014e9 test: review includes 2022-08-05 12:06:10 +02:00
Michele Caini
749106aa47 test: suppress iwyu warnings for odr.cpp 2022-08-05 12:05:45 +02:00
Michele Caini
b828e0295a build system: update analyzer workflow 2022-08-05 11:46:53 +02:00
Michele Caini
2345002c1c build system: add iwyu workflow (see #777) 2022-08-05 08:56:35 +02:00
Michele Caini
2ce18a47b4 cleanup TODO file 2022-08-05 08:54:20 +02:00
Michele Caini
76b380d7c0 meta: review meta_any::allow_cast 2022-08-04 15:14:43 +02:00
Michele Caini
d3244ab4da cleanup TODO file 2022-08-04 10:58:00 +02:00
Michele Caini
d06ccfb8e3 test: remove unused variable 2022-08-03 18:16:22 +02:00
Michele Caini
6f807d6f9e dense_set: added count 2022-08-03 18:10:03 +02:00
Michele Caini
2b0045e23e dense_map: added count 2022-08-03 18:09:52 +02:00
Michele Caini
57067bc362 dense_set: add max_size 2022-08-03 17:47:54 +02:00
Michele Caini
abe185c003 dense_map: add max_size 2022-08-03 17:47:45 +02:00
Michele Caini
85ca2f3562 doc: updated entity.md and README files 2022-08-03 11:24:23 +02:00
Michele Caini
3d03b01439 storage: full support for non-movable types (close #905) 2022-08-03 10:57:51 +02:00
Michele Caini
879e7d775f component: yet another piece to fully support non-movable types (see #905) 2022-08-02 14:06:35 +02:00
Michele Caini
e9dbd10db4 storage: fix cross range-erase can break when using built-in iterators (close #914) 2022-08-02 09:56:24 +02:00
Michele Caini
acc95bd9b7 doc: registry context 2022-08-02 08:41:45 +02:00
Michele Caini
504c7b5d6d registry (close #911):
* added context emplace_as
* deprecated context emplace_hint
2022-08-02 08:40:06 +02:00
Michele Caini
b20ab29d82 registry: context insert_or_assign 2022-08-02 08:35:10 +02:00
Michele Caini
95b16a0b04 sparse_set: fix cross range-erase can break when using built-in iterators (close #913) 2022-08-01 11:04:56 +02:00
Michele Caini
6ee64d1dc2 *: add a couple of <functional> because of equal_to 2022-07-29 12:06:25 +02:00
Michele Caini
83ecd2d1d9 test: suppress all death tests in release 2022-07-29 10:49:03 +02:00
Michele Caini
325a5dd353 test: utilities to suppress death tests in release 2022-07-29 10:46:15 +02:00
Michele Caini
e0ee35da61 sparse_set/storage/sigh_storage_mixin:
* prepare to support non-movable, non-copyable types
* improve destroying entities
2022-07-29 09:26:28 +02:00
Michele Caini
b3fde98020 build system: make pkg-config work with includedir as absolute paths (close #890) 2022-07-28 11:14:32 +02:00
Michele Caini
3c7c21cea3 cmake: add hand made join_paths (because we don't use cmake v3.20+ yet) 2022-07-28 11:13:12 +02:00
Michele Caini
c73d6c52bf registry context: add get, deprecate at (close #911) 2022-07-28 08:54:43 +02:00
Michele Caini
c38c1454b4 test: code coverage 2022-07-27 10:09:09 +02:00
Michele Caini
06d1d23273 test: minor changes 2022-07-27 09:48:47 +02:00
Michele Caini
4081b46302 test: clean up 2022-07-27 08:55:11 +02:00
Michele Caini
914bf49656 natvis: update emitter definition 2022-07-27 08:54:42 +02:00
Michele Caini
dc634c61c4 natvis: runtime view 2022-07-27 08:54:19 +02:00
Michele Caini
566878b29c natvis: update registry context definition 2022-07-27 08:54:03 +02:00
Michele Caini
0060479e33 cmake: remove aob workflow 2022-07-26 10:23:04 +02:00
Michele Caini
1a0d892201 doc: cleanup 2022-07-26 09:41:10 +02:00
Michele Caini
0424b63bf1 registry: decouple asserts 2022-07-26 09:41:01 +02:00
Michele Caini
de9d3c04e2 registry: remove redundant check 2022-07-25 17:08:19 +02:00
Michele Caini
b0e4a853cf view: drop redundant asserts 2022-07-25 16:35:09 +02:00
Michele Caini
ac8dfe29ae group: drop redundant asserts 2022-07-25 16:35:03 +02:00
Michele Caini
9d33a38ec4 registry: bypassing the check is possible already, remove it as a whole then 2022-07-25 15:25:06 +02:00
Michele Caini
e3076fa5d1 registry: drop useless validity check from remove 2022-07-21 17:14:59 +02:00
Michele Caini
2067b2aea6 registry: remove redundant validity check from orphan 2022-07-21 15:05:01 +02:00
Michele Caini
a14af95f9d registry: remove useless validity check from a get 2022-07-21 11:39:31 +02:00
Michele Caini
8fd2ce8d47 registry: remove useless validity check from erase 2022-07-21 10:56:53 +02:00
Michele Caini
d6edc64d65 registry: remove useless check when invoking patch 2022-07-21 10:19:36 +02:00
Michele Caini
f882158387 registry: renaming for consistency 2022-07-20 17:59:32 +02:00
Michele Caini
6f852c2dcb registry: minor changes 2022-07-20 17:59:22 +02:00
Michele Caini
e47e74fc76 registry: remove validity check from erase 2022-07-20 14:49:49 +02:00
Michele Caini
e604060369 registry: remove validity check from try_get 2022-07-20 14:47:54 +02:00
Michele Caini
80f8051c57 registry: remove validity check from patch 2022-07-20 12:53:44 +02:00
Michele Caini
612c499a3d registry: remove validity check from get 2022-07-20 12:52:11 +02:00
Michele Caini
cceffe6ac4 registry: renaming for consistency 2022-07-19 19:15:04 +02:00
Michele Caini
a74416c730 registry: remove validity check from any_of/all_of 2022-07-19 16:47:33 +02:00
Michele Caini
0830704484 container/*: minor changes 2022-07-19 15:14:08 +02:00
Michele Caini
79f7eaaf9a handle: include null as it ought to be 2022-07-19 08:08:43 +02:00
Michele Caini
389e038445 registry/context: prepare to allocator support 2022-07-18 15:18:00 +02:00
Michele Caini
8f84bd7091 emitter: allocator support 2022-07-18 14:29:31 +02:00
Michele Caini
2146e3ded9 dispatcher: minor changes 2022-07-18 14:28:59 +02:00
Michele Caini
97c0582765 emitter: cleanup/simplification 2022-07-15 08:43:44 +02:00
Michele Caini
c3f230956c organizer: cleanup/remove dependency from <algorithm> 2022-07-15 08:41:46 +02:00
Michele Caini
b914a4a93e meta: try to please all compilers (again) 2022-07-14 09:22:57 +02:00
Michele Caini
befa0fe213 doc: meta 2022-07-14 08:46:06 +02:00
Michele Caini
61ef5a44e0 meta:
* improved sequence container support for non-contiguous containers
* added support to (standard) deque as sequence containers
2022-07-14 08:45:59 +02:00
Michele Caini
131fd0d778 doc: updated readme 2022-07-14 08:43:33 +02:00
Michele Caini
8973757b43 updated TODO (gh stuff) 2022-07-13 11:48:30 +02:00
Michele Caini
14ce88730f meta: minimal (and still inefficient) support for lists as sequence containers 2022-07-13 11:48:30 +02:00
Michele Caini
84cbfb2f91 meta: use clear rather than reserve to spot dynamic sequence containers 2022-07-13 11:48:30 +02:00
Michele Caini
e8f8520251 dense_set: fix an issue when erasing movable keys 2022-07-13 11:24:40 +02:00
Michele Caini
c26558cd6d dense_map: fix an issue when erasing movable keys 2022-07-13 11:24:29 +02:00
Paolo Monteverde
71feb0516d adjacency_matrix: update allocator aware constructor (#909) 2022-07-13 11:22:20 +02:00
Michele Caini
382187089c meta: make meta_type::from_void const as it ought to be 2022-07-11 10:31:08 +02:00
Michele Caini
4faeb5c44e dispatcher: removed unused/useless code 2022-07-07 10:41:53 +02:00
Michele Caini
ac8f569280 nativs: updated meta type representation 2022-07-06 12:16:47 +02:00
Michele Caini
669420d31c meta: try to please all compilers (as usual) 2022-07-06 11:52:32 +02:00
Michele Caini
df48cc9471 meta: minor changes 2022-07-06 11:30:45 +02:00
Michele Caini
274a08070f meta: meta_type::from_void support 2022-07-06 11:30:43 +02:00
Michele Caini
c0e20825ac metx: ctx.hpp -> context.hpp 2022-07-06 11:30:40 +02:00
Michele Caini
15d821f2f8 helper: review includes 2022-07-05 08:39:48 +02:00
Michele Caini
acbd38c1ed container/entity: noexcept-ness review 2022-07-05 08:39:16 +02:00
Michele Caini
92f5f97d83 entity/*: updated includes 2022-07-05 08:36:24 +02:00
Michele Caini
1128b9de81 dispatcher: remove unused include 2022-07-04 17:46:33 +02:00
Michele Caini
fcd60467a7 memory: minor/internal changes 2022-07-04 17:46:03 +02:00
Michele Caini
2f51341633 meta: a few optimizations/improvements (size bench review) 2022-07-04 08:27:05 +02:00
Michele Caini
5799f407ae meta: minor changes 2022-07-04 08:27:02 +02:00
Michele Caini
c7a5e09c0e meta container: small changes 2022-07-04 08:26:58 +02:00
Michele Caini
3318ac2699 meta: reduce a little the number and size of vtables/fake functions 2022-07-04 08:26:53 +02:00
Michele Caini
437f1fea54 view: suppress shadow warnings 2022-07-03 12:23:08 +02:00
Michele Caini
3ab43f894f organizer: suppress shadow warnings 2022-07-03 12:23:03 +02:00
Michele Caini
86f98f40a1 test: added missing include 2022-07-03 12:22:53 +02:00
Michele Caini
655f1dd906 doc: minor changes 2022-07-01 18:56:02 +02:00
Michele Caini
243a382485 registry: drop some lambdas and calls to std:: 2022-07-01 18:09:37 +02:00
Michele Caini
4b74163306 meta: turn the meta_range class into an alias of iterable_adaptor 2022-07-01 18:09:35 +02:00
Michele Caini
50e67d7c15 view: drop <algorithm> (no longer required) 2022-07-01 16:00:47 +02:00
Michele Caini
c5afd8f589 dense_map: remove <algorithm> (no longer required) 2022-07-01 16:00:44 +02:00
Michele Caini
c6ab65d552 meta: coding style 2022-07-01 09:50:55 +02:00
Michele Caini
1a853fe145 doc: core, iterator.hpp 2022-07-01 09:18:00 +02:00
Michele Caini
72abc8e4c4 doc: minor changes 2022-07-01 09:17:49 +02:00
Michele Caini
e15ad2e21b storage: minor changes (for consistency) 2022-06-30 18:35:38 +02:00
Michele Caini
5afc5529c2 doc: runtime_view 2022-06-30 18:32:57 +02:00
Michele Caini
7eed368dc2 sparse_set: minor changes 2022-06-30 16:09:28 +02:00
Michele Caini
600303bb5b observer: derive from storage rather than using one internally 2022-06-30 15:52:43 +02:00
Michele Caini
bcfd6d1b4f runtime view: allocator support 2022-06-29 18:27:43 +02:00
Michele Caini
e65b3a790d runtime view: const/non-const support 2022-06-29 18:27:41 +02:00
Michele Caini
a28467d393 dense set/map: drop <algorithm> and save some bytes here and there 2022-06-29 18:27:25 +02:00
Michele Caini
bf13d9363d updated TODO 2022-06-29 18:27:21 +02:00
Michele Caini
ff9c472f86 registry: remove unused header 2022-06-29 18:27:17 +02:00
Michele Caini
46e601db6e natvis: print both the index and the entity for the storage representation 2022-06-29 18:27:14 +02:00
Michele Caini
d4482d0d26 oeganizer: use a flow builder under the hood 2022-06-29 18:27:11 +02:00
Michele Caini
281289c46a flow: set-with-mode function to ease the transition of the observer class 2022-06-29 18:27:09 +02:00
Michele Caini
bc85d96938 meta: remove a few lambdas 2022-06-29 18:26:12 +02:00
Michele Caini
c2475381fd meta: make meta_associative_container::erase return the number of elements removed 2022-06-29 18:25:47 +02:00
Michele Caini
6ac14f35ad doc: minor changes 2022-06-29 18:25:32 +02:00
Michele Caini
de18834c91 view: remove useless member 2022-06-24 10:51:08 +02:00
Michele Caini
fc7d28c723 test: view constructors 2022-06-24 08:55:31 +02:00
Michele Caini
7ac2ce50a0 registry: use internal type member storage_for_type 2022-06-24 08:53:45 +02:00
Michele Caini
9cf9661484 doc: minor changes 2022-06-24 08:22:51 +02:00
Michele Caini
8dbf00ad3a flow: minor changes 2022-06-23 14:43:22 +02:00
Michele Caini
e0e623fa36 doc: links 2022-06-23 08:57:34 +02:00
Michele Caini
4094669222 doc: typo 2022-06-23 08:51:12 +02:00
Michele Caini
9e19244659 flow: added a couple of [[nodiscard]] 2022-06-23 08:37:17 +02:00
Michele Caini
d41ccb6b34 doc: tabs -> spaces 2022-06-23 08:36:28 +02:00
Michele Caini
72c1da2507 view: storage based model 2022-06-22 09:07:25 +02:00
Michele Caini
2e8c5ea2de doc: typo 2022-06-22 09:05:31 +02:00
Michele Caini
65561fe431 group: minor changes 2022-06-22 09:02:37 +02:00
Michele Caini
cf401aa0b5 doc: minor changes 2022-06-22 09:00:46 +02:00
Michele Caini
9b2c9936c2 doc: dot 2022-06-21 18:30:26 +02:00
Michele Caini
e4aabc7feb adjacency_matrix: single edge iterator 2022-06-21 18:11:36 +02:00
Michele Caini
610951771e adjacency_matrix: add error messages 2022-06-21 14:31:59 +02:00
Michele Caini
f76959af63 test: suppress warnings due to unused variables 2022-06-21 14:24:49 +02:00
Michele Caini
0eb5b0437b dot: directed/undirected support 2022-06-21 12:36:23 +02:00
Michele Caini
c1ac684f9a adjacency_matrix: directed/undirected tag 2022-06-21 12:28:59 +02:00
Michele Caini
473c36aba5 adjacency_matrix:
* make swap accept the right type
* make resize work properly
2022-06-21 11:02:23 +02:00
Michele Caini
38e6722358 dot: try to also please gcc 2022-06-21 09:49:47 +02:00
Michele Caini
d2a0f86908 dot: first draft 2022-06-21 09:26:32 +02:00
Michele Caini
c6707bec97 test: handle 2022-06-20 12:49:33 +02:00
Michele Caini
5c6a11cb8f test: minor changes 2022-06-20 08:30:26 +02:00
Michele Caini
600cc5e167 handle: since it's a reference type, we don't need two overloads for storage 2022-06-20 08:27:57 +02:00
Michele Caini
c441a9ad97 handle: remove visit, use iterable objects instead 2022-06-20 08:22:57 +02:00
Michele Caini
c2d2ba29ea doc: typo 2022-06-18 16:21:37 +02:00
Michele Caini
25af23d3ff registry: minor changes 2022-06-18 16:17:25 +02:00
Michele Caini
cbd6fd8aee view: minor changes 2022-06-18 16:17:07 +02:00
Michele Caini
7a7fc20438 doc: typo (close #898) 2022-06-17 17:10:50 +02:00
Michele Caini
ca4b2b68a7 updated TODO 2022-06-17 17:01:47 +02:00
Michele Caini
f3ae553706 doc: minor changes - thanks @morbo84 2022-06-17 16:27:04 +02:00
Michele Caini
fe6696b107 graph: sync point 2022-06-17 16:06:49 +02:00
Michele Caini
3a85d0f179 doc: graph 2022-06-17 11:39:07 +02:00
Michele Caini
9845d2c87d adjacency_matrix:
* iterator review
* in_edges iterable
2022-06-17 11:36:11 +02:00
Michele Caini
ea8730c2a9 doc: typo (close #896) 2022-06-16 09:53:51 +02:00
Michele Caini
c81868f8f7 flow: removed ::tasks, added operator[] 2022-06-16 09:51:18 +02:00
Michele Caini
33d1839b75 flow: task -> bind 2022-06-16 09:37:12 +02:00
Michele Caini
df10a01af9 flow: increase code coverage, simplify the internals 2022-06-16 09:30:21 +02:00
Michele Caini
4aa40aba4c build system: try to satisfy codecov requirements 2022-06-16 09:01:01 +02:00
Michele Caini
696c94e2ea flow: suppress shadow warnings 2022-06-16 08:23:30 +02:00
Michele Caini
bc5dfb9371 graph: flow (first draft) 2022-06-16 08:11:45 +02:00
Michele Caini
88c63b941d natvis: graph 2022-06-16 07:48:41 +02:00
Michele Caini
b8e12dc42a doc: minor changes 2022-06-15 09:21:49 +02:00
Michele Caini
2974e959e5 doc:: minor changes 2022-06-15 09:11:36 +02:00
Michele Caini
67b2fc085c view: prepare to storage based model 2022-06-15 09:01:57 +02:00
Michele Caini
cb202c15a5 group: minor changes 2022-06-15 09:01:41 +02:00
Michele Caini
850abd440b doc: typo 2022-06-15 08:28:00 +02:00
Michele Caini
01d125f53d group: storage based model 2022-06-14 08:07:01 +02:00
Michele Caini
3f0572c5ce graph: class vs struct definition 2022-06-13 00:39:53 +02:00
Michele Caini
cc6c45f591 adjacency_matrix: edges -> out_edges 2022-06-04 11:40:52 +02:00
Michele Caini
8029777c4e graph: (currently directed only) adjacency_matrix 2022-06-04 10:52:28 +02:00
Michele Caini
a6171551bd input_iterator_pointer: operator* 2022-06-04 09:16:18 +02:00
Michele Caini
6bb67ab5da process: fwd file 2022-06-03 19:42:37 +02:00
Michele Caini
a31c492c83 core: iota_iterator (waiting for C++20) 2022-06-03 19:25:47 +02:00
Michele Caini
c36d5e4a9c organizer: minor changes 2022-06-03 18:56:52 +02:00
Michele Caini
17b3fc93b0 updated todo file 2022-06-01 09:42:02 +02:00
Michele Caini
d2f4ffc433 registry/storage: minor changes 2022-06-01 09:41:41 +02:00
Michele Caini
1c8a296f49 doc: minor changes 2022-06-01 09:21:43 +02:00
Michele Caini
de0e5862dd meta: use a more explicit static_cast (!! tricks some tools) 2022-05-31 10:37:04 +02:00
Michele Caini
e822b8c99e meta: minor changes 2022-05-31 10:33:27 +02:00
Michele Caini
48d767749d meta: removed redundant meta_traits::is_pointer 2022-05-31 10:23:34 +02:00
Michele Caini
fa48c76dd1 any: drop useless remove_const_t 2022-05-29 12:10:32 +02:00
Michele Caini
754fe9f4ec any: make things explicit to avoid cast to same type warnings 2022-05-29 12:09:23 +02:00
Michele Caini
1ad3adfff0 any: drop pointless cast 2022-05-29 12:03:42 +02:00
Michele Caini
0c0fd4d7f7 storage_for: minor changes 2022-05-29 10:08:07 +02:00
Michele Caini
72f5df82b2 doc: some links :) 2022-05-29 09:41:56 +02:00
Michele Caini
c7407f5b6a view:
* reduce (a lot) the number of instantiations due to tuples
* review operator|
2022-05-27 19:03:28 +02:00
Michele Caini
f57975acca view: avoid delegating constructors with tuples 2022-05-27 18:12:38 +02:00
Michele Caini
a8a0c9e571 test: minor changes 2022-05-27 16:39:54 +02:00
Michele Caini
e05277d56a registry: use storage_for[_t] 2022-05-26 11:50:31 +02:00
Michele Caini
0b1985ca7e view: use storage_for[_t] 2022-05-26 11:50:22 +02:00
Michele Caini
637764ee4e group: use storage_for[_t] 2022-05-26 08:46:53 +02:00
Michele Caini
c6e613c317 storage: storage_for[_t] utility 2022-05-26 08:25:47 +02:00
Michele Caini
aa3e769463 doc: type_list_transform 2022-05-25 23:04:15 +02:00
Michele Caini
630ba195d1 input_iterator_pointer: no reason for which it shouldn't be copyable 2022-05-25 16:51:44 +02:00
Michele Caini
13276d2f10 input_iterator_pointer: minor changes 2022-05-25 16:48:07 +02:00
Michele Caini
d59407a339 any: makes assign work for all basic_any types 2022-05-25 16:46:50 +02:00
Michele Caini
92c2fd9409 hashed_string: nit 2022-05-25 11:42:10 +02:00
Michele Caini
063e6160e0 natvis: explicit entity-component mapping 2022-05-25 11:39:42 +02:00
Michele Caini
6155a10037 doc: minor changes 2022-05-25 11:24:20 +02:00
Michele Caini
7428cb353c storage: add default entity type to storage_type 2022-05-25 10:32:40 +02:00
Michele Caini
fe3b5b03eb entity/invoke: properly decay deduced argument to avoid nasty errors with reference types 2022-05-24 14:11:19 +02:00
Michele Caini
497fb90b12 doc: updated core.md 2022-05-24 10:59:50 +02:00
Michele Caini
48ab892de1 type_traits: type_list_transform[_t] utility 2022-05-24 10:59:40 +02:00
Michele Caini
a85ad88d5a entitiy/invoke: use nth_argument_t and avoid explicitly mentioning the registry 2022-05-24 08:31:14 +02:00
Michele Caini
cf2566ff74 doc: nth_argument (core) 2022-05-23 11:47:04 +02:00
Michele Caini
619f51518a type_traits: nth_argument utility (with tests) 2022-05-23 11:46:50 +02:00
Michele Caini
b26330adab delegate: minor changes 2022-05-23 11:35:11 +02:00
Michele Caini
83009bac02 resource: remove use_count (close #889) 2022-05-21 14:18:05 +02:00
Michele Caini
8780d536c7 resource: add member function handle 2022-05-21 14:14:15 +02:00
Michele Caini
99f4134d9d resource: add type member handle_type 2022-05-21 14:12:31 +02:00
Michele Caini
ca02ab7d5d resource: add type member element_type 2022-05-21 14:11:25 +02:00
kcalbCube
dc295ca0e1 doc: add an notice about possible undefined behaviour. (#887) 2022-05-20 10:44:25 +02:00
Michele Caini
8ee91095c5 organizer: make it depend on the registry type and not the entity type 2022-05-20 09:07:32 +02:00
Michele Caini
49c7b2f8f4 entity/*: renaming things to make them clear 2022-05-19 09:00:04 +02:00
Michele Caini
5d80cf11ef helper: decouple invoke and to_entity from the registry type 2022-05-19 08:15:17 +02:00
Michele Caini
bc929bcb90 snapshot: suppress warnings/errors due to shadow template parameters 2022-05-18 15:21:35 +02:00
Michele Caini
26a3057acf handle: decouple from entity type, make it work with all registry types 2022-05-18 15:02:25 +02:00
Michele Caini
96cf0a6d02 handle: prepare for a registry oriented version 2022-05-18 11:12:53 +02:00
Michele Caini
12e773f3fb as_group/as_view: make them transparent to the registry type 2022-05-17 12:40:47 +02:00
Michele Caini
c321997591 snapshot/loader: support all types of registry (allocator oriented) 2022-05-17 12:35:45 +02:00
Michele Caini
b2d98452f1 observer: support all types of registry (allocator oriented) 2022-05-17 12:28:54 +02:00
Michele Caini
16e48aa10f storage_type_t: simplify the definition to make it work with default template arguments for storage_type 2022-05-17 12:17:44 +02:00
Michele Caini
4da85a5f4a storage_type[_t]: flip entity type and value type 2022-05-17 12:07:21 +02:00
Michele Caini
a5c9d3a809 basic_storage: flip entity type and value type 2022-05-17 11:55:53 +02:00
Michele Caini
f288ba744d test: cleanup 2022-05-17 11:35:32 +02:00
Michele Caini
ba5b85de00 storage: use storage_type_t everywhere 2022-05-16 08:59:04 +02:00
Michele Caini
bd2f412225 storage: add storage_type_t 2022-05-16 08:25:50 +02:00
Michele Caini
a86cf32f55 entity: storage_traits -> storage_type 2022-05-16 08:25:23 +02:00
Michele Caini
0c8178c753 view/group/registry: storage_type -> storage_for (prepare for storage_type_t) 2022-05-15 10:45:33 +02:00
Michele Caini
b59e06ec89 storage_traits: storage_type -> type 2022-05-13 14:11:23 +02:00
Michele Caini
10153a371b sparse_set: use null values as watchdogs 2022-05-13 12:12:48 +02:00
Michele Caini
a93c1478c0 sparse_set: check against null rather than tombstone (prepare support for enable/disable) 2022-05-13 11:10:08 +02:00
Michele Caini
215b7a19c9 test: suppress warning due to integral conversions 2022-05-12 17:51:03 +02:00
Michele Caini
14ed666b91 helper: suppress warning with gcc from to_entity 2022-05-12 17:50:13 +02:00
Michele Caini
ac1d61b2c4 sparse_set: refine the check of the bump function 2022-05-12 17:32:25 +02:00
Michele Caini
acb6e90158 sparse_set: bump doesn't allow to set a tombstone version (yet) 2022-05-12 15:58:38 +02:00
Michele Caini
d3609737f5 view: minor changes 2022-05-12 14:23:45 +02:00
Michele Caini
95b91cd7dd runtime_view: remove the dependency on the sparse set class 2022-05-12 12:43:00 +02:00
Michele Caini
affd2a3b91 registry: ::storage<T> doesn't accept const types anymore 2022-05-11 13:48:03 +02:00
Michele Caini
d392259364 TODO: cleanup 2022-05-11 07:49:37 +02:00
Michele Caini
e03f4fac64 sigh_storage_mixin: added fwd decl to entity/fwd.hpp 2022-05-11 07:49:14 +02:00
Michele Caini
538840351a natvis: updated definition for meta_type_node 2022-05-11 07:48:42 +02:00
Michele Caini
1ddad3577c registry: minor changes 2022-05-11 07:47:58 +02:00
Michele Caini
d44d1325fc meta: add meta_type::is_integral and meta_type::is_signed (close #884) 2022-05-10 14:43:08 +02:00
Michele Caini
dc07af6ad1 sigh: updated noexcept token 2022-05-09 12:16:57 +02:00
Michele Caini
c6f1809d60 sigh:
* cleanup
* conditionally noexcept
2022-05-09 12:07:28 +02:00
Michele Caini
261e73bf3e y_combinator: conditionally noexcept 2022-05-09 12:07:13 +02:00
Michele Caini
8c7d2a1e96 allocation_deleter: conditionally noexcept 2022-05-09 12:06:42 +02:00
Michele Caini
72507977bd input_iterator_pointer: conditionally noexcept 2022-05-09 12:05:56 +02:00
Michele Caini
270829f05b iterable_adaptor: constructors are conditionally noexcept now 2022-05-09 08:32:11 +02:00
Michele Caini
b92e4f7e65 iterable_adaptor: move iterators on construction 2022-05-09 08:23:51 +02:00
Michele Caini
8e890135fe compressed pair: make the full class conditionally noexcept 2022-05-06 12:25:07 +02:00
Michele Caini
a6601939d5 compressed_pair: make compressed_pair_element conditionally noexcept 2022-05-06 12:19:14 +02:00
Michele Caini
c608e735d2 test: use page size variables 2022-05-06 12:01:37 +02:00
Michele Caini
e0a1a338a5 view: security net and explicit arrays to avoid regressions 2022-05-06 09:31:23 +02:00
Michele Caini
7aa276df5a entity: oops, typo :) 2022-05-06 08:44:03 +02:00
Michele Caini
d939a72219 config: drop ENTT_NOEXCEPT[_IF] 2022-05-06 08:41:22 +02:00
Michele Caini
96fc59eee5 updated TODO 2022-05-06 08:40:33 +02:00
Michele Caini
989f8568cf helper: use the right page size in all cases 2022-05-06 08:40:17 +02:00
Michele Caini
66f451124f entity: prepare to remove ENTT_NOEXCEPT[_IF] 2022-05-06 08:37:41 +02:00
Michele Caini
e59ff47f6f core: prepare to remove ENTT_NOEXCEPT[_IF] 2022-05-06 08:30:49 +02:00
Michele Caini
b176be9ef7 meta: prepare to remove ENTT_NOEXCEPT[_IF] 2022-05-06 08:23:52 +02:00
Michele Caini
942879bbba signal: prepare to remove ENTT_NOEXCEPT[_IF] 2022-05-06 08:23:42 +02:00
Michele Caini
2065c4294f resource: prepare to remove ENTT_NOEXCEPT[_IF] 2022-05-06 08:23:30 +02:00
Michele Caini
cb02f0621c process: prepare to remove ENTT_NOEXCEPT[_IF] 2022-05-06 08:23:22 +02:00
Michele Caini
971f371eab poly: prepare to remove ENTT_NOEXCEPT[_IF] 2022-05-06 08:23:14 +02:00
Michele Caini
f21c56bd98 locator: prepare to remove ENTT_NOEXCEPT[_IF] 2022-05-06 08:23:03 +02:00
Michele Caini
363299a27d containter: prepare to remove ENTT_NOEXCEPT[_IF] 2022-05-06 08:22:55 +02:00
Michele Caini
10e74dad41 doc: drop mentions of ENTT_NOEXCEPT 2022-05-05 14:54:04 +02:00
Michele Caini
dc041b7ea0 test: cleanup/update 2022-05-05 14:53:05 +02:00
Michele Caini
584cfdf64c test: avoid using ENTT_NOEXCEPT in the test suite 2022-05-05 09:24:02 +02:00
Michele Caini
74c498cf15 doc: avoid using ENTT_NOEXCEPT in the doc 2022-05-05 09:02:38 +02:00
Michele Caini
a1e5855f2b updated TODO 2022-05-05 09:00:03 +02:00
Michele Caini
d8e5a97ef3 entity: iterator constexpr-ness review (close #883) 2022-05-04 16:18:37 +02:00
Michele Caini
96804b0b28 meta: constexpr all the way (see #883) 2022-05-04 16:10:37 +02:00
Michele Caini
b0d69c50da resource_cache: constexpr all the way (see #883) 2022-05-04 16:06:54 +02:00
Michele Caini
de6b2e139b container: constexpr all the way (see #883) 2022-05-04 16:04:55 +02:00
Michele Caini
7204840a8a resource: fixed typo 2022-05-04 09:30:23 +02:00
Michele Caini
76369a01ad group: avoid unnecessary instantiations and try to please all compilers 2022-05-04 08:38:28 +02:00
Michele Caini
3a92a93604 y_combinator: constexpr-ness all the way (see #883) 2022-05-03 18:51:03 +02:00
Michele Caini
f1c968372f memory: constexpr-ness all the way (see #883) 2022-05-03 18:48:54 +02:00
Michele Caini
759d9a642f config: add ENTT_ENTT_CONSTEXPR to use in combination with ENTT_TRY and the like (waiting for C++20) 2022-05-03 18:48:11 +02:00
Michele Caini
86d86c3044 iterator: constexpr-ness all the way (see #883) 2022-05-03 18:41:15 +02:00
Michele Caini
c38708c483 compressed_pair: constexpr-ness all the way (see #883) 2022-05-03 18:37:39 +02:00
Michele Caini
1673a5ade9 doc: minor changes 2022-05-03 17:07:06 +02:00
Michele Caini
c56a49ddce group: prepare to the storage reference semantics move 2022-05-02 15:36:05 +02:00
Michele Caini
03477ce400 type_traits: type_list_index[_v] 2022-05-02 10:58:11 +02:00
Michele Caini
14d213d13e ident/family: change names for consistency 2022-05-02 09:14:53 +02:00
Michele Caini
8d86816d8d view: tuple constructor 2022-04-30 11:56:04 +02:00
Michele Caini
12cf3fd8e7 *: spot and clear some misues of = default 2022-04-29 12:35:11 +02:00
Michele Caini
8c23f2de8b core/entity: spot and remove useless add_const_t 2022-04-29 12:24:47 +02:00
Michele Caini
837481a854 group: support both const and non-const excluded types 2022-04-29 12:22:54 +02:00
Michele Caini
b682e58df7 view:
* prepare to storage getters for filters
* support both const and non-const excluded types
2022-04-29 12:18:12 +02:00
Michele Caini
c4f430d0d0 view: minor changes 2022-04-28 23:02:00 +02:00
Michele Caini
c7930ab349 natvis: update registry definition 2022-04-28 16:56:54 +02:00
Michele Caini
045baba7ea compressed_pair: re-add base_type to avoid breaking natvis 2022-04-28 16:51:04 +02:00
Michele Caini
d17ac421ec updated authors and todo files 2022-04-28 16:36:55 +02:00
Qix
049e529f66 test: add mention of storage initialization workaround (ref #827) (#879) 2022-04-28 16:34:45 +02:00
Dominic Koepke
ef6e47f625 tuple: forward_apply functional type (#876) 2022-04-28 16:14:25 +02:00
Michele Caini
1330cb9126 doc: typo 2022-04-27 16:55:43 +02:00
Michele Caini
f0ee8bc89d meta: minor changes 2022-04-27 09:32:32 +02:00
Michele Caini
ebc0c18534 test: add missing template keywords (thanks msvc) 2022-04-27 09:22:07 +02:00
Michele Caini
379a4bdda6 meta: re-added meta_type::remove_pointer (close #878) 2022-04-27 09:17:18 +02:00
Michele Caini
2ce106c50f meta: internal changes 2022-04-26 19:46:57 +02:00
Michele Caini
0ebdfe59ee meta: minor changes 2022-04-26 19:01:15 +02:00
Michele Caini
80c700b1f8 sigh_storage_mixin: allocator support 2022-04-26 11:43:59 +02:00
Michele Caini
103f935d61 meta (close #872):
* container traits don't really support plain arrays anymore (if they ever did)
* fix an issue with insert/erase of meta sequence containers
* add non-regression tests
2022-04-24 17:17:47 +02:00
Michele Caini
164476721a compressed_pair: cleanup 2022-04-22 10:40:10 +02:00
Michele Caini
54dd716d02 any: avoid duplicating operation/policy for all specializations 2022-04-22 10:35:01 +02:00
Michele Caini
ab681ce637 registry: minor changes to ease the transition 2022-04-22 00:02:55 +02:00
Michele Caini
a355de8e97 registry: delegating constructor 2022-04-21 23:39:15 +02:00
Michele Caini
56921d6449 config/component: ENTT_IGNORE_IF_EMPTY -> ENTT_ETO_TYPE 2022-04-21 16:54:50 +02:00
Michele Caini
7e900626bc test: suppress shadow warnings 2022-04-21 13:59:27 +02:00
Michele Caini
dc30c29f4e config/component/storage:
* ENTT_IGNORE_IF_EMPTY is an internal def-only macro
* component_traits review to also support void type
* updated tests for component_traits
* added a non-regression test for storage<void>
2022-04-21 11:43:42 +02:00
Michele Caini
370865bb57 doc: add billy engine 2022-04-21 09:10:23 +02:00
Michele Caini
80015e83d4 sigh/dispatcher: use allocator<void> 2022-04-20 16:40:19 +02:00
Michele Caini
c37c35b52b registry: avoid code duplication 2022-04-19 15:35:39 +02:00
Corentin Schreiber
069004d4eb registry: overflow of version and max number of entities (#864) 2022-04-19 10:58:17 +02:00
Michele Caini
f11695200e doc: updated config.md 2022-04-19 09:10:01 +02:00
Michele Caini
ef2f8a1a18 config: decouple ENTT_NOEXCEPT and exceptions handling (close #867) 2022-04-19 09:09:25 +02:00
Michele Caini
54cc687c50 doc: typo 2022-04-19 00:08:25 +02:00
Michele Caini
51f279160f resource: added more comparison operators for resource handles 2022-04-16 11:38:45 +02:00
Michele Caini
e3113f6976 sparse_set: nodiscard get(s) 2022-04-15 16:02:53 +02:00
Michele Caini
485e29a672 meta: reduce number of generated symbols 2022-04-15 15:10:40 +02:00
Michele Caini
00e67c50ca nativs: updated definition for type_info 2022-04-15 11:46:08 +02:00
Michele Caini
3e7b3edb9c group: reduce instantiations due to extended iterators and merge their definitions 2022-04-15 11:46:08 +02:00
Michele Caini
3c6c9d9462 emitter: minor changes 2022-04-15 11:46:08 +02:00
Michele Caini
6b06a9ff2b storage: cleanup 2022-04-15 11:46:08 +02:00
Michele Caini
803db476bb entity:
* drop utility.hpp
* turn get_t/exclude_t into aliases for type_list
* updated api for basic_registry<...>::group/group_if_exists
* doc review to reflect all the changes above
2022-04-15 11:46:08 +02:00
Michele Caini
c134ea3098 doc: updated signal.md 2022-04-15 11:46:08 +02:00
Michele Caini
6e64f36b39 natvis: review both dispatcher and emitter 2022-04-15 11:46:08 +02:00
Michele Caini
36af39e2b4 emitter: full review 2022-04-15 11:46:08 +02:00
Michele Caini
88929ab730 natvis: minor changes 2022-04-15 11:46:08 +02:00
Michele Caini
02f00e5339 dispatcher: assert within assure as it ought to be 2022-04-15 11:46:08 +02:00
Michele Caini
ee67032af1 sigh: cleanup to reduce redundancy 2022-04-15 11:46:08 +02:00
Michele Caini
8aea00f527 delegate: cleanup to reduce redundancy 2022-04-15 11:46:07 +02:00
Michele Caini
50faed4a50 dispatcher: minor changes 2022-04-15 11:46:07 +02:00
Michele Caini
b982817a56 now working on v3.11.0 2022-04-15 11:45:56 +02:00
Michele Caini
e5172a9240 update single include file 2022-04-15 11:44:22 +02:00
Michele Caini
dcac7942fa type_info: a default constructible type isn't a good idea actually 2022-04-08 12:17:14 +02:00
Michele Caini
4e13529adb registry: ctor that reserves enough memory for count pools 2022-04-08 09:58:05 +02:00
Michele Caini
c553835228 doc: add the kindest feedback ever received to the README 2022-04-07 18:48:38 +02:00
Michele Caini
1b87193fc1 doc: add Ember Sword to the list of games :) 2022-04-07 18:47:40 +02:00
Michele Caini
25fca56319 doc: update AUTHORS file 2022-04-07 18:47:15 +02:00
Alexandr Timofeev
bf4252394c *: protect against minmax (#862) 2022-04-07 14:28:30 +02:00
Michele Caini
22757e064f *: review remove_cv/remove_ref tokens after spotting an error by chance 2022-04-06 15:57:26 +02:00
Michele Caini
fc9fa37e4e doc: minor changes 2022-04-06 15:52:49 +02:00
Michele Caini
2d5e3402fa type_info: allow to construct type_info objects directly 2022-04-06 11:25:44 +02:00
Michele Caini
b7dd26121a type_info: cleanup 2022-04-06 09:55:31 +02:00
Michele Caini
23bdbeef4e doc: updated type_info section 2022-04-06 09:50:42 +02:00
Michele Caini
9ac81c5219 natvis: updated type_info snippet 2022-04-06 09:49:48 +02:00
Michele Caini
6b9d346b8b type_info:
* reserve a seq identifier for empty type_info objects
* require type_index to return non-zero values
* make type_info default constructible
* add type_info::operator bool()
2022-04-06 08:53:55 +02:00
Michele Caini
9e68eb4d2c type_id: type_info from variable 2022-04-05 08:50:08 +02:00
Michele Caini
f1f47ee44a entity: internal changes/cleanup 2022-04-05 08:42:36 +02:00
Michele Caini
436b2b3140 core: use fold expressions rather than std::disjunction if possible 2022-04-05 08:42:20 +02:00
Michele Caini
f6cfa8ae49 enum_as_bitmask: internal changes 2022-04-05 08:41:36 +02:00
Michele Caini
13949a8d1f updated internal TODO list 2022-04-04 17:13:49 +02:00
Michele Caini
88db623dc1 view: avoid unnecessary parameter pack 2022-04-04 12:27:28 +02:00
Michele Caini
976413173a any: invoke type_id with decayed types to avoid unnecessary instantiations 2022-04-04 09:46:52 +02:00
Michele Caini
91d3349585 view: slightly reduce instantiations 2022-04-04 09:46:20 +02:00
Michele Caini
6e1a774921 sigh: slightly reduce instantiations 2022-04-04 09:46:00 +02:00
Michele Caini
6b53b509fa registry/storage: minor changes 2022-04-04 09:18:10 +02:00
Michele Caini
b8b6203ecd doc: minor changes 2022-04-04 09:17:40 +02:00
Michele Caini
81e1500675 dense_set: slightly reduce instantiations 2022-04-04 09:17:13 +02:00
Michele Caini
d2cd18cb1e test: minor changes (try to also please codecov) 2022-04-02 16:10:00 +02:00
Michele Caini
f5ac73f681 resource_cache: use actual template parameters on sfinae expressions 2022-04-01 14:48:52 +02:00
Michele Caini
413630813a resource: updated doc 2022-04-01 14:41:38 +02:00
Michele Caini
73b6ef2293 resource: updated natvis file 2022-04-01 14:41:15 +02:00
Michele Caini
428bfbd810 tests: updated tests for the resource module 2022-03-31 15:43:44 +02:00
Michele Caini
c54409bdfb resource: fully review the resource module 2022-03-31 15:43:07 +02:00
Michele Caini
b63aebfdaf dense_set: strong exception guarantee (emplace/insert) 2022-03-30 15:34:45 +02:00
Michele Caini
335f876a46 dense_map: strong exception guarantee (emplace/insert) 2022-03-30 15:26:39 +02:00
Michele Caini
c5e99342a3 tests: minor changes 2022-03-30 15:14:26 +02:00
Michele Caini
1710eb9249 dense_map: minor changes 2022-03-29 16:56:49 +02:00
Michele Caini
d03770f91f meta: avoid using =default to avoid tricking VS toolset v141 2022-03-29 16:26:01 +02:00
Michele Caini
9fe6f7a6ea entity: avoid using =default to avoid tricking VS toolset v141 2022-03-29 16:25:53 +02:00
Michele Caini
2fc605fc3e container: avoid using =default to avoid tricking VS toolset v141 2022-03-29 16:25:37 +02:00
Michele Caini
edcd5c4713 dense_set: use underlying iterators to exploit their checks 2022-03-28 16:25:09 +02:00
Michele Caini
bd3df1e06a dense_map: use underlying iterators to exploit their checks 2022-03-28 16:24:52 +02:00
Michele Caini
b785d1c82b meta: minor changes (coding style) 2022-03-27 23:25:50 +02:00
Michele Caini
93bf14f84f organizer: cleanup + renaming to avoid conflicts 2022-03-27 23:24:54 +02:00
Michele Caini
5a84646282 dense_map: updated built-in doc 2022-03-25 17:34:44 +01:00
Michele Caini
2e6cfc08f0 registry: refine storage proxy iterator and guarantee iterator conversions 2022-03-25 17:20:23 +01:00
Michele Caini
4b6d3d47ec registry: suppress a false warning from clang 2022-03-25 15:12:25 +01:00
Michele Caini
985abaa12a dense_map/set: minor changes 2022-03-24 17:38:51 +01:00
Michele Caini
a381a7253a resource: updated doc 2022-03-23 15:32:11 +01:00
Michele Caini
b8bb509d5c resource:
* drop the resource_loader class
* made the loader a template parameter of the resource_cache
* updated the API of the resource_cache
2022-03-23 15:31:55 +01:00
Michele Caini
f48dbd0e19 resource_handle: updated doc 2022-03-23 15:29:44 +01:00
Michele Caini
31c1278374 config: removed ENTT_LAUNDER (unused) 2022-03-22 12:44:21 +01:00
Michele Caini
f6aaafd60f config: add ENTT_NOEXCEPT_IF (for future uses) 2022-03-22 12:43:47 +01:00
Michele Caini
ae3dec19fd registry: internal changes to avoid ambiguous calls 2022-03-22 12:43:24 +01:00
Michele Caini
990baa0929 test: typo 2022-03-21 16:14:20 +01:00
Michele Caini
7ecb65a141 doc: updated links 2022-03-21 10:41:53 +01:00
Michele Caini
a1e55103be enum: typo 2022-03-21 10:41:45 +01:00
Michele Caini
1b4fc54405 dense_set:
* emplace create-and-discard mode if strictly required only
* insert uses the insert_or_do_nothing utility internally
* opaque value_to_bucket function
2022-03-21 10:41:28 +01:00
Michele Caini
e5dcea1fa0 dense_map: emplace create-and-discard mode if strictly required only 2022-03-21 10:19:47 +01:00
Michele Caini
9f25195629 dense_map: use insert_or_do_nothing from within insert 2022-03-21 10:17:55 +01:00
Michele Caini
6936fa1c1c dense_map: opaque key_to_bucket function 2022-03-21 08:42:44 +01:00
Michele Caini
7b25eacfc8 dense_map:
* try_emplace should not consume arguments if the element exists
* clean up
2022-03-18 10:51:16 +01:00
Michele Caini
33989a61e3 dense_set: claen up 2022-03-18 10:49:52 +01:00
Michele Caini
08d9e8d076 dense_map/set: minor changes 2022-03-17 14:23:29 +01:00
Michele Caini
da43ef0982 dense_set: avoid potential UBs 2022-03-17 12:36:00 +01:00
Michele Caini
02f12bde81 dense_map: avoid potential UBs 2022-03-17 12:35:46 +01:00
Michele Caini
b55d5375ac *: added missing messages to static asserts 2022-03-17 11:39:45 +01:00
Michele Caini
281f40bd56 dense_set: avoid dispatching based on iterator category if possible 2022-03-17 11:39:45 +01:00
Michele Caini
dcb7c0c27e dense_map: constrain the allocator type 2022-03-17 11:39:45 +01:00
Michele Caini
d3c44a6fa6 dense_map: avoid dispatching based on iterator category if possible 2022-03-17 11:39:45 +01:00
Michele Caini
f432dc6bdc dense_map:
* uses-allocator construction
* iterators model forward/random access iter types but are in the input iter category
* iter value_type is pair<const T &, U &>/pair<const T &, const U &> (zip iter types)
* no risky UBs due to type punning or destroy/construct within a vector
2022-03-17 11:39:45 +01:00
Michele Caini
ce21ee6001 test: minor changes 2022-03-17 11:39:36 +01:00
Michele Caini
a431f5a674 registry: allow creating pools during a destroy (close #853) 2022-03-16 17:18:14 +01:00
Michele Caini
f6153f17ad storage: return a meaningful msg when the type is not movable 2022-03-16 17:17:38 +01:00
Michele Caini
c17ecbc78c resource: add operator==/!= to resource handles 2022-03-16 17:17:35 +01:00
Michele Caini
0feb9f0c56 resource_handle: update member types 2022-03-16 17:17:33 +01:00
Michele Caini
e69cb3d950 memory: suppress warnings due to unreferenced parameters 2022-03-16 17:17:30 +01:00
Michele Caini
e7c03dd512 memory: minor changes 2022-03-16 17:17:26 +01:00
Michele Caini
0c1371ffae test: suppress warning due to unused variables 2022-03-16 17:16:54 +01:00
Michele Caini
8a350acf39 dispatcher: allocator support 2022-03-16 17:16:50 +01:00
Michele Caini
594b3b5531 component: use ignore_as_empty_v to simplify the code here and there 2022-03-16 17:16:36 +01:00
Michele Caini
e13d06fe20 component: reintroduce utility ignore_as_empty_v (it's actually useful sometimes) 2022-03-16 17:16:32 +01:00
Michele Caini
805bb84c8f component_traits:
* removed ::ignore_if_empty member
* use ::page_size 0 for empty types
2022-03-16 17:16:21 +01:00
Michele Caini
1a62338349 storage: split sigh_storage_mixin 2022-03-16 17:15:49 +01:00
Michele Caini
4795ba83ba config: remove module-specific mismatch checks (we cannot protect everyone from themselves) 2022-03-16 17:15:41 +01:00
Michele Caini
ad5b362bca config: use pragma detect_mismatch if possible 2022-03-16 17:15:28 +01:00
Michele Caini
8a735452de config: detect version mismatch 2022-03-16 17:15:25 +01:00
Michele Caini
03d0f3e9ca test: merge no-eto tests with registry tests 2022-03-16 17:15:18 +01:00
Michele Caini
ff0983cc42 storage: more about uses-allocator construction 2022-03-16 17:15:00 +01:00
Michele Caini
159a413c7d meta: avoid creating internal namespace that messes with friend declarations 2022-03-16 17:14:37 +01:00
Michele Caini
6a753d1316 meta: remove unused data member 2022-03-16 17:14:34 +01:00
Michele Caini
c89bf30e05 meta: dereferencing a pointer-like object which converts to bool works in all cases (false implies empty meta_any) 2022-03-16 17:14:32 +01:00
Michele Caini
ba4b5ef9f2 meta: minor changes 2022-03-16 17:14:30 +01:00
Michele Caini
5b39ee221f meta: reduce the number of instantiations due to basic_meta_sequence_container_traits 2022-03-16 17:14:28 +01:00
Michele Caini
65c4432325 meta: use adl lookup within basic_meta_sequence_container_traits 2022-03-16 17:14:26 +01:00
Michele Caini
32bbb27c9f meta: further reduce the number of instantiations due to meta sequence containers 2022-03-16 17:14:24 +01:00
Michele Caini
ef3c030576 meta: further optimize meta sequence containers' iterators 2022-03-16 17:14:22 +01:00
Michele Caini
554a182229 meta: reduce instantiations due to meta containers (drop get_fn) 2022-03-16 17:14:20 +01:00
Michele Caini
9154d78e58 meta: make the meta associative container's iterator an internal class as all other iterators 2022-03-16 17:14:18 +01:00
Michele Caini
82d933aa3d meta: make the meta sequence container's iterator an internal class as all other iterators 2022-03-16 17:14:16 +01:00
Michele Caini
ef0fe9b13c meta:
* relax meta sequence container requirements (::clear is no longer required)
* reduce instantiations due to meta sequence containers
2022-03-16 17:14:14 +01:00
Michele Caini
f6700b7094 meta: drop meta_sequence_container::meta_iterator::base() 2022-03-16 17:14:12 +01:00
Michele Caini
21f00cf251 meta: make meta_sequence_container::meta_iterator model a bidirectional iterator (and keep staying in the input iterator category) 2022-03-16 17:14:10 +01:00
Michele Caini
900d2bf816 meta: prepare meta_sequence_container::meta_iterator to model a bidirectional iterator 2022-03-16 17:14:07 +01:00
Michele Caini
3846fa3f28 meta: begin/end adl lookup 2022-03-16 17:14:04 +01:00
Michele Caini
52f77d61ba sigh:
* fixed doc
* test review/cleanup
2022-03-16 17:13:16 +01:00
Michele Caini
039341de69 poly: fixed forward file 2022-03-16 17:13:09 +01:00
Michele Caini
5adf332a5f registry: ::sortable -> ::owned for component types (close #847) 2022-03-16 17:13:04 +01:00
Michele Caini
efbb32a498 sparse_set: added the ::bump function 2022-03-16 17:12:56 +01:00
Michele Caini
3156dd1321 sigh: constrain the allocator type 2022-03-16 17:12:45 +01:00
Michele Caini
2fbeeafbb8 dense_set: constrain the allocator type 2022-03-16 17:12:42 +01:00
Michele Caini
db680f3bcd snapshot: try to get around an issue of VS, toolset v141 2022-03-16 17:12:01 +01:00
Michele Caini
4a20fa5275 snapshot: internal changes 2022-03-16 17:11:55 +01:00
Michele Caini
3fb2da7174 group: internal changes 2022-03-16 17:11:51 +01:00
Michele Caini
7f8bebbdd5 view: internal changes 2022-03-16 17:11:47 +01:00
Michele Caini
597fc0265f natvis: dense_set 2022-03-16 17:11:31 +01:00
Michele Caini
d5d5770dac natvis: dispatcher 2022-03-16 17:11:26 +01:00
Michele Caini
772ac64e3b config: add ENTT_VERSION 2022-03-16 17:11:03 +01:00
Michele Caini
92d7337f04 config: macro.h (just in case) 2022-03-16 17:10:55 +01:00
Michele Caini
200425114c test: address some feedback by iwyu 2022-03-16 17:10:40 +01:00
Michele Caini
b92a73a2a2 workflow: minor changes 2022-03-16 17:10:34 +01:00
Michele Caini
e83c77b99f build system: updated workflow(s) 2022-03-16 17:10:23 +01:00
Michele Caini
28aa35160d hashed_string: minor changes 2022-02-27 17:46:03 +01:00
Michele Caini
18c9bfa134 compressed_pair: minor changes 2022-02-27 17:45:56 +01:00
Michele Caini
bdb7763237 sigh: rebind allocator internally 2022-02-27 17:45:50 +01:00
Michele Caini
bc9ee46b8f dispatcher: minor changes 2022-02-27 17:45:45 +01:00
Michele Caini
b92b734db2 doc: fixed typo 2022-02-25 16:38:13 +01:00
Michele Caini
2748a6cd3c dense_set: remove the constraint on the allocator type 2022-02-25 15:15:09 +01:00
Michele Caini
888876185d doc: fixed typo 2022-02-25 15:14:14 +01:00
Michele Caini
03fea6358b view/runtime_view: make iterator_type private 2022-02-25 14:10:15 +01:00
Michele Caini
59b0dc6735 test: minor changes 2022-02-25 14:09:22 +01:00
Michele Caini
35a42b2172 dense_set: cleanup 2022-02-24 18:48:28 +01:00
Michele Caini
daa4056f45 registry/storage/sparse_set: minor changes to get around an issue of gcc7.5 2022-02-24 18:48:06 +01:00
Michele Caini
bb5abe633f dense_set: review constructors/assignment operators 2022-02-24 11:46:42 +01:00
Michele Caini
dc238db355 compressed_pair: correctly manage references with piecewise construction 2022-02-24 11:33:12 +01:00
Michele Caini
4c692c23bb test: refine tracked_memory_resource::do_is_equal 2022-02-24 11:33:04 +01:00
Michele Caini
b093e82db3 memory: uninitialized_construct_using_allocator (waiting for C++20) 2022-02-23 09:41:32 +01:00
Michele Caini
7a1c2108a1 dispatcher: enable fetching the number of pending events (#848)
Co-authored-by: WoLfulus <WoLfulus@users.noreply.github.com>
2022-02-23 08:42:33 +01:00
Michele Caini
4aa2b49649 updated TODO file 2022-02-23 08:41:56 +01:00
Michele Caini
cdaced4df6 memory: uses_allocator_construction_args pairs support 2022-02-23 00:19:55 +01:00
Michele Caini
cdd029853b any:
* strong exception guarantee applies
* a test to avoid future regressions
2022-02-22 15:03:07 +01:00
Michele Caini
507bafdd9c any/meta_any: revert changes to introduce ::hash 2022-02-22 12:15:09 +01:00
Michele Caini
07a36123e5 dense_map/set: get around a nasty issue of gcc 7.5 with deduced return types and friend functions 2022-02-22 12:03:41 +01:00
Michele Caini
a205e7ada9 test: it's not a good idea to use discarded values, the sanitizer may complain :) 2022-02-22 09:55:03 +01:00
Michele Caini
25e9330bb4 memory: avoid ambiguous call with C++20 2022-02-22 09:45:03 +01:00
Michele Caini
b2edfa454c test: minor changes (to please all compilers) 2022-02-22 09:30:46 +01:00
Michele Caini
07767a09d9 doc: fixed typo 2022-02-22 08:40:25 +01:00
Michele Caini
e8d85d9269 resource: updated doc/tests 2022-02-22 08:15:09 +01:00
Michele Caini
5cf0ba079f memory: make_obj_using_allocator utility (waiting for C++20) 2022-02-21 16:31:36 +01:00
Michele Caini
e08b1f82ce memory: uses_allocator_construction_args (waiting for C++20) 2022-02-21 08:07:01 +01:00
Michele Caini
c2196149ee test: minor changes 2022-02-20 23:55:04 +01:00
Michele Caini
65b5ce7880 doc: minor changes 2022-02-20 23:44:33 +01:00
Michele Caini
9c254ec3e0 doc: mark C++20 feature (to help the future me find them) 2022-02-20 09:57:24 +01:00
Michele Caini
f4418e0205 test: increase code coverage 2022-02-19 10:46:18 +01:00
Michele Caini
a314f7b42e test: minor changes (code coverage) 2022-02-19 10:41:35 +01:00
Michele Caini
dc5a72cda5 dense set:
* cleaned up implementation
* uses-allocator construction support
* a few more tests
2022-02-19 09:49:47 +01:00
Michele Caini
380cb41ca9 entity: cleanup 2022-02-18 17:08:29 +01:00
Michele Caini
83f7e633a3 tests: allocate_unique with types that don't support uses-allocator construction 2022-02-18 17:08:07 +01:00
Michele Caini
ab1c920435 tests: storage with types that don't support uses-allocator construction 2022-02-18 17:07:44 +01:00
Michele Caini
7094d658f8 test: minor changes 2022-02-18 13:47:59 +01:00
Michele Caini
11617291e3 container: minor changes 2022-02-18 13:47:14 +01:00
Michele Caini
790aa03834 scheduler: allow attaching tasks from already running processes (close #845) 2022-02-18 11:34:42 +01:00
Michele Caini
bcd16ea5ea entity: adjust noexcept policy 2022-02-17 12:17:07 +01:00
Michele Caini
81c044760b core: adjust noexcept policy 2022-02-17 12:16:46 +01:00
Michele Caini
b0e0e80b69 meta: adjust noexcept policy 2022-02-17 09:33:48 +01:00
Michele Caini
280bb1d84f dense_set: suppress shadow warning 2022-02-17 09:22:57 +01:00
Michele Caini
bb42dceaca natvis: updated container/dense_set snippet 2022-02-17 09:22:55 +01:00
Michele Caini
d0873ed551 dense_map: adjust noexcept policy 2022-02-17 09:03:28 +01:00
Michele Caini
0fbddfc47b dense_set: adjust noexcept policy 2022-02-17 09:03:11 +01:00
Michele Caini
3f1dee2650 dense_set: uses-allocator construction 2022-02-17 09:02:35 +01:00
Michele Caini
a4b8b93e7f dense_set: emplace always consumes its arguments 2022-02-17 09:02:21 +01:00
Michele Caini
02d1417ef4 process/scheduler: update noexcept policy 2022-02-16 17:36:49 +01:00
Michele Caini
50812a908c signal: update noexcept policy 2022-02-16 12:40:33 +01:00
Michele Caini
1a1ed55485 resource_handle: minor changes 2022-02-16 12:33:55 +01:00
Michele Caini
09fa322a0e poly: update noexcept policy 2022-02-16 12:33:38 +01:00
Michele Caini
1a9a423c35 locator: adjust noexcept policy 2022-02-16 12:33:22 +01:00
Michele Caini
7b0449213c doc: minor changes 2022-02-16 12:32:33 +01:00
Michele Caini
c0251f5c29 sparse_set/storage: support entity and component types with custom swap functions 2022-02-16 12:29:45 +01:00
Michele Caini
4509d8a60b snapshot: swap properly internally 2022-02-16 12:29:43 +01:00
Michele Caini
b1738b0902 natvis: updated signal/delegate snippet 2022-02-16 12:28:29 +01:00
Michele Caini
45259462aa any: remove call to ENTT_LAUNDER, no longer required due to do p1971r0 2022-02-16 12:27:52 +01:00
Michele Caini
772a7427a2 doc: another update for the EnTT in Action list 2022-02-16 12:26:29 +01:00
Michele Caini
afa58b81f6 doc: added D&D Dark Alliance to the EnTT in Action list 2022-02-16 12:26:25 +01:00
Michele Caini
6822c0f0e3 test: minor changes 2022-02-13 18:40:14 +01:00
Michele Caini
0a155ecb68 test: uses-allocator construction guaranteed for allocate_unique 2022-02-13 18:33:31 +01:00
Michele Caini
15fff94447 test: uses-allocator construction guaranteed for storage classes 2022-02-13 18:32:58 +01:00
Michele Caini
ff06df2acb test: tracked_memory_resource utility 2022-02-13 18:32:10 +01:00
Michele Caini
df9301d591 bjuild system/tests: check for <version> (old compilers support) 2022-02-13 18:31:26 +01:00
Michele Caini
e51b1bbb25 compressed_pair: avoid noexcept specification which cannot be supported 2022-02-13 18:29:34 +01:00
Chris Ohk
aa275f4b1c doc: fix minor typos (#842) 2022-02-12 15:52:43 +01:00
Michele Caini
ed11bda9fd component: automatic traits deduction 2022-02-11 10:35:43 +01:00
Michele Caini
ed34a3f5d4 locator:
* service_locator -> locator
* API review + allocator support
* updated doc and tests
2022-02-10 11:31:55 +01:00
Michele Caini
a99b8b7984 build system: get prepared for the windows-latest switch on GH 2022-02-10 10:32:06 +01:00
Michele Caini
f750254cc2 allocate_unique: static assert that Type isn't an array type 2022-02-09 12:32:36 +01:00
Michele Caini
21ece182f5 any: let the wrapper decide what it means to be an owner 2022-02-09 09:42:49 +01:00
Michele Caini
6439dca43a memory: suppress a (shadow) warning from gcc 2022-02-08 11:56:52 +01:00
Michele Caini
ca424a4577 type_traits: try to also please clang-cl 2022-02-08 11:50:53 +01:00
Michele Caini
87bc2cb1ab any: try to also please gcc7 2022-02-08 11:20:49 +01:00
Michele Caini
58f22cc3b5 meta_any: ::hash function for hashable types (+ bonus doc review) 2022-02-08 11:04:14 +01:00
Michele Caini
fa8362f000 any: ::hash function for hashable types (close #629) 2022-02-08 11:02:30 +01:00
Michele Caini
1816206dfc type_traits: is_std_hashable[_v] 2022-02-08 09:58:26 +01:00
Michele Caini
fcfa994152 doc: compressed_pair, std::tuple_size and std::tuple_element specializations 2022-02-08 09:57:10 +01:00
Michele Caini
e7262660c2 dispatcher: API review to support named queues 2022-02-07 10:52:04 +01:00
Michele Caini
a1e14d5740 doc: memory (power of two, fast modulus, allocate_unique, ...) 2022-02-05 00:18:57 +01:00
Michele Caini
60c11f3f30 dispatcher: minor changes 2022-02-05 00:18:42 +01:00
Michele Caini
3fe584d366 any: rename local variable to make it easier for me to read too :) 2022-02-05 00:18:18 +01:00
Michele Caini
28e38321ee test: put basic test allocator in its own file 2022-02-05 00:18:03 +01:00
Michele Caini
1faeeeeabc memory: allocation_deleter/allocate_unique 2022-02-05 00:14:31 +01:00
Michele Caini
75a0c672b1 iterable_adaptor: decouple iterator types 2022-02-04 08:54:16 +01:00
Michele Caini
db829b21aa doc: minor changes 2022-02-04 08:53:23 +01:00
Michele Caini
24bdc29c27 input_iterator_pointer: minor changes 2022-02-03 08:12:35 +01:00
Michele Caini
692a78984f doc: updated documentation about context variables 2022-02-03 08:09:52 +01:00
Michele Caini
77a399738c registry: support to named context variables (see emplace_hint) 2022-02-03 08:06:52 +01:00
Michele Caini
5d7358899d registry: cleanup the standalone context class 2022-02-03 07:52:27 +01:00
Michele Caini
aca25b9999 build: updated build workflow 2022-02-02 11:55:08 +01:00
Paolo Monteverde
182c6c534b meta: rearrange member data of meta nodes to optimize memory usage (#833) 2022-02-02 08:15:51 +01:00
Michele Caini
0500f155e6 delegate: ::instance() -> ::data() 2022-02-02 08:02:03 +01:00
Michele Caini
125b826f62 meta/signal: added missing includes 2022-02-01 23:11:25 +01:00
Michele Caini
922bfbf724 test: fixed includes (while trying iwyu) 2022-02-01 23:01:04 +01:00
Michele Caini
f1e584fad9 scheduler: add missing header 2022-02-01 14:12:23 +01:00
Michele Caini
0c4dcdea71 config/core: include cstdint also when ENTT_ID_TYPE is defined 2022-02-01 14:11:41 +01:00
Michele Caini
ec4b383198 build: minor changes to workflows 2022-02-01 11:31:44 +01:00
Michele Caini
3328c7e78b doc: fixed funding.yml 2022-02-01 11:30:23 +01:00
Michele Caini
357fcd44d7 poly: make Member type explicit to avoid errors with older compilers 2022-01-31 14:48:20 +01:00
Michele Caini
5a0a682d35 meta: relaxed checks on conversion functions 2022-01-31 09:55:53 +01:00
Michele Caini
1fcb7e5aba dispatcher: minor changes 2022-01-31 08:44:40 +01:00
Michele Caini
eec867bc9e enum:
* remove unused functions
* avoid errors due to narrowing conversions
2022-01-31 08:44:24 +01:00
Michele Caini
5a956d2914 poly: compile-time checks on embedded vtables + code coverage 2022-01-30 16:53:27 +01:00
Michele Caini
e0e29cc363 test: cleanup 2022-01-30 16:52:51 +01:00
Michele Caini
9fc8e03f72 poly: refined fwd file, updated (typed-)tests 2022-01-29 17:32:15 +01:00
Michele Caini
b054e93f0e build system: removed the in-source build check 2022-01-29 17:31:37 +01:00
Michele Caini
653680a356 doc: minor changes 2022-01-29 17:30:20 +01:00
Michele Caini
40035f2e52 gh: updated funding file 2022-01-29 17:29:05 +01:00
Michele Caini
a70b7daec4 build system: workflow cleanup 2022-01-29 17:25:34 +01:00
Michele Caini
0f3e7b5dac doc: minor changes to suppress warnings 2022-01-29 16:15:40 +01:00
Michele Caini
2fbc08b606 test: a handful of minor changes to please all compilers from the CI and remove some lambdas 2022-01-29 11:31:57 +01:00
Michele Caini
e4897f709e test: merge poly tests in a single file, use typed tests to reduce the boilerplate 2022-01-29 10:51:25 +01:00
Michele Caini
84445aa28b test: use gtest typed test suite for enums 2022-01-29 10:50:33 +01:00
Michele Caini
0795f9a9f2 test: separate death tests as suggested in the gtest doc 2022-01-29 10:47:22 +01:00
Michele Caini
44ae0d67f6 sparse_set: set the free list to tombstone rather than null within ::clear 2022-01-28 15:53:36 +01:00
Michele Caini
a74f0ca370 test: code coverage 2022-01-28 14:06:22 +01:00
Michele Caini
266c1fcdcb registry: better/faster remove 2022-01-28 14:06:22 +01:00
Michele Caini
977c3407e7 registry: better/faster erase 2022-01-28 14:06:22 +01:00
Michele Caini
99c2299ed4 test: added missing typename keyword 2022-01-28 14:06:22 +01:00
Michele Caini
39a08f17da sparse_set: clear no longer creates tombstones 2022-01-28 14:06:22 +01:00
Michele Caini
57de1187fc sparse_set/storage:
* reintroduce the swap_and_pop vs in_place_pop split for perf reasons
* rollback to a model with two iterators on virtual functions
* even faster range-erase/clear
2022-01-28 14:06:22 +01:00
Michele Caini
2bba6d4c0d test: code coverage 2022-01-28 14:06:22 +01:00
Michele Caini
2f03b225f7 sparse_set: remove the cursed ::slot function (finally) 2022-01-28 14:06:22 +01:00
Michele Caini
533bc1ce94 sparse_set: review ::clear 2022-01-28 14:06:22 +01:00
Michele Caini
add9df6058 doc: updated todo list 2022-01-28 14:06:21 +01:00
Michele Caini
d3496f3ff5 sparse_set: apparently using an invalid iterator isn't a good idea :) 2022-01-28 14:06:21 +01:00
Michele Caini
e97f7ee725 doc: minor changes 2022-01-28 14:06:21 +01:00
Michele Caini
37497295fb sparse_set/storage:
* refine the try_erase to make it accept an iterator and a count (easier to work with at the call site)
* added a test for the stable clear
* added a note for future improvements
2022-01-28 14:06:21 +01:00
Michele Caini
2e89b3b5b9 sparse_set/storage: make try_erase accept a range of entities 2022-01-28 14:06:21 +01:00
Michele Caini
518bbc651e sparse_set/storage:
* try_emplace returns a basic iterator
* try_erase accepts a basic iterator (prepare for an even faster remove/erase/clear/whatever)
2022-01-28 14:06:21 +01:00
Michele Caini
ffd1d97e03 natvis: updated container.natvis to use the right names 2022-01-28 14:05:41 +01:00
Michele Caini
e503d431f1 doc: minor changes 2022-01-28 14:00:54 +01:00
Michele Caini
49a066714a test: minor changes 2022-01-28 14:00:33 +01:00
Michele Caini
7eec610d21 container:
* dense_hash_map -> dense_map
* dense_hash_set -> dense_set
2022-01-28 13:35:16 +01:00
Michele Caini
530507c36b meta: some compile-time checks to avoid subtle runtime errors 2022-01-27 22:49:35 +01:00
Michele Caini
4d2584d8fc doc: added home hearth to the links page 2022-01-25 18:09:37 +01:00
Michele Caini
0f5057920e doc: added gaia-ecs to the list of similar projects 2022-01-25 18:00:34 +01:00
Michele Caini
a98000cf3b test: I am the winner of the best error message ever but I remain humble :) 2022-01-25 14:56:00 +01:00
Michele Caini
0cec8de164 dense_hash_map/set: suppress warnings due to integral conversions 2022-01-25 09:09:37 +01:00
Michele Caini
1caa8d923d sparse_set/storage: iterator's ::index returns the right offset 2022-01-23 13:05:45 +01:00
Michele Caini
4fa51f8c52 type_traits: removed is_iterator_type[_v], it may be ambiguous and cause errors 2022-01-22 16:59:17 +01:00
Michele Caini
a8be765aa8 registry: disable optimizations based on is_iterator_type, free pools allow to implement them on the user side and more efficiently when needed 2022-01-22 16:52:45 +01:00
Michele Caini
d2d35d490a doc: updated entity.md 2022-01-22 16:45:05 +01:00
Michele Caini
26ba137424 registry: template ::storage support to const qualified types 2022-01-21 19:00:49 +01:00
Michele Caini
e6006663ec registry: remove [[nodiscard]] from the template ::storage method 2022-01-21 11:08:07 +01:00
Michele Caini
74eb2772b6 natvis: support standalone registry context 2022-01-20 15:58:32 +01:00
Michele Caini
3878a696af registry: standalone context type (close #575) 2022-01-20 09:37:31 +01:00
Michele Caini
49ac34c405 doc: avoid confusion with context variables 2022-01-19 16:02:04 +01:00
Michele Caini
a7d4a980ba *: more consistent policy for final classes 2022-01-19 12:41:50 +01:00
Michele Caini
2196db562e registry:: non-template storage(id) returns an iterator rather than a naked pointer 2022-01-19 12:15:22 +01:00
Michele Caini
2ad3e0ed4c hashed_string: updated natvis representation 2022-01-19 09:30:35 +01:00
Michele Caini
6e03fe77ae doc: updated copyright 2022-01-19 07:43:58 +01:00
Michele Caini
af8ec7b5dd registry: remove/erase dispatch based on the iterator type 2022-01-18 08:30:43 +01:00
Michele Caini
7fa29e7341 registry: strict check on storage types to prevent subtle bugs in case of errors 2022-01-18 07:45:03 +01:00
Michele Caini
9c6950d163 hashed_string: I managed to crash clang but I remain humble and try to help it :) 2022-01-17 14:02:02 +01:00
Michele Caini
5d4cbfe8e7 hashed_string: make it work with vs toolset v141 2022-01-17 13:49:11 +01:00
Michele Caini
4747422110 *: added a bunch of final here and there 2022-01-17 13:43:55 +01:00
Michele Caini
7d1416ac74 hashed_string: store size information (close #824) 2022-01-17 08:25:56 +01:00
Michele Caini
2efaa7af7b *: allocator aware classes fail to compile if allocator's value type and container's value type differ 2022-01-15 16:48:33 +01:00
Michele Caini
68e259870f sparse_set/storage:
* support ::erase suppression
* support ::emplace with invalid entities when suppressed
* support ::erase/::remove with invalid entities when suppressed
2022-01-15 00:48:07 +01:00
Michele Caini
29c2c94784 doc: suppress warnings from doc generation 2022-01-15 00:45:35 +01:00
Michele Caini
3f2e1d078f sparse_set/storage: replace the whole try_insert machinery with a force_back parameter to try_emplace 2022-01-15 00:44:47 +01:00
Michele Caini
0a259da05a sparse_set: opaque insert always appends elements 2022-01-14 14:06:41 +01:00
Michele Caini
1b22fe6de2 storage: insert for non-empty types always appends elements 2022-01-13 15:01:06 +01:00
Michele Caini
9b700c3bd2 natvis: removed count filter from sparse set, it makes it harder to debug internal issues 2022-01-13 15:00:34 +01:00
Michele Caini
3b72e30c36 sparse_set: use the right iterator in the catch branch of insert 2022-01-13 14:44:27 +01:00
Michele Caini
9eba103de9 storage: insert for empty types always appends elements 2022-01-13 14:05:33 +01:00
Michele Caini
ecadee3876 sparse_set: added basic virtual try_insert (insert does not use it yet) 2022-01-13 13:47:22 +01:00
Michele Caini
699f9105ae storage: arguments are always ignored for empty types 2022-01-13 13:41:32 +01:00
Michele Caini
8a19e8dafe storage: support chained constructors i.e. parent-to-child propagation 2022-01-13 12:00:15 +01:00
Michele Caini
588c056205 sparse_set/storage: minor changes, more tests 2022-01-11 22:56:22 +01:00
Michele Caini
866a7fb641 natvis: added info about the sparse array of a sparse set 2022-01-11 18:18:41 +01:00
Michele Caini
a5fe42268f test: cleanup 2022-01-11 08:15:09 +01:00
Michele Caini
0bd6816bdd sparse_set: pop_at(pos) -> try_erase(entt) (prepare for inhibited deletions) 2022-01-11 08:06:20 +01:00
Michele Caini
1c6670c7a1 sparse_set: merge ::swap_and_pop and ::in_place_pop 2022-01-10 22:55:46 +01:00
Michele Caini
699a0eb934 sigh_storage_mixin:
* always check the owner in debug
* fixed a test that doesn't invoke bind
2022-01-10 17:22:34 +01:00
Michele Caini
72440ab937 sigh_storage_mixin: always trigger an emplace request notification (in sync with unbalanced destroy) 2022-01-10 00:23:18 +01:00
Michele Caini
9ad807bd58 storage: doc cleanup 2022-01-10 00:16:10 +01:00
Michele Caini
9fb1970ac0 sparse_set/storage: rollback ::policy(pol), incompatible with views 2022-01-09 16:15:47 +01:00
Michele Caini
48dfac2588 storage:
* also support (in theory) fancy pointers
* removed the internal ::construct function
2022-01-09 15:06:41 +01:00
Michele Caini
c6d3714e6f sparse_set: also support (in theory) fancy pointers 2022-01-09 15:06:17 +01:00
Michele Caini
1345c257c3 storage: make final virtual functions private (moving towards private-only hooks) 2022-01-09 14:42:56 +01:00
Michele Caini
19112a8f27 storage: cleanup 2022-01-09 14:25:41 +01:00
Michele Caini
e0979fcf3f sparse_set/storage: make empty virtual functions private (moving towards private-only hooks) 2022-01-08 16:14:54 +01:00
Michele Caini
d514ecbd5e doc: updated documentation about deletion policies 2022-01-08 14:36:04 +01:00
Michele Caini
a53dbb6950 registry: deletion policy is checked at runtime for groups since we can change it dynamically now 2022-01-08 14:34:21 +01:00
Michele Caini
a03b88e0eb dense_hash_[map/set]: suppress super annoying warnings 2022-01-07 14:07:35 +01:00
Michele Caini
4472eb1c40 updated TODO file 2022-01-06 00:23:58 +01:00
Michele Caini
3443987127 meta: meta_type::invoke also searches into the base types for a candidate function 2022-01-04 14:55:30 +01:00
Michele Caini
c73a79fd42 view: cleanup 2022-01-04 13:53:00 +01:00
Michele Caini
dedbe3d431 storage: make shrink_to_size check for tombstones only when needed 2022-01-03 21:30:53 +01:00
Michele Caini
87ef713a17 dense_hash_[map/set]: cleanup 2022-01-03 21:17:37 +01:00
Michele Caini
4ba8ac4fa1 sparse_set: opaque emplace/insert return (eventually invalid) iterators to the inserted elements 2022-01-02 17:21:21 +01:00
Michele Caini
e74e0531bd sparse_set/storage: minor changes 2022-01-02 16:51:08 +01:00
Michele Caini
b67cb4bd1f sparse_set/storage: minor changes to make it easier to read for the future me :) 2022-01-01 17:09:34 +01:00
Michele Caini
22628c9ac4 sparse_set/storage: prepare them for a faster and opaque ::insert 2021-12-31 17:23:50 +01:00
Michele Caini
4dd0862fad runtime_view:
* added ::iterate and ::exclude member functions to attach pools at runtime
* removed vector-based constructor
* removed basic_registry<...>::runtime_view member function
* updated benchmarks accordingly (also reviewed them as a whole just because)
2021-12-30 14:41:05 +01:00
Michele Caini
0ec57fbb8d sparse_set: removed redundant check 2021-12-30 14:38:51 +01:00
Michele Caini
19ab584d32 doc: updated FAQs 2021-12-29 16:34:26 +01:00
Michele Caini
97fe978d14 runtime_view: removed redundant validity check 2021-12-29 00:25:11 +01:00
Michele Caini
2a74c7d897 runtime_view: support to all types of sparse set 2021-12-28 09:28:41 +01:00
Michele Caini
cdf9c2fc6f registry: ctx internal review 2021-12-27 16:18:17 +01:00
Michele Caini
235f84a0d4 registry: minor changes 2021-12-27 15:58:09 +01:00
Michele Caini
ccaa490a2f registry: removed unnecessary dispatching from non-const try_ctx 2021-12-27 15:54:49 +01:00
Michele Caini
8eaf11b510 sparse_set: added the possibility to change the deletion policy at runtime 2021-12-27 15:08:42 +01:00
Michele Caini
57a5faa448 sparse_set: updated doc 2021-12-26 23:31:36 +01:00
Michele Caini
be87191d0a sparse_set:
* opaque emplace returns bool
* opaque insert returnes the number of entities actually emplaced
2021-12-26 17:04:10 +01:00
Michele Caini
40aabe76c7 sparse_set: fixed a throwing case that could leave the set in an inconsistent state 2021-12-26 16:36:30 +01:00
Michele Caini
9d304cb35c doc: fixed typo about in_place_delete 2021-12-23 16:31:07 +01:00
Michele Caini
ee08a4966f doc: updated list of links, added D2R to it too 2021-12-23 14:35:34 +01:00
Michele Caini
aeca69903e doc: updated similar projects 2021-12-22 17:53:45 +01:00
Michele Caini
e1b3f2b95a registry: added weak ::storage for opaque cross registry operations 2021-12-22 16:21:55 +01:00
Michele Caini
25c7436652 doc: minor changes 2021-12-21 14:10:33 +01:00
Michele Caini
771c449621 bump the version number 2021-12-21 13:27:04 +01:00
Michele Caini
61ecaa5756 storage: review to avoid code duplication 2021-12-21 08:33:46 +01:00
Michele Caini
c05dddc56e runtime_view: slightly optimized iterators 2021-12-21 08:33:46 +01:00
265 changed files with 86417 additions and 45765 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

8
.github/FUNDING.yml vendored
View File

@@ -1,12 +1,4 @@
# These are supported funding model platforms
github: skypjack
patreon:
open_collective:
ko_fi:
tidelift:
community_bridge:
liberapay:
issuehunt:
otechie:
custom: https://www.paypal.me/skypjack

61
.github/workflows/analyzer.yml vendored Normal file
View File

@@ -0,0 +1,61 @@
name: analyzer
on:
push:
branches:
- master
- wip
jobs:
iwyu:
timeout-minutes: 30
env:
IWYU: "0.20"
LLVM: "16"
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- name: Install llvm/clang
# see: https://apt.llvm.org/
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-$LLVM main"
sudo apt update
sudo apt remove -y "llvm*"
sudo apt remove -y "libclang-dev*"
sudo apt remove -y "clang*"
sudo apt install -y llvm-$LLVM-dev
sudo apt install -y libclang-$LLVM-dev
sudo apt install -y clang-$LLVM
- name: Compile iwyu
# see: https://github.com/include-what-you-use/include-what-you-use
working-directory: build
run: |
git clone https://github.com/include-what-you-use/include-what-you-use.git --branch $IWYU --depth 1
mkdir include-what-you-use/build
cd include-what-you-use/build
cmake -DCMAKE_C_COMPILER=clang-$LLVM \
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
-DCMAKE_INSTALL_PREFIX=./ \
..
make -j4
bin/include-what-you-use --version
- name: Compile tests
working-directory: build
run: |
export PATH=$PATH:${GITHUB_WORKSPACE}/build/include-what-you-use/build/bin
cmake -DCMAKE_C_COMPILER=clang-$LLVM \
-DCMAKE_CXX_COMPILER=clang++-$LLVM \
-DENTT_BUILD_TESTING=ON \
-DENTT_BUILD_BENCHMARK=ON \
-DENTT_BUILD_EXAMPLE=ON \
-DENTT_BUILD_LIB=ON \
-DENTT_BUILD_SNAPSHOT=ON \
-DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="include-what-you-use;-Xiwyu;--mapping_file=${GITHUB_WORKSPACE}/entt.imp;-Xiwyu;--no_fwd_decls;-Xiwyu;--verbose=1" \
..
make -j4

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

@@ -5,40 +5,65 @@ on: [push, pull_request]
jobs:
linux:
timeout-minutes: 10
timeout-minutes: 15
strategy:
matrix:
os: [ubuntu-latest, ubuntu-20.04]
compiler:
- pkg: g++-7
exe: g++-7
- pkg: g++-8
exe: g++-8
- pkg: g++-9
exe: g++-9
- pkg: g++
exe: g++
- pkg: clang-8
exe: clang++-8
- pkg: clang-9
exe: clang++-9
- pkg: clang-10
exe: clang++-10
- pkg: clang
exe: clang++
- { pkg: g++, exe: 'g++', version: 7 }
- { pkg: g++, exe: 'g++', version: 8 }
- { pkg: g++, exe: 'g++', version: 9 }
- { pkg: g++, exe: 'g++', version: 10 }
- { pkg: g++, exe: 'g++', version: 11 }
- { pkg: g++, exe: 'g++', version: 12 }
- { pkg: clang, exe: 'clang++', version: 8 }
- { pkg: clang, exe: 'clang++', version: 9 }
- { pkg: clang, exe: 'clang++', version: 10 }
- { pkg: clang, exe: 'clang++', version: 11 }
- { pkg: clang, exe: 'clang++', version: 12 }
- { pkg: clang, exe: 'clang++', version: 13 }
- { pkg: clang, exe: 'clang++', version: 14 }
exclude:
- os: ubuntu-latest
compiler: { pkg: g++, exe: 'g++', version: 7 }
- os: ubuntu-latest
compiler: { pkg: g++, exe: 'g++', version: 8 }
- os: ubuntu-latest
compiler: { pkg: g++, exe: 'g++', version: 9 }
- os: ubuntu-latest
compiler: { pkg: clang, exe: 'clang++', version: 8 }
- os: ubuntu-latest
compiler: { pkg: clang, exe: 'clang++', version: 9 }
- os: ubuntu-latest
compiler: { pkg: clang, exe: 'clang++', version: 10 }
- os: ubuntu-latest
compiler: { pkg: clang, exe: 'clang++', version: 11 }
- os: ubuntu-20.04
compiler: { pkg: g++, exe: 'g++', version: 10 }
- os: ubuntu-20.04
compiler: { pkg: g++, exe: 'g++', version: 11 }
- os: ubuntu-20.04
compiler: { pkg: g++, exe: 'g++', version: 12 }
- os: ubuntu-20.04
compiler: { pkg: clang, exe: 'clang++', version: 12 }
- os: ubuntu-20.04
compiler: { pkg: clang, exe: 'clang++', version: 13 }
- os: ubuntu-20.04
compiler: { pkg: clang, exe: 'clang++', version: 14 }
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Install compiler
run: |
sudo apt-get update
sudo apt-get install ${{ matrix.compiler.pkg }} -y
sudo apt update
sudo apt install -y ${{ matrix.compiler.pkg }}-${{ matrix.compiler.version }}
- name: Compile tests
working-directory: build
env:
CXX: ${{ matrix.compiler.exe }}
CXX: ${{ matrix.compiler.exe }}-${{ matrix.compiler.version }}
run: |
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
make -j4
@@ -46,55 +71,26 @@ jobs:
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
linux-extra:
timeout-minutes: 10
strategy:
matrix:
compiler: [g++, clang++]
id_type: [uint32, uint64]
cxx_std: [cxx_std_17, cxx_std_20]
include:
- id_type: uint64
id_type_variable: -DENTT_ID_TYPE=std::uint64_t
- cxx_std: cxx_std_20
cxx_std_variable: -DENTT_CXX_STD=cxx_std_20
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
env:
CXX: ${{ matrix.compiler }}
run: |
cmake -DENTT_BUILD_TESTING=ON ${{ matrix.id_type_variable }} ${{ matrix.cxx_std_variable }} ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4
windows:
timeout-minutes: 10
timeout-minutes: 15
strategy:
matrix:
toolset: [clang-cl, default, v141]
toolset: [default, v141, v142, clang-cl]
include:
- toolset: clang-cl
toolset_option: -T"ClangCl"
- toolset: v141
toolset_option: -T"v141"
- toolset: v142
toolset_option: -T"v142"
- toolset: clang-cl
toolset_option: -T"ClangCl"
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Compile tests
working-directory: build
run: |
@@ -104,42 +100,14 @@ jobs:
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
windows-extra:
timeout-minutes: 10
strategy:
matrix:
id_type: [uint32, uint64]
cxx_std: [cxx_std_17, cxx_std_20]
include:
- id_type: uint64
id_type_variable: -DENTT_ID_TYPE=std::uint64_t
- cxx_std: cxx_std_20
cxx_std_variable: -DENTT_CXX_STD=cxx_std_20
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
run: |
cmake -DENTT_BUILD_TESTING=ON ${{ matrix.id_type_variable }} ${{ matrix.cxx_std_variable }} ..
cmake --build . -j 4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4
macos:
timeout-minutes: 10
timeout-minutes: 15
runs-on: macOS-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Compile tests
working-directory: build
run: |
@@ -149,32 +117,28 @@ jobs:
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4
macos-extra:
timeout-minutes: 10
extra:
timeout-minutes: 15
strategy:
matrix:
id_type: [uint32, uint64]
os: [windows-latest, macOS-latest, ubuntu-latest]
id_type: ["std::uint32_t", "std::uint64_t"]
cxx_std: [cxx_std_17, cxx_std_20]
include:
- id_type: uint64
id_type_variable: -DENTT_ID_TYPE=std::uint64_t
- cxx_std: cxx_std_20
cxx_std_variable: -DENTT_CXX_STD=cxx_std_20
runs-on: macOS-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Compile tests
working-directory: build
run: |
cmake -DENTT_BUILD_TESTING=ON ${{ matrix.id_type_variable }} ${{ matrix.cxx_std_variable }} ..
make -j4
cmake -DENTT_BUILD_TESTING=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} ..
cmake --build . -j 4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4

View File

@@ -5,34 +5,34 @@ on: [push, pull_request]
jobs:
codecov:
timeout-minutes: 10
timeout-minutes: 15
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
env:
CXXFLAGS: "--coverage -fno-inline"
CXX: g++
run: |
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
- name: Collect data
working-directory: build
run: |
sudo apt install lcov
lcov -c -d . -o coverage.info
lcov -l coverage.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: build/coverage.info
name: EnTT
fail_ci_if_error: true
- uses: actions/checkout@v4
- name: Compile tests
working-directory: build
env:
CXXFLAGS: "--coverage -fno-elide-constructors -fno-inline -fno-default-inline"
CXX: g++
run: |
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest -C Debug -j4
- name: Collect data
working-directory: build
run: |
sudo apt install lcov
lcov -c -d . -o coverage.info
lcov -l coverage.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: build/coverage.info
name: EnTT
fail_ci_if_error: true

View File

@@ -15,7 +15,7 @@ jobs:
FORMULA: entt.rb
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Clone repository
working-directory: build
env:

View File

@@ -4,33 +4,30 @@ on: [push, pull_request]
jobs:
linux:
timeout-minutes: 10
clang:
timeout-minutes: 15
strategy:
matrix:
compiler: [clang++]
id_type: [uint32, uint64]
id_type: ["std::uint32_t", "std::uint64_t"]
cxx_std: [cxx_std_17, cxx_std_20]
include:
- id_type: uint64
id_type_variable: -DENTT_ID_TYPE=std::uint64_t
- cxx_std: cxx_std_20
cxx_std_variable: -DENTT_CXX_STD=cxx_std_20
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- 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:
CXX: ${{ matrix.compiler }}
run: |
cmake -DENTT_USE_SANITIZER=ON -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.id_type_variable }} ${{ matrix.cxx_std_variable }} ..
cmake -DENTT_USE_SANITIZER=ON -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON -DENTT_CXX_STD=${{ matrix.cxx_std }} -DENTT_ID_TYPE=${{ matrix.id_type }} ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 30 -C Debug -j4
run: ctest -C Debug -j4

2
.gitignore vendored
View File

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

View File

@@ -11,10 +11,12 @@ ceeac
ColinH
corystegel
Croydon
cschreib
cugone
dbacchet
dBagrat
djarek
DNKpp
DonKult
drglove
eliasdaler
@@ -31,6 +33,7 @@ Lawrencemm
markand
mhammerc
Milerius
Minimonium
morbo84
m-waka
netpoetica
@@ -39,6 +42,7 @@ Oortonaut
Paolo-Oliverio
pgruenbacher
prowolf
Qix-
stefanofiorentino
suVrik
szunhammer
@@ -46,6 +50,7 @@ The5-1
vblanco20-1
willtunnels
WizardIke
WoLfulus
w1th0utnam3
xissburg
zaucy

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,29 +1,15 @@
#
# EnTT
#
cmake_minimum_required(VERSION 3.12.4)
cmake_minimum_required(VERSION 3.15.7)
#
# Building in-tree is not allowed (we take care of your craziness).
#
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
message(FATAL_ERROR "Prevented in-tree built. Please create a build directory outside of the source code and call cmake from there. Thank you.")
endif()
#
# 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
@@ -39,15 +25,18 @@ endif()
message(VERBOSE "*")
message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
message(VERBOSE "* Copyright (c) 2017-2021 Michele Caini <michele.caini@gmail.com>")
message(VERBOSE "* Copyright (c) 2017-2023 Michele Caini <michele.caini@gmail.com>")
message(VERBOSE "*")
#
# Compiler stuff
#
# CMake stuff
option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if availbale." OFF)
option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags if availbale." OFF)
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)
@@ -67,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()
@@ -78,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)
@@ -119,9 +114,10 @@ if(ENTT_INCLUDE_HEADERS)
EnTT
INTERFACE
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/config.h>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/macro.h>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/config/version.h>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_hash_map.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_hash_set.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_map.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/dense_set.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/container/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/algorithm.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/core/any.hpp>
@@ -144,6 +140,7 @@ if(ENTT_INCLUDE_HEADERS)
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/group.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/handle.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/mixin.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/helper.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/observer.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/organizer.hpp>
@@ -152,12 +149,15 @@ if(ENTT_INCLUDE_HEADERS)
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/snapshot.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/sparse_set.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/storage.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/utility.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/entity/view.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/adjacency_matrix.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/dot.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/flow.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/graph/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/locator/locator.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/adl_pointer.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/container.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/ctx.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/context.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/factory.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/meta/meta.hpp>
@@ -172,12 +172,13 @@ if(ENTT_INCLUDE_HEADERS)
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/platform/android-ndk-r17.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/poly/poly.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/process.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/process/scheduler.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/cache.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/fwd.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/handle.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/loader.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/resource/resource.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/delegate.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/dispatcher.hpp>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src/entt/signal/emitter.hpp>
@@ -196,6 +197,7 @@ if(ENTT_HAS_NATVIS)
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/container.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/core.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/entity.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/graph.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/locator.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/meta.natvis>
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/natvis/entt/platform.natvis>
@@ -211,16 +213,22 @@ 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)
set(EnTT_PKGCONFIG ${CMAKE_CURRENT_BINARY_DIR}/entt.pc)
join_paths(EnTT_PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
configure_file(
${EnTT_SOURCE_DIR}/cmake/in/entt.pc.in
${EnTT_PKGCONFIG}
@@ -232,9 +240,7 @@ install(
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
#
# Install EnTT
#
include(CMakePackageConfigHelpers)
@@ -276,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)
@@ -301,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)
@@ -314,22 +330,3 @@ if(ENTT_BUILD_DOCS)
add_subdirectory(docs)
endif()
endif()
#
# AOB
#
add_custom_target(
aob
SOURCES
.github/workflows/build.yml
.github/workflows/coverage.yml
.github/workflows/deploy.yml
.github/workflows/sanitizer.yml
.github/FUNDING.yml
AUTHORS
CONTRIBUTING.md
LICENSE
README.md
TODO
)

View File

@@ -1,7 +1,7 @@
# Contributing
First of all, thank you very much for taking the time to contribute to the
`EnTT` framework.<br/>
`EnTT` library.<br/>
How to do it mostly depends on the type of contribution:
* If you have a question, **please** ensure there isn't already an answer for
@@ -28,7 +28,7 @@ How to do it mostly depends on the type of contribution:
* If you found a bug and you wrote a patch to fix it, open a new
[pull request](https://github.com/skypjack/entt/pulls) with your code.
**Please**, add some tests to avoid regressions in future if possible, it
would be really appreciated. Note that the `EnTT` framework has a
would be really appreciated. Note that the `EnTT` library has a
[coverage at 100%](https://coveralls.io/github/skypjack/entt?branch=master)
(at least it was at 100% at the time I wrote this file) and this is the reason
for which you can be confident with using it in a production environment.

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2017-2021 Michele Caini, author of EnTT
Copyright (c) 2017-2023 Michele Caini, author of EnTT
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

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,10 +6,16 @@
[![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)
[![Documentation](https://img.shields.io/badge/docs-docsforge-blue)](http://entt.docsforge.com/)
[![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
>
> -- Every EnTT User Ever
`EnTT` is a header-only, tiny and easy to use library for game programming and
much more written in **modern C++**.<br/>
@@ -33,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:
@@ -45,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)
@@ -75,18 +82,20 @@ codebase has grown as more and more classes and functionalities were added.<br/>
Here is a brief, yet incomplete list of what it offers today:
* Built-in **RTTI system** mostly similar to the standard one.
* A `constexpr` utility for human readable **resource names**.
* A `constexpr` utility for human-readable **resource names**.
* Minimal **configuration system** built using the monostate pattern.
* Incredibly fast **entity-component system** with its own _pay for what you
use_ policy.
use_ policy, unconstrained component types with optional pointer stability and
hooks for storage customization.
* Views and groups to iterate entities and components and allow different access
patterns, from **perfect SoA** to fully random.
* A lot of **facilities** built on top of the entity-component system to help
the users and avoid reinventing the wheel.
* General purpose **execution graph builder** for optimal scheduling.
* The smallest and most basic implementation of a **service locator** ever seen.
* A built-in, non-intrusive and macro-free runtime **reflection system**.
* **Static polymorphism** made simple and within everyone's reach.
* A few homemade containers, like a sparse set based **dense hash map**.
* A few homemade containers, like a sparse set based **hash map**.
* A **cooperative scheduler** for processes of any type.
* All that is needed for **resource management** (cache, loaders, handles).
* Delegates, **signal handlers** and a tiny event dispatcher.
@@ -94,16 +103,12 @@ Here is a brief, yet incomplete list of what it offers today:
* And **much more**! Check out the
[**wiki**](https://github.com/skypjack/entt/wiki).
**Breaking news**:
Consider this list a work in progress as well as the project. The whole API is
fully documented in-code for those who are brave enough to read it.<br/>
Please, do note that all tools are also DLL-friendly now and run smoothly across
boundaries.
* The ECS allows attaching multiple components of the same type to an entity.
* All tools work perfectly across boundaries (DLL-friendly)!!
:slightly_smiling_face:
Consider these lists a work in progress as well as the project. The whole API is
fully documented in-code for those who are brave enough to read it.
It is also known that `EnTT` is used in **Minecraft**.<br/>
One thing known to most is that `EnTT` is also used in **Minecraft**.<br/>
Given that the game is available literally everywhere, I can confidently say
that the library has been sufficiently tested on every platform that can come to
mind.
@@ -160,7 +165,7 @@ int main() {
## Motivation
I started developing `EnTT` for the _wrong_ reason: my goal was to design an
entity-component system to beat another well known open source solution both in
entity-component system to beat another well known open source library both in
terms of performance and possibly memory usage.<br/>
In the end, I did it, but it wasn't very satisfying. Actually it wasn't
satisfying at all. The fastest and nothing more, fairly little indeed. When I
@@ -171,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
@@ -323,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
@@ -340,8 +348,8 @@ The documentation is based on [doxygen](http://www.doxygen.nl/). To build it:
$ cmake .. -DENTT_BUILD_DOCS=ON
$ make
The API reference will be created in HTML format within the directory
`build/docs/html`. To navigate it with your favorite browser:
The API reference is created in HTML format in the `build/docs/html` directory.
To navigate it with your favorite browser:
$ cd build
$ your_favorite_browser docs/html/index.html
@@ -350,10 +358,7 @@ The API reference will be created in HTML format within the directory
@cond TURN_OFF_DOXYGEN
-->
The same version is also available [online](https://skypjack.github.io/entt/)
for the latest release, that is the last stable tag. If you are looking for
something more pleasing to the eye, consider reading the nice-looking version
available on [docsforge](https://entt.docsforge.com/): same documentation, much
more pleasant to read.<br/>
for the latest release, that is the last stable tag.<br/>
Moreover, there exists a [wiki](https://github.com/skypjack/entt/wiki) dedicated
to the project where users can find all related documentation pages.
<!--
@@ -363,9 +368,8 @@ to the project where users can find all related documentation pages.
# Tests
To compile and run the tests, `EnTT` requires *googletest*.<br/>
`cmake` will download and compile the library before compiling anything else.
In order to build the tests, set the `CMake` option `ENTT_BUILD_TESTING` to
`ON`.
`cmake` downloads and compiles the library before compiling anything else. In
order to build the tests, set the `CMake` option `ENTT_BUILD_TESTING` to `ON`.
To build the most basic set of tests:
@@ -417,7 +421,7 @@ know who has participated so far.
# License
Code and documentation Copyright (c) 2017-2021 Michele Caini.<br/>
Code and documentation Copyright (c) 2017-2023 Michele Caini.<br/>
Colorful logo Copyright (c) 2018-2021 Richard Caseres.
Code released under

50
TODO
View File

@@ -1,25 +1,31 @@
* long term feature: shared_ptr less locator and resource cache
* debugging tools (#60): the issue online already contains interesting tips on this, look at it
* work stealing job system (see #100) + mt scheduler based on const awareness for types
* add examples (and credits) from @alanjfs :)
EXAMPLES
* filter on runtime values/variables (not only types)
* support to polymorphic types (see #859)
WIP:
* add the possibility of disabling entities without deleting components thanks to the new full check
* add registry::storage id -> basic_sparse_set (no template arg), add example of use
* fast-contains for sparse sets (low prio but nice-to-have)
* runtime events (dispatcher/emitter), runtime context variables...
* runtime_view/registry, remove reference to basic_sparse_set<E>
* dedicated entity storage, in-place O(1) release/destroy for non-orphaned entities, out-of-sync model
* custom allocators all over
DOC:
* custom storage/view
* 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
WIP:
* customizable any_vtable, sfinae-friendly definition and op::custom for user-def
* resource, forward the id to the loader from the cache and if constexpr the call to load, update doc and describe customization points
* add user data to type_info
* headless (sparse set only) view
* write documentation for custom storages and views!!
* make runtime views use opaque storage and therefore return also elements.
* add exclude-only views to combine with packs
* entity-aware observer, add observer functions aside observer class
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 meta resolve function by id (bimap)
* get rid of observers, storage based views made them pointless - document alternatives
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
* snapshot: support for range-based archives
* 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,5 +1,5 @@
prefix=@CMAKE_INSTALL_PREFIX@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
includedir=@EnTT_PKGCONFIG_INCLUDEDIR@
Name: EnTT
Description: Gaming meets modern C++

View File

@@ -0,0 +1,23 @@
# This module provides function for joining paths
# known from most languages
#
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Pythons os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()

View File

@@ -1,9 +1,23 @@
#
# Doxygen configuration (documentation)
#
set(DOXY_DEPS_DIRECTORY ${EnTT_SOURCE_DIR}/deps)
include(FetchContent)
FetchContent_Declare(
doxygen-awesome-css
GIT_REPOSITORY https://github.com/jothepro/doxygen-awesome-css
GIT_TAG main
GIT_SHALLOW 1
)
FetchContent_GetProperties(doxygen-awesome-css)
if(NOT doxygen-awesome-css_POPULATED)
FetchContent_Populate(doxygen-awesome-css)
set(doxygen-awesome-css_INCLUDE_DIR ${doxygen-awesome-css_SOURCE_DIR})
endif()
set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src)
set(DOXY_CSS_DIRECTORY ${doxygen-awesome-css_INCLUDE_DIR})
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})

File diff suppressed because it is too large Load Diff

View File

@@ -7,24 +7,25 @@
* [Introduction](#introduction)
* [Definitions](#definitions)
* [ENTT_NOEXCEPTION](#entt_noexcept)
* [ENTT_NOEXCEPTION](#entt_noexception)
* [ENTT_USE_ATOMIC](#entt_use_atomic)
* [ENTT_ID_TYPE](#entt_id_type)
* [ENTT_SPARSE_PAGE](#entt_sparse_page)
* [ENTT_PACKED_PAGE](#entt_packed_page)
* [ENTT_ASSERT](#entt_assert)
* [ENTT_ASSERT_CONSTEXPR](#entt_assert_constexpr)
* [ENTT_DISABLE_ASSERT](#entt_disable_assert)
* [ENTT_NO_ETO](#entt_no_eto)
* [ENTT_STANDARD_CPP](#entt_standard_cpp)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
`EnTT` doesn't offer many hooks for customization but it certainly offers
some.<br/>
`EnTT` has become almost completely customizable over time, in many
respects. These variables are just one of the many ways to customize how it
works.<br/>
In the vast majority of cases, users will have no interest in changing the
default parameters. For all other cases, the list of possible configurations
with which it's possible to adjust the behavior of the library at runtime can be
@@ -40,17 +41,17 @@ will remain stable over time unlike the options below.
## ENTT_NOEXCEPTION
This parameter can be used to switch off exception handling in `EnTT`.<br/>
To do this, simply define the variable without assigning any value to it. This
is roughly equivalent to setting the compiler flag `-ff-noexceptions`.
Define this variable without assigning any value to it to turn off exception
handling in `EnTT`.<br/>
This is roughly equivalent to setting the compiler flag `-fno-exceptions` but is
also limited to this library only.
## ENTT_USE_ATOMIC
In general, `EnTT` doesn't offer primitives to support multi-threading. Many of
the features can be split over multiple threads without any explicit control and
the user is the only one who knows if and when a synchronization point is
required.<br/>
However, some features aren't easily accessible to users and can be made
the user is the one who knows if a synchronization point is required.<br/>
However, some features aren't easily accessible to users and are made
thread-safe by means of this definition.
## ENTT_ID_TYPE
@@ -70,9 +71,9 @@ power of 2.
## ENTT_PACKED_PAGE
Similar to sparse arrays, packed arrays of components are paginated as well. In
However, int this case the aim isn't to reduce memory usage but to have pointer
stability upon component creation.<br/>
As it happens with sparse arrays, packed arrays are also paginated. However, in
this case the aim isn't to reduce memory usage but to have pointer stability
upon component creation.<br/>
Default size of pages (that is, the number of elements they contain) is 1024 but
users can adjust it if appropriate. In all case, the chosen value **must** be a
power of 2.
@@ -83,21 +84,29 @@ For performance reasons, `EnTT` doesn't use exceptions or any other control
structures. In fact, it offers many features that result in undefined behavior
if not used correctly.<br/>
To get around this, the library relies on a lot of asserts for the purpose of
detecting errors in debug builds. By default, it uses `assert` internally, but
users are allowed to overwrite its behavior by setting this variable.
detecting errors in debug builds. By default, it uses `assert` internally. Users
are allowed to overwrite its behavior by setting this variable.
### ENTT_ASSERT_CONSTEXPR
Usually, an assert within a `constexpr` function isn't a big deal. However, in
case of extreme customizations, it might be useful to differentiate.<br/>
For this purpose, `EnTT` introduces an admittedly badly named variable to make
the job easier in this regard. By default, this variable forwards its arguments
to `ENTT_ASSERT`.
### ENTT_DISABLE_ASSERT
Assertions may in turn affect performance to an extent when enabled. Whether
`ENTT_ASSERT` is redefined or not, all asserts can be disabled at once by means
of this definition.<br/>
Note that `ENTT_DISABLE_ASSERT` takes precedence over the redefinition of
`ENTT_ASSERT` and is therefore meant to disable all controls no matter what.
`ENTT_ASSERT` and `ENTT_ASSERT_CONSTEXPR` are redefined or not, all asserts can
be disabled at once by means of this definition.<br/>
Note that `ENTT_DISABLE_ASSERT` takes precedence over the redefinition of the
other variables and is therefore meant to disable all controls no matter what.
## ENTT_NO_ETO
In order to reduce memory consumption and increase performance, empty types are
never stored by the ECS module of `EnTT`.<br/>
never instantiated nor stored by the ECS module of `EnTT`.<br/>
Use this variable to treat these types like all others and therefore to create a
dedicated storage for them.
@@ -105,7 +114,7 @@ dedicated storage for them.
`EnTT` mixes non-standard language features with others that are perfectly
compliant to offer some of its functionalities.<br/>
This definition will prevent the library from using non-standard techniques,
that is, functionalities that aren't fully compliant with the standard C++.<br/>
This definition prevents the library from using non-standard techniques, that
is, functionalities that aren't fully compliant with the standard C++.<br/>
While there are no known portability issues at the time of this writing, this
should make the library fully portable anyway if needed.

View File

@@ -7,9 +7,8 @@
* [Introduction](#introduction)
* [Containers](#containers)
* [Dense hash map](#dense-hash-map)
* [Dense hash set](#dense-hash-set)
* [Dense map](#dense-map)
* [Dense set](#dense-set)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@@ -21,7 +20,7 @@ difficult to do better (although it's very easy to do worse, as many examples
available online demonstrate).<br/>
`EnTT` doesn't try in any way to replace what is offered by the standard. Quite
the opposite, given the widespread use that is made of standard containers.<br/>
However, the library also tries to fill a gap in features and functionality by
However, the library also tries to fill a gap in features and functionalities by
making available some containers initially developed for internal use.
This section of the library is likely to grow larger over time. However, for the
@@ -31,26 +30,38 @@ guaranteed as usual.
# Containers
## Dense hash map
## Dense map
The dense hash map made available in `EnTT` is a map that aims to return a
The dense map made available in `EnTT` is a hash map that aims to return a
packed array of elements, so as to reduce the number of jumps in memory during
the iteration.<br/>
iterations.<br/>
The implementation is based on _sparse sets_ and each bucket is identified by an
implicit list within the packed array itself.
The interface is very close to its counterpart in the standard library, that is,
the `std::unordered_map` class.<br/>
However, both local and non-local iterators returned by a dense map belong to
the input iterator category although they respectively model the concepts of a
_forward iterator_ type and a _random access iterator_ type.<br/>
This is because they return a pair of references rather than a reference to a
pair. In other words, dense maps return a so called _proxy iterator_ the value
type of which is:
* `std::pair<const Key &, Type &>` for non-const iterator types.
* `std::pair<const Key &, const Type &>` for const iterator types.
This is quite different from what any standard library map returns and should be
taken into account when looking for a drop-in replacement.
## Dense set
The dense set made available in `EnTT` is a hash set that aims to return a
packed array of elements, so as to reduce the number of jumps in memory during
iterations.<br/>
The implementation is based on _sparse sets_ and each bucket is identified by an
implicit list within the packed array itself.
The interface is in all respects similar to its counterpart in the standard
library, that is, `std::unordered_map`.<br/>
Therefore, there is no need to go into the API description.
## Dense hash set
The dense hash set made available in `EnTT` is a set that aims to return a
packed array of elements, so as to reduce the number of jumps in memory during
the iteration.<br/>
The implementation is based on _sparse sets_ and each bucket is identified by an
implicit list within the packed array itself.
The interface is in all respects similar to its counterpart in the standard
library, that is, `std::unordered_set`.<br/>
Therefore, there is no need to go into the API description.
library, that is, the `std::unordered_set` class.<br/>
However, this type of set also supports reverse iteration and therefore offers
all the functions necessary for the purpose (such as `rbegin` and `rend`).

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -14,18 +14,20 @@
* [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
-->
# Introduction
This is a constantly updated section where I'll try to put the answers to the
This is a constantly updated section where I'm trying to put the answers to the
most frequently asked questions.<br/>
If you don't find your answer here, there are two cases: nobody has done it yet
or this section needs updating. In both cases, try to
[open a new issue](https://github.com/skypjack/entt/issues/new) or enter the
[gitter channel](https://gitter.im/skypjack/entt) and ask your question.
or this section needs updating. In both cases, you can
[open a new issue](https://github.com/skypjack/entt/issues/new) or enter either
the [gitter channel](https://gitter.im/skypjack/entt) or the
[discord server](https://discord.gg/5BjPWBd) to ask for help.<br/>
Probably someone already has an answer for you and we can then integrate this
part of the documentation.
@@ -45,14 +47,14 @@ lot, achieving good results in many cases.
First of all, there are two things to do in a Windows project:
* Disable the [`/JMC`](https://docs.microsoft.com/cpp/build/reference/jmc)
option (_Just My Code_ debugging), available starting in Visual Studio 2017
option (_Just My Code_ debugging), available starting with Visual Studio 2017
version 15.8.
* Set the [`_ITERATOR_DEBUG_LEVEL`](https://docs.microsoft.com/cpp/standard-library/iterator-debug-level)
macro to 0. This will disable checked iterators and iterator debugging.
Moreover, the macro `ENTT_ASSERT` should be redefined to disable internal checks
made by `EnTT` in debug:
Moreover, set the `ENTT_DISABLE_ASSERT` variable or redefine the `ENTT_ASSERT`
macro to disable internal debug checks in `EnTT`:
```cpp
#define ENTT_ASSERT(...) ((void)0)
@@ -61,22 +63,22 @@ made by `EnTT` in debug:
These asserts are introduced to help the users but they require to access to the
underlying containers and therefore risk ruining the performance in some cases.
With these changes, debug performance should increase enough for most cases. If
you want something more, you can can also switch to an optimization level `O0`
or preferably `O1`.
With these changes, debug performance should increase enough in most cases. If
you want something more, you can also switch to an optimization level `O0` or
preferably `O1`.
## How can I represent hierarchies with my components?
This is one of the first questions that anyone makes when starting to work with
the entity-component-system architectural pattern.<br/>
There are several approaches to the problem and whats the best one depends
mainly on the real problem one is facing. In all cases, how to do it doesn't
strictly depend on the library in use, but the latter can certainly allow or
not different techniques depending on how the data are laid out.
There are several approaches to the problem and the best one depends mainly on
the real problem one is facing. In all cases, how to do it doesn't strictly
depend on the library in use, but the latter certainly allows or not different
techniques depending on how the data are laid out.
I tried to describe some of the techniques that fit well with the model of
`EnTT`. [Here](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) is the
first post of a series that tries to explore the problem. More will probably
I tried to describe some of the approaches that fit well with the model of
`EnTT`. [This](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) is the
first post of a series that tries to _explore_ the problem. More will probably
come in future.<br/>
In addition, `EnTT` also offers the possibility to create stable storage types
and therefore have pointer stability for one, all or some components. This is by
@@ -90,6 +92,7 @@ Custom entity identifiers are definitely a good idea in two cases at least:
* If `std::uint32_t` isn't large enough for your purposes, since this is the
underlying type of `entt::entity`.
* If you want to avoid conflicts when using multiple registries.
Identifiers can be defined through enum classes and class types that define an
@@ -105,7 +108,7 @@ There is no limit to the number of identifiers that can be defined.
## Warning C4307: integral constant overflow
According to [this](https://github.com/skypjack/entt/issues/121) issue, using a
hashed string under VS could generate a warning.<br/>
hashed string under VS (toolset v141) could generate a warning.<br/>
First of all, I want to reassure you: it's expected and harmless. However, it
can be annoying.
@@ -136,7 +139,7 @@ errors during compilation.
It's a pretty big problem but fortunately it's not a problem of `EnTT` and there
is a fairly simple solution to it.<br/>
It consists in defining the `NOMINMAX` macro before to include any other header
It consists in defining the `NOMINMAX` macro before including any other header
so as to get rid of the extra definitions:
```cpp
@@ -149,15 +152,14 @@ more details.
## The standard and the non-copyable types
`EnTT` uses internally the trait `std::is_copy_constructible_v` to check if a
component is actually copyable. This trait doesn't check if an object can
actually be copied but only verifies if there is a copy constructor
available.<br/>
This can lead to surprising results due to some idiosyncrasies of the standard
mainly related to the need to guarantee backward compatibility.
component is actually copyable. However, this trait doesn't really check whether
a type is actually copyable. Instead, it just checks that a suitable copy
constructor and copy operator exist.<br/>
This can lead to surprising results due to some idiosyncrasies of the standard.
For example, `std::vector` defines a copy constructor no matter if its value
type is copyable or not. As a result, `std::is_copy_constructible_v` is true
for the following specialization:
For example, `std::vector` defines a copy constructor that is conditionally
enabled depending on whether the value type is copyable or not. As a result,
`std::is_copy_constructible_v` returns true for the following specialization:
```cpp
struct type {
@@ -165,31 +167,42 @@ struct type {
};
```
When trying to assign an instance of this type to an entity in the ECS part,
this may trigger a compilation error because we cannot really make a copy of
it.<br/>
As a workaround, users can mark the type explicitly as non-copyable:
However, the copy constructor is effectively disabled upon specialization.
Therefore, trying to assign an instance of this type to an entity may trigger a
compilation error.<br/>
As a workaround, users can mark the type explicitly as non-copyable. This also
suppresses the implicit generation of the move constructor and operator, which
will therefore have to be defaulted accordingly:
```cpp
struct type {
type(const type &) = delete;
type(type &&) = default;
type & operator=(const type &) = delete;
type & operator=(type &&) = default;
std::vector<std::unique_ptr<action>> vec;
};
```
Unfortunately, this will also disable aggregate initialization.
Note that aggregate initialization is also disabled as a consequence.<br/>
Fortunately, this type of trick is quite rare. The bad news is that there is no
way to deal with it at the library level, this being due to the design of the
language. On the other hand, the fact that the language itself also offers a way
to mitigate the problem makes it manageable.
## Which functions trigger which signals
The `registry` class offers three signals that are emitted following specific
Storage classes offer three _signals_ that are emitted following specific
operations. Maybe not everyone knows what these operations are, though.<br/>
If this isn't clear, below you can find a _vademecum_ for this purpose:
* `on_created` is invoked when a component is first added (neither modified nor
replaced) to an entity.
* `on_update` is called whenever an existing component is modified or replaced.
* `on_destroyed` is called when a component is explicitly or implicitly removed
from an entity.
@@ -201,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.

372
docs/md/graph.md Normal file
View File

@@ -0,0 +1,372 @@
# Crash Course: graph
<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents
* [Introduction](#introduction)
* [Data structures](#data-structures)
* [Adjacency matrix](#adjacency-matrix)
* [Graphviz dot language](#graphviz-dot-language)
* [Flow builder](#flow-builder)
* [Tasks and resources](#tasks-and-resources)
* [Fake resources and order of execution](#fake-resources-and-order-of-execution)
* [Sync points](#sync-points)
* [Execution graph](#execution-graph)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
`EnTT` doesn't aim to offer everything one needs to work with graphs. Therefore,
anyone looking for this in the _graph_ submodule will be disappointed.<br/>
Quite the opposite is true though. This submodule is minimal and contains only
the data structures and algorithms strictly necessary for the development of
some tools such as the _flow builder_.
# Data structures
As anticipated in the introduction, the aim isn't to offer all possible data
structures suitable for representing and working with graphs. Many will likely
be added or refined over time. However I want to discourage anyone expecting
tight scheduling on the subject.<br/>
The data structures presented in this section are mainly useful for the
development and support of some tools which are also part of the same submodule.
## Adjacency matrix
The adjacency matrix is designed to represent either a directed or an undirected
graph:
```cpp
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{};
```
The `directed_tag` type _creates_ the graph as directed. There is also an
`undirected_tag` counterpart which creates it as undirected.<br/>
The interface deviates slightly from the typical double indexing of C and offers
an API that is perhaps more familiar to a C++ programmer. Therefore, the access
and modification of an element takes place via the `contains`, `insert` and
`erase` functions rather than a double call to an `operator[]`:
```cpp
if(adjacency_matrix.contains(0u, 1u)) {
adjacency_matrix.erase(0u, 1u);
} else {
adjacency_matrix.insert(0u, 1u);
}
```
Both `insert` and` erase` are _idempotent_ functions which have no effect if the
element already exists or has already been deleted.<br/>
The first one returns an `std::pair` containing the iterator to the element and
a boolean value indicating whether the element was newly inserted or not. The
second one returns the number of deleted elements (0 or 1).
An adjacency matrix is initialized with the number of elements (vertices) when
constructing it but can also be resized later using the `resize` function:
```cpp
entt::adjacency_matrix<entt::directed_tag> adjacency_matrix{3u};
```
To visit all vertices, the class offers a function named `vertices` that returns
an iterable object suitable for the purpose:
```cpp
for(auto &&vertex: adjacency_matrix.vertices()) {
// ...
}
```
The same result is obtained with the following snippet, since the vertices are
plain unsigned integral values:
```cpp
for(auto last = adjacency_matrix.size(), pos = {}; pos < last; ++pos) {
// ...
}
```
As for visiting the edges, a few functions are available.<br/>
When the purpose is to visit all the edges of a given adjacency matrix, the
`edges` function returns an iterable object that is used to get them as pairs of
vertices:
```cpp
for(auto [lhs, rhs]: adjacency_matrix.edges()) {
// ...
}
```
If the goal is to visit all the in- or out-edges of a given vertex instead, the
`in_edges` and `out_edges` functions are meant for that:
```cpp
for(auto [lhs, rhs]: adjacency_matrix.out_edges(3u)) {
// ...
}
```
Both the functions expect the vertex to visit (that is, to return the in- or
out-edges for) as an argument.<br/>
Finally, the adjacency matrix is an allocator-aware container and offers most of
the functionalities one would expect from this type of containers, such as
`clear` or 'get_allocator` and so on.
## Graphviz dot language
As it's one of the most popular formats, the library offers minimal support for
converting a graph to a Graphviz dot snippet.<br/>
The simplest way is to pass both an output stream and a graph to the `dot`
function:
```cpp
std::ostringstream output{};
entt::dot(output, adjacency_matrix);
```
It's also possible to provide a callback to which the vertices are passed and
which can be used to add (`dot`) properties to the output as needed:
```cpp
std::ostringstream output{};
entt::dot(output, adjacency_matrix, [](auto &output, auto vertex) {
out << "label=\"v\"" << vertex << ",shape=\"box\"";
});
```
This second mode is particularly convenient when the user wants to associate
externally managed data to the graph being converted.
# Flow builder
A flow builder is used to create execution graphs from tasks and resources.<br/>
The implementation is as generic as possible and doesn't bind to any other part
of the library.
This class is designed as a sort of _state machine_ to which a specific task is
attached for which the resources accessed in read-only or read-write mode are
specified.<br/>
Most of the functions in the API also return the flow builder itself, according
to what is the common sense API when it comes to builder classes.
Once all tasks are registered and resources assigned to them, an execution graph
in the form of an adjacency matrix is returned to the user.<br/>
This graph contains all the tasks assigned to the flow builder in the form of
_vertices_. The _vertex_ itself is used as an index to get the identifier passed
during registration.
## Tasks and resources
Although these terms are used extensively in the documentation, the flow builder
has no real concept of tasks and resources.<br/>
This class works mainly with _identifiers_, that is, values of type `id_type`.
In other terms, both tasks and resources are identified by integral values.<br/>
This allows not to couple the class itself to the rest of the library or to any
particular data structure. On the other hand, it requires the user to keep track
of the association between identifiers and operations or actual data.
Once a flow builder is created (which requires no constructor arguments), the
first thing to do is to bind a task. This tells to the builder _who_ intends to
consume the resources that are specified immediately after:
```cpp
entt::flow builder{};
builder.bind("task_1"_hs);
```
The example uses the `EnTT` hashed string to generate an identifier for the
task.<br/>
Indeed, the use of `id_type` as an identifier type isn't by accident. In fact,
it matches well with the internal hashed string class. Moreover, it's also the
same type returned by the hash function of the internal RTTI system, in case the
user wants to rely on that.<br/>
However, being an integral value, it leaves the user full freedom to rely on his
own tools if necessary.
Once a task is associated with the flow builder, it's also assigned read-only or
read-write resources as appropriate:
```cpp
builder
.bind("task_1"_hs)
.ro("resource_1"_hs)
.ro("resource_2"_hs)
.bind("task_2"_hs)
.rw("resource_2"_hs)
```
As mentioned, many functions return the builder itself and it's therefore easy
to concatenate the different calls.<br/>
Also in the case of resources, they are identified by numeric values of type
`id_type`. As above, the choice is not entirely random. This goes well with the
tools offered by the library while leaving room for maximum flexibility.
Finally, both the `ro` and` rw` functions also offer an overload that accepts a
pair of iterators, so that one can pass a range of resources in one go.
### Rebinding
The `flow` class is resource based rather than task based. This means that graph
generation is driven by resources and not by the order of _appearance_ of tasks
during flow definition.<br/>
Although this concept is particularly important, it's almost irrelevant for the
vast majority of cases. However, it becomes relevant when _rebinding_ resources
or tasks.
In fact, nothing prevents rebinding elements to a flow.<br/>
However, the behavior changes slightly from case to case and has some nuances
that it's worth knowing about.
Directly rebinding a resource without the task being replaced trivially results
in the task's access mode for that resource being updated:
```cpp
builder.bind("task"_hs).rw("resource"_hs).ro("resource"_hs)
```
In this case, the resource is accessed in read-only mode, regardless of the
first call to `rw`.<br/>
Behind the scenes, the call doesn't actually _replace_ the previous one but is
queued after it instead, overwriting it when generating the graph. Thus, a large
number of resource rebindings may even impact processing times (very difficult
to observe but theoretically possible).
Rebinding resources and also combining it with changes to tasks has far more
implications instead.<br/>
As mentioned, graph generation takes place starting from resources and not from
tasks. Therefore, the result may not be as expected:
```cpp
builder
.bind("task_1"_hs)
.ro("resource"_hs)
.bind("task_2"_hs)
.ro("resource"_hs)
.bind("task_1"_hs)
.rw("resource"_hs);
```
What happens here is that the resource first _sees_ a read-only access request
from the first task, then a read-write request from the second task and finally
a new read-only request from the first task.<br/>
Although this definition would probably be counted as an error, the resulting
graph may be unexpected. This in fact consists of a single edge outgoing from
the second task and directed to the first task.<br/>
To intuitively understand what happens, it's enough to think of the fact that a
task never has an edge pointing to itself.
While not obvious, this approach has its pros and cons like any other solution.
For example, creating loops is actually simple in the context of resource-based
graph generations:
```cpp
builder
.bind("task_1"_hs)
.rw("resource"_hs)
.bind("task_2"_hs)
.rw("resource"_hs)
.bind("task_1"_hs)
.rw("resource"_hs);
```
As expected, this definition leads to the creation of two edges that define a
loop between the two tasks.
As a general rule, rebinding resources and tasks is highly discouraged because
it could lead to subtle bugs if users don't know what they're doing.<br/>
However, once the mechanisms of resource-based graph generation are understood,
it can offer to the expert user a flexibility and a range of possibilities
otherwise inaccessible.
## Fake resources and order of execution
The flow builder doesn't offer the ability to specify when a task should execute
before or after another task.<br/>
In fact, the order of _registration_ on the resources also determines the order
in which the tasks are processed during the generation of the execution graph.
However, there is a way to _force_ the execution order of two processes.<br/>
Briefly, since accessing a resource in opposite modes requires sequential rather
than parallel scheduling, it's possible to make use of fake resources to rule on
the execution order:
```cpp
builder
.bind("task_1"_hs)
.ro("resource_1"_hs)
.rw("fake"_hs)
.bind("task_2"_hs)
.ro("resource_2"_hs)
.ro("fake"_hs)
.bind("task_3"_hs)
.ro("resource_2"_hs)
.ro("fake"_hs)
```
This snippet forces the execution of `task_1` **before** `task_2` and `task_3`.
This is due to the fact that the former sets a read-write requirement on a fake
resource that the other tasks also want to access in read-only mode.<br/>
Similarly, it's possible to force a task to run **after** a certain group:
```cpp
builder
.bind("task_1"_hs)
.ro("resource_1"_hs)
.ro("fake"_hs)
.bind("task_2"_hs)
.ro("resource_1"_hs)
.ro("fake"_hs)
.bind("task_3"_hs)
.ro("resource_2"_hs)
.rw("fake"_hs)
```
In this case, since there are a number of processes that want to read a specific
resource, they will do so in parallel by forcing `task_3` to run after all the
others tasks.
## Sync points
Sometimes it's useful to assign the role of _sync point_ to a node.<br/>
Whether it accesses new resources or is simply a watershed, the procedure for
assigning this role to a vertex is always the same. First it's tied to the flow
builder, then the `sync` function is invoked:
```cpp
builder.bind("sync_point"_hs).sync();
```
The choice to assign an _identity_ to this type of nodes lies in the fact that,
more often than not, they also perform operations on resources.<br/>
If this isn't the case, it will still be possible to create no-op vertices to
which empty tasks are assigned.
## Execution graph
Once both the resources and their consumers have been properly registered, the
purpose of this tool is to generate an execution graph that takes into account
all specified constraints to return the best scheduling for the vertices:
```cpp
entt::adjacency_matrix<entt::directed_tag> graph = builder.graph();
```
Searching for the main vertices (that is, those without in-edges) is usually the
first thing required:
```cpp
for(auto &&vertex: graph) {
if(auto in_edges = graph.in_edges(vertex); in_edges.begin() == in_edges.end()) {
// ...
}
}
```
Then it's possible to instantiate an execution graph by means of other functions
such as `out_edges` to retrieve the children of a given task or `edges` to get
the identifiers.

View File

@@ -19,14 +19,12 @@
general and on GNU/Linux when default visibility was set to hidden. The
limitation was mainly due to a custom utility used to assign unique, sequential
identifiers with different types.<br/>
Fortunately, nowadays using `EnTT` across boundaries is much easier.
Fortunately, nowadays `EnTT` works smoothly across boundaries.
## Smooth until proven otherwise
Many classes in `EnTT` make extensive use of type erasure for their purposes.
This isn't a problem on itself (in fact, it's the basis of an API so convenient
to use). However, a way is needed to recognize the objects whose type has been
erased on the other side of a boundary.<br/>
This raises the need to identify objects whose type has been erased.<br/>
The `type_hash` class template is how identifiers are generated and thus made
available to the rest of the library. In general, this class doesn't arouse much
interest. The only exception is when a conflict between identifiers occurs
@@ -36,13 +34,13 @@ The section dedicated to `type_info` contains all the details to get around the
issue in a concise and elegant way. Please refer to the specific documentation.
When working with linked libraries, compile definitions `ENTT_API_EXPORT` and
`ENTT_API_IMPORT` can be used where there is a need to import or export symbols,
so as to make everything work nicely across boundaries.<br/>
`ENTT_API_IMPORT` are to import or export symbols, so as to make everything work
nicely across boundaries.<br/>
On the other hand, everything should run smoothly when working with plugins or
shared libraries that don't export any symbols.
For anyone who needs more details, the test suite contains multiple examples
covering the most common cases (see the `lib` directory for all details).<br/>
For those who need more details, the test suite contains many examples covering
the most common cases (see the `lib` directory for all details).<br/>
It goes without saying that it's impossible to cover **all** possible cases.
However, what is offered should hopefully serve as a basis for all of them.
@@ -50,40 +48,29 @@ However, what is offered should hopefully serve as a basis for all of them.
The runtime reflection system deserves a special mention when it comes to using
it across boundaries.<br/>
Since it's linked already to a static context to which the visible components
are attached and different contexts don't relate to each other, they must be
_shared_ to allow the use of meta types across boundaries.
Since it's linked already to a static context to which the elements are attached
and different contexts don't relate to each other, they must be _shared_ to
allow the use of meta types across boundaries.
Sharing a context is trivial though. First of all, the local one must be
acquired in the main space:
Fortunately, sharing a context is also trivial to do. First of all, the local
one is acquired in the main space:
```cpp
entt::meta_ctx ctx{};
auto handle = entt::locator<entt::meta_ctx>::handle();
```
Then, it must passed to the receiving space that will set it as its global
context, thus releasing the local one that remains available but is no longer
referred to by the runtime reflection system:
Then, it's passed to the receiving space that sets it as its default context,
thus discarding or storing aside the local one:
```cpp
entt::meta_ctx::bind(ctx);
entt::locator<entt::meta_ctx>::reset(handle);
```
From now on, both spaces will refer to the same context and on it will be
attached the new visible meta types, no matter where they are created.<br/>
A context can also be reset and then associated again locally as:
```cpp
entt::meta_ctx::bind(entt::meta_ctx{});
```
This is allowed because local and global contexts are separated. Therefore, it's
always possible to make the local context the current one again.
Before to release a context, all locally registered types should be reset to
avoid dangling references. Otherwise, if a type is accessed from another space
by name, there could be an attempt to address its parts that are no longer
available.
From now on, both spaces refer to the same context and on it are attached all
new meta types, no matter where they are created.<br/>
Note that _replacing_ the main context doesn't also propagate changes across
boundaries. In other words, replacing a context results in the decoupling of the
two sides and therefore a divergence in the contents.
## Memory Management

View File

@@ -1,5 +1,22 @@
# EnTT in Action
<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents
* [Introduction](#introduction)
* [EnTT in Action](#entt-in-action)
* [Games](#games)
* [Engines and the like](#engines-and-the-like)
* [Articles, videos and blog posts](#articles-videos-and-blog-posts)
* [Any Other Business](#any-other-business)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
`EnTT` is widely used in private and commercial applications. I cannot even
mention most of them because of some signatures I put on some documents time
ago. Fortunately, there are also people who took the time to implement open
@@ -7,25 +24,43 @@ source projects based on `EnTT` and didn't hold back when it came to documenting
them.
Below an incomplete list of games, applications and articles that can be used as
a reference. Where I put the word _apparently_ means that the use of `EnTT` is
documented but the authors didn't make explicit announcements or contacted me
directly.
a reference.<br/>
Where I put the word _apparently_ means that the use of `EnTT` is documented but
the authors didn't make explicit announcements or contacted me directly.
I hope this list can grow much more in the future:
If you know of other resources out there that are about `EnTT`, feel free to
open an issue or a PR and I'll be glad to add them to this page.<br/>
I hope the following lists can grow much more in the future.
# EnTT in Action
## Games
* Games:
* [Minecraft](https://minecraft.net/en-us/attribution/) by
[Mojang](https://mojang.com/): of course, **that** Minecraft, see the
open source attributions page for more details.
* [Minecraft 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.
* [Ember Sword](https://embersword.com/): a modern Free-to-Play MMORPG with a
player-driven economy, a classless combat system, and scarce, tradable
cosmetic collectibles.
* Apparently [Diablo II: Resurrected](https://diablo2.blizzard.com/) by
[Blizzard](https://www.blizzard.com/): monsters, heroes, items, spells, all
resurrected. Thanks unknown insider.
* [Apparently](https://www.youtube.com/watch?v=P8xvOA3ikrQ&t=1105s)
[Call of Duty: Vanguard](https://www.callofduty.com/vanguard) by
[Sledgehammer Games](https://www.sledgehammergames.com/): I can neither
confirm nor deny but there is a license I know in the credits.
* Apparently [D&D Dark Alliance](https://darkalliance.wizards.com) by
[Wizards of the Coast](https://company.wizards.com): your party, their
funeral.
* [TiltedOnline](https://github.com/tiltedphoques/TiltedOnline) by
[Tilted Phoques](https://github.com/tiltedphoques): Skyrim and Fallout 4 mod
to play online.
* [Apparently](https://www.youtube.com/watch?v=P8xvOA3ikrQ&t=1105s)
[Call of Duty: Vanguard](https://www.callofduty.com/vanguard): I can neither
confirm nor deny but there is a license I know in the credits.
* [Antkeeper](https://github.com/antkeeper/antkeeper-source): an ant colony
simulation [game](https://antkeeper.com/).
* [Openblack](https://github.com/openblack/openblack): open source
@@ -44,7 +79,7 @@ I hope this list can grow much more in the future:
puzzler with logic gates and other cool stuff.
[Check it out](https://indi-kernick.itch.io/the-machine-web-version).
* [EnTTPong](https://github.com/DomRe/EnttPong): a basic game made to showcase
different parts of EnTT and C++17.
different parts of `EnTT` and C++17.
* [Randballs](https://github.com/gale93/randballs): simple `SFML` and `EnTT`
playground.
* [EnTT Tower Defense](https://github.com/Daivuk/tddod): a data oriented tower
@@ -80,8 +115,31 @@ I hope this list can grow much more in the future:
space ship through a large 2D open world.
* [PokeMaster](https://github.com/utilForever/PokeMaster): Pokemon Battle
simulator using C++ with some reinforcement learning.
* [HomeHearth](https://youtu.be/GrEWl8npL9Y): choose your hero, protect the
town, before it's too late.
* [City Builder Game](https://github.com/PhiGei2000/CityBuilderGame): a simple
city-building game using C++ and OpenGL.
* [BattleSub](https://github.com/bfeldpw/battlesub): two player 2D submarine
game with some fluid dynamics.
* [Crimson Rush](https://github.com/WilKam01/LuaCGame): a dungeon-crawler and
rougelike inspired game about exploring and surviving as long as possible.
* [Space Fight](https://github.com/cholushkin/SpaceFight): one screen
multi-player arcade shooter game prototype.
* [Confetti Party](https://github.com/hexerei/entt-confetti): C++ sample
application as a starting point using `EnTT` and `SDL2`.
* [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:
* Engines and the like:
* [Aether Engine](https://hadean.com/spatial-simulation/)
[v1.1+](https://docs.hadean.com/v1.1/Licenses/) by
[Hadean](https://hadean.com/): a library designed for spatially partitioning
@@ -135,13 +193,37 @@ I hope this list can grow much more in the future:
oriented game engine.
* [Becketron](https://github.com/Doctor-Foxling/Becketron): a game engine
written mostly in C++.
* [Spatial Engine](https://github.com/luizgabriel/Spatial.Engine): A
* [Spatial Engine](https://github.com/luizgabriel/Spatial.Engine): a
cross-platform engine created on top of google's filament rendering engine.
* [Kaguya](https://github.com/KaiH0717/Kaguya): D3D12 Rendering Engine.
* [OpenAWE](https://github.com/OpenAWE-Project/OpenAWE): Open implementation
* [OpenAWE](https://github.com/OpenAWE-Project/OpenAWE): open implementation
of the Alan Wake Engine.
* [Nazara Engine](https://github.com/DigitalPulseSoftware/NazaraEngine): fast,
cross-platform, object-oriented API to help in daily developer life.
* [Billy Engine](https://github.com/billy4479/BillyEngine): some kind of a 2D
engine based on `SDL2` and `EnTT`.
* [Ducktape](https://github.com/DucktapeEngine/Ducktape): an open source C++
2D & 3D game engine that focuses on being fast and powerful.
* [The Worst Engine](https://github.com/Parasik72/TWE): a game engine based on
OpenGL.
* [Ecsact](https://ecsact.dev/): a language aimed at describing ECS, with a
[runtime implementation](https://github.com/ecsact-dev/ecsact_rt_entt) based
on `EnTT`.
* [AGE (Arc Game Engine)](https://github.com/MohitSethi99/ArcGameEngine): an
open-source engine for building 2D & 3D real-time rendering and interactive
contents.
* [Kengine](https://github.com/phisko/kengine): the _Koala engine_ is a game
engine entirely implemented as an entity-component-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:
* Articles, videos and blog posts:
* [Some posts](https://skypjack.github.io/tags/#entt) on my personal
[blog](https://skypjack.github.io/) are about `EnTT`, for those who want to
know **more** on this project.
@@ -165,6 +247,23 @@ I hope this list 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.
* [Use EnTT When You Need An ECS](https://www.codingwiththomas.com/blog/use-entt-when-you-need-an-ecs)
by [Thomas](https://www.codingwiththomas.com/): I couldn't have said it
better.
* [Space Battle: Huge edition](http://victor.madtriangles.com/code%20experiment/2018/06/11/post-ecs-battle-huge.html):
huge space battle built entirely from scratch.
* [Space Battle](https://github.com/vblanco20-1/ECS_SpaceBattle): huge space
@@ -187,8 +286,12 @@ I hope this list can grow much more in the future:
project retrospect by [Eric Hildebrand](https://www.erichildebrand.net/).
* [EnTT Entity Component System Gaming Library](https://gamefromscratch.com/entt-entity-component-system-gaming-library/):
`EnTT` on GameFromScratch.com.
* [Custom C++ server for UE5](https://youtu.be/fbXZVNCOvjM) optimized for
MMO(RPG)s and its [follow-up](https://youtu.be/yGlZeopx2hU) episode about
player bots and full external ECS: a series definitely worth looking at.
## Any Other Business:
* Any Other Business:
* [ArcGIS Runtime SDKs](https://developers.arcgis.com/arcgis-runtime/) by
[Esri](https://www.esri.com/): they use `EnTT` for the internal ECS and the
cross platform C++ rendering engine. The SDKs are utilized by a lot of
@@ -230,6 +333,3 @@ I hope this list can grow much more in the future:
* GitHub contains also
[many other examples](https://github.com/search?o=desc&q=%22skypjack%2Fentt%22&s=indexed&type=Code)
of use of `EnTT` from which to take inspiration if interested.
If you know of other resources out there that are about `EnTT`, feel free to
open an issue or a PR and I'll be glad to add them to this page.

View File

@@ -7,69 +7,82 @@
* [Introduction](#introduction)
* [Service locator](#service-locator)
* [Opaque handles](#opaque-handles)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
Usually service locators are tightly bound to the services they expose and it's
hard to define a general purpose solution. This template based implementation
tries to fill the gap and to get rid of the burden of defining a different
specific locator for each application.<br/>
This class is tiny, partially unsafe and thus risky to use. Moreover it doesn't
fit probably most of the scenarios in which a service locator is required. Look
at it as a small tool that can sometimes be useful if users know how to handle
it.
Usually, service locators are tightly bound to the services they expose and it's
hard to define a general purpose solution.<br/>
This tiny class tries to fill the gap and gets rid of the burden of defining a
different specific locator for each application.
# Service locator
The API is straightforward. The basic idea is that services are implemented by
means of interfaces and rely on polymorphism.<br/>
The locator is instantiated with the base type of the service if any and a
concrete implementation is provided along with all the parameters required to
initialize it. As an example:
The service locator API tries to mimic that of `std::optional` and adds some
extra functionalities on top of it such as allocator support.<br/>
There are a couple of functions to set up a service, namely `emplace` and
`allocate_emplace`:
```cpp
// the service has no base type, a locator is used to treat it as a kind of singleton
entt::service_locator<my_service>::set(params...);
// sets up an opaque service
entt::service_locator<audio_interface>::set<audio_implementation>(params...);
// resets (destroys) the service
entt::service_locator<audio_interface>::reset();
entt::locator<interface>::emplace<service>(argument);
entt::locator<interface>::allocate_emplace<service>(allocator, argument);
```
The locator can also be queried to know if an active service is currently set
and to retrieve it if necessary (either as a pointer or as a reference):
The difference is that the latter expects an allocator as the first argument and
uses it to allocate the service itself.<br/>
Once a service is set up, it's retrieved using the `value` function:
```cpp
// no service currently set
auto empty = entt::service_locator<audio_interface>::empty();
// gets a (possibly empty) shared pointer to the service ...
std::shared_ptr<audio_interface> ptr = entt::service_locator<audio_interface>::get();
// ... or a reference, but it's undefined behaviour if the service isn't set yet
audio_interface &ref = entt::service_locator<audio_interface>::ref();
interface &service = entt::locator<interface>::value();
```
A common use is to wrap the different locators in a container class, creating
aliases for the various services:
Since the service may not be set (and therefore this function may result in an
undefined behavior), the `has_value` and `value_or` functions are also available
to test a service locator and to get a fallback service in case there is none:
```cpp
struct locator {
using camera = entt::service_locator<camera_interface>;
using audio = entt::service_locator<audio_interface>;
// ...
};
// ...
void init() {
locator::camera::set<camera_null>();
locator::audio::set<audio_implementation>(params...);
if(entt::locator<interface>::has_value()) {
// ...
}
interface &service = entt::locator<interface>::value_or<fallback_impl>(argument);
```
All arguments are used only if necessary, that is, if a service doesn't already
exist and therefore the fallback service is constructed and returned. In all
other cases, they are discarded.<br/>
Finally, to reset a service, use the `reset` function.
## Opaque handles
Sometimes it's useful to _transfer_ a copy of a service to another locator. For
example, when working across boundaries it's common to _share_ a service with a
dynamically loaded module.<br/>
Options aren't much in this case. Among these is the possibility of _exporting_
services and assigning them to a different locator.
This is what the `handle` and `reset` functions are meant for.<br/>
The former returns an opaque object useful for _exporting_ (or rather, obtaining
a reference to) a service. The latter also accepts an optional argument to a
handle which then allows users to reset a service by initializing it with an
opaque handle:
```cpp
auto handle = entt::locator<interface>::handle();
entt::locator<interface>::reset(handle);
```
It's worth noting that it's possible to get handles for uninitialized services
and use them with other locators. Of course, all a user will get is to have an
uninitialized service elsewhere as well.
Note that exporting a service allows users to _share_ the object currently set
in a locator. Replacing it won't replace the element even where a service has
been configured with a handle to the previous item.<br/>
In other words, if an audio service is replaced with a null object to silence an
application and the original service was shared, this operation won't propagate
to the other locators. Therefore, a module that share the ownership of the
original audio service is still able to emit sounds.

View File

@@ -15,10 +15,12 @@
* [Template information](#template-information)
* [Automatic conversions](#automatic-conversions)
* [Implicitly generated default constructor](#implicitly-generated-default-constructor)
* [From void to any](#from-void-to-any)
* [Policies: the more, the less](#policies-the-more-the-less)
* [Named constants and enums](#named-constants-and-enums)
* [Properties and meta objects](#properties-and-meta-objects)
* [Unregister types](#unregister-types)
* [Meta context](#meta-context)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@@ -26,7 +28,7 @@
# Introduction
Reflection (or rather, its lack) is a trending topic in the C++ world and a tool
that can unlock a lot of interesting feature in the specific case of `EnTT`. I
that can unlock a lot of interesting features in the specific case of `EnTT`. I
looked for a third-party library that met my needs on the subject, but I always
came across some details that I didn't like: macros, being intrusive, too many
allocations, and so on.<br/>
@@ -42,22 +44,22 @@ when it comes to working with names and identifiers. It does this by offering an
API that works with opaque identifiers that may or may not be generated by means
of a hashed string.<br/>
This means that users can assign any type of identifier to the meta objects, as
long as they are numeric. It doesn't matter if they are generated at runtime, at
long as they're numeric. It doesn't matter if they're generated at runtime, at
compile-time or with custom functions.
That being said, the examples in the following sections are all based on the
`hashed_string` class as provided by this library. Therefore, where an
identifier is required, it's likely that an user defined literal is used as
identifier is required, it's likely that a user defined literal is used as
follows:
```cpp
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
```
For what it's worth, this is likely completely equivalent to:
For what it's worth, this is completely equivalent to:
```cpp
auto factory = entt::meta<my_type>().type(42);
auto factory = entt::meta<my_type>().type(42u);
```
Obviously, human-readable identifiers are more convenient to use and highly
@@ -65,69 +67,61 @@ recommended.
# Reflection in a nutshell
Reflection always starts from real types (users cannot reflect imaginary types
and it would not make much sense, we wouldn't be talking about reflection
anymore).<br/>
To create a meta node, the library provides the `meta` function that accepts a
type to reflect as a template parameter:
Reflection always starts from actual C++ types. Users cannot reflect _imaginary_
types.<br/>
The `meta` function is where it all starts:
```cpp
auto factory = entt::meta<my_type>();
```
This isn't enough to _export_ the given type and make it visible though.<br/>
The returned value is a factory object to use to continue building the meta
type. In order to make the type _visible_, users can assign it an identifier:
The returned value is a _factory object_ to use to continue building the meta
type.
By default, a meta type is associated with the identifier returned by the
runtime type identification system built-in in `EnTT`.<br/>
However, it's also possible to assign custom identifiers to meta types:
```cpp
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
```
Or use the default one, that is, the built-in identifier for the given type:
Identifiers are used to _retrieve_ meta types at runtime by _name_ other than by
type.<br/>
However, users can be interested in adding features to a reflected type so that
the reflection system can use it correctly under the hood, while they don't want
to also make the type _searchable_. In this case, it's sufficient not to invoke
`type`.
```cpp
auto factory = entt::meta<my_type>().type();
```
A factory is such that all its member functions return the factory itself. It's
generally used to create the following:
Identifiers are important because users can retrieve meta types at runtime by
searching for them by _name_ other than by type.<br/>
On the other hand, there are cases in which users can be interested in adding
features to a reflected type so that the reflection system can use it correctly
under the hood, but they don't want to also make the type _searchable_. In this
case, it's sufficient not to invoke `type`.
A factory is such that all its member functions return the factory itself or a
decorated version of it. This object can be used to add the following:
* _Constructors_. Actual constructors can be assigned to a reflected type by
specifying their list of arguments. Free functions (namely, factories) can be
used as well, as long as the return type is the expected one. From a client's
point of view, nothing changes if a constructor is a free function or an
actual constructor.<br/>
Use the `ctor` member function for this purpose:
* _Constructors_. A constructors is assigned to a reflected type by specifying
its _list of arguments_. Free functions are also accepted if the return type
is the expected one. From a client perspective, nothing changes between a free
function or an actual constructor:
```cpp
entt::meta<my_type>().ctor<int, char>().ctor<&factory>();
```
* _Destructors_. Free functions and member functions can be used as destructors
of reflected types. The purpose is to give users the ability to free up
resources that require special treatment before an object is actually
destroyed.<br/>
Use the `dtor` member function for this purpose:
Meta default constructors are implicitly generated, if possible.
* _Destructors_. Both free functions and member functions are valid destructors:
```cpp
entt::meta<my_type>().dtor<&destroy>();
```
The purpose is to offer the possibility to free up resources that require
_special treatment_ before an object is actually destroyed.<br/>
A function should neither delete nor explicitly invoke the destructor of a
given instance.
* _Data members_. Both real data members of the underlying type and static and
global variables, as well as constants of any kind, can be attached to a meta
type. From the point of view of the client, all the variables associated with
the reflected type will appear as if they were part of the type itself.<br/>
Use the `data` member function for this purpose:
* _Data members_. Meta data members are actual data members of the underlying
type but also static and global variables or constants of any kind. From the
point of view of the client, all the variables associated with the reflected
type appear as if they were part of the type itself:
```cpp
entt::meta<my_type>()
@@ -136,13 +130,11 @@ decorated version of it. This object can be used to add the following:
.data<&global_variable>("global"_hs);
```
The function requires as an argument the identifier to give to the meta data
once created. Users can then access meta data at runtime by searching for them
by _name_.<br/>
Data members can also be defined by means of a setter and getter pair. Setters
and getters can be either free functions, class members or a mix of them, as
long as they respect the required signatures. This approach is also convenient
to create a read-only variable from a non-const data member:
The `data` function requires the identifier to use for the meta data member.
Users can then access it by _name_ at runtime.<br/>
Data members are also defined by means of a setter and getter pair. These are
either free functions, class members or a mix of them. This approach is also
convenient to create read-only properties from a non-const data member:
```cpp
entt::meta<my_type>().data<nullptr, &my_type::data_member>("member"_hs);
@@ -154,13 +146,10 @@ decorated version of it. This object can be used to add the following:
entt::meta<my_type>().data<entt::value_list<&from_int, &from_string>, &my_type::data_member>("member"_hs);
```
Refer to the inline documentation for all the details.
* _Member functions_. Both real member functions of the underlying type and free
functions can be attached to a meta type. From the point of view of the
client, all the functions associated with the reflected type will appear as if
they were part of the type itself.<br/>
Use the `func` member function for this purpose:
* _Member functions_. Meta member functions are actual member functions of the
underlying type but also plain free functions. From the point of view of the
client, all the functions associated with the reflected type appear as if they
were part of the type itself:
```cpp
entt::meta<my_type>()
@@ -169,40 +158,31 @@ decorated version of it. This object can be used to add the following:
.func<&free_function>("free"_hs);
```
The function requires as an argument the identifier to give to the meta
function once created. Users can then access meta functions at runtime by
searching for them by _name_.<br/>
The `func` function requires the identifier to use for the meta data function.
Users can then access it by _name_ at runtime.<br/>
Overloading of meta functions is supported. Overloaded functions are resolved
at runtime by the reflection system according to the types of the arguments.
* _Base classes_. A base class is such that the underlying type is actually
derived from it. In this case, the reflection system tracks the relationship
and allows for implicit casts at runtime when required.<br/>
Use the `base` member function for this purpose:
derived from it:
```cpp
entt::meta<derived_type>().base<base_type>();
```
From now on, wherever a `base_type` is required, an instance of `derived_type`
will also be accepted.
The reflection system tracks the relationship and allows for implicit casts at
runtime when required. In other terms, wherever a `base_type` is required, an
instance of `derived_type` is also accepted.
* _Conversion functions_. Actual types can be converted, this is a fact. Just
think of the relationship between a `double` and an `int` to see it. Similar
to bases, conversion functions allow users to define conversions that will be
implicitly performed by the reflection system when required.<br/>
Use the `conv` member function for this purpose:
* _Conversion functions_. Conversion functions allow users to define conversions
that are implicitly performed by the reflection system when required:
```cpp
entt::meta<double>().conv<int>();
```
That's all, everything users need to create meta types and enjoy the reflection
system. At first glance it may not seem that much, but users usually learn to
appreciate it over time.<br/>
Also, do not forget what these few lines hide under the hood: a built-in,
non-intrusive and macro-free system for reflection in C++. Features that are
definitely worth the price, at least for me.
This is everything users need to create meta types. Refer to the inline
documentation for further details.
## Any to the rescue
@@ -215,13 +195,13 @@ The API is very similar to that of the `any` type. The class `meta_any` _wraps_
many of the feature to infer a meta node, before forwarding some or all of the
arguments to the underlying storage.<br/>
Among the few relevant differences, `meta_any` adds support for containers and
pointer-like types (see the following sections for more details), while `any`
does not.<br/>
Similar to `any`, this class can also be used to create _aliases_ for unmanaged
pointer-like types, while `any` doesn't.<br/>
Similar to `any`, this class is also used to create _aliases_ for unmanaged
objects either with `forward_as_meta` or using the `std::in_place_type<T &>`
disambiguation tag, as well as from an existing object by means of the `as_ref`
member function. However, unlike `any`, `meta_any` treats an empty instance and
one initialized with `void` differently:
member function.<br/>
Unlike `any` instead, `meta_any` treats an empty instance and one initialized
with `void` differently:
```cpp
entt::meta_any empty{};
@@ -230,21 +210,19 @@ entt::meta_any other{std::in_place_type<void>};
While `any` considers both as empty, `meta_any` treats objects initialized with
`void` as if they were _valid_ ones. This allows to differentiate between failed
function calls and function calls that are successful but return nothing.<br/>
function calls and function calls that are successful but return nothing.
Finally, the member functions `try_cast`, `cast` and `allow_cast` are used to
cast the underlying object to a given type (either a reference or a value type)
or to _convert_ a `meta_any` in such a way that a cast becomes viable for the
resulting object. There is in fact no `any_cast` equivalent for `meta_any`.
resulting object.<br/>
There is in fact no `any_cast` equivalent for `meta_any`.
## Enjoy the runtime
Once the web of reflected types has been constructed, it's a matter of using it
at runtime where required.<br/>
All this has the great merit that the reflection system stands in fact as a
non-intrusive tool for the runtime, unlike the vast majority of the things
offered by this library and closely linked to the compile-time.
To search for a reflected type there are a few options:
Once the web of reflected types is constructed, it's a matter of using it at
runtime where required.<br/>
There are a few options to search for a reflected type:
```cpp
// direct access to a reflected type
@@ -257,25 +235,23 @@ auto by_id = entt::resolve("reflected_type"_hs);
auto by_type_id = entt::resolve(entt::type_id<my_type>());
```
There exits also an overload of the `resolve` function to use to iterate all the
reflected types at once. It returns an iterable object that can be used in a
range-for loop:
There exists also an overload of the `resolve` function to use to iterate all
reflected types at once. It returns an iterable object to be used in a range-for
loop:
```cpp
for(auto type: entt::resolve()) {
for(auto &&[id, type]: entt::resolve()) {
// ...
}
```
In all cases, the returned value is an instance of `meta_type`. This kind of
objects offer an API to know their _runtime identifiers_, to iterate all the
meta objects associated with them and even to build instances of the underlying
type.<br/>
Refer to the inline documentation for all the details.
In all cases, the returned value is an instance of `meta_type` (possibly with
its id). This kind of objects offer an API to know their _runtime identifiers_,
to iterate all the meta objects associated with them and even to build instances
of the underlying type.<br/>
Meta data members and functions are accessed by name:
The meta objects that compose a meta type are accessed in the following ways:
* _Meta data_. They are accessed by _name_:
* Meta data members:
```cpp
auto data = entt::resolve<my_type>().data("member"_hs);
@@ -287,7 +263,7 @@ The meta objects that compose a meta type are accessed in the following ways:
know if it's a const or a static one), to get the meta type of the variable
and to set or get the contained value.
* _Meta functions_. They are accessed by _name_:
* Meta function members:
```cpp
auto func = entt::resolve<my_type>().func("member"_hs);
@@ -298,20 +274,11 @@ The meta objects that compose a meta type are accessed in the following ways:
A meta function object offers an API to query the underlying type (for
example, to know if it's a const or a static function), to know the number of
arguments, the meta return type and the meta types of the parameters. In
addition, a meta function object can be used to invoke the underlying function
and then get the return value in the form of a `meta_any` object.
addition, a meta function object is used to invoke the underlying function and
then get the return value in the form of a `meta_any` object.
* _Meta bases_. They are accessed through the _name_ of the base types:
```cpp
auto base = entt::resolve<derived_type>().base("base"_hs);
```
The returned type is `meta_type` and may be invalid if there is no meta base
object associated with the given identifier.
All the objects thus obtained as well as the meta types can be explicitly
converted to a boolean value to check if they are valid:
All the meta objects thus obtained as well as the meta types explicitly convert
to a boolean value to check for validity:
```cpp
if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
@@ -319,35 +286,33 @@ if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
}
```
Furthermore, all them are also returned by specific overloads that provide the
caller with iterable ranges of top-level elements. As an example:
Furthermore, all them (and a few more, like meta basis) are returned by a bunch
of overloads that provide the caller with iterable ranges of top-level elements.
As an example:
```cpp
for(auto data: entt::resolve<my_type>().data()) {
for(auto &&[id, type]: entt::resolve<my_type>().base()) {
// ...
}
```
A meta type can be used to `construct` actual instances of the underlying
Meta type are also used to `construct` actual instances of the underlying
type.<br/>
In particular, the `construct` member function accepts a variable number of
arguments and searches for a match. It then returns a `meta_any` object that may
or may not be initialized, depending on whether a suitable constructor has been
found or not.
or may not be initialized, depending on whether a suitable constructor was found
or not.
There is no object that wraps the destructor of a meta type nor a `destroy`
member function in its API. Destructors are invoked implicitly by `meta_any`
behind the scenes and users have not to deal with them explicitly. Furthermore,
they have no name, cannot be searched and wouldn't have member functions to
expose anyway.<br/>
Similarly, conversion functions aren't directly accessible. They are used
they've no name, cannot be searched and wouldn't have member functions to expose
anyway.<br/>
Similarly, conversion functions aren't directly accessible. They're used
internally by `meta_any` and the meta objects when needed.
Meta types and meta objects in general contain much more than what is said: a
plethora of functions in addition to those listed whose purposes and uses go
unfortunately beyond the scope of this document.<br/>
I invite anyone interested in the subject to look at the code, experiment and
read the inline documentation to get the best out of this powerful tool.
Meta types and meta objects in general contain much more than what was said.
Refer to the inline documentation for further details.
## Container support
@@ -358,13 +323,15 @@ meta system in many cases.
To make a container be recognized as such by the meta system, users are required
to provide specializations for either the `meta_sequence_container_traits` class
or the `meta_associative_container_traits` class, according with the actual type
or the `meta_associative_container_traits` class, according to the actual _type_
of the container.<br/>
`EnTT` already exports the specializations for some common classes. In
particular:
* `std::vector` and `std::array` are exported as _sequence containers_.
* `std::map`, `std::set` and their unordered counterparts are exported as
* `std::vector`, `std::array`, `std::deque` and `std::list` (but not
`std::forward_list`) are supported as _sequence containers_.
* `std::map`, `std::set` and their unordered counterparts are supported as
_associative containers_.
It's important to include the header file `container.hpp` to make these
@@ -393,11 +360,10 @@ if(any.type().is_sequence_container()) {
The method to use to get a proxy object for associative containers is
`as_associative_container` instead.<br/>
It goes without saying that it's not necessary to perform a double check.
Instead, it's sufficient to query the meta type or verify that the proxy object
is valid. In fact, proxies are contextually convertible to bool to know if they
are valid. For example, invalid proxies are returned when the wrapped object
isn't a container.<br/>
It's not necessary to perform a double check actually. Instead, it's enough to
query the meta type or verify that the proxy object is valid. In fact, proxies
are contextually convertible to bool to check for validity. For example, invalid
proxies are returned when the wrapped object isn't a container.<br/>
In all cases, users aren't expected to _reflect_ containers explicitly. It's
sufficient to assign a container for which a specialization of the traits
classes exists to a `meta_any` object to be able to get its proxy object.
@@ -409,32 +375,22 @@ to case. In particular:
* The `value_type` member function returns the meta type of the elements.
* The `size` member function returns the number of elements in the container as
an unsigned integer value:
```cpp
const auto size = view.size();
```
an unsigned integer value.
* The `resize` member function allows to resize the wrapped container and
returns true in case of succes:
```cpp
const bool ok = view.resize(3u);
```
returns true in case of success.<br/>
For example, it's not possible to resize fixed size containers.
* The `clear` member function allows to clear the wrapped container and returns
true in case of success:
```cpp
const bool ok = view.clear();
```
true in case of success.<br/>
For example, it's not possible to clear fixed size containers.
* The `begin` and `end` member functions return opaque iterators that can be
used to iterate the container directly:
* 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:
```cpp
for(entt::meta_any element: view) {
@@ -448,7 +404,7 @@ to case. In particular:
All meta iterators are input iterators and don't offer an indirection operator
on purpose.
* The `insert` member function can be used to add elements to the container. It
* The `insert` member function is used to add elements to the container. It
accepts a meta iterator and the element to insert:
```cpp
@@ -458,15 +414,15 @@ to case. In particular:
```
This function returns a meta iterator pointing to the inserted element and a
boolean value to indicate whether the operation was successful or not. Note
that a call to `insert` may silently fail in case of fixed size containers or
whether the arguments aren't at least convertible to the required types.<br/>
Since the meta iterators are contextually convertible to bool, users can rely
on them to know if the operation has failed on the actual container or
upstream, for example for an argument conversion problem.
boolean value to indicate whether the operation was successful or not. A call
to `insert` may silently fail in case of fixed size containers or whether the
arguments aren't at least convertible to the required types.<br/>
Since meta iterators are contextually convertible to bool, users can rely on
them to know if the operation failed on the actual container or upstream, for
example due to an argument conversion problem.
* The `erase` member function can be used to remove elements from the container.
It accepts a meta iterator to the element to remove:
* The `erase` member function is used to remove elements from the container. It
accepts a meta iterator to the element to remove:
```cpp
auto first = view.begin();
@@ -475,11 +431,11 @@ to case. In particular:
```
This function returns a meta iterator following the last removed element and a
boolean value to indicate whether the operation was successful or not. Note
that a call to `erase` may silently fail in case of fixed size containers.
boolean value to indicate whether the operation was successful or not. A call
to `erase` may silently fail in case of fixed size containers.
* The `operator[]` can be used to access elements in a container. It accepts a
single argument, that is the position of the element to return:
* The `operator[]` is used to access container elements. It accepts a single
argument, the position of the element to return:
```cpp
for(std::size_t pos{}, last = view.size(); pos < last; ++pos) {
@@ -489,8 +445,12 @@ to case. In particular:
```
The function returns instances of `meta_any` that directly refer to the actual
elements. Modifying the returned object will then directly modify the element
inside the container.
elements. Modifying the returned object directly modifies the element inside
the container.<br/>
Depending on the underlying sequence container, this operation may not be as
efficient. For example, in the case of an `std::list`, a positional access
translates to a linear visit of the list itself (probably not what the user
expects).
Similarly, also the interface of the `meta_associative_container` proxy object
is the same for all types of associative containers. However, there are some
@@ -511,21 +471,17 @@ differences in behavior in the case of key-only containers. In particular:
`std::map<int, char>`.
* The `size` member function returns the number of elements in the container as
an unsigned integer value:
```cpp
const auto size = view.size();
```
an unsigned integer value.
* The `clear` member function allows to clear the wrapped container and returns
true in case of success:
true in case of success.
```cpp
const bool ok = view.clear();
```
* 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 can be
used to iterate the container directly:
* The `begin` and `end` member functions return opaque iterators that are used
to iterate the container directly:
```cpp
for(std::pair<entt::meta_any, entt::meta_any> element: view) {
@@ -542,11 +498,11 @@ differences in behavior in the case of key-only containers. In particular:
While the accessed key is usually constant in the associative containers and
is therefore returned by copy, the value (if any) is wrapped by an instance of
`meta_any` that directly refers to the actual element. Modifying it will then
directly modify the element inside the container.
`meta_any` that directly refers to the actual element. Modifying it directly
modifies the element inside the container.
* The `insert` member function can be used to add elements to the container. It
accepts two arguments, respectively the key and the value to be inserted:
* The `insert` member function is used to add elements to a container. It gets
two arguments, respectively the key and the value to insert:
```cpp
auto last = view.end();
@@ -555,39 +511,39 @@ differences in behavior in the case of key-only containers. In particular:
```
This function returns a boolean value to indicate whether the operation was
successful or not. Note that a call to `insert` may fail when the arguments
aren't at least convertible to the required types.
successful or not. A call to `insert` may fail when the arguments aren't at
least convertible to the required types.
* The `erase` member function can be used to remove elements from the container.
It accepts a single argument, that is the key to be removed:
* The `erase` member function is used to remove elements from a container. It
gets a single argument, the key to remove:
```cpp
view.erase(42);
```
This function returns a boolean value to indicate whether the operation was
successful or not. Note that a call to `erase` may fail when the argument
isn't at least convertible to the required type.
successful or not. A call to `erase` may fail when the argument isn't at least
convertible to the required type.
* The `operator[]` can be used to access elements in a container. It accepts a
single argument, that is the key of the element to return:
* The `operator[]` is used to access elements in a container. It gets a single
argument, the key of the element to return:
```cpp
entt::meta_any value = view[42];
```
The function returns instances of `meta_any` that directly refer to the actual
elements. Modifying the returned object will then directly modify the element
inside the container.
elements. Modifying the returned object directly modifies the element inside
the container.
Container support is minimal but likely sufficient to satisfy all needs.
## Pointer-like types
As with containers, it's also possible to communicate to the meta system which
types to consider _pointers_. This will allow to dereference instances of
`meta_any`, thus obtaining light _references_ to the pointed objects that are
also correctly associated with their meta types.<br/>
As with containers, it's also possible to _tell_ to the meta system which types
are _pointers_. This makes it possible to dereference instances of `meta_any`,
thus obtaining light _references_ to pointed objects that are also correctly
associated with their meta types.<br/>
To make the meta system recognize a type as _pointer-like_, users can specialize
the `is_meta_pointer_like` class. `EnTT` already exports the specializations for
some common classes. In particular:
@@ -617,13 +573,12 @@ if(any.type().is_pointer_like()) {
}
```
Of course, it's not necessary to perform a double check. Instead, it's enough to
query the meta type or verify that the returned object is valid. For example,
invalid instances are returned when the wrapped object isn't a pointer-like
type.<br/>
Note that dereferencing a pointer-like object returns an instance of `meta_any`
which refers to the pointed object and allows users to modify it directly
(unless the returned element is const, of course).
It's not necessary to perform a double check. Instead, it's enough to query the
meta type or verify that the returned object is valid. For example, invalid
instances are returned when the wrapped object isn't a pointer-like type.<br/>
Dereferencing a pointer-like object returns an instance of `meta_any` which
_refers_ to the pointed object. Modifying it means modifying the pointed object
directly (unless the returned element is const).
In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However,
`EnTT` also supports classes that don't offer an `operator*`. In particular:
@@ -651,15 +606,15 @@ In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However,
};
```
In all other cases, that is, when dereferencing a pointer works as expected and
regardless of the pointed type, no user intervention is required.
In all other cases and when dereferencing a pointer works as expected regardless
of the pointed type, no user intervention is required.
## Template information
Meta types also provide a minimal set of information about the nature of the
Meta types also provide a minimal set of information about the _nature_ of the
original type in case it's a class template.<br/>
By default, this works out of the box and requires no user action. However, it's
important to include the header file `template.hpp` to make these information
important to include the header file `template.hpp` to make this information
available to the compiler when needed.
Meta template information are easily found:
@@ -691,9 +646,9 @@ template<typename Ret, typename... Args>
struct function_type<Ret(Args...)> {};
```
In this case, rather than the function type, the user might want the return type
and unpacked arguments as if they were different template parameters for the
original class template.<br/>
In this case, rather than the function type, it might be useful to provide the
return type and unpacked arguments as if they were different template parameters
for the original class template.<br/>
To achieve this, users must enter the library internals and provide their own
specialization for the class template `entt::meta_template_traits`, such as:
@@ -707,8 +662,8 @@ struct entt::meta_template_traits<function_type<Ret(Args...)>> {
The reflection system doesn't verify the accuracy of the information nor infer a
correspondence between real types and meta types.<br/>
Therefore, the specialization will be used as is and the information it contains
will be associated with the appropriate type when required.
Therefore, the specialization is used as is and the information it contains is
associated with the appropriate type when required.
## Automatic conversions
@@ -726,7 +681,7 @@ entt::meta<int>()
```
Repeated for each type eligible to undergo this type of conversions. This is
both error prone and repetitive.<br/>
both error-prone and repetitive.<br/>
Similarly, the language allows users to silently convert unscoped enums to their
underlying types and offers what it takes to do the same for scoped enums. It
would result in the following if it were to be done explicitly:
@@ -755,34 +710,51 @@ any.allow_cast(type);
int value = any.cast<int>();
```
This should make working with arithmetic types and scoped or unscoped enums as
easy as it is in C++.<br/>
It's also worth noting that it's still possible to set up conversion functions
manually and these will always be preferred over the automatic ones.
This makes working with arithmetic types and scoped or unscoped enums as easy as
it is in C++.<br/>
It's still possible to set up conversion functions manually and these are always
preferred over the automatic ones.
## Implicitly generated default constructor
In many cases, it's useful to be able to create objects of default constructible
types through the reflection system, while not having to explicitly register the
meta type or the default constructor.<br/>
Creating objects of default constructible types through the reflection system
while not having to explicitly register the meta type or its default constructor
is also possible.<br/>
For example, in the case of primitive types like `int` or `char`, but not just
them.
For this reason and only for default constructible types, default constructors
are automatically defined and associated with their meta types, whether they are
explicitly or implicitly generated.<br/>
For default constructible types only, default constructors are automatically
defined and associated with their meta types, whether they are explicitly or
implicitly generated.<br/>
Therefore, this is all is needed to construct an integer from its meta type:
```cpp
entt::resolve<int>().construct();
```
Where the meta type can be for example the one returned from a meta container,
Where the meta type is for example the one returned from a meta container,
useful for building keys without knowing or having to register the actual types.
In all cases, when users register default constructors, they are preferred both
during searches and when the `construct` member function is invoked.
## From void to any
Sometimes all a user has is an opaque pointer to an object of a known meta type.
It would be handy in this case to be able to construct a `meta_any` element from
it.<br/>
For this purpose, the `meta_type` class offers a `from_void` member function
designed to convert an opaque pointer into a `meta_any`:
```cpp
entt::meta_any any = entt::resolve(id).from_void(element);
```
Unfortunately, it's not possible to do a check on the actual type. Therefore,
this call can be considered as a _static cast_ with all its _problems_.<br/>
On the other hand, the ability to construct a `meta_any` from an opaque pointer
opens the door to some pretty interesting uses that are worth exploring.
## Policies: the more, the less
Policies are a kind of compile-time directives that can be used when registering
@@ -811,17 +783,17 @@ There are a few alternatives available at the moment:
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
```
If the use with functions is obvious, it must be said that it's also possible
to use this policy with constructors and data members. In the first case, the
constructor will be invoked but the returned wrapper will actually be empty.
In the second case, instead, the property will not be accessible for reading.
If the use with functions is obvious, perhaps less so is use with constructors
and data members. In the first case, the returned wrapper is always empty even
though the constructor is still invoked. In the second case, the property
isn't accessible for reading instead.
* The _as-ref_ and _as-cref_ policies, associated with the types
`entt::as_ref_t` and `entt::as_cref_t`.<br/>
They allow to build wrappers that act as references to unmanaged objects.
Accessing the object contained in the wrapper for which the _reference_ was
requested will make it possible to directly access the instance used to
initialize the wrapper itself:
requested makes it possible to directly access the instance used to initialize
the wrapper itself:
```cpp
entt::meta<my_type>().data<&my_type::data_member, entt::as_ref_t>("member"_hs);
@@ -839,21 +811,16 @@ obvious corner cases that can in turn be solved with the use of policies.
## Named constants and enums
A special mention should be made for constant values and enums. It wouldn't be
necessary, but it will help distracted readers.
As mentioned, the `data` member function can be used to reflect constants of any
type among the other things.<br/>
This allows users to create meta types for enums that will work exactly like any
other meta type built from a class. Similarly, arithmetic types can be enriched
As mentioned, the `data` member function is used to reflect constants of any
type.<br/>
This allows users to create meta types for enums that work exactly like any
other meta type built from a class. Similarly, arithmetic types are _enriched_
with constants of special meaning where required.<br/>
Personally, I find it very useful not to export what is the difference between
enums and classes in C++ directly in the space of the reflected types.
All values thus exported appear to users as if they were constant data members
of the reflected types. This avoids the need to _export_ what is the difference
between enums and classes in C++ directly in the space of the reflected types.
All the values thus exported will appear to users as if they were constant data
members of the reflected types.
Exporting constant values or elements from an enum is as simple as ever:
Exposing constant values or elements from an enum is quite simple:
```cpp
entt::meta<my_enum>()
@@ -863,68 +830,40 @@ entt::meta<my_enum>()
entt::meta<int>().data<2048>("max_int"_hs);
```
It goes without saying that accessing them is trivial as well. It's a matter of
doing the following, as with any other data member of a meta type:
Accessing them is trivial as well. It's a matter of doing the following, as with
any other data member of a meta type:
```cpp
auto value = entt::resolve<my_enum>().data("a_value"_hs).get({}).cast<my_enum>();
auto max = entt::resolve<int>().data("max_int"_hs).get({}).cast<int>();
```
As a side note, remember that all this happens behind the scenes without any
allocation because of the small object optimization performed by the `meta_any`
class.
All this happens behind the scenes without any allocation because of the small
object optimization performed by the `meta_any` class.
## Properties and meta objects
Sometimes (for example, when it comes to creating an editor) it might be useful
to attach properties to the meta objects created. Fortunately, this is possible
for most of them.<br/>
For the meta objects that support properties, the member functions of the
factory used for registering them will return a decorated version of the factory
itself. The latter can be used to attach properties to the last created meta
object.<br/>
Apparently, it's more difficult to say than to do:
for most of them:
```cpp
entt::meta<my_type>().type("reflected_type"_hs).prop("tooltip"_hs, "message");
```
Properties are always in the key/value form. There are no restrictions on the
type of the key or value, as long as they are copy constructible objects.<br/>
Multiple formats are supported when it comes to defining a property:
Properties are always in the key/value form. The key is a numeric identifier,
mostly similar to the identifier used to register meta objects. There are no
restrictions on the type of the value instead, as long as it's movable.<br/>
Key only properties are also supported out of the box:
* Properties as key/value pairs:
```cpp
entt::meta<my_type>().type("reflected_type"_hs).prop(my_enum::key_only);
```
```cpp
entt::meta<my_type>().type("reflected_type"_hs).prop("tooltip"_hs, "message");
```
* Properties as `std::pair`s:
```cpp
entt::meta<my_type>().type("reflected_type"_hs).prop(std::make_pair("tooltip"_hs, "message"));
```
* Key only properties:
```cpp
entt::meta<my_type>().type("reflected_type"_hs).prop(my_enum::key_only);
```
* Properties as `std::tuple`s:
```cpp
entt::meta<my_type>().type("reflected_type"_hs).prop(std::make_tuple(std::make_pair("tooltip"_hs, "message"), my_enum::key_only));
```
A tuple contains one or more properties. All of them are treated individually.
Note that it's not possible to invoke `prop` multiple times for the same meta
object and trying to do that will result in a compilation error.<br/>
However, the `props` function is available to associate several properties at
once. In this case, properties in the key/value form aren't allowed, since they
would be interpreted as two different properties rather than a single one.
To attach multiple properties to a meta object, just invoke `prop` more than
once.<br/>
It's also possible to call `prop` at different times, as long as the factory is
reset to the meta object of interest.
The meta objects for which properties are supported are currently meta types,
meta data and meta functions.<br/>
@@ -933,7 +872,7 @@ properties at once or to search a specific property by key:
```cpp
// iterate all properties of a meta type
for(auto prop: entt::resolve<my_type>().prop()) {
for(auto &&[id, prop]: entt::resolve<my_type>().prop()) {
// ...
}
@@ -942,37 +881,89 @@ auto prop = entt::resolve<my_type>().prop("tooltip"_hs);
```
Meta properties are objects having a fairly poor interface, all in all. They
only provide the `key` and the `value` member functions to be used to retrieve
the key and the value contained in the form of `meta_any` objects, respectively.
only provide the `value` member function to retrieve the contained value in the
form of a `meta_any` object.
## Unregister types
A type registered with the reflection system can also be unregistered. This
A type registered with the reflection system can also be _unregistered_. This
means unregistering all its data members, member functions, conversion functions
and so on. However, base classes aren't unregistered as well, since they don't
necessarily depend on it. Similarly, implicitly generated types (as an example,
the meta types implicitly generated for function parameters when needed) aren't
unregistered.<br/>
necessarily depend on it.<br/>
Roughly speaking, unregistering a type means disconnecting all associated meta
objects from it and making its identifier no longer visible. The underlying node
will remain available though, as if it were implicitly generated:
objects from it and making its identifier no longer available:
```cpp
entt::meta_reset<my_type>();
```
It's also possible to reset types by their unique identifiers if required:
It's also possible to reset types by their unique identifiers:
```cpp
entt::meta_reset("my_type"_hs);
```
Finally, there exists a non-template overload of the `meta_reset` function that
doesn't accept argument and resets all searchable types (that is, all types that
were assigned an unique identifier):
doesn't accept arguments and resets all meta types at once:
```cpp
entt::meta_reset();
```
All types can be re-registered later with a completely different name and form.
A type can be re-registered later with a completely different name and form.
## Meta context
All meta types and their parts are created at runtime and stored in a default
_context_. This is obtained via a service locator as:
```cpp
auto &&context = entt::locator<entt::meta_context>::value_or();
```
By itself, a context is an opaque object that the user cannot do much with.
However, users can replace an existing context with another at any time:
```cpp
entt::meta_context other{};
auto &&context = entt::locator<entt::meta_context>::value_or();
std::swap(context, other);
```
This is useful for testing purposes or to define multiple context objects with
different meta type to use as appropriate.
If _replacing_ the default context isn't enough, `EnTT` also offers the ability
to use multiple and externally managed contexts with the runtime reflection
system.<br/>
For example, to create new meta types within a context other than the default
one, simply pass it as an argument to the `meta` call:
```cpp
entt::meta_ctx context{};
auto factory = entt::meta<my_type>(context).type("reflected_type"_hs);
```
By doing so, the new meta type isn't available in the default context but is
usable by passing around the new context when needed, such as when creating a
new `meta_any` object:
```cpp
entt::meta_any any{context, std::in_place_type<my_type>};
```
Similarly, to search for meta types in a context other than the default one,
it's necessary to pass it to the `resolve` function:
```cpp
entt::meta_type type = entt::resolve(context, "reflected_type"_hs)
```
More generally, when using externally managed contexts, it's always required to
provide the system with the context to use, at least at the _entry point_.<br/>
For example, once the `meta_type` instant is obtained, it's no longer necessary
to pass the context around as the meta type takes the information with it and
eventually propagates it to all its parts.<br/>
On the other hand, it's necessary to instruct the library on where meta types
are to be fetched when `meta_any`s and `meta_handle`s are constructed, a factory
created or a meta type resolved.

View File

@@ -10,7 +10,7 @@
* [Concept and implementation](#concept-and-implementation)
* [Deduced interface](#deduced-interface)
* [Defined interface](#defined-interface)
* [Fullfill a concept](#fullfill-a-concept)
* [Fulfill a concept](#fulfill-a-concept)
* [Inheritance](#inheritance)
* [Static polymorphism in the wild](#static-polymorphism-in-the-wild)
* [Storage size and alignment requirement](#storage-size-and-alignment-requirement)
@@ -24,19 +24,18 @@ Static polymorphism is a very powerful tool in C++, albeit sometimes cumbersome
to obtain.<br/>
This module aims to make it simple and easy to use.
The library allows to define _concepts_ as interfaces to fullfill with concrete
classes withouth having to inherit from a common base.<br/>
This is, among others, one of the advantages of static polymorphism in general
The library allows to define _concepts_ as interfaces to fulfill with concrete
classes without having to inherit from a common base.<br/>
Among others, this is one of the advantages of static polymorphism in general
and of a generic wrapper like that offered by the `poly` class template in
particular.<br/>
What users get is an object that can be passed around as such and not through a
reference or a pointer, as happens when it comes to working with dynamic
polymorphism.
The result is an object to pass around as such and not through a reference or a
pointer, as it happens when it comes to working with dynamic polymorphism.
Since the `poly` class template makes use of `entt::any` internally, it also
supports most of its feature. Among the most important, the possibility to
create aliases to existing and thus unmanaged objects. This allows users to
exploit the static polymorphism while maintaining ownership of objects.<br/>
supports most of its feature. For example, the possibility to create aliases to
existing and thus unmanaged objects. This allows users to exploit the static
polymorphism while maintaining ownership of objects.<br/>
Likewise, the `poly` class template also benefits from the small buffer
optimization offered by the `entt::any` class and therefore minimizes the number
of allocations, avoiding them altogether where possible.
@@ -44,7 +43,7 @@ of allocations, avoiding them altogether where possible.
## Other libraries
There are some very interesting libraries regarding static polymorphism.<br/>
Among all, the two that I prefer are:
The ones that I like more are:
* [`dyno`](https://github.com/ldionne/dyno): runtime polymorphism done right.
* [`Poly`](https://github.com/facebook/folly/blob/master/folly/docs/Poly.md):
@@ -69,18 +68,18 @@ use the terminology introduced by Eric Niebler) is to define a _concept_ that
types will have to adhere to.<br/>
For this purpose, the library offers a single class that supports both deduced
and fully defined interfaces. Although having interfaces deduced automatically
is convenient and allows users to write less code in most cases, this has some
is convenient and allows users to write less code in most cases, it has some
limitations and it's therefore useful to be able to get around the deduction by
providing a custom definition for the static virtual table.
Once the interface is defined, it will be sufficient to provide a generic
implementation to fullfill the concept.<br/>
Once the interface is defined, a generic implementation is needed to fulfill the
concept itself.<br/>
Also in this case, the library allows customizations based on types or families
of types, so as to be able to go beyond the generic case where necessary.
## Deduced interface
This is how a concept with a deduced interface is introduced:
This is how a concept with a deduced interface is defined:
```cpp
struct Drawable: entt::type_list<> {
@@ -94,7 +93,7 @@ struct Drawable: entt::type_list<> {
```
It's recognizable by the fact that it inherits from an empty type list.<br/>
Functions can also be const, accept any number of paramters and return a type
Functions can also be const, accept any number of parameters and return a type
other than `void`:
```cpp
@@ -108,12 +107,12 @@ struct Drawable: entt::type_list<> {
};
```
In this case, all parameters must be passed to `invoke` after the reference to
In this case, all parameters are passed to `invoke` after the reference to
`this` and the return value is whatever the internal call returns.<br/>
As for `invoke`, this is a name that is injected into the _concept_ through
`Base`, from which one must necessarily inherit. Since it's also a dependent
name, the `this-> template` form is unfortunately necessary due to the rules of
the language. However, there exists also an alternative that goes through an
the language. However, there also exists an alternative that goes through an
external call:
```cpp
@@ -165,12 +164,12 @@ struct Drawable: entt::type_list<bool(int) const> {
Why should a user fully define a concept if the function types are the same as
the deduced ones?<br>
Because, in fact, this is exactly the limitation that can be worked around by
manually defining the static virtual table.
In fact, this is the limitation that can be worked around by manually defining
the static virtual table.
When things are deduced, there is an implicit constraint.<br/>
If the concept exposes a member function called `draw` with function type
`void()`, a concept can be satisfied:
`void()`, a concept is satisfied:
* Either by a class that exposes a member function with the same name and the
same signature.
@@ -179,7 +178,7 @@ If the concept exposes a member function called `draw` with function type
interface itself.
In other words, it's not possible to make use of functions not belonging to the
interface, even if they are present in the types that fulfill the concept.<br/>
interface, even if they're part of the types that fulfill the concept.<br/>
Similarly, it's not possible to deduce a function in the static virtual table
with a function type different from that of the associated member function in
the interface itself.
@@ -187,7 +186,7 @@ the interface itself.
Explicitly defining a static virtual table suppresses the deduction step and
allows maximum flexibility when providing the implementation for a concept.
## Fullfill a concept
## Fulfill a concept
The `impl` alias template of a concept is used to define how it's fulfilled:
@@ -200,9 +199,9 @@ struct Drawable: entt::type_list<> {
};
```
In this case, it's stated that the `draw` method of a generic type will be
enough to satisfy the requirements of the `Drawable` concept.<br/>
Both member functions and free functions are supported to fullfill concepts:
In this case, it's stated that the `draw` method of a generic type is enough to
satisfy the requirements of the `Drawable` concept.<br/>
Both member functions and free functions are supported to fulfill concepts:
```cpp
template<typename Type>
@@ -251,15 +250,15 @@ struct DrawableAndErasable: entt::type_list<> {
```
The static virtual table is empty and must remain so.<br/>
On the other hand, `type` no longer inherits from `Base` and instead forwards
On the other hand, `type` no longer inherits from `Base`. Instead, it forwards
its template parameter to the type exposed by the _base class_. Internally, the
size of the static virtual table of the base class is used as an offset for the
local indexes.<br/>
_size_ of the static virtual table of the base class is used as an offset for
the local indexes.<br/>
Finally, by means of the `value_list_cat_t` utility, the implementation consists
in appending the new functions to the previous list.
As for a defined concept instead, also the list of types must be extended, in a
similar way to what is shown for the implementation of the above concept.<br/>
As for a defined concept instead, the list of types is _extended_ in a similar
way to what is shown for the implementation of the above concept.<br/>
To do this, it's useful to declare a function that allows to convert a _concept_
into its underlying `type_list` object:
@@ -268,8 +267,8 @@ template<typename... Type>
entt::type_list<Type...> as_type_list(const entt::type_list<Type...> &);
```
The definition isn't strictly required, since the function will only be used
through a `decltype` as it follows:
The definition isn't strictly required, since the function is only used through
a `decltype` as it follows:
```cpp
struct DrawableAndErasable: entt::type_list_cat_t<
@@ -286,9 +285,8 @@ Everything else is the same as already shown instead.
# Static polymorphism in the wild
Once the _concept_ and implementation have been introduced, it will be possible
to use the `poly` class template to contain instances that meet the
requirements:
Once the _concept_ and implementation are defined, it's possible to use the
`poly` class template to _wrap_ instances that meet the requirements:
```cpp
using drawable = entt::poly<Drawable>;
@@ -310,9 +308,9 @@ instance = square{};
instance->draw();
```
The `poly` class template offers a wide range of constructors, from the default
one (which will return an uninitialized `poly` object) to the copy and move
constructors, as well as the ability to create objects in-place.<br/>
This class offers a wide range of constructors, from the default one (which
returns an uninitialized `poly` object) to the copy and move constructors, as
well as the ability to create objects in-place.<br/>
Among others, there is also a constructor that allows users to wrap unmanaged
objects in a `poly` instance (either const or non-const ones):
@@ -329,14 +327,14 @@ drawable other = instance.as_ref();
```
In both cases, although the interface of the `poly` object doesn't change, it
won't construct any element or take care of destroying the referenced objects.
doesn't construct any element or take care of destroying the referenced objects.
Note also how the underlying concept is accessed via a call to `operator->` and
not directly as `instance.draw()`.<br/>
This allows users to decouple the API of the wrapper from that of the concept.
Therefore, where `instance.data()` will invoke the `data` member function of the
poly object, `instance->data()` will map directly to the functionality exposed
by the underlying concept.
Therefore, where `instance.data()` invokes the `data` member function of the
poly object, `instance->data()` maps directly to the functionality exposed by
the underlying concept.
# Storage size and alignment requirement
@@ -351,9 +349,9 @@ entt::basic_poly<Drawable, sizeof(double[4]), alignof(double[4])>
The default size is `sizeof(double[2])`, which seems like a good compromise
between a buffer that is too large and one unable to hold anything larger than
an integer. The alignment requirement is optional instead and by default such
that it's the most stringent (the largest) for any object whose size is at most
equal to the one provided.<br/>
an integer. The alignment requirement is optional and by default such that it's
the most stringent (the largest) for any object whose size is at most equal to
the one provided.<br/>
It's worth noting that providing a size of 0 (which is an accepted value in all
respects) will force the system to dynamically allocate the contained objects in
all cases.

View File

@@ -15,18 +15,17 @@
# Introduction
Sometimes processes are a useful tool to work around the strict definition of a
system and introduce logic in a different way, usually without resorting to the
introduction of other components.
`EnTT` offers a minimal support to this paradigm by introducing a few classes
that users can use to define and execute cooperative processes.
Processes are a useful tool to work around the strict definition of a system and
introduce logic in a different way, usually without resorting to other component
types.<br/>
`EnTT` offers minimal support to this paradigm by introducing a few classes used
to define and execute cooperative processes.
# The process
A typical process must inherit from the `process` class template that stays true
to the CRTP idiom. Moreover, derived classes must specify what's the intended
type for elapsed times.
A typical task inherits from the `process` class template that stays true to the
CRTP idiom. Moreover, derived classes specify what the intended type for elapsed
times is.
A process should expose publicly the following member functions whether needed
(note that it isn't required to define a function unless the derived class wants
@@ -34,39 +33,38 @@ to _override_ the default behavior):
* `void update(Delta, void *);`
It's invoked once per tick until a process is explicitly aborted or it
terminates either with or without errors. Even though it's not mandatory to
declare this member function, as a rule of thumb each process should at
least define it to work properly. The `void *` parameter is an opaque pointer
to user data (if any) forwarded directly to the process during an update.
This is invoked once per tick until a process is explicitly aborted or ends
either with or without errors. Even though it's not mandatory to declare this
member function, as a rule of thumb each process should at least define it to
work _properly_. The `void *` parameter is an opaque pointer to user data (if
any) forwarded directly to the process during an update.
* `void init();`
It's invoked when the process joins the running queue of a scheduler. This
happens as soon as it's attached to the scheduler if the process is a top
level one, otherwise when it replaces its parent if the process is a
continuation.
This is invoked when the process joins the running queue of a scheduler. It
happens usually as soon as the process is attached to the scheduler if it's a
top level one, otherwise when it replaces its parent if it's a _continuation_.
* `void succeeded();`
It's invoked in case of success, immediately after an update and during the
This is invoked in case of success, immediately after an update and during the
same tick.
* `void failed();`
It's invoked in case of errors, immediately after an update and during the
This is invoked in case of errors, immediately after an update and during the
same tick.
* `void aborted();`
It's invoked only if a process is explicitly aborted. There is no guarantee
that it executes in the same tick, this depends solely on whether the
process is aborted immediately or not.
This is invoked only if a process is explicitly aborted. There is no guarantee
that it executes in the same tick, it depends solely on whether the process is
aborted immediately or not.
Derived classes can also change the internal state of a process by invoking
`succeed` and `fail`, as well as `pause` and `unpause` the process itself. All
these are protected member functions made available to be able to manage the
life cycle of a process from a derived class.
`succeed` and `fail`, as well as `pause` and `unpause` the process itself.<br/>
All these are protected member functions made available to manage the life cycle
of a process from a derived class.
Here is a minimal example for the sake of curiosity:
@@ -95,14 +93,14 @@ private:
## Adaptor
Lambdas and functors can't be used directly with a scheduler for they are not
Lambdas and functors can't be used directly with a scheduler because they aren't
properly defined processes with managed life cycles.<br/>
This class helps in filling the gap and turning lambdas and functors into
full featured processes usable by a scheduler.
full-featured processes usable by a scheduler.
The function call operator has a signature similar to the one of the `update`
function of a process but for the fact that it receives two extra arguments to
call whenever a process is terminated with success or with an error:
function of a process but for the fact that it receives two extra callbacks to
invoke whenever a process terminates with success or with an error:
```cpp
void(Delta delta, void *data, auto succeed, auto fail);
@@ -127,9 +125,9 @@ A cooperative scheduler runs different processes and helps managing their life
cycles.
Each process is invoked once per tick. If it terminates, it's removed
automatically from the scheduler and it's never invoked again. Otherwise it's
automatically from the scheduler and it's never invoked again. Otherwise, it's
a good candidate to run one more time the next tick.<br/>
A process can also have a child. In this case, the parent process is replaced
A process can also have a _child_. In this case, the parent process is replaced
with its child when it terminates and only if it returns with success. In case
of errors, both the parent process and its child are discarded. This way, it's
easy to create chain of processes to run sequentially.
@@ -138,18 +136,25 @@ Using a scheduler is straightforward. To create it, users must provide only the
type for the elapsed times and no arguments at all:
```cpp
entt::scheduler<std::uint32_t> scheduler;
entt::basic_scheduler<std::uint64_t> scheduler;
```
It has member functions to query its internal data structures, like `empty` or
`size`, as well as a `clear` utility to reset it to a clean state:
Otherwise, the `scheduler` alias is also available for the most common cases. It
uses `std::uint32_t` as a default type:
```cpp
entt::scheduler scheduler;
```
The class has member functions to query its internal data structures, like
`empty` or `size`, as well as a `clear` utility to reset it to a clean state:
```cpp
// checks if there are processes still running
const auto empty = scheduler.empty();
// gets the number of processes still running
entt::scheduler<std::uint32_t>::size_type size = scheduler.size();
entt::scheduler::size_type size = scheduler.size();
// resets the scheduler to its initial state and discards all the processes
scheduler.clear();
@@ -172,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 to use 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
@@ -201,7 +206,7 @@ scheduler.update(delta, &data);
```
In addition to these functions, the scheduler offers an `abort` member function
that can be used to discard all the running processes at once:
that is used to discard all the running processes at once:
```cpp
// aborts all the processes abruptly ...

View File

@@ -1,18 +1,35 @@
# Similar projects
<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents
* [Introduction](#introduction)
* [Similar projects](#similar-projects)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
There are many projects similar to `EnTT`, both open source and not.<br/>
Some even borrowed some ideas from this library and expressed them in different
languages.<br/>
Others developed different architectures from scratch and therefore offer
alternative solutions with their pros and cons.
Below an incomplete list of those that I've come across so far.<br/>
If you know of other similar projects out there, feel free to open an issue or a
PR and I'll be glad to add them to this page.<br/>
I hope the following lists can grow much more in the future.
# Similar projects
Below an incomplete list of similar projects that I've come across so far.<br/>
If some terms or designs aren't clear, I recommend referring to the
[_ECS Back and Forth_](https://skypjack.github.io/tags/#ecs) series for all the
details.
I hope this list can grow much more in the future:
* C:
* [destral_ecs](https://github.com/roig/destral_ecs): a single-file ECS based
on sparse sets.
@@ -28,10 +45,14 @@ I hope this list can grow much more in the future:
ECS that uses sparse sets to keep track of entities in systems.
* [EntityX](https://github.com/alecthomas/entityx): a bitset based ECS that
uses a single large matrix of components indexed with entities.
* [Gaia-ECS](https://github.com/richardbiely/gaia-ecs): a chunk based
archetype ECS.
* [Polypropylene](https://github.com/pmbittner/Polypropylene): a hybrid
solution between an ECS and dynamic mixins.
* C#
* [Arch](https://github.com/genaray/Arch): a simple, fast and _unity entities_
inspired archetype ECS with optional multithreading.
* [Entitas](https://github.com/sschmid/Entitas-CSharp): the ECS framework for
C# and Unity, where _reactive systems_ were invented.
* [LeoECS](https://github.com/Leopotam/ecs): simple lightweight C# Entity
@@ -61,11 +82,10 @@ I hope this list can grow much more in the future:
* [Legion](https://github.com/TomGillen/legion): a chunk based archetype ECS.
* [Shipyard](https://github.com/leudz/shipyard): it borrows some ideas from
`EnTT` and offers a sparse sets based ECS with grouping functionalities.
* [Sparsey](https://github.com/LechintanTudor/sparsey): sparse set based ECS
written in Rust.
* [Specs](https://github.com/amethyst/specs): a parallel ECS based mainly on
hierarchical bitsets that allows different types of storage as needed.
* Zig
* [zig-ecs](https://github.com/prime31/zig-ecs): a _zig-ification_ of `EnTT`.
If you know of other resources out there that can be of interest for the reader,
feel free to open an issue or a PR and I'll be glad to add them to this page.

View File

@@ -7,225 +7,185 @@
* [Introduction](#introduction)
* [The resource, the loader and the cache](#the-resource-the-loader-and-the-cache)
* [Resource handle](#resource-handle)
* [Loaders](#loader)
* [The cache class](#the-cache)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
Resource management is usually one of the most critical part of a software like
a game. Solutions are often tuned to the particular application. There exist
several approaches and all of them are perfectly fine as long as they fit the
Resource management is usually one of the most critical parts of a game.
Solutions are often tuned to the particular application. There exist several
approaches and all of them are perfectly fine as long as they fit the
requirements of the piece of software in which they are used.<br/>
Examples are loading everything on start, loading on request, predictive
loading, and so on.
`EnTT` doesn't pretend to offer a _one-fits-all_ solution for the different
cases. Instead, it offers a minimal and perhaps trivial cache that can be useful
most of the time during prototyping and sometimes even in a production
environments.<br/>
For those interested in the subject, the plan is to improve it considerably over
time in terms of performance, memory usage and functionalities. Hoping to make
it, of course, one step at a time.
cases.<br/>
Instead, the library comes with a minimal, general purpose resource cache that
might be useful in many cases.
# The resource, the loader and the cache
There are three main actors in the model: the resource, the loader and the
cache.
The _resource_ is whatever users want it to be. An image, a video, an audio,
whatever. There are no limits.<br/>
As a minimal example:
Resource, loader and cache are the three main actors for the purpose.<br/>
The _resource_ is an image, an audio, a video or any other type:
```cpp
struct my_resource { const int value; };
```
A _loader_ is a class the aim of which is to load a specific resource. It has to
inherit directly from a dedicated base class as in the following example:
The _loader_ is a callable type the aim of which is to load a specific resource:
```cpp
struct my_loader final: entt::resource_loader<my_loader, my_resource> {
// ...
};
```
struct my_loader final {
using result_type = std::shared_ptr<my_resource>;
Where `my_resource` is the type of resources it creates.<br/>
A resource loader must also expose a public const member function named `load`
that accepts a variable number of arguments and returns a shared pointer to a
resource.<br/>
As an example:
```cpp
struct my_loader: entt::resource_loader<my_loader, my_resource> {
std::shared_ptr<my_resource> load(int value) const {
result_type operator()(int value) const {
// ...
return std::shared_ptr<my_resource>(new my_resource{ value });
return std::make_shared<my_resource>(value);
}
};
```
In general, resource loaders should not have a state or retain data of any type.
They should let the cache manage their resources instead.<br/>
As a side note, base class and CRTP idiom aren't strictly required with the
current implementation. One could argue that a cache can easily work with
loaders of any type. However, future changes won't be breaking ones by forcing
the use of a base class today and that's why the model is already in its place.
Its function operator can accept any arguments and should return a value of the
declared result type (`std::shared_ptr<my_resource>` in the example).<br/>
A loader can also overload its function call operator to make it possible to
construct the same or another resource from different lists of arguments.
Finally, a cache is a specialization of a class template tailored to a specific
resource:
resource and (optionally) a loader:
```cpp
using my_cache = entt::resource_cache<my_resource>;
using my_cache = entt::resource_cache<my_resource, my_loader>;
// ...
my_cache cache{};
```
The idea is to create different caches for different types of resources and to
manage each one independently in the most appropriate way.<br/>
The class is designed to create different caches for different resource types
and to manage each one independently in the most appropriate way.<br/>
As a (very) trivial example, audio tracks can survive in most of the scenes of
an application while meshes can be associated with a single scene and then
discarded when users leave it.
an application while meshes can be associated with a single scene only, then
discarded when a player leaves it.
A cache offers a set of basic functionalities to query its internal state and to
_organize_ it:
## Resource handle
Resources aren't returned directly to the caller. Instead, they are wrapped in a
_resource handle_, an instance of the `entt::resource` class template.<br/>
For those who know the _flyweight design pattern_ already, that's exactly what
it is. To all others, this is the time to brush up on some notions instead.
A shared pointer could have been used as a resource handle. In fact, the default
implementation mostly maps the interface of its standard counterpart and only
adds a few things on top of it.<br/>
However, the handle in `EnTT` is designed as a standalone class template. This
is due to the fact that specializing a class in the standard library is often
undefined behavior while having the ability to specialize the handle for one,
more or all resource types could help over time.
## Loaders
A loader is responsible for _loading_ resources (quite obviously).<br/>
By default, it's just a callable object that forwards its arguments to the
resource itself. That is, a _passthrough type_. All the work is demanded to the
constructor(s) of the resource itself.<br/>
Loaders also are fully customizable as expected.
A custom loader is a class with at least one function call operator and a member
type named `result_type`.<br/>
The loader isn't required to return a resource handle. As long as `return_type`
is suitable for constructing a handle, that's fine.
When using the default handle, it expects a resource type which is convertible
to or suitable for constructing an `std::shared_ptr<Type>` (where `Type` is the
actual resource type).<br/>
In other terms, the loader should return shared pointers to the given resource
type. However, this isn't mandatory. Users can easily get around this constraint
by specializing both the handle and the loader.
A cache forwards all its arguments to the loader if required. This means that
loaders can also support tag dispatching to offer different loading policies:
```cpp
// gets the number of resources managed by a cache
const auto size = cache.size();
struct my_loader {
using result_type = std::shared_ptr<my_resource>;
// checks if a cache contains at least a valid resource
const auto empty = cache.empty();
struct from_disk_tag{};
struct from_network_tag{};
// clears a cache and discards its content
cache.clear();
template<typename Args>
result_type operator()(from_disk_tag, Args&&... args) {
// ...
return std::make_shared<my_resource>(std::forward<Args>(args)...);
}
template<typename Args>
result_type operator()(from_network_tag, Args&&... args) {
// ...
return std::make_shared<my_resource>(std::forward<Args>(args)...);
}
}
```
Besides these member functions, a cache contains what is needed to load, use and
discard resources of the given type.<br/>
Before exploring this part of the interface, it makes sense to mention how
resources are identified. They have type `id_type` and therefore they can be
created explicitly as in the following example:
This makes the whole loading logic quite flexible and easy to extend over time.
## The cache class
The cache is the class that is asked to _connect the dots_.<br/>
It loads the resources, stores them aside and returns handles as needed:
```cpp
constexpr auto identifier = "my/resource/identifier"_hs;
// this is equivalent to the following
constexpr entt::id_type hs = entt::hashed_string{"my/resource/identifier"};
entt::resource_cache<my_resource, my_loader> cache{};
```
The class `hashed_string` is described in a dedicated section, so I won't go in
details here.
Resources are loaded and thus stored in a cache through the `load` member
function. It accepts the loader to use as a template parameter, the resource
identifier and the parameters used to construct the resource as arguments:
Under the hood, a cache is nothing more than a map where the key value has type
`entt::id_type` while the mapped value is whatever type its loader returns.<br/>
For this reason, it offers most of the functionalities a user would expect from
a map, such as `empty` or `size` and so on. Similarly, it's an iterable type
that also supports indexing by resource id:
```cpp
// uses the identifier declared above
cache.load<my_loader>(identifier, 0);
for(auto [id, res]: cache) {
// ...
}
// uses a hashed string directly
cache.load<my_loader>("another/identifier"_hs, 42);
```
The function returns a handle to the resource, whether it already exists or is
loaded. In case the loader returns an invalid pointer, the handle is invalid as
well and therefore it can be easily used with an `if` statement:
```cpp
if(entt::resource_handle handle = cache.load<my_loader>("another/identifier"_hs, 42); handle) {
if(entt::resource<my_resource> res = cache["resource/id"_hs]; res) {
// ...
}
```
Before trying to load a resource, the `contains` member function can be used to
know if a cache already contains a specific resource:
Please, refer to the inline documentation for all the details about the other
functions (such as `contains` or `erase`).
Set aside the part of the API that this class _shares_ with a map, it also adds
something on top of it in order to address the most common requirements of a
resource cache.<br/>
In particular, it doesn't have an `emplace` member function which is replaced by
`load` and `force_load` instead (where the former loads a new resource only if
not present while the second triggers a forced loading in any case):
```cpp
auto exists = cache.contains("my/identifier"_hs);
auto ret = cache.load("resource/id"_hs);
// true only if the resource was not already present
const bool loaded = ret.second;
// takes the resource handle pointed to by the returned iterator
entt::resource<my_resource> res = ret.first->second;
```
There exists also a member function to use to force a reload of an already
existing resource if needed:
Note that the hashed string is used for convenience in the example above.<br/>
Resource identifiers are nothing more than integral values. Therefore, plain
numbers as well as non-class enum value are accepted.
```cpp
auto handle = cache.reload<my_loader>("another/identifier"_hs, 42);
```
As above, the function returns a handle to the resource that is invalid in case
of errors. The `reload` member function is a kind of alias of the following
snippet:
```cpp
cache.discard(identifier);
cache.load<my_loader>(identifier, 42);
```
Where the `discard` member function is used to get rid of a resource if loaded.
In case the cache doesn't contain a resource for the given identifier, `discard`
does nothing and returns immediately.
So far, so good. Resources are finally loaded and stored within the cache.<br/>
They are returned to users in the form of handles. To get one of them later on:
```cpp
auto handle = cache.handle("my/identifier"_hs);
```
The idea behind a handle is the same of the flyweight pattern. In other terms,
resources aren't copied around. Instead, instances are shared between handles.
Users of a resource own a handle that guarantees that a resource isn't destroyed
until all the handles are destroyed, even if the resource itself is removed from
the cache.<br/>
Handles are tiny objects both movable and copyable. They return the contained
resource as a (possibly const) reference on request:
* By means of the `get` member function:
```cpp
auto &resource = handle.get();
```
* Using the proper cast operator:
```cpp
auto &resource = handle;
```
* Through the dereference operator:
```cpp
auto &resource = *handle;
```
The resource can also be accessed directly using the arrow operator if required:
```cpp
auto value = handle->value;
```
To test if a handle is still valid, the cast operator to `bool` allows users to
use it in a guard:
```cpp
if(handle) {
// ...
}
```
Finally, in case there is the need to load a resource and thus to get a handle
without storing the resource itself in the cache, users can rely on the `temp`
member function template.<br/>
The declaration is similar to that of `load`, a (possibly invalid) handle for
the resource is returned also in this case:
```cpp
if(auto handle = cache.temp<my_loader>(42); handle) {
// ...
}
```
Do not forget to test the handle for validity. Otherwise, getting a reference to
the resource it points may result in undefined behavior.
It's worth mentioning that the iterators of a cache as well as its indexing
operators return resource handles rather than instances of the mapped type.<br/>
Since the cache has no control over the loader and a resource isn't required to
also be convertible to bool, these handles can be invalid. This usually means an
error in the user logic but it may also be an _expected_ event.<br/>
It's therefore recommended to verify handles validity with a check in debug (for
example, when loading) or an appropriate logic in retail.

View File

@@ -9,8 +9,10 @@
* [Delegate](#delegate)
* [Runtime arguments](#runtime-arguments)
* [Lambda support](#lambda-support)
* [Raw access](#raw-access)
* [Signals](#signals)
* [Event dispatcher](#event-dispatcher)
* [Named queues](#named-queues)
* [Event emitter](#event-emitter)
<!--
@endcond TURN_OFF_DOXYGEN
@@ -18,27 +20,27 @@
# Introduction
Signals are usually a core part of games and software architectures in
general.<br/>
Roughly speaking, they help to decouple the various parts of a system while
allowing them to communicate with each other somehow.
Signals are more often than not a core part of games and software architectures
in general.<br/>
They help to decouple the various parts of a system while allowing them to
communicate with each other somehow.
The so called _modern C++_ comes with a tool that can be useful in these terms,
The so called _modern C++_ comes with a tool that can be useful in this regard,
the `std::function`. As an example, it can be used to create delegates.<br/>
However, there is no guarantee that an `std::function` does not perform
However, there is no guarantee that an `std::function` doesn't perform
allocations under the hood and this could be problematic sometimes. Furthermore,
it solves a problem but may not adapt well to other requirements that may arise
from time to time.
In case that the flexibility and power of an `std::function` isn't required or
if the price to pay for them is too high,` EnTT` offers a complete set of
if the price to pay for them is too high, `EnTT` offers a complete set of
lightweight classes to solve the same and many other problems.
# Delegate
A delegate can be used as a general purpose invoker with no memory overhead for
free functions and members provided along with an instance on which to invoke
them.<br/>
free functions, lambdas and members provided along with an instance on which to
invoke them.<br/>
It doesn't claim to be a drop-in replacement for an `std::function`, so don't
expect to use it whenever an `std::function` fits well. That said, it's most
likely even a better fit than an `std::function` in a lot of cases, so expect to
@@ -51,15 +53,13 @@ delegates:
entt::delegate<int(int)> delegate{};
```
All what is needed to create an instance is to specify the type of the function
the delegate will _contain_, that is the signature of the free function or the
member one wants to assign to it.
What is needed to create an instance is to specify the type of the function the
delegate _accepts_, that is the signature of the functions it models.<br/>
However, attempting to use an empty delegate by invoking its function call
operator results in undefined behavior or most likely a crash.
Attempting to use an empty delegate by invoking its function call operator
results in undefined behavior or most likely a crash. Before to use a delegate,
it must be initialized.<br/>
There exists a bunch of overloads of the `connect` member function to do that.
As an example of use:
There exist a few overloads of the `connect` member function to initialize a
delegate:
```cpp
int f(int i) { return i; }
@@ -76,7 +76,7 @@ my_struct instance;
delegate.connect<&my_struct::f>(instance);
```
The delegate class accepts also data members, if needed. In this case, the
The delegate class also accepts data members, if needed. In this case, the
function type of the delegate is such that the parameter list is empty and the
value of the data member is at least convertible to the return type.
@@ -93,14 +93,11 @@ delegate.connect<&g>(c);
delegate(42);
```
The function `g` will be invoked with a reference to `c` and `42`. However, the
function type of the delegate is still `void(int)`. This is also the signature
of its function call operator.
Another interesting aspect of the delegate class is that it accepts also
functions with a list of parameters that is shorter than that of the function
type used to specialize the delegate itself.<br/>
The following code is therefore perfectly valid:
Function `g` is invoked with a reference to `c` and `42`. However, the function
type of the delegate is still `void(int)`. This is also the signature of its
function call operator.<br/>
Another interesting aspect of the delegate class is that it accepts functions
with a list of parameters that is shorter than that of its function type:
```cpp
void g() { /* ... */ }
@@ -109,9 +106,15 @@ delegate(42);
```
Where the function type of the delegate is `void(int)` as above. It goes without
saying that the extra arguments are silently discarded internally.<br/>
This is a nice-to-have feature in a lot of cases, as an example when the
`delegate` class is used as a building block of a signal-slot system.
saying that the extra arguments are silently discarded internally. This is a
nice-to-have feature in a lot of cases, as an example when the `delegate` class
is used as a building block of a signal-slot system.<br/>
In fact, this filtering works both ways. The class tries to pass its first
_count_ arguments **first**, then the last _count_. Watch out for conversion
rules if in doubt when connecting a listener!<br/>
Arbitrary functions that pull random arguments from the delegate list aren't
supported instead. Other feature were preferred, such as support for functions
with compatible argument lists although not equal to those of the delegate.
To create and initialize a delegate at once, there are a few specialized
constructors. Because of the rules of the language, the listener is provided by
@@ -139,7 +142,7 @@ already shown in the examples above:
auto ret = delegate(42);
```
In all cases, the listeners don't have to strictly follow the signature of the
In all cases, listeners don't have to strictly follow the signature of the
delegate. As long as a listener can be invoked with the given arguments to yield
a result that is convertible to the given result type, everything works just
fine.
@@ -157,7 +160,7 @@ my_struct instance;
delegate(instance, 42);
```
In this case, it's not possible to deduce the function type since the first
In this case, it's not possible to _deduce_ the function type since the first
argument doesn't necessarily have to be a reference (for example, it can be a
pointer, as well as a const reference).<br/>
Therefore, the function type must be declared explicitly for unbound members.
@@ -165,9 +168,9 @@ Therefore, the function type must be declared explicitly for unbound members.
## Runtime arguments
The `delegate` class is meant to be used primarily with template arguments.
However, as a consequence of its design, it can also offer minimal support for
However, as a consequence of its design, it also offers minimal support for
runtime arguments.<br/>
When used in this modality, some feature aren't supported though. In particular:
When used like this, some features aren't supported though. In particular:
* Curried functions aren't accepted.
* Functions with an argument list that differs from that of the delegate aren't
@@ -208,7 +211,7 @@ their nuances. The reason is pretty simple: a `delegate` isn't a drop-in
replacement for an `std::function`. Instead, it tries to overcome the problems
with the latter.<br/>
That being said, non-capturing lambda functions are supported, even though some
feature aren't available in this case.
features aren't available in this case.
This is a logical consequence of the support for connecting functions at
runtime. Therefore, lambda functions undergo the same rules and
@@ -235,6 +238,24 @@ As above, the first parameter (`const void *`) isn't part of the function type
of the delegate and is used to dispatch arbitrary user data back and forth. In
other terms, the function type of the delegate above is `int(int)`.
## Raw access
While not recommended, a delegate also allows direct access to the stored
callable function target and underlying data, if any.<br/>
This makes it possible to bypass the behavior of the delegate itself and force
calls on different instances:
```cpp
my_struct other;
delegate.target(&other, 42);
```
It goes without saying that this type of approach is **very** risky, especially
since there is no way of knowing whether the contained function was originally a
member function of some class, a free function or a lambda.<br/>
Another possible (and meaningful) use of this feature is that of identifying a
particular delegate through its descriptive _traits_ instead.
# Signals
Signal handlers work with references to classes, function pointers and pointers
@@ -246,16 +267,17 @@ Signals make use of delegates internally and therefore they undergo the same
rules and offer similar functionalities. It may be a good idea to consult the
documentation of the `delegate` class for further information.
A signal handler can be used as a private data member without exposing any
_publish_ functionality to the clients of a class. The basic idea is to impose a
clear separation between the signal itself and the `sink` class, that is a tool
to be used to connect and disconnect listeners on the fly.
A signal handler is can be used as a private data member without exposing any
_publish_ functionality to the clients of a class.<br/>
The basic idea is to impose a clear separation between the signal itself and the
`sink` class, that is a tool to be used to connect and disconnect listeners on
the fly.
The API of a signal handler is straightforward. If a collector is supplied to
the signal when something is published, all the values returned by the listeners
can be literally _collected_ and used later by the caller. Otherwise, the class
the signal when something is published, all the values returned by its listeners
are literally _collected_ and used later by the caller. Otherwise, the class
works just like a plain signal that emits events from time to time.<br/>
To create instances of signal handlers it is sufficient to provide the type of
To create instances of signal handlers it's sufficient to provide the type of
function to which they refer:
```cpp
@@ -293,41 +315,31 @@ sink.disconnect<&foo>();
sink.disconnect<&listener::bar>(instance);
// disconnect all member functions of an instance, if any
sink.disconnect(instance);
sink.disconnect(&instance);
// discards all listeners at once
sink.disconnect();
```
As shown above, the listeners don't have to strictly follow the signature of the
As shown above, listeners don't have to strictly follow the signature of the
signal. As long as a listener can be invoked with the given arguments to yield a
result that is convertible to the given return type, everything works just
fine.<br/>
It's also possible to connect a listener before other listeners already
contained by the signal. The `before` function returns a `sink` object correctly
initialized for the purpose that can be used to connect one or more listeners in
order and in the desired position:
```cpp
sink.before<&foo>().connect<&listener::bar>(instance);
```
In all cases, the `connect` member function returns by default a `connection`
object to be used as an alternative to break a connection by means of its
`release` member function. A `scoped_connection` can also be created from a
connection. In this case, the link is broken automatically as soon as the object
goes out of scope.
`release` member function.<br/>
A `scoped_connection` can also be created from a connection. In this case, the
link is broken automatically as soon as the object goes out of scope.
Once listeners are attached (or even if there are no listeners at all), events
and data in general can be published through a signal by means of the `publish`
and data in general are published through a signal by means of the `publish`
member function:
```cpp
signal.publish(42, 'c');
```
To collect data, the `collect` member function should be used instead. Below is
a minimal example to show how to use it:
To collect data, the `collect` member function is used instead:
```cpp
int f() { return 0; }
@@ -361,7 +373,7 @@ case:
struct my_collector {
std::vector<int> vec{};
bool operator()(int v) noexcept {
bool operator()(int v) {
vec.push_back(v);
return true;
}
@@ -375,23 +387,20 @@ signal.collect(std::ref(collector));
# Event dispatcher
The event dispatcher class is designed so as to be used in a loop. It allows
users both to trigger immediate events or to queue events to be published all
together once per tick.<br/>
This class shares part of its API with the one of the signal handler, but it
doesn't require that all the types of events are specified when declared:
The event dispatcher class allows users to trigger immediate events or to queue
and publish them all together later.<br/>
This class lazily instantiates its queues. Therefore, it's not necessary to
_announce_ the event types in advance:
```cpp
// define a general purpose dispatcher
entt::dispatcher dispatcher{};
```
In order to register an instance of a class to a dispatcher, its type must
expose one or more member functions the arguments of which are such that `E &`
can be converted to them for each type of event `E`, no matter what the return
value is.<br/>
The name of the member function aimed to receive the event must be provided to
the `connect` member function of the sink in charge for the specific event:
A listener registered with a dispatcher is such that its type offers one or more
member functions that take arguments of type `Event &` for any type of event,
regardless of the return value.<br/>
These functions are linked directly via `connect` to a _sink_:
```cpp
struct an_event { int value; };
@@ -409,23 +418,21 @@ dispatcher.sink<an_event>().connect<&listener::receive>(listener);
dispatcher.sink<another_event>().connect<&listener::method>(listener);
```
The `disconnect` member function follows the same pattern and can be used to
remove one listener at a time or all of them at once:
Note that connecting listeners within event handlers can result in undefined
behavior.<br/>
The `disconnect` member function is used to remove one listener at a time or all
of them at once:
```cpp
dispatcher.sink<an_event>().disconnect<&listener::receive>(listener);
dispatcher.sink<another_event>().disconnect(listener);
dispatcher.sink<another_event>().disconnect(&listener);
```
The `trigger` member function serves the purpose of sending an immediate event
to all the listeners registered so far. It offers a convenient approach that
relieves users from having to create the event itself. Instead, it's enough to
specify the type of event and provide all the parameters required to construct
it.<br/>
As an example:
to all the listeners registered so far:
```cpp
dispatcher.trigger<an_event>(42);
dispatcher.trigger(an_event{42});
dispatcher.trigger<another_event>();
```
@@ -434,16 +441,14 @@ method can be used to push around urgent messages like an _is terminating_
notification on a mobile app.
On the other hand, the `enqueue` member function queues messages together and
allows to maintain control over the moment they are sent to listeners. The
signature of this method is more or less the same of `trigger`:
helps to maintain control over the moment they are sent to listeners:
```cpp
dispatcher.enqueue<an_event>(42);
dispatcher.enqueue<another_event>();
dispatcher.enqueue(another_event{});
```
Events are stored aside until the `update` member function is invoked, then all
the messages that are still pending are sent to the listeners at once:
Events are stored aside until the `update` member function is invoked:
```cpp
// emits all the events of the given type at once
@@ -456,6 +461,30 @@ dispatcher.update();
This way users can embed the dispatcher in a loop and literally dispatch events
once per tick to their systems.
## Named queues
All queues within a dispatcher are associated by default with an event type and
then retrieved from it.<br/>
However, it's possible to create queues with different _names_ (and therefore
also multiple queues for a single type). In fact, more or less all functions
also take an additional parameter. As an example:
```cpp
dispatcher.sink<an_event>("custom"_hs).connect<&listener::receive>(listener);
```
In this case, the term _name_ is misused as these are actual numeric identifiers
of type `id_type`.<br/>
An exception to this rule is the `enqueue` function. There is no additional
parameter for it but rather a different function:
```cpp
dispatcher.enqueue_hint<an_event>("custom"_hs, 42);
```
This is mainly due to the template argument deduction rules and unfortunately
there is no real (elegant) way to avoid it.
# Event emitter
A general purpose event emitter thought mainly for those cases where it comes to
@@ -464,8 +493,7 @@ Originally designed to fit the requirements of
[`uvw`](https://github.com/skypjack/uvw) (a wrapper for `libuv` written in
modern C++), it was adapted later to be included in this library.
To create a custom emitter type, derived classes must inherit directly from the
base class as:
To create an emitter type, derived classes must inherit from the base as:
```cpp
struct my_emitter: emitter<my_emitter> {
@@ -473,18 +501,10 @@ struct my_emitter: emitter<my_emitter> {
}
```
The full list of accepted types of events isn't required. Handlers are created
internally on the fly and thus each type of event is accepted by default.
Whenever an event is published, an emitter provides the listeners with a
reference to itself along with a reference to the event. Therefore listeners
have an handy way to work with it without incurring in the need of capturing a
reference to the emitter itself.<br/>
In addition, an opaque object is returned each time a connection is established
between an emitter and a listener, allowing the caller to disconnect them at a
later time.<br/>
The opaque object used to handle connections is both movable and copyable. On
the other side, an event emitter is movable but not copyable by default.
Handlers for the different events are created internally on the fly. It's not
required to specify in advance the full list of accepted events.<br/>
Moreover, whenever an event is published, an emitter also passes a reference
to itself to its listeners.
To create new instances of an emitter, no arguments are required:
@@ -492,90 +512,54 @@ To create new instances of an emitter, no arguments are required:
my_emitter emitter{};
```
Listeners must be movable and callable objects (free functions, lambdas,
functors, `std::function`s, whatever) whose function type is compatible with:
Listeners are movable and callable objects (free functions, lambdas, functors,
`std::function`s, whatever) whose function type is compatible with:
```cpp
void(Event &, my_emitter &)
void(Type &, my_emitter &)
```
Where `Event` is the type of event they want to listen.<br/>
There are two ways to attach a listener to an event emitter that differ
slightly from each other:
* To register a long-lived listener, use the `on` member function. It is meant
to register a listener designed to be invoked more than once for the given
event type.<br/>
As an example:
```cpp
auto conn = emitter.on<my_event>([](const my_event &event, my_emitter &emitter) {
// ...
});
```
The connection object can be freely discarded. Otherwise, it can be used later
to disconnect the listener if required.
* To register a short-lived listener, use the `once` member function. It is
meant to register a listener designed to be invoked only once for the given
event type. The listener is automatically disconnected after the first
invocation.<br/>
As an example:
```cpp
auto conn = emitter.once<my_event>([](const my_event &event, my_emitter &emitter) {
// ...
});
```
The connection object can be freely discarded. Otherwise, it can be used later
to disconnect the listener if required.
In both cases, the connection object can be used with the `erase` member
function:
Where `Type` is the type of event they want to receive.<br/>
To attach a listener to an emitter, there exists the `on` member function:
```cpp
emitter.erase(conn);
emitter.on<my_event>([](const my_event &event, my_emitter &emitter) {
// ...
});
```
There are also two member functions to use either to disconnect all the
listeners for a given type of event or to clear the emitter:
Similarly, the `reset` member function is used to disconnect listeners given a
type while `clear` is used to disconnect all listeners at once:
```cpp
// removes all the listener for the specific event
emitter.clear<my_event>();
// resets the listener for my_event
emitter.erase<my_event>();
// removes all the listeners registered so far
emitter.clear();
// resets all listeners
emitter.clear()
```
To send an event to all the listeners that are interested in it, the `publish`
member function offers a convenient approach that relieves users from having to
create the event:
To send an event to the listener registered on a given type, the `publish`
function is the way to go:
```cpp
struct my_event { int i; };
// ...
emitter.publish<my_event>(42);
emitter.publish(my_event{42});
```
Finally, the `empty` member function tests if there exists at least either a
listener registered with the event emitter or to a given type of event:
Finally, the `empty` member function tests if there exists at least a listener
registered with the event emitter while `contains` is used to check if a given
event type is associated with a valid listener:
```cpp
bool empty;
// checks if there is any listener registered for the specific event
empty = emitter.empty<my_event>();
// checks it there are listeners registered with the event emitter
empty = emitter.empty();
if(emitter.contains<my_event>()) {
// ...
}
```
In general, the event emitter is a handy tool when the derived classes _wrap_
asynchronous operations, because it introduces a _nice-to-have_ model based on
events and listeners that kindly hides the complexity behind the scenes. However
it is not limited to such uses.
This class introduces a _nice-to-have_ model based on events and listeners.<br/>
More in general, it's a handy tool when the derived classes _wrap_ asynchronous
operations but it's not limited to such uses.

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

42
entt.imp Normal file
View File

@@ -0,0 +1,42 @@
[
# gtest only
{ "include": [ "@<gtest/internal/.*>", "private", "<gtest/gtest.h>", "public" ] },
{ "include": [ "@<gtest/gtest-.*>", "private", "<gtest/gtest.h>", "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,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="entt::dense_hash_map&lt;*&gt;">
<Type Name="entt::dense_map&lt;*&gt;">
<Intrinsic Name="size" Expression="packed.first_base::value.size()"/>
<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/>
<DisplayString>{{ size={ size() } }}</DisplayString>
@@ -15,7 +15,7 @@
</IndexListItems>
</Expand>
</Type>
<Type Name="entt::dense_hash_set&lt;*&gt;">
<Type Name="entt::dense_set&lt;*&gt;">
<Intrinsic Name="size" Expression="packed.first_base::value.size()"/>
<Intrinsic Name="bucket_count" Expression="sparse.first_base::value.size()"/>
<DisplayString>{{ size={ size() } }}</DisplayString>
@@ -26,7 +26,7 @@
<Item Name="[max_load_factor]" ExcludeView="simple">threshold</Item>
<IndexListItems>
<Size>size()</Size>
<ValueNode>packed.first_base::value[$i].element</ValueNode>
<ValueNode>packed.first_base::value[$i].second</ValueNode>
</IndexListItems>
</Expand>
</Type>

View File

@@ -15,10 +15,11 @@
</Expand>
</Type>
<Type Name="entt::basic_hashed_string&lt;*&gt;">
<DisplayString Condition="str != nullptr">{{ hash={ hash } }}</DisplayString>
<DisplayString Condition="base_type::repr != nullptr">{{ hash={ base_type::hash } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[data]">str,na</Item>
<Item Name="[data]">base_type::repr,na</Item>
<Item Name="[length]">base_type::length</Item>
</Expand>
</Type>
<Type Name="entt::type_info">

View File

@@ -1,102 +1,97 @@
<?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="pools_size" Expression="pools.packed.first_base::value.size()"/>
<Intrinsic Name="vars_size" Expression="vars.packed.first_base::value.size()"/>
<Intrinsic Name="to_entity" Expression="*((entity_traits::entity_type *)&amp;entity) &amp; entity_traits::entity_mask">
<Parameter Name="entity" Type="entity_traits::value_type &amp;"/>
</Intrinsic>
<DisplayString>{{ size={ entities.size() } }}</DisplayString>
<DisplayString>{{ pools={ pools.size() } }}</DisplayString>
<Expand>
<Item IncludeView="simple" Name="[entities]">entities,view(simple)nr</Item>
<Synthetic Name="[entities]" ExcludeView="simple">
<DisplayString>{ entities.size() }</DisplayString>
<Expand>
<CustomListItems>
<Variable Name="pos" InitialValue="0" />
<Variable Name="last" InitialValue="entities.size()"/>
<Loop>
<Break Condition="pos == last"/>
<If Condition="to_entity(entities[pos]) == pos">
<Item Name="[{ pos }]">entities[pos]</Item>
</If>
<Exec>++pos</Exec>
</Loop>
</CustomListItems>
</Expand>
</Synthetic>
<Synthetic Name="[destroyed]" ExcludeView="simple">
<DisplayString>{ to_entity(free_list) != entity_traits::entity_mask }</DisplayString>
<Expand>
<CustomListItems>
<Variable Name="it" InitialValue="to_entity(free_list)" />
<Loop>
<Break Condition="it == entity_traits::entity_mask"/>
<Item Name="[{ it }]">entities[it]</Item>
<Exec>it = to_entity(entities[it])</Exec>
</Loop>
</CustomListItems>
</Expand>
</Synthetic>
<Item Name="[entities]">entities</Item>
<Synthetic Name="[pools]">
<DisplayString>{ pools_size() }</DisplayString>
<DisplayString>{ pools.size() }</DisplayString>
<Expand>
<IndexListItems ExcludeView="simple">
<Size>pools_size()</Size>
<Size>pools.size()</Size>
<ValueNode>*pools.packed.first_base::value[$i].element.second</ValueNode>
</IndexListItems>
<IndexListItems IncludeView="simple">
<Size>pools_size()</Size>
<Size>pools.size()</Size>
<ValueNode>*pools.packed.first_base::value[$i].element.second,view(simple)</ValueNode>
</IndexListItems>
</Expand>
</Synthetic>
<Item Name="[groups]" ExcludeView="simple">groups.size()</Item>
<Synthetic Name="[vars]">
<DisplayString>{ vars_size() }</DisplayString>
<DisplayString>{ vars.ctx.size() }</DisplayString>
<Expand>
<IndexListItems>
<Size>vars_size()</Size>
<ValueNode>vars.packed.first_base::value[$i].element.second</ValueNode>
<Size>vars.ctx.size()</Size>
<ValueNode>vars.ctx.packed.first_base::value[$i].element.second</ValueNode>
</IndexListItems>
</Expand>
</Synthetic>
</Expand>
</Type>
<Type Name="entt::basic_sparse_set&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>
<ExpandedItem IncludeView="simple">packed,view(simple)</ExpandedItem>
<CustomListItems ExcludeView="simple">
<Variable Name="pos" InitialValue="0" />
<Variable Name="last" InitialValue="packed.size()"/>
<Loop>
<Break Condition="pos == last"/>
<If Condition="*((entity_traits::entity_type *)&amp;packed[pos]) &lt; ~entity_traits::entity_mask">
<Item Name="[{ pos }]">packed[pos]</Item>
</If>
<Exec>++pos</Exec>
</Loop>
</CustomListItems>
<Item Name="[free_list]">head</Item>
<Synthetic Name="[sparse]">
<DisplayString>{ sparse.size() * traits_type::page_size }</DisplayString>
<Expand>
<ExpandedItem IncludeView="simple">sparse,view(simple)</ExpandedItem>
<CustomListItems ExcludeView="simple">
<Variable Name="pos" InitialValue="0"/>
<Variable Name="page" InitialValue="0"/>
<Variable Name="offset" InitialValue="0"/>
<Variable Name="last" InitialValue="sparse.size() * traits_type::page_size"/>
<Loop>
<Break Condition="pos == last"/>
<Exec>page = pos / traits_type::page_size</Exec>
<Exec>offset = pos &amp; (traits_type::page_size - 1)</Exec>
<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>
</Loop>
</CustomListItems>
</Expand>
</Synthetic>
<Synthetic Name="[packed]">
<DisplayString>{ packed.size() }</DisplayString>
<Expand>
<ExpandedItem IncludeView="simple">packed,view(simple)</ExpandedItem>
<CustomListItems ExcludeView="simple">
<Variable Name="pos" InitialValue="0"/>
<Variable Name="last" InitialValue="packed.size()"/>
<Loop>
<Break Condition="pos == last"/>
<If Condition="*((traits_type::entity_type *)&amp;packed[pos]) &lt; cap()">
<Item Name="[{ pos }]">packed[pos]</Item>
</If>
<Exec>++pos</Exec>
</Loop>
</CustomListItems>
</Expand>
</Synthetic>
</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">packed.first_base::value.capacity() * comp_traits::page_size</Item>
<Item Name="[page size]" Optional="true" ExcludeView="simple">comp_traits::page_size</Item>
<Item Name="[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="[base]" ExcludeView="simple">(base_type*)this,nand</Item>
<Item Name="[base]" IncludeView="simple">(base_type*)this,view(simple)nand</Item>
<!-- having SFINAE-like techniques in natvis is priceless :) -->
<CustomListItems Condition="packed.first_base::value.size() != 0" Optional="true">
<CustomListItems Condition="payload.size() != 0" Optional="true">
<Variable Name="pos" InitialValue="0" />
<Variable Name="last" InitialValue="base_type::packed.size()"/>
<Loop>
<Break Condition="pos == last"/>
<If Condition="*((base_type::entity_traits::entity_type *)&amp;base_type::packed[pos]) &lt; ~base_type::entity_traits::entity_mask">
<Item Name="[{ pos }]">packed.first_base::value[pos / comp_traits::page_size][pos &amp; (comp_traits::page_size - 1)]</Item>
<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>
</Loop>
@@ -104,7 +99,17 @@
</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]" 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;">
<DisplayString Condition="pools.size() != 0u">{{ size_hint={ pools[0]->packed.size() } }}</DisplayString>
<DisplayString>{{ size_hint=0 }}</DisplayString>
<Expand>
<Item Name="[pools]">pools,na</Item>
<Item Name="[filter]">filter,na</Item>

19
natvis/entt/graph.natvis Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="entt::adjacency_matrix&lt;*&gt;">
<DisplayString>{{ size={ vert } }}</DisplayString>
<Expand>
<CustomListItems>
<Variable Name="pos" InitialValue="0" />
<Variable Name="last" InitialValue="vert * vert"/>
<Loop>
<Break Condition="pos == last"/>
<If Condition="matrix[pos] != 0u">
<Item Name="{pos / vert}">pos % vert</Item>
</If>
<Exec>++pos</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
</AutoVisualizer>

View File

@@ -1,115 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="entt::meta_any">
<DisplayString Condition="node != nullptr">{{ type={ node->info->alias,na }, policy={ storage.mode,en } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">*node</ExpandedItem>
</Expand>
</Type>
<Type Name="entt::meta_associative_container">
<DisplayString Condition="mapped_type_node != nullptr">{{ key_type={ key_type_node->info->alias,na }, mapped_type={ mapped_type_node->info->alias,na } }}</DisplayString>
<DisplayString Condition="key_type_node != nullptr">{{ key_type={ key_type_node->info->alias,na } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
</Type>
<Type Name="entt::internal::meta_base_node">
<DisplayString Condition="type != nullptr">{{ type={ type->info->alias,na } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
</Type>
<Type Name="entt::internal::meta_conv_node">
<DisplayString Condition="type != nullptr">{{ type={ type->info->alias,na } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
</Type>
<Type Name="entt::internal::meta_ctor_node">
<DisplayString Condition="arg != nullptr">{{ arity={ arity } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<DisplayString>{{ arity={ arity } }}</DisplayString>
</Type>
<Type Name="entt::internal::meta_data_node">
<Intrinsic Name="has_property" Expression="!!(traits &amp; property)">
<Parameter Name="property" Type="int"/>
</Intrinsic>
<DisplayString Condition="type != nullptr">{{ type={ type->info->alias,na } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<DisplayString>{{ arity={ arity } }}</DisplayString>
<Expand>
<Item Name="[id]">id</Item>
<Item Name="[arity]">arity</Item>
<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item>
<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item>
<Synthetic Name="[prop]" Condition="prop != nullptr">
<Expand>
<LinkedListItems>
<HeadPointer>prop</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
</Expand>
</Type>
<Type Name="entt::meta_data">
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
<Item Name="[prop]">prop</Item>
</Expand>
</Type>
<Type Name="entt::internal::meta_func_node" >
<Intrinsic Name="has_property" Expression="!!(traits &amp; property)">
<Parameter Name="property" Type="int"/>
</Intrinsic>
<DisplayString Condition="ret != nullptr">{{ arity={ arity }, ret={ ret->info->alias,na } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<DisplayString>{{ arity={ arity } }}</DisplayString>
<Expand>
<Item Name="[id]">id</Item>
<Item Name="[is_const]">has_property(entt::internal::meta_traits::is_const)</Item>
<Item Name="[is_static]">has_property(entt::internal::meta_traits::is_static)</Item>
<Synthetic Name="[prop]" Condition="prop != nullptr">
<Expand>
<LinkedListItems>
<HeadPointer>prop</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
<Item Name="[next]" Condition="next != nullptr">*next</Item>
<Item Name="[prop]">prop</Item>
</Expand>
</Type>
<Type Name="entt::meta_func">
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
</Expand>
</Type>
<Type Name="entt::meta_handle">
<DisplayString>{ any }</DisplayString>
</Type>
<Type Name="entt::internal::meta_prop_node">
<DisplayString Condition="value.node != nullptr">{{ key_type={ id.node->info->alias,na }, mapped_type={ value.node->info->alias,na } }}</DisplayString>
<DisplayString Condition="id.node != nullptr">{{ key_type={ id.node->info->alias,na } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[key]">id</Item>
<Item Name="[value]">value</Item>
</Expand>
</Type>
<Type Name="entt::meta_prop">
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
</Expand>
</Type>
<Type Name="entt::meta_sequence_container">
<DisplayString Condition="value_type_node != nullptr">{{ value_type={ value_type_node->info->alias,na } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<DisplayString>{ value }</DisplayString>
</Type>
<Type Name="entt::internal::meta_template_node">
<DisplayString Condition="type != nullptr">{{ type={ type->info->alias,na } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<Item Name="[arity]">arity</Item>
</Expand>
<DisplayString>{{ arity={ arity } }}</DisplayString>
</Type>
<Type Name="entt::internal::meta_type_node">
<Intrinsic Name="has_property" Expression="!!(traits &amp; property)">
@@ -121,77 +49,73 @@
<Item Name="[id]">id</Item>
<Item Name="[sizeof]">size_of</Item>
<Item Name="[is_arithmetic]">has_property(entt::internal::meta_traits::is_arithmetic)</Item>
<Item Name="[is_integral]">has_property(entt::internal::meta_traits::is_integral)</Item>
<Item Name="[is_signed]">has_property(entt::internal::meta_traits::is_signed)</Item>
<Item Name="[is_array]">has_property(entt::internal::meta_traits::is_array)</Item>
<Item Name="[is_enum]">has_property(entt::internal::meta_traits::is_enum)</Item>
<Item Name="[is_class]">has_property(entt::internal::meta_traits::is_class)</Item>
<Item Name="[is_pointer]">has_property(entt::internal::meta_traits::is_pointer)</Item>
<Item Name="[is_meta_pointer_like]">has_property(entt::internal::meta_traits::is_meta_pointer_like)</Item>
<Item Name="[is_meta_sequence_container]">has_property(entt::internal::meta_traits::is_meta_sequence_container)</Item>
<Item Name="[is_meta_associative_container]">has_property(entt::internal::meta_traits::is_meta_associative_container)</Item>
<Item Name="[default_constructor]">default_constructor != nullptr</Item>
<Item Name="[conversion_helper]">conversion_helper != nullptr</Item>
<Item Name="[template_info]" Condition="templ != nullptr">*templ</Item>
<Synthetic Name="[ctor]" Condition="ctor != nullptr">
<Expand>
<LinkedListItems>
<HeadPointer>ctor</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
<Synthetic Name="[base]" Condition="base != nullptr">
<Expand>
<LinkedListItems>
<HeadPointer>base</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
<Synthetic Name="[conv]" Condition="conv != nullptr">
<Expand>
<LinkedListItems>
<HeadPointer>conv</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
<Synthetic Name="[data]" Condition="data != nullptr">
<Expand>
<LinkedListItems>
<HeadPointer>data</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
<Synthetic Name="[func]" Condition="func != nullptr">
<Expand>
<LinkedListItems>
<HeadPointer>func</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
<Synthetic Name="[prop]" Condition="prop != nullptr">
<Expand>
<LinkedListItems>
<HeadPointer>prop</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>*this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
<Item Name="[from_void]">from_void != nullptr</Item>
<Item Name="[template_info]">templ</Item>
<Item Name="[details]" Condition="details != nullptr">*details</Item>
</Expand>
</Type>
<Type Name="entt::meta_type">
<Type Name="entt::meta_any">
<DisplayString Condition="node.info != nullptr">{{ type={ node.info->alias,na }, policy={ storage.mode,en } }}</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem>node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
</Expand>
</Type>
<Type Name="entt::meta_handle">
<DisplayString>{ any }</DisplayString>
</Type>
<Type Name="entt::meta_associative_container">
<DisplayString>{ storage }</DisplayString>
<Expand>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
</Expand>
</Type>
<Type Name="entt::meta_sequence_container">
<DisplayString>{ storage }</DisplayString>
<Expand>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
</Expand>
</Type>
<Type Name="entt::meta_data">
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
</Expand>
</Type>
<Type Name="entt::meta_func">
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
</Expand>
</Type>
<Type Name="entt::meta_prop">
<DisplayString Condition="node != nullptr">{ *node }</DisplayString>
<DisplayString>{{}}</DisplayString>
<Expand>
<ExpandedItem Condition="node != nullptr">node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
</Expand>
</Type>
<Type Name="entt::meta_type">
<DisplayString>{ node }</DisplayString>
<Expand>
<ExpandedItem>node</ExpandedItem>
<Item Name="[context]" Condition="ctx != nullptr">ctx->value</Item>
</Expand>
</Type>
</AutoVisualizer>

View File

@@ -1,3 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="entt::resource&lt;*&gt;">
<DisplayString>{ value }</DisplayString>
<Expand>
<ExpandedItem>value</ExpandedItem>
</Expand>
</Type>
<Type Name="entt::resource_cache&lt;*&gt;">
<DisplayString>{ pool.first_base::value }</DisplayString>
<Expand>
<ExpandedItem>pool.first_base::value</ExpandedItem>
</Expand>
</Type>
</AutoVisualizer>

View File

@@ -1,35 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="entt::connection">
<DisplayString>{{ bound={ signal != nullptr } }}</DisplayString>
</Type>
<Type Name="entt::delegate&lt;*&gt;">
<DisplayString>{{ type={ "$T1" } }}</DisplayString>
<Expand>
<Item Name="[empty]">fn == nullptr</Item>
<Item Name="[data]">data</Item>
<Item Name="[data]">instance</Item>
</Expand>
</Type>
<Type Name="entt::dispatcher">
<DisplayString>{{ size={ pools.size() } }}</DisplayString>
<Type Name="entt::basic_dispatcher&lt;*&gt;">
<Intrinsic Name="size" Expression="pools.first_base::value.size()"/>
<DisplayString>{{ size={ size() } }}</DisplayString>
<Expand>
<Synthetic Name="[pools]">
<DisplayString>{ pools.size() }</DisplayString>
<DisplayString>{ size() }</DisplayString>
<Expand>
<IndexListItems>
<Size>pools.size()</Size>
<ValueNode>*pools.packed.first_base::value[$i].element.second</ValueNode>
<Size>size()</Size>
<ValueNode>*pools.first_base::value.packed.first_base::value[$i].element.second</ValueNode>
</IndexListItems>
</Expand>
</Synthetic>
</Expand>
</Type>
<Type Name="entt::dispatcher::pool_handler&lt;*&gt;">
<Type Name="entt::internal::dispatcher_handler&lt;*&gt;">
<DisplayString>{{ size={ events.size() }, event={ "$T1" } }}</DisplayString>
<Expand>
<Item Name="[signal]">signal</Item>
</Expand>
</Type>
<Type Name="entt::emitter&lt;*&gt;">
<DisplayString>{{ size={ handlers.first_base::value.packed.first_base::value.size() } }}</DisplayString>
</Type>
<Type Name="entt::connection">
<DisplayString>{{ bound={ signal != nullptr } }}</DisplayString>
</Type>
<Type Name="entt::scoped_connection">
<DisplayString>{ conn }</DisplayString>
</Type>
@@ -46,7 +50,6 @@
<DisplayString>{{ type={ "$T1" } }}</DisplayString>
<Expand>
<Item Name="[signal]">signal,na</Item>
<Item Name="[offset]">offset</Item>
</Expand>
</Type>
</AutoVisualizer>

File diff suppressed because it is too large Load Diff

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

@@ -1,35 +1,32 @@
#ifndef ENTT_CONFIG_CONFIG_H
#define ENTT_CONFIG_CONFIG_H
#include "version.h"
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
# define ENTT_NOEXCEPT noexcept
# define ENTT_CONSTEXPR
# define ENTT_THROW throw
# define ENTT_TRY try
# define ENTT_CATCH catch(...)
#else
# define ENTT_NOEXCEPT
# define ENTT_CONSTEXPR constexpr // use only with throwing functions (waiting for C++20)
# define ENTT_THROW
# define ENTT_TRY if(true)
# define ENTT_CATCH if(false)
#endif
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
# include <new>
# define ENTT_LAUNDER(expr) std::launder(expr)
#else
# define ENTT_LAUNDER(expr) expr
#endif
#ifndef ENTT_USE_ATOMIC
# define ENTT_MAYBE_ATOMIC(Type) Type
#else
#ifdef ENTT_USE_ATOMIC
# include <atomic>
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
#else
# define ENTT_MAYBE_ATOMIC(Type) Type
#endif
#ifndef ENTT_ID_TYPE
# include <cstdint>
# define ENTT_ID_TYPE std::uint32_t
#else
# include <cstdint> // provides coverage for types in the std namespace
#endif
#ifndef ENTT_SPARSE_PAGE
@@ -42,19 +39,31 @@
#ifdef ENTT_DISABLE_ASSERT
# undef ENTT_ASSERT
# define ENTT_ASSERT(...) (void(0))
# define ENTT_ASSERT(condition, msg) (void(0))
#elif !defined ENTT_ASSERT
# include <cassert>
# define ENTT_ASSERT(condition, ...) assert(condition)
# define ENTT_ASSERT(condition, msg) assert(condition)
#endif
#ifdef ENTT_DISABLE_ASSERT
# undef ENTT_ASSERT_CONSTEXPR
# define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0))
#elif !defined ENTT_ASSERT_CONSTEXPR
# define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg)
#endif
#define ENTT_FAIL(msg) ENTT_ASSERT(false, msg);
#ifdef ENTT_NO_ETO
# define ENTT_IGNORE_IF_EMPTY false
# define ENTT_ETO_TYPE(Type) void
#else
# define ENTT_IGNORE_IF_EMPTY true
# define ENTT_ETO_TYPE(Type) Type
#endif
#ifndef ENTT_STANDARD_CPP
#ifdef ENTT_STANDARD_CPP
# define ENTT_NONSTD false
#else
# define ENTT_NONSTD true
# if defined __clang__ || defined __GNUC__
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
# define ENTT_PRETTY_FUNCTION_PREFIX '='
@@ -66,4 +75,11 @@
# endif
#endif
#if defined _MSC_VER
# pragma detect_mismatch("entt.version", ENTT_VERSION)
# pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY))
# pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE))
# pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD))
#endif
#endif

7
src/entt/config/macro.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef ENTT_CONFIG_MACRO_H
#define ENTT_CONFIG_MACRO_H
#define ENTT_STR(arg) #arg
#define ENTT_XSTR(arg) ENTT_STR(arg)
#endif

View File

@@ -1,8 +1,14 @@
#ifndef ENTT_CONFIG_VERSION_H
#define ENTT_CONFIG_VERSION_H
#include "macro.h"
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 9
#define ENTT_VERSION_PATCH 0
#define ENTT_VERSION_MINOR 13
#define ENTT_VERSION_PATCH 2
#define ENTT_VERSION \
ENTT_XSTR(ENTT_VERSION_MAJOR) \
"." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH)
#endif

View File

@@ -1,7 +1,6 @@
#ifndef ENTT_CONTAINER_DENSE_HASH_SET_HPP
#define ENTT_CONTAINER_DENSE_HASH_SET_HPP
#ifndef ENTT_CONTAINER_DENSE_SET_HPP
#define ENTT_CONTAINER_DENSE_SET_HPP
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <functional>
@@ -20,184 +19,170 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type>
struct dense_hash_set_node final {
template<typename... Args>
dense_hash_set_node(const std::size_t pos, Args &&...args)
: next{pos},
element{std::forward<Args>(args)...} {}
std::size_t next;
Type element;
};
template<typename It>
class dense_hash_set_iterator {
friend dense_hash_set_iterator<const std::remove_pointer_t<It> *>;
using iterator_traits = std::iterator_traits<decltype(std::addressof(std::as_const(std::declval<It>()->element)))>;
class dense_set_iterator final {
template<typename>
friend class dense_set_iterator;
public:
using value_type = typename iterator_traits::value_type;
using pointer = typename iterator_traits::pointer;
using reference = typename iterator_traits::reference;
using difference_type = typename iterator_traits::difference_type;
using value_type = typename It::value_type::second_type;
using pointer = const value_type *;
using reference = const value_type &;
using difference_type = std::ptrdiff_t;
using iterator_category = std::random_access_iterator_tag;
dense_hash_set_iterator() ENTT_NOEXCEPT = default;
constexpr dense_set_iterator() noexcept
: it{} {}
dense_hash_set_iterator(const It iter) ENTT_NOEXCEPT
constexpr dense_set_iterator(const It iter) noexcept
: it{iter} {}
template<bool Const = std::is_const_v<std::remove_pointer_t<It>>, typename = std::enable_if_t<Const>>
dense_hash_set_iterator(const dense_hash_set_iterator<std::remove_const_t<std::remove_pointer_t<It>> *> &other)
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
constexpr dense_set_iterator(const dense_set_iterator<Other> &other) noexcept
: it{other.it} {}
dense_hash_set_iterator &operator++() ENTT_NOEXCEPT {
constexpr dense_set_iterator &operator++() noexcept {
return ++it, *this;
}
dense_hash_set_iterator operator++(int) ENTT_NOEXCEPT {
dense_hash_set_iterator orig = *this;
constexpr dense_set_iterator operator++(int) noexcept {
dense_set_iterator orig = *this;
return ++(*this), orig;
}
dense_hash_set_iterator &operator--() ENTT_NOEXCEPT {
constexpr dense_set_iterator &operator--() noexcept {
return --it, *this;
}
dense_hash_set_iterator operator--(int) ENTT_NOEXCEPT {
dense_hash_set_iterator orig = *this;
constexpr dense_set_iterator operator--(int) noexcept {
dense_set_iterator orig = *this;
return operator--(), orig;
}
dense_hash_set_iterator &operator+=(const difference_type value) ENTT_NOEXCEPT {
constexpr dense_set_iterator &operator+=(const difference_type value) noexcept {
it += value;
return *this;
}
dense_hash_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
dense_hash_set_iterator copy = *this;
constexpr dense_set_iterator operator+(const difference_type value) const noexcept {
dense_set_iterator copy = *this;
return (copy += value);
}
dense_hash_set_iterator &operator-=(const difference_type value) ENTT_NOEXCEPT {
constexpr dense_set_iterator &operator-=(const difference_type value) noexcept {
return (*this += -value);
}
dense_hash_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
constexpr dense_set_iterator operator-(const difference_type value) const noexcept {
return (*this + -value);
}
[[nodiscard]] reference operator[](const difference_type value) const {
return it[value].element;
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
return it[value].second;
}
[[nodiscard]] pointer operator->() const {
return std::addressof(it->element);
[[nodiscard]] constexpr pointer operator->() const noexcept {
return std::addressof(it->second);
}
[[nodiscard]] reference operator*() const {
[[nodiscard]] constexpr reference operator*() const noexcept {
return *operator->();
}
template<typename ILhs, typename IRhs>
friend auto operator-(const dense_hash_set_iterator<ILhs> &, const dense_hash_set_iterator<IRhs> &) ENTT_NOEXCEPT;
template<typename Lhs, typename Rhs>
friend constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
template<typename ILhs, typename IRhs>
friend bool operator==(const dense_hash_set_iterator<ILhs> &, const dense_hash_set_iterator<IRhs> &) ENTT_NOEXCEPT;
template<typename Lhs, typename Rhs>
friend constexpr bool operator==(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
template<typename ILhs, typename IRhs>
friend bool operator<(const dense_hash_set_iterator<ILhs> &, const dense_hash_set_iterator<IRhs> &) ENTT_NOEXCEPT;
template<typename Lhs, typename Rhs>
friend constexpr bool operator<(const dense_set_iterator<Lhs> &, const dense_set_iterator<Rhs> &) noexcept;
private:
It it;
};
template<typename ILhs, typename IRhs>
[[nodiscard]] auto operator-(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return lhs.it - rhs.it;
}
template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator==(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator==(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator!=(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator!=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return !(lhs == rhs);
}
template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator<(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator<(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return lhs.it < rhs.it;
}
template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator>(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator>(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return rhs < lhs;
}
template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator<=(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator<=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return !(lhs > rhs);
}
template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator>=(const dense_hash_set_iterator<ILhs> &lhs, const dense_hash_set_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator>=(const dense_set_iterator<Lhs> &lhs, const dense_set_iterator<Rhs> &rhs) noexcept {
return !(lhs < rhs);
}
template<typename It>
class dense_hash_set_local_iterator {
friend dense_hash_set_local_iterator<const std::remove_pointer_t<It> *>;
using iterator_traits = std::iterator_traits<decltype(std::addressof(std::as_const(std::declval<It>()->element)))>;
class dense_set_local_iterator final {
template<typename>
friend class dense_set_local_iterator;
public:
using value_type = typename iterator_traits::value_type;
using pointer = typename iterator_traits::pointer;
using reference = typename iterator_traits::reference;
using difference_type = typename iterator_traits::difference_type;
using value_type = typename It::value_type::second_type;
using pointer = const value_type *;
using reference = const value_type &;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
dense_hash_set_local_iterator() ENTT_NOEXCEPT = default;
constexpr dense_set_local_iterator() noexcept
: it{},
offset{} {}
dense_hash_set_local_iterator(It iter, const std::size_t pos) ENTT_NOEXCEPT
constexpr dense_set_local_iterator(It iter, const std::size_t pos) noexcept
: it{iter},
offset{pos} {}
template<bool Const = std::is_const_v<std::remove_pointer_t<It>>, typename = std::enable_if_t<Const>>
dense_hash_set_local_iterator(const dense_hash_set_local_iterator<std::remove_const_t<std::remove_pointer_t<It>> *> &other)
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
constexpr dense_set_local_iterator(const dense_set_local_iterator<Other> &other) noexcept
: it{other.it},
offset{other.offset} {}
dense_hash_set_local_iterator &operator++() ENTT_NOEXCEPT {
return offset = it[offset].next, *this;
constexpr dense_set_local_iterator &operator++() noexcept {
return offset = it[offset].first, *this;
}
dense_hash_set_local_iterator operator++(int) ENTT_NOEXCEPT {
dense_hash_set_local_iterator orig = *this;
constexpr dense_set_local_iterator operator++(int) noexcept {
dense_set_local_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] pointer operator->() const {
return std::addressof(it[offset].element);
[[nodiscard]] constexpr pointer operator->() const noexcept {
return std::addressof(it[offset].second);
}
[[nodiscard]] reference operator*() const {
[[nodiscard]] constexpr reference operator*() const noexcept {
return *operator->();
}
[[nodiscard]] std::size_t index() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr std::size_t index() const noexcept {
return offset;
}
@@ -206,22 +191,18 @@ private:
std::size_t offset;
};
template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator==(const dense_hash_set_local_iterator<ILhs> &lhs, const dense_hash_set_local_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator==(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
return lhs.index() == rhs.index();
}
template<typename ILhs, typename IRhs>
[[nodiscard]] bool operator!=(const dense_hash_set_local_iterator<ILhs> &lhs, const dense_hash_set_local_iterator<IRhs> &rhs) ENTT_NOEXCEPT {
template<typename Lhs, typename Rhs>
[[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator<Lhs> &lhs, const dense_set_local_iterator<Rhs> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief Associative container for unique objects of a given type.
@@ -236,27 +217,26 @@ template<typename ILhs, typename IRhs>
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Type, typename Hash, typename KeyEqual, typename Allocator>
class dense_hash_set final {
class dense_set {
static constexpr float default_threshold = 0.875f;
static constexpr std::size_t minimum_capacity = 8u;
using allocator_traits = std::allocator_traits<Allocator>;
using alloc = typename allocator_traits::template rebind_alloc<Type>;
using alloc_traits = typename std::allocator_traits<alloc>;
using node_type = internal::dense_hash_set_node<Type>;
using node_type = std::pair<std::size_t, Type>;
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Type>, "Invalid value type");
using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
using packed_container_type = std::vector<node_type, typename alloc_traits::template rebind_alloc<node_type>>;
[[nodiscard]] std::size_t hash_to_bucket(const std::size_t hash) const ENTT_NOEXCEPT {
return fast_mod(hash, bucket_count());
template<typename Other>
[[nodiscard]] std::size_t value_to_bucket(const Other &value) const noexcept {
return fast_mod(static_cast<size_type>(sparse.second()(value)), bucket_count());
}
template<typename Other>
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) {
for(auto it = begin(bucket), last = end(bucket); it != last; ++it) {
if(packed.second()(*it, value)) {
return begin() + it.index();
return begin() + static_cast<typename iterator::difference_type>(it.index());
}
}
@@ -267,61 +247,45 @@ class dense_hash_set final {
[[nodiscard]] auto constrained_find(const Other &value, std::size_t bucket) const {
for(auto it = cbegin(bucket), last = cend(bucket); it != last; ++it) {
if(packed.second()(*it, value)) {
return cbegin() + it.index();
return cbegin() + static_cast<typename iterator::difference_type>(it.index());
}
}
return cend();
}
template<typename Arg>
[[nodiscard]] auto get_or_emplace(Arg &&arg) {
const auto hash = sparse.second()(arg);
auto index = hash_to_bucket(hash);
template<typename Other>
[[nodiscard]] auto insert_or_do_nothing(Other &&value) {
const auto index = value_to_bucket(value);
if(auto it = constrained_find(arg, index); it != end()) {
if(auto it = constrained_find(value, index); it != end()) {
return std::make_pair(it, false);
}
if(const auto count = size() + 1u; count > (bucket_count() * max_load_factor())) {
rehash(bucket_count() * 2u);
index = hash_to_bucket(hash);
}
packed.first().emplace_back(sparse.first()[index], std::forward<Arg>(arg));
// update goes after emplace to enforce exception guarantees
sparse.first()[index] = size() - 1u;
packed.first().emplace_back(sparse.first()[index], std::forward<Other>(value));
sparse.first()[index] = packed.first().size() - 1u;
rehash_if_required();
return std::make_pair(--end(), true);
}
template<typename Other>
bool do_erase(const Other &value) {
for(size_type *curr = sparse.first().data() + bucket(value); *curr != std::numeric_limits<size_type>::max(); curr = &packed.first()[*curr].next) {
if(packed.second()(packed.first()[*curr].element, value)) {
const auto index = *curr;
*curr = packed.first()[*curr].next;
move_and_pop(index);
return true;
}
}
return false;
}
void move_and_pop(const std::size_t pos) {
if(const auto last = size() - 1u; pos != last) {
size_type *curr = sparse.first().data() + bucket(packed.first().back().element);
for(; *curr != last; curr = &packed.first()[*curr].next) {}
*curr = pos;
// basic exception guarantees when value type has a throwing move constructor
size_type *curr = sparse.first().data() + value_to_bucket(packed.first().back().second);
packed.first()[pos] = std::move(packed.first().back());
for(; *curr != last; curr = &packed.first()[*curr].first) {}
*curr = pos;
}
packed.first().pop_back();
}
void rehash_if_required() {
if(size() > (bucket_count() * max_load_factor())) {
rehash(bucket_count() * 2u);
}
}
public:
/*! @brief Key type of the container. */
using key_type = Type;
@@ -336,179 +300,194 @@ public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Random access iterator type. */
using iterator = internal::dense_hash_set_iterator<typename packed_container_type::pointer>;
using iterator = internal::dense_set_iterator<typename packed_container_type::iterator>;
/*! @brief Constant random access iterator type. */
using const_iterator = internal::dense_hash_set_iterator<typename packed_container_type::const_pointer>;
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_hash_set_local_iterator<typename packed_container_type::pointer>;
using local_iterator = internal::dense_set_local_iterator<typename packed_container_type::iterator>;
/*! @brief Constant forward iterator type. */
using const_local_iterator = internal::dense_hash_set_local_iterator<typename packed_container_type::const_pointer>;
using const_local_iterator = internal::dense_set_local_iterator<typename packed_container_type::const_iterator>;
/*! @brief Default constructor. */
dense_hash_set()
: dense_hash_set(minimum_capacity) {}
dense_set()
: dense_set{minimum_capacity} {}
/**
* @brief Constructs an empty container with a given allocator.
* @param allocator The allocator to use.
*/
explicit dense_hash_set(const allocator_type &allocator)
: dense_hash_set{minimum_capacity, hasher{}, key_equal{}, allocator} {}
explicit dense_set(const allocator_type &allocator)
: dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {}
/**
* @brief Constructs an empty container with a given allocator and user
* supplied minimal number of buckets.
* @param bucket_count Minimal number of buckets.
* @param cnt Minimal number of buckets.
* @param allocator The allocator to use.
*/
dense_hash_set(const size_type bucket_count, const allocator_type &allocator)
: dense_hash_set{bucket_count, hasher{}, key_equal{}, allocator} {}
dense_set(const size_type cnt, const allocator_type &allocator)
: dense_set{cnt, hasher{}, key_equal{}, allocator} {}
/**
* @brief Constructs an empty container with a given allocator, hash
* function and user supplied minimal number of buckets.
* @param bucket_count Minimal number of buckets.
* @param cnt Minimal number of buckets.
* @param hash Hash function to use.
* @param allocator The allocator to use.
*/
dense_hash_set(const size_type bucket_count, const hasher &hash, const allocator_type &allocator)
: dense_hash_set{bucket_count, hash, key_equal{}, allocator} {}
dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator)
: dense_set{cnt, hash, key_equal{}, allocator} {}
/**
* @brief Constructs an empty container with a given allocator, hash
* function, compare function and user supplied minimal number of buckets.
* @param bucket_count Minimal number of buckets.
* @param cnt Minimal number of buckets.
* @param hash Hash function to use.
* @param equal Compare function to use.
* @param allocator The allocator to use.
*/
explicit dense_hash_set(const size_type bucket_count, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type())
explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{})
: sparse{allocator, hash},
packed{allocator, equal},
threshold{default_threshold} {
rehash(bucket_count);
rehash(cnt);
}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
dense_hash_set(const dense_hash_set &other)
: dense_hash_set{other, alloc_traits::select_on_container_copy_construction(other.get_allocator())} {}
/*! @brief Default copy constructor. */
dense_set(const dense_set &) = default;
/**
* @brief Allocator-extended copy constructor.
* @param other The instance to copy from.
* @param allocator The allocator to use.
*/
dense_hash_set(const dense_hash_set &other, const allocator_type &allocator)
: sparse{sparse_container_type{other.sparse.first(), allocator}, other.sparse.second()},
// cannot copy the container directly due to a nasty issue of apple clang :(
packed{packed_container_type{other.packed.first().begin(), other.packed.first().end(), allocator}, other.packed.second()},
threshold{other.threshold} {
}
dense_set(const dense_set &other, const allocator_type &allocator)
: sparse{std::piecewise_construct, std::forward_as_tuple(other.sparse.first(), allocator), std::forward_as_tuple(other.sparse.second())},
packed{std::piecewise_construct, std::forward_as_tuple(other.packed.first(), allocator), std::forward_as_tuple(other.packed.second())},
threshold{other.threshold} {}
/**
* @brief Default move constructor.
* @param other The instance to move from.
*/
dense_hash_set(dense_hash_set &&other) ENTT_NOEXCEPT = default;
/*! @brief Default move constructor. */
dense_set(dense_set &&) noexcept(std::is_nothrow_move_constructible_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_constructible_v<compressed_pair<packed_container_type, key_equal>>) = default;
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
dense_hash_set(dense_hash_set &&other, const allocator_type &allocator) ENTT_NOEXCEPT
: sparse{sparse_container_type{std::move(other.sparse.first()), allocator}, std::move(other.sparse.second())},
// cannot move the container directly due to a nasty issue of apple clang :(
packed{packed_container_type{std::make_move_iterator(other.packed.first().begin()), std::make_move_iterator(other.packed.first().end()), allocator}, std::move(other.packed.second())},
dense_set(dense_set &&other, const allocator_type &allocator)
: sparse{std::piecewise_construct, std::forward_as_tuple(std::move(other.sparse.first()), allocator), std::forward_as_tuple(std::move(other.sparse.second()))},
packed{std::piecewise_construct, std::forward_as_tuple(std::move(other.packed.first()), allocator), std::forward_as_tuple(std::move(other.packed.second()))},
threshold{other.threshold} {}
/*! @brief Default destructor. */
~dense_hash_set() = default;
/**
* @brief Copy assignment operator.
* @param other The instance to copy from.
* @brief Default copy assignment operator.
* @return This container.
*/
dense_hash_set &operator=(const dense_hash_set &other) {
threshold = other.threshold;
sparse.first().clear();
packed.first().clear();
rehash(other.bucket_count());
packed.first().reserve(other.packed.first().size());
insert(other.cbegin(), other.cend());
return *this;
}
dense_set &operator=(const dense_set &) = default;
/**
* @brief Default move assignment operator.
* @param other The instance to move from.
* @return This container.
*/
dense_hash_set &operator=(dense_hash_set &&other) ENTT_NOEXCEPT = default;
dense_set &operator=(dense_set &&) noexcept(std::is_nothrow_move_assignable_v<compressed_pair<sparse_container_type, hasher>> &&std::is_nothrow_move_assignable_v<compressed_pair<packed_container_type, key_equal>>) = default;
/**
* @brief Returns the associated allocator.
* @return The associated allocator.
*/
[[nodiscard]] constexpr allocator_type get_allocator() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
return sparse.first().get_allocator();
}
/**
* @brief Returns an iterator to the beginning.
*
* The returned iterator points to the first instance of the internal array.
* If the array is empty, the returned iterator will be equal to `end()`.
*
* @return An iterator to the first instance of the internal array.
*/
[[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT {
return packed.first().data();
[[nodiscard]] const_iterator cbegin() const noexcept {
return packed.first().begin();
}
/*! @copydoc cbegin */
[[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT {
[[nodiscard]] const_iterator begin() const noexcept {
return cbegin();
}
/*! @copydoc begin */
[[nodiscard]] iterator begin() ENTT_NOEXCEPT {
return packed.first().data();
[[nodiscard]] iterator begin() noexcept {
return packed.first().begin();
}
/**
* @brief Returns an iterator to the end.
*
* The returned iterator points to the element following the last instance
* of the internal array. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @return An iterator to the element following the last instance of the
* internal array.
*/
[[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT {
return packed.first().data() + size();
[[nodiscard]] const_iterator cend() const noexcept {
return packed.first().end();
}
/*! @copydoc cend */
[[nodiscard]] const_iterator end() const ENTT_NOEXCEPT {
[[nodiscard]] const_iterator end() const noexcept {
return cend();
}
/*! @copydoc end */
[[nodiscard]] iterator end() ENTT_NOEXCEPT {
return packed.first().data() + size();
[[nodiscard]] iterator end() noexcept {
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.
*/
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
[[nodiscard]] bool empty() const noexcept {
return packed.first().empty();
}
@@ -516,12 +495,20 @@ public:
* @brief Returns the number of elements in a container.
* @return Number of elements in a container.
*/
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
[[nodiscard]] size_type size() const noexcept {
return packed.first().size();
}
/**
* @brief Returns the maximum possible number of elements.
* @return Maximum possible number of elements.
*/
[[nodiscard]] size_type max_size() const noexcept {
return packed.first().max_size();
}
/*! @brief Clears the container. */
void clear() ENTT_NOEXCEPT {
void clear() noexcept {
sparse.first().clear();
packed.first().clear();
rehash(0u);
@@ -535,12 +522,12 @@ public:
* insertion took place.
*/
std::pair<iterator, bool> insert(const value_type &value) {
return emplace(value);
return insert_or_do_nothing(value);
}
/*! @copydoc insert */
std::pair<iterator, bool> insert(value_type &&value) {
return emplace(std::move(value));
return insert_or_do_nothing(std::move(value));
}
/**
@@ -552,12 +539,16 @@ public:
template<typename It>
void insert(It first, It last) {
for(; first != last; ++first) {
emplace(*first);
insert(*first);
}
}
/**
* @brief Constructs an element in-place, if it does not exist.
*
* The element is also constructed when the container already has the key,
* in which case the newly constructed object is destroyed immediately.
*
* @tparam Args Types of arguments to forward to the constructor of the
* element.
* @param args Arguments to forward to the constructor of the element.
@@ -567,10 +558,21 @@ public:
*/
template<typename... Args>
std::pair<iterator, bool> emplace(Args &&...args) {
if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::remove_const_t<std::remove_reference_t<Args>>, value_type>)) {
return get_or_emplace(std::forward<Args>(args)...);
if constexpr(((sizeof...(Args) == 1u) && ... && std::is_same_v<std::decay_t<Args>, value_type>)) {
return insert_or_do_nothing(std::forward<Args>(args)...);
} else {
return get_or_emplace(value_type{std::forward<Args>(args)...});
auto &node = packed.first().emplace_back(std::piecewise_construct, std::make_tuple(packed.first().size()), std::forward_as_tuple(std::forward<Args>(args)...));
const auto index = value_to_bucket(node.second);
if(auto it = constrained_find(node.second, index); it != end()) {
packed.first().pop_back();
return std::make_pair(it, false);
}
std::swap(node.first, sparse.first()[index]);
rehash_if_required();
return std::make_pair(--end(), true);
}
}
@@ -580,9 +582,9 @@ public:
* @return An iterator following the removed element.
*/
iterator erase(const_iterator pos) {
const auto dist = std::distance(cbegin(), pos);
const auto diff = pos - cbegin();
erase(*pos);
return begin() + dist;
return begin() + diff;
}
/**
@@ -592,13 +594,13 @@ public:
* @return An iterator following the last removed element.
*/
iterator erase(const_iterator first, const_iterator last) {
const auto dist = std::distance(cbegin(), first);
const auto dist = first - cbegin();
for(auto rfirst = std::make_reverse_iterator(last), rlast = std::make_reverse_iterator(first); rfirst != rlast; ++rfirst) {
erase(*rfirst);
for(auto from = last - cbegin(); from != dist; --from) {
erase(packed.first()[from - 1u].second);
}
return dist > static_cast<decltype(dist)>(size()) ? end() : (begin() + dist);
return (begin() + dist);
}
/**
@@ -607,20 +609,50 @@ public:
* @return Number of elements removed (either 0 or 1).
*/
size_type erase(const value_type &value) {
return do_erase(value);
for(size_type *curr = sparse.first().data() + value_to_bucket(value); *curr != (std::numeric_limits<size_type>::max)(); curr = &packed.first()[*curr].first) {
if(packed.second()(packed.first()[*curr].second, value)) {
const auto index = *curr;
*curr = packed.first()[*curr].first;
move_and_pop(index);
return 1u;
}
}
return 0u;
}
/**
* @brief Exchanges the contents with those of a given container.
* @param other Container to exchange the content with.
*/
void swap(dense_hash_set &other) {
void swap(dense_set &other) {
using std::swap;
swap(sparse, other.sparse);
swap(packed, other.packed);
swap(threshold, other.threshold);
}
/**
* @brief Returns the number of elements matching a value (either 1 or 0).
* @param key Key value of an element to search for.
* @return Number of elements matching the key (either 1 or 0).
*/
[[nodiscard]] size_type count(const value_type &key) const {
return find(key) != end();
}
/**
* @brief Returns the number of elements matching a key (either 1 or 0).
* @tparam Other Type of the key value of an element to search for.
* @param key Key value of an element to search for.
* @return Number of elements matching the key (either 1 or 0).
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, size_type>>
count(const Other &key) const {
return find(key) != end();
}
/**
* @brief Finds an element with a given value.
* @param value Value of an element to search for.
@@ -628,12 +660,12 @@ public:
* element is found, a past-the-end iterator is returned.
*/
[[nodiscard]] iterator find(const value_type &value) {
return constrained_find(value, bucket(value));
return constrained_find(value, value_to_bucket(value));
}
/*! @copydoc find */
[[nodiscard]] const_iterator find(const value_type &value) const {
return constrained_find(value, bucket(value));
return constrained_find(value, value_to_bucket(value));
}
/**
@@ -646,14 +678,54 @@ public:
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, iterator>>
find(const Other &value) {
return constrained_find(value, bucket(value));
return constrained_find(value, value_to_bucket(value));
}
/*! @copydoc find */
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, const_iterator>>
find(const Other &value) const {
return constrained_find(value, bucket(value));
return constrained_find(value, value_to_bucket(value));
}
/**
* @brief Returns a range containing all elements with a given value.
* @param value Value of an element to search for.
* @return A pair of iterators pointing to the first element and past the
* last element of the range.
*/
[[nodiscard]] std::pair<iterator, iterator> equal_range(const value_type &value) {
const auto it = find(value);
return {it, it + !(it == end())};
}
/*! @copydoc equal_range */
[[nodiscard]] std::pair<const_iterator, const_iterator> equal_range(const value_type &value) const {
const auto it = find(value);
return {it, it + !(it == cend())};
}
/**
* @brief Returns a range containing all elements that compare _equivalent_
* to a given value.
* @tparam Other Type of an element to search for.
* @param value Value of an element to search for.
* @return A pair of iterators pointing to the first element and past the
* last element of the range.
*/
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<iterator, iterator>>>
equal_range(const Other &value) {
const auto it = find(value);
return {it, it + !(it == end())};
}
/*! @copydoc equal_range */
template<typename Other>
[[nodiscard]] std::enable_if_t<is_transparent_v<hasher> && is_transparent_v<key_equal>, std::conditional_t<false, Other, std::pair<const_iterator, const_iterator>>>
equal_range(const Other &value) const {
const auto it = find(value);
return {it, it + !(it == cend())};
}
/**
@@ -684,7 +756,7 @@ public:
* @return An iterator to the beginning of the given bucket.
*/
[[nodiscard]] const_local_iterator cbegin(const size_type index) const {
return {packed.first().data(), sparse.first()[index]};
return {packed.first().begin(), sparse.first()[index]};
}
/**
@@ -702,7 +774,7 @@ public:
* @return An iterator to the beginning of the given bucket.
*/
[[nodiscard]] local_iterator begin(const size_type index) {
return {packed.first().data(), sparse.first()[index]};
return {packed.first().begin(), sparse.first()[index]};
}
/**
@@ -711,7 +783,7 @@ public:
* @return An iterator to the end of the given bucket.
*/
[[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const {
return {packed.first().data(), std::numeric_limits<size_type>::max()};
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
}
/**
@@ -719,7 +791,7 @@ public:
* @param index An index of a bucket to access.
* @return An iterator to the end of the given bucket.
*/
[[nodiscard]] const_local_iterator end([[maybe_unused]] const size_type index) const {
[[nodiscard]] const_local_iterator end(const size_type index) const {
return cend(index);
}
@@ -729,7 +801,7 @@ public:
* @return An iterator to the end of the given bucket.
*/
[[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) {
return {packed.first().data(), std::numeric_limits<size_type>::max()};
return {packed.first().begin(), (std::numeric_limits<size_type>::max)()};
}
/**
@@ -763,7 +835,7 @@ public:
* @return The bucket for the given element.
*/
[[nodiscard]] size_type bucket(const value_type &value) const {
return hash_to_bucket(sparse.second()(value));
return value_to_bucket(value);
}
/**
@@ -795,19 +867,23 @@ public:
/**
* @brief Reserves at least the specified number of buckets and regenerates
* the hash table.
* @param count New number of buckets.
* @param cnt New number of buckets.
*/
void rehash(const size_type count) {
auto value = (std::max)(count, minimum_capacity);
value = (std::max)(value, static_cast<size_type>(size() / max_load_factor()));
void rehash(const size_type cnt) {
auto value = cnt > minimum_capacity ? cnt : minimum_capacity;
const auto cap = static_cast<size_type>(size() / max_load_factor());
value = value > cap ? value : cap;
if(const auto sz = next_power_of_two(value); sz != bucket_count()) {
sparse.first().resize(sz);
std::fill(sparse.first().begin(), sparse.first().end(), std::numeric_limits<size_type>::max());
for(auto &&elem: sparse.first()) {
elem = (std::numeric_limits<size_type>::max)();
}
for(size_type pos{}, last = size(); pos < last; ++pos) {
const auto index = bucket(packed.first()[pos].element);
packed.first()[pos].next = std::exchange(sparse.first()[index], pos);
const auto index = value_to_bucket(packed.first()[pos].second);
packed.first()[pos].first = std::exchange(sparse.first()[index], pos);
}
}
}
@@ -815,11 +891,11 @@ public:
/**
* @brief Reserves space for at least the specified number of elements and
* regenerates the hash table.
* @param count New number of elements.
* @param cnt New number of elements.
*/
void reserve(const size_type count) {
packed.first().reserve(count);
rehash(static_cast<size_type>(std::ceil(count / max_load_factor())));
void reserve(const size_type cnt) {
packed.first().reserve(cnt);
rehash(static_cast<size_type>(std::ceil(cnt / max_load_factor())));
}
/**

View File

@@ -3,22 +3,24 @@
#include <functional>
#include <memory>
#include <utility>
namespace entt {
template<
typename Key, typename Type,
typename Key,
typename Type,
typename = std::hash<Key>,
typename = std::equal_to<Key>,
typename = std::allocator<std::pair<const Key, Type>>>
class dense_hash_map;
class dense_map;
template<
typename Type,
typename = std::hash<Type>,
typename = std::equal_to<Type>,
typename = std::allocator<Type>>
class dense_hash_set;
class dense_set;
} // namespace entt

View File

@@ -95,14 +95,15 @@ struct radix_sort {
template<typename It, typename Getter = identity>
void operator()(It first, It last, Getter getter = Getter{}) const {
if(first < last) {
static constexpr auto mask = (1 << Bit) - 1;
static constexpr auto buckets = 1 << Bit;
static constexpr auto passes = N / Bit;
constexpr auto passes = N / Bit;
using value_type = typename std::iterator_traits<It>::value_type;
std::vector<value_type> aux(std::distance(first, last));
auto part = [getter = std::move(getter)](auto from, auto to, auto out, auto start) {
constexpr auto mask = (1 << Bit) - 1;
constexpr auto buckets = 1 << Bit;
std::size_t index[buckets]{};
std::size_t count[buckets]{};

View File

@@ -13,6 +13,32 @@
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
enum class any_operation : std::uint8_t {
copy,
move,
transfer,
assign,
destroy,
compare,
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
};
/**
* @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.
@@ -20,82 +46,70 @@ namespace entt {
*/
template<std::size_t Len, std::size_t Align>
class basic_any {
enum class operation : std::uint8_t {
copy,
move,
transfer,
assign,
destroy,
compare,
get
};
enum class policy : std::uint8_t {
owner,
ref,
cref
};
using storage_type = std::aligned_storage_t<Len + !Len, Align>;
using operation = internal::any_operation;
using vtable_type = const void *(const operation, const basic_any &, const void *);
template<typename Type>
static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v<Type>;
struct storage_type {
alignas(Align) std::byte data[Len + !Len];
};
template<typename Type>
static const void *basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &value, [[maybe_unused]] const void *other) {
static_assert(!std::is_same_v<Type, void> && std::is_same_v<std::remove_reference_t<std::remove_const_t<Type>>, Type>, "Invalid type");
const Type *instance = nullptr;
static constexpr bool in_situ = Len && alignof(Type) <= Align && sizeof(Type) <= Len && std::is_nothrow_move_constructible_v<Type>;
template<typename Type>
static const void *basic_vtable(const operation op, const basic_any &value, const void *other) {
static_assert(!std::is_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>) {
instance = (value.mode == policy::owner) ? ENTT_LAUNDER(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 {
instance = static_cast<const Type *>(value.instance);
element = static_cast<const Type *>(value.instance);
}
switch(op) {
case operation::copy:
if constexpr(std::is_copy_constructible_v<Type>) {
static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*instance);
static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*element);
}
break;
case operation::move:
if constexpr(in_situ<Type>) {
if(value.mode == policy::owner) {
return new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(instance))};
if(value.mode == any_policy::owner) {
return new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(element))};
}
}
return (static_cast<basic_any *>(const_cast<void *>(other))->instance = std::exchange(const_cast<basic_any &>(value).instance, nullptr));
case operation::transfer:
if constexpr(std::is_move_assignable_v<Type>) {
*const_cast<Type *>(instance) = std::move(*static_cast<Type *>(const_cast<void *>(other)));
*const_cast<Type *>(element) = std::move(*static_cast<Type *>(const_cast<void *>(other)));
return other;
}
[[fallthrough]];
case operation::assign:
if constexpr(std::is_copy_assignable_v<Type>) {
*const_cast<Type *>(instance) = *static_cast<const Type *>(other);
*const_cast<Type *>(element) = *static_cast<const Type *>(other);
return other;
}
break;
case operation::destroy:
if constexpr(in_situ<Type>) {
instance->~Type();
element->~Type();
} else if constexpr(std::is_array_v<Type>) {
delete[] instance;
delete[] element;
} else {
delete instance;
delete element;
}
break;
case operation::compare:
if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
return *static_cast<const Type *>(instance) == *static_cast<const Type *>(other) ? other : nullptr;
return *element == *static_cast<const Type *>(other) ? other : nullptr;
} else {
return (instance == other) ? other : nullptr;
return (element == other) ? other : nullptr;
}
case operation::get:
return instance;
return element;
}
return nullptr;
@@ -103,31 +117,32 @@ class basic_any {
template<typename Type, typename... Args>
void initialize([[maybe_unused]] Args &&...args) {
info = &type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
if constexpr(!std::is_void_v<Type>) {
vtable = basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>;
info = &type_id<Type>();
vtable = basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
if constexpr(std::is_lvalue_reference_v<Type>) {
static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments");
mode = std::is_const_v<std::remove_reference_t<Type>> ? policy::cref : policy::ref;
static_assert((std::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "Invalid arguments");
mode = std::is_const_v<std::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
instance = (std::addressof(args), ...);
} else if constexpr(in_situ<Type>) {
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
new(&storage) Type{std::forward<Args>(args)...};
} else if constexpr(in_situ<std::remove_cv_t<std::remove_reference_t<Type>>>) {
if constexpr(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>)) {
new(&storage) std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...};
} else {
new(&storage) Type(std::forward<Args>(args)...);
new(&storage) std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...);
}
} else {
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
instance = new Type{std::forward<Args>(args)...};
if constexpr(std::is_aggregate_v<std::remove_cv_t<std::remove_reference_t<Type>>> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>)) {
instance = new std::remove_cv_t<std::remove_reference_t<Type>>{std::forward<Args>(args)...};
} else {
instance = new Type(std::forward<Args>(args)...);
instance = new std::remove_cv_t<std::remove_reference_t<Type>>(std::forward<Args>(args)...);
}
}
}
}
basic_any(const basic_any &other, const policy pol) ENTT_NOEXCEPT
basic_any(const basic_any &other, const any_policy pol) noexcept
: instance{other.data()},
info{other.info},
vtable{other.vtable},
@@ -140,11 +155,8 @@ public:
static constexpr auto alignment = Align;
/*! @brief Default constructor. */
basic_any() ENTT_NOEXCEPT
: instance{},
info{&type_id<void>()},
vtable{},
mode{policy::owner} {}
constexpr basic_any() noexcept
: basic_any{std::in_place_type<void>} {}
/**
* @brief Constructs a wrapper by directly initializing the new object.
@@ -154,7 +166,10 @@ public:
*/
template<typename Type, typename... Args>
explicit basic_any(std::in_place_type_t<Type>, Args &&...args)
: basic_any{} {
: instance{},
info{},
vtable{},
mode{any_policy::owner} {
initialize<Type>(std::forward<Args>(args)...);
}
@@ -165,9 +180,7 @@ public:
*/
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
basic_any(Type &&value)
: basic_any{} {
initialize<std::decay_t<Type>>(std::forward<Type>(value));
}
: basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
/**
* @brief Copy constructor.
@@ -184,7 +197,7 @@ public:
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_any(basic_any &&other) ENTT_NOEXCEPT
basic_any(basic_any &&other) noexcept
: instance{},
info{other.info},
vtable{other.vtable},
@@ -196,7 +209,7 @@ public:
/*! @brief Frees the internal storage, whatever it means. */
~basic_any() {
if(vtable && mode == policy::owner) {
if(vtable && (mode == any_policy::owner)) {
vtable(operation::destroy, *this, nullptr);
}
}
@@ -221,7 +234,7 @@ public:
* @param other The instance to move from.
* @return This any object.
*/
basic_any &operator=(basic_any &&other) ENTT_NOEXCEPT {
basic_any &operator=(basic_any &&other) noexcept {
reset();
if(other.vtable) {
@@ -251,7 +264,7 @@ public:
* @brief Returns the object type if any, `type_id<void>()` otherwise.
* @return The object type if any, `type_id<void>()` otherwise.
*/
[[nodiscard]] const type_info &type() const ENTT_NOEXCEPT {
[[nodiscard]] const type_info &type() const noexcept {
return *info;
}
@@ -259,7 +272,7 @@ public:
* @brief Returns an opaque pointer to the contained instance.
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] const void *data() const ENTT_NOEXCEPT {
[[nodiscard]] const void *data() const noexcept {
return vtable ? vtable(operation::get, *this, nullptr) : nullptr;
}
@@ -268,7 +281,7 @@ public:
* @param req Expected type.
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] const void *data(const type_info &req) const ENTT_NOEXCEPT {
[[nodiscard]] const void *data(const type_info &req) const noexcept {
return *info == req ? data() : nullptr;
}
@@ -276,8 +289,8 @@ public:
* @brief Returns an opaque pointer to the contained instance.
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] void *data() ENTT_NOEXCEPT {
return (!vtable || mode == policy::cref) ? nullptr : const_cast<void *>(vtable(operation::get, *this, nullptr));
[[nodiscard]] void *data() noexcept {
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data());
}
/**
@@ -285,8 +298,8 @@ public:
* @param req Expected type.
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] void *data(const type_info &req) ENTT_NOEXCEPT {
return *info == req ? data() : nullptr;
[[nodiscard]] void *data(const type_info &req) noexcept {
return mode == any_policy::cref ? nullptr : const_cast<void *>(std::as_const(*this).data(req));
}
/**
@@ -302,25 +315,21 @@ public:
}
/**
* @brief Copy assigns a value to the contained object without replacing it.
* @brief Assigns a value to the contained object without replacing it.
* @param other The value to assign to the contained object.
* @return True in case of success, false otherwise.
*/
bool assign(const any &other) {
if(vtable && mode != policy::cref && *info == *other.info) {
bool assign(const basic_any &other) {
if(vtable && mode != any_policy::cref && *info == *other.info) {
return (vtable(operation::assign, *this, other.data()) != nullptr);
}
return false;
}
/**
* @brief Move assigns a value to the contained object without replacing it.
* @param other The value to assign to the contained object.
* @return True in case of success, false otherwise.
*/
bool assign(any &&other) {
if(vtable && mode != policy::cref && *info == *other.info) {
/*! @copydoc assign */
bool assign(basic_any &&other) {
if(vtable && mode != any_policy::cref && *info == *other.info) {
if(auto *val = other.data(); val) {
return (vtable(operation::transfer, *this, val) != nullptr);
} else {
@@ -333,20 +342,22 @@ public:
/*! @brief Destroys contained object */
void reset() {
if(vtable && mode == policy::owner) {
if(vtable && (mode == any_policy::owner)) {
vtable(operation::destroy, *this, nullptr);
}
// unnecessary but it helps to detect nasty bugs
ENTT_ASSERT((instance = nullptr) == nullptr, "");
info = &type_id<void>();
vtable = nullptr;
mode = policy::owner;
mode = any_policy::owner;
}
/**
* @brief Returns false if a wrapper is empty, true otherwise.
* @return False if the wrapper is empty, true otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
[[nodiscard]] explicit operator bool() const noexcept {
return vtable != nullptr;
}
@@ -355,7 +366,7 @@ public:
* @param other Wrapper with which to compare.
* @return False if the two objects differ in their content, true otherwise.
*/
bool operator==(const basic_any &other) const ENTT_NOEXCEPT {
[[nodiscard]] bool operator==(const basic_any &other) const noexcept {
if(vtable && *info == *other.info) {
return (vtable(operation::compare, *this, other.data()) != nullptr);
}
@@ -363,25 +374,42 @@ public:
return (!vtable && !other.vtable);
}
/**
* @brief Checks if two wrappers differ in their content.
* @param other Wrapper with which to compare.
* @return True if the two objects differ in their content, false otherwise.
*/
[[nodiscard]] bool operator!=(const basic_any &other) const noexcept {
return !(*this == other);
}
/**
* @brief Aliasing constructor.
* @return A wrapper that shares a reference to an unmanaged object.
*/
[[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT {
return basic_any{*this, (mode == policy::cref ? policy::cref : policy::ref)};
[[nodiscard]] basic_any as_ref() noexcept {
return basic_any{*this, (mode == any_policy::cref ? any_policy::cref : any_policy::ref)};
}
/*! @copydoc as_ref */
[[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT {
return basic_any{*this, policy::cref};
[[nodiscard]] basic_any as_ref() const noexcept {
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 ENTT_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:
@@ -391,22 +419,9 @@ private:
};
const type_info *info;
vtable_type *vtable;
policy mode;
any_policy mode;
};
/**
* @brief Checks if two wrappers differ in their content.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
* @param lhs A wrapper, either empty or not.
* @param rhs A wrapper, either empty or not.
* @return True if the two wrappers differ in their content, false otherwise.
*/
template<std::size_t Len, std::size_t Align>
[[nodiscard]] inline bool operator!=(const basic_any<Len, Align> &lhs, const basic_any<Len, Align> &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/**
* @brief Performs type-safe access to the contained object.
* @tparam Type Type to which conversion is required.
@@ -416,7 +431,7 @@ template<std::size_t Len, std::size_t Align>
* @return The element converted to the requested type.
*/
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(const basic_any<Len, Align> &data) ENTT_NOEXCEPT {
[[nodiscard]] Type any_cast(const basic_any<Len, Align> &data) noexcept {
const auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
@@ -424,7 +439,7 @@ Type any_cast(const basic_any<Len, Align> &data) ENTT_NOEXCEPT {
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(basic_any<Len, Align> &data) ENTT_NOEXCEPT {
[[nodiscard]] Type any_cast(basic_any<Len, Align> &data) noexcept {
// forces const on non-reference types to make them work also with wrappers for const references
auto *const instance = any_cast<std::remove_reference_t<const Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
@@ -433,8 +448,8 @@ Type any_cast(basic_any<Len, Align> &data) ENTT_NOEXCEPT {
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(basic_any<Len, Align> &&data) ENTT_NOEXCEPT {
if constexpr(std::is_copy_constructible_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
[[nodiscard]] Type any_cast(basic_any<Len, Align> &&data) noexcept {
if constexpr(std::is_copy_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
if(auto *const instance = any_cast<std::remove_reference_t<Type>>(&data); instance) {
return static_cast<Type>(std::move(*instance));
} else {
@@ -449,17 +464,21 @@ Type any_cast(basic_any<Len, Align> &&data) ENTT_NOEXCEPT {
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
const Type *any_cast(const basic_any<Len, Align> *data) ENTT_NOEXCEPT {
const auto &info = type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
[[nodiscard]] const Type *any_cast(const basic_any<Len, Align> *data) noexcept {
const auto &info = type_id<std::remove_cv_t<Type>>();
return static_cast<const Type *>(data->data(info));
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type *any_cast(basic_any<Len, Align> *data) ENTT_NOEXCEPT {
const auto &info = type_id<std::remove_const_t<std::remove_reference_t<Type>>>();
// last attempt to make wrappers for const references return their values
return static_cast<Type *>(static_cast<constness_as_t<basic_any<Len, Align>, Type> *>(data)->data(info));
[[nodiscard]] Type *any_cast(basic_any<Len, Align> *data) noexcept {
if constexpr(std::is_const_v<Type>) {
// last attempt to make wrappers for const references return their values
return any_cast<Type>(&std::as_const(*data));
} else {
const auto &info = type_id<std::remove_cv_t<Type>>();
return static_cast<Type *>(data->data(info));
}
}
/**
@@ -472,7 +491,7 @@ Type *any_cast(basic_any<Len, Align> *data) ENTT_NOEXCEPT {
* @return A properly initialized wrapper for an object of the given type.
*/
template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args>
basic_any<Len, Align> make_any(Args &&...args) {
[[nodiscard]] basic_any<Len, Align> make_any(Args &&...args) {
return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...};
}
@@ -485,8 +504,8 @@ basic_any<Len, Align> make_any(Args &&...args) {
* @return A properly initialized and not necessarily owning wrapper.
*/
template<std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename Type>
basic_any<Len, Align> forward_as_any(Type &&value) {
return basic_any<Len, Align>{std::in_place_type<std::conditional_t<std::is_rvalue_reference_v<Type>, std::decay_t<Type>, Type>>, std::forward<Type>(value)};
[[nodiscard]] basic_any<Len, Align> forward_as_any(Type &&value) {
return basic_any<Len, Align>{std::in_place_type<Type &&>, std::forward<Type>(value)};
}
} // namespace entt

View File

@@ -5,16 +5,11 @@
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "type_traits.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type, std::size_t, typename = void>
@@ -23,22 +18,22 @@ struct compressed_pair_element {
using const_reference = const Type &;
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<Type>>>
compressed_pair_element()
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<Type>)
: value{} {}
template<typename Args, typename = std::enable_if_t<!std::is_same_v<std::remove_const_t<std::remove_reference_t<Args>>, compressed_pair_element>>>
compressed_pair_element(Args &&args)
: value{std::forward<Args>(args)} {}
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<Type, Arg>)
: value{std::forward<Arg>(arg)} {}
template<typename... Args, std::size_t... Index>
compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>)
: value{std::get<Index>(args)...} {}
constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<Type, Args...>)
: value{std::forward<Args>(std::get<Index>(args))...} {}
[[nodiscard]] reference get() ENTT_NOEXCEPT {
[[nodiscard]] constexpr reference get() noexcept {
return value;
}
[[nodiscard]] const_reference get() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr const_reference get() const noexcept {
return value;
}
@@ -53,32 +48,28 @@ struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Ty
using base_type = Type;
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<base_type>>>
compressed_pair_element()
constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<base_type>)
: base_type{} {}
template<typename Args, typename = std::enable_if_t<!std::is_same_v<std::remove_const_t<std::remove_reference_t<Args>>, compressed_pair_element>>>
compressed_pair_element(Args &&args)
: base_type{std::forward<Args>(args)} {}
template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<base_type, Arg>)
: base_type{std::forward<Arg>(arg)} {}
template<typename... Args, std::size_t... Index>
compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>)
: base_type{std::get<Index>(args)...} {}
constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<base_type, Args...>)
: base_type{std::forward<Args>(std::get<Index>(args))...} {}
[[nodiscard]] reference get() ENTT_NOEXCEPT {
[[nodiscard]] constexpr reference get() noexcept {
return *this;
}
[[nodiscard]] const_reference get() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr const_reference get() const noexcept {
return *this;
}
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @endcond */
/**
* @brief A compressed pair.
@@ -111,7 +102,7 @@ public:
* @tparam Dummy Dummy template parameter used for internal purposes.
*/
template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>>
constexpr compressed_pair()
constexpr compressed_pair() noexcept(std::is_nothrow_default_constructible_v<first_base> &&std::is_nothrow_default_constructible_v<second_base>)
: first_base{},
second_base{} {}
@@ -119,13 +110,13 @@ public:
* @brief Copy constructor.
* @param other The instance to copy from.
*/
constexpr compressed_pair(const compressed_pair &other) = default;
constexpr compressed_pair(const compressed_pair &other) noexcept(std::is_nothrow_copy_constructible_v<first_base> &&std::is_nothrow_copy_constructible_v<second_base>) = default;
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
constexpr compressed_pair(compressed_pair &&other) ENTT_NOEXCEPT = default;
constexpr compressed_pair(compressed_pair &&other) noexcept(std::is_nothrow_move_constructible_v<first_base> &&std::is_nothrow_move_constructible_v<second_base>) = default;
/**
* @brief Constructs a pair from its values.
@@ -135,7 +126,7 @@ public:
* @param other Value to use to initialize the second element.
*/
template<typename Arg, typename Other>
constexpr compressed_pair(Arg &&arg, Other &&other)
constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(std::is_nothrow_constructible_v<first_base, Arg> &&std::is_nothrow_constructible_v<second_base, Other>)
: first_base{std::forward<Arg>(arg)},
second_base{std::forward<Other>(other)} {}
@@ -147,7 +138,7 @@ public:
* @param other Arguments to use to initialize the second element.
*/
template<typename... Args, typename... Other>
constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other)
constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other) noexcept(std::is_nothrow_constructible_v<first_base, Args...> &&std::is_nothrow_constructible_v<second_base, Other...>)
: first_base{std::move(args), std::index_sequence_for<Args...>{}},
second_base{std::move(other), std::index_sequence_for<Other...>{}} {}
@@ -156,25 +147,25 @@ public:
* @param other The instance to copy from.
* @return This compressed pair object.
*/
constexpr compressed_pair &operator=(const compressed_pair &other) = default;
constexpr compressed_pair &operator=(const compressed_pair &other) noexcept(std::is_nothrow_copy_assignable_v<first_base> &&std::is_nothrow_copy_assignable_v<second_base>) = default;
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This compressed pair object.
*/
constexpr compressed_pair &operator=(compressed_pair &&other) ENTT_NOEXCEPT = default;
constexpr compressed_pair &operator=(compressed_pair &&other) noexcept(std::is_nothrow_move_assignable_v<first_base> &&std::is_nothrow_move_assignable_v<second_base>) = default;
/**
* @brief Returns the first element that a pair stores.
* @return The first element that a pair stores.
*/
[[nodiscard]] first_type &first() ENTT_NOEXCEPT {
[[nodiscard]] constexpr first_type &first() noexcept {
return static_cast<first_base &>(*this).get();
}
/*! @copydoc first */
[[nodiscard]] const first_type &first() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr const first_type &first() const noexcept {
return static_cast<const first_base &>(*this).get();
}
@@ -182,12 +173,12 @@ public:
* @brief Returns the second element that a pair stores.
* @return The second element that a pair stores.
*/
[[nodiscard]] second_type &second() ENTT_NOEXCEPT {
[[nodiscard]] constexpr second_type &second() noexcept {
return static_cast<second_base &>(*this).get();
}
/*! @copydoc second */
[[nodiscard]] const second_type &second() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr const second_type &second() const noexcept {
return static_cast<const second_base &>(*this).get();
}
@@ -195,7 +186,7 @@ public:
* @brief Swaps two compressed pair objects.
* @param other The compressed pair to swap with.
*/
void swap(compressed_pair &other) {
constexpr void swap(compressed_pair &other) noexcept(std::is_nothrow_swappable_v<first_type> &&std::is_nothrow_swappable_v<second_type>) {
using std::swap;
swap(first(), other.first());
swap(second(), other.second());
@@ -208,7 +199,7 @@ public:
* reference to the second element if `Index` is 1.
*/
template<std::size_t Index>
decltype(auto) get() ENTT_NOEXCEPT {
constexpr decltype(auto) get() noexcept {
if constexpr(Index == 0u) {
return first();
} else {
@@ -219,7 +210,7 @@ public:
/*! @copydoc get */
template<std::size_t Index>
decltype(auto) get() const ENTT_NOEXCEPT {
constexpr decltype(auto) get() const noexcept {
if constexpr(Index == 0u) {
return first();
} else {
@@ -245,7 +236,7 @@ compressed_pair(Type &&, Other &&) -> compressed_pair<std::decay_t<Type>, std::d
* @param rhs A valid compressed pair object.
*/
template<typename First, typename Second>
inline void swap(compressed_pair<First, Second> &lhs, compressed_pair<First, Second> &rhs) {
inline constexpr void swap(compressed_pair<First, Second> &lhs, compressed_pair<First, Second> &rhs) {
lhs.swap(rhs);
}
@@ -255,9 +246,20 @@ inline void swap(compressed_pair<First, Second> &lhs, compressed_pair<First, Sec
#if !defined __clang_major__ || __clang_major__ > 6
namespace std {
/**
* @brief `std::tuple_size` specialization for `compressed_pair`s.
* @tparam First The type of the first element that the pair stores.
* @tparam Second The type of the second element that the pair stores.
*/
template<typename First, typename Second>
struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_t, 2u> {};
/**
* @brief `std::tuple_element` specialization for `compressed_pair`s.
* @tparam Index The index of the type to return.
* @tparam First The type of the first element that the pair stores.
* @tparam Second The type of the second element that the pair stores.
*/
template<size_t Index, typename First, typename Second>
struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {
static_assert(Index < 2u, "Index out of bounds");

View File

@@ -1,8 +1,7 @@
#ifndef ENTT_CORE_FLAG_HPP
#define ENTT_CORE_FLAG_HPP
#ifndef ENTT_CORE_ENUM_HPP
#define ENTT_CORE_ENUM_HPP
#include <type_traits>
#include "../config/config.h"
namespace entt {
@@ -15,7 +14,7 @@ struct enum_as_bitmask: std::false_type {};
/*! @copydoc enum_as_bitmask */
template<typename Type>
struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>: std::true_type {};
struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>: std::is_enum<Type> {};
/**
* @brief Helper variable template.
@@ -35,23 +34,23 @@ inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value;
* two values provided.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
operator|(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
return Type{static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs)};
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
operator|(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs));
}
/*! @copydoc operator| */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
operator&(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
return Type{static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs)};
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
operator&(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs));
}
/*! @copydoc operator| */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
operator^(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
return Type{static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs)};
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
operator^(const Type lhs, const Type rhs) noexcept {
return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(rhs));
}
/**
@@ -62,51 +61,37 @@ operator^(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
* value provided.
*/
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
operator~(const Type value) ENTT_NOEXCEPT {
return Type{~static_cast<std::underlying_type_t<Type>>(value)};
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
operator~(const Type value) noexcept {
return static_cast<Type>(~static_cast<std::underlying_type_t<Type>>(value));
}
/*! @copydoc operator~ */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, bool>
operator!(const Type value) ENTT_NOEXCEPT {
[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, bool>
operator!(const Type value) noexcept {
return !static_cast<std::underlying_type_t<Type>>(value);
}
/*! @copydoc operator| */
template<typename Type>
constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type &>
operator|=(Type &lhs, const Type rhs) ENTT_NOEXCEPT {
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
operator|=(Type &lhs, const Type rhs) noexcept {
return (lhs = (lhs | rhs));
}
/*! @copydoc operator| */
template<typename Type>
constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type &>
operator&=(Type &lhs, const Type rhs) ENTT_NOEXCEPT {
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
operator&=(Type &lhs, const Type rhs) noexcept {
return (lhs = (lhs & rhs));
}
/*! @copydoc operator| */
template<typename Type>
constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type &>
operator^=(Type &lhs, const Type rhs) ENTT_NOEXCEPT {
constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
operator^=(Type &lhs, const Type rhs) noexcept {
return (lhs = (lhs ^ rhs));
}
/*! @copydoc operator| */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
operator==(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
return (static_cast<std::underlying_type_t<Type>>(lhs) == static_cast<std::underlying_type_t<Type>>(rhs));
}
/*! @copydoc operator| */
template<typename Type>
[[nodiscard]] constexpr std::enable_if_t<std::is_enum_v<Type> && entt::enum_as_bitmask_v<Type>, Type>
operator!=(const Type lhs, const Type rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
#endif

View File

@@ -19,12 +19,12 @@ class family {
public:
/*! @brief Unsigned integer type. */
using family_type = id_type;
using value_type = id_type;
/*! @brief Statically generated unique identifier for the given type. */
template<typename... Type>
// at the time I'm writing, clang crashes during compilation if auto is used instead of family_type
inline static const family_type type = identifier++;
inline static const value_type value = identifier++;
};
} // namespace entt

View File

@@ -1,12 +1,12 @@
#ifndef ENTT_CORE_FWD_HPP
#define ENTT_CORE_FWD_HPP
#include <type_traits>
#include <cstddef>
#include "../config/config.h"
namespace entt {
template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(typename std::aligned_storage_t<Len + !Len>)>
template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(double[2])>
class basic_any;
/*! @brief Alias declaration for type identifiers. */

View File

@@ -3,16 +3,11 @@
#include <cstddef>
#include <cstdint>
#include "../config/config.h"
#include "fwd.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename>
@@ -32,18 +27,25 @@ struct fnv1a_traits<std::uint64_t> {
static constexpr std::uint64_t prime = 1099511628211ull;
};
} // namespace internal
template<typename Char>
struct basic_hashed_string {
using value_type = Char;
using size_type = std::size_t;
using hash_type = id_type;
/**
* Internal details not to be documented.
* @endcond
*/
const value_type *repr;
size_type length;
hash_type hash;
};
} // namespace internal
/*! @endcond */
/**
* @brief Zero overhead unique identifier.
*
* A hashed string is a compile-time tool that allows users to use
* human-readable identifers in the codebase while using their numeric
* human-readable identifiers in the codebase while using their numeric
* counterparts at runtime.<br/>
* Because of that, a hashed string can also be used in constant expressions if
* required.
@@ -55,62 +57,67 @@ struct fnv1a_traits<std::uint64_t> {
* @tparam Char Character type.
*/
template<typename Char>
class basic_hashed_string {
using hs_traits = internal::fnv1a_traits<id_type>;
class basic_hashed_string: internal::basic_hashed_string<Char> {
using base_type = internal::basic_hashed_string<Char>;
using traits_type = internal::fnv1a_traits<id_type>;
struct const_wrapper {
// non-explicit constructor on purpose
constexpr const_wrapper(const Char *curr) ENTT_NOEXCEPT: str{curr} {}
const Char *str;
constexpr const_wrapper(const Char *str) noexcept
: repr{str} {}
const Char *repr;
};
// FowlerNollVo hash function v. 1a - the good
[[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT {
auto value = hs_traits::offset;
[[nodiscard]] static constexpr auto helper(const Char *str) noexcept {
base_type base{str, 0u, traits_type::offset};
while(*curr != 0) {
value = (value ^ static_cast<hs_traits::type>(*(curr++))) * hs_traits::prime;
for(; str[base.length]; ++base.length) {
base.hash = (base.hash ^ static_cast<traits_type::type>(str[base.length])) * traits_type::prime;
}
return value;
return base;
}
// FowlerNollVo hash function v. 1a - the good
[[nodiscard]] static constexpr auto helper(const Char *str, const std::size_t len) noexcept {
base_type base{str, len, traits_type::offset};
for(size_type pos{}; pos < len; ++pos) {
base.hash = (base.hash ^ static_cast<traits_type::type>(str[pos])) * traits_type::prime;
}
return base;
}
public:
/*! @brief Character type. */
using value_type = Char;
using value_type = typename base_type::value_type;
/*! @brief Unsigned integer type. */
using hash_type = id_type;
using size_type = typename base_type::size_type;
/*! @brief Unsigned integer type. */
using hash_type = typename base_type::hash_type;
/**
* @brief Returns directly the numeric representation of a string view.
* @param str Human-readable identifer.
* @param size Length of the string to hash.
* @param str Human-readable identifier.
* @param len Length of the string to hash.
* @return The numeric representation of the string.
*/
[[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
id_type partial{hs_traits::offset};
while(size--) { partial = (partial ^ (str++)[0]) * hs_traits::prime; }
return partial;
[[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept {
return basic_hashed_string{str, len};
}
/**
* @brief Returns directly the numeric representation of a string.
*
* Forcing template resolution avoids implicit conversions. An
* human-readable identifier can be anything but a plain, old bunch of
* characters.<br/>
* Example of use:
* @code{.cpp}
* const auto value = basic_hashed_string<char>::value("my.png");
* @endcode
*
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifer.
* @param str Human-readable identifier.
* @return The numeric representation of the string.
*/
template<std::size_t N>
[[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT {
return helper(str);
[[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) noexcept {
return basic_hashed_string{str};
}
/**
@@ -118,33 +125,30 @@ public:
* @param wrapper Helps achieving the purpose by relying on overloading.
* @return The numeric representation of the string.
*/
[[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT {
return helper(wrapper.str);
[[nodiscard]] static constexpr hash_type value(const_wrapper wrapper) noexcept {
return basic_hashed_string{wrapper};
}
/*! @brief Constructs an empty hashed string. */
constexpr basic_hashed_string() ENTT_NOEXCEPT
: str{nullptr},
hash{} {}
constexpr basic_hashed_string() noexcept
: base_type{} {}
/**
* @brief Constructs a hashed string from a string view.
* @param str Human-readable identifier.
* @param len Length of the string to hash.
*/
constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept
: base_type{helper(str, len)} {}
/**
* @brief Constructs a hashed string from an array of const characters.
*
* Forcing template resolution avoids implicit conversions. An
* human-readable identifier can be anything but a plain, old bunch of
* characters.<br/>
* Example of use:
* @code{.cpp}
* basic_hashed_string<char> hs{"my.png"};
* @endcode
*
* @tparam N Number of characters of the identifier.
* @param curr Human-readable identifer.
* @param str Human-readable identifier.
*/
template<std::size_t N>
constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT
: str{curr},
hash{helper(curr)} {}
constexpr basic_hashed_string(const value_type (&str)[N]) noexcept
: base_type{helper(str)} {}
/**
* @brief Explicit constructor on purpose to avoid constructing a hashed
@@ -155,53 +159,61 @@ public:
*
* @param wrapper Helps achieving the purpose by relying on overloading.
*/
explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
: str{wrapper.str},
hash{helper(wrapper.str)} {}
explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept
: base_type{helper(wrapper.repr)} {}
/**
* @brief Returns the size a hashed string.
* @return The size of the hashed string.
*/
[[nodiscard]] constexpr size_type size() const noexcept {
return base_type::length; // NOLINT
}
/**
* @brief Returns the human-readable representation of a hashed string.
* @return The string used to initialize the instance.
* @return The string used to initialize the hashed string.
*/
[[nodiscard]] constexpr const value_type *data() const ENTT_NOEXCEPT {
return str;
[[nodiscard]] constexpr const value_type *data() const noexcept {
return base_type::repr;
}
/**
* @brief Returns the numeric representation of a hashed string.
* @return The numeric representation of the instance.
* @return The numeric representation of the hashed string.
*/
[[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT {
return hash;
[[nodiscard]] constexpr hash_type value() const noexcept {
return base_type::hash;
}
/*! @copydoc data */
[[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr operator const value_type *() const noexcept {
return data();
}
/**
* @brief Returns the numeric representation of a hashed string.
* @return The numeric representation of the instance.
* @return The numeric representation of the hashed string.
*/
[[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr operator hash_type() const noexcept {
return value();
}
private:
const value_type *str;
hash_type hash;
};
/**
* @brief Deduction guide.
*
* It allows to deduce the character type of the hashed string directly from a
* human-readable identifer provided to the constructor.
*
* @tparam Char Character type.
* @param str Human-readable identifier.
* @param len Length of the string to hash.
*/
template<typename Char>
basic_hashed_string(const Char *str, const std::size_t len) -> basic_hashed_string<Char>;
/**
* @brief Deduction guide.
* @tparam Char Character type.
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifer.
* @param str Human-readable identifier.
*/
template<typename Char, std::size_t N>
basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>;
@@ -214,7 +226,7 @@ basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>;
* @return True if the two hashed strings are identical, false otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator==(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator==(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return lhs.value() == rhs.value();
}
@@ -226,7 +238,7 @@ template<typename Char>
* @return True if the two hashed strings differ, false otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return !(lhs == rhs);
}
@@ -238,7 +250,7 @@ template<typename Char>
* @return True if the first element is less than the second, false otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator<(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator<(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return lhs.value() < rhs.value();
}
@@ -251,7 +263,7 @@ template<typename Char>
* otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator<=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator<=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return !(rhs < lhs);
}
@@ -264,7 +276,7 @@ template<typename Char>
* otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator>(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator>(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return rhs < lhs;
}
@@ -277,7 +289,7 @@ template<typename Char>
* false otherwise.
*/
template<typename Char>
[[nodiscard]] constexpr bool operator>=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator>=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
return !(lhs < rhs);
}
@@ -294,8 +306,8 @@ inline namespace literals {
* @param str The literal without its suffix.
* @return A properly initialized hashed string.
*/
[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT {
return entt::hashed_string{str};
[[nodiscard]] constexpr hashed_string operator"" _hs(const char *str, std::size_t) noexcept {
return hashed_string{str};
}
/**
@@ -303,8 +315,8 @@ inline namespace literals {
* @param str The literal without its suffix.
* @return A properly initialized hashed wstring.
*/
[[nodiscard]] constexpr entt::hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) ENTT_NOEXCEPT {
return entt::hashed_wstring{str};
[[nodiscard]] constexpr hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) noexcept {
return hashed_wstring{str};
}
} // namespace literals

View File

@@ -4,54 +4,30 @@
#include <cstddef>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "fwd.hpp"
#include "type_traits.hpp"
namespace entt {
/**
* @brief Types identifiers.
*
* Variable template used to generate identifiers at compile-time for the given
* types. Use the `get` member function to know what's the identifier associated
* to the specific type.
*
* @note
* Identifiers are constant expression and can be used in any context where such
* an expression is required. As an example:
* @code{.cpp}
* using id = entt::identifier<a_type, another_type>;
*
* switch(a_type_identifier) {
* case id::type<a_type>:
* // ...
* break;
* case id::type<another_type>:
* // ...
* break;
* default:
* // ...
* }
* @endcode
*
* @tparam Types List of types for which to generate identifiers.
* @brief Type integral identifiers.
* @tparam Type List of types for which to generate identifiers.
*/
template<typename... Types>
class identifier {
template<typename Type, std::size_t... Index>
[[nodiscard]] static constexpr id_type get(std::index_sequence<Index...>) {
static_assert(std::disjunction_v<std::is_same<Type, Types>...>, "Invalid type");
return (0 + ... + (std::is_same_v<Type, type_list_element_t<Index, type_list<std::decay_t<Types>...>>> ? id_type{Index} : id_type{}));
template<typename... Type>
class ident {
template<typename Curr, std::size_t... Index>
[[nodiscard]] static constexpr id_type get(std::index_sequence<Index...>) noexcept {
static_assert((std::is_same_v<Curr, Type> || ...), "Invalid type");
return (0 + ... + (std::is_same_v<Curr, type_list_element_t<Index, type_list<std::decay_t<Type>...>>> ? id_type{Index} : id_type{}));
}
public:
/*! @brief Unsigned integer type. */
using identifier_type = id_type;
using value_type = id_type;
/*! @brief Statically generated unique identifier for the given type. */
template<typename Type>
static constexpr identifier_type type = get<std::decay_t<Type>>(std::index_sequence_for<Types...>{});
template<typename Curr>
static constexpr value_type value = get<std::decay_t<Curr>>(std::index_sequence_for<Type...>{});
};
} // namespace entt

View File

@@ -3,8 +3,8 @@
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"
namespace entt {
@@ -14,76 +14,157 @@ namespace entt {
*/
template<typename Type>
struct input_iterator_pointer final {
/*! @brief Value type. */
using value_type = Type;
/*! @brief Pointer type. */
using pointer = decltype(std::addressof(std::declval<Type &>()));
/*! @brief Default copy constructor, deleted on purpose. */
input_iterator_pointer(const input_iterator_pointer &) = delete;
/*! @brief Default move constructor. */
input_iterator_pointer(input_iterator_pointer &&) = default;
using pointer = Type *;
/*! @brief Reference type. */
using reference = Type &;
/**
* @brief Constructs a proxy object by move.
* @param val Value to use to initialize the proxy object.
*/
input_iterator_pointer(Type &&val)
constexpr input_iterator_pointer(value_type &&val) noexcept(std::is_nothrow_move_constructible_v<value_type>)
: value{std::move(val)} {}
/**
* @brief Default copy assignment operator, deleted on purpose.
* @return This proxy object.
*/
input_iterator_pointer &operator=(const input_iterator_pointer &) = delete;
/**
* @brief Default move assignment operator.
* @return This proxy object.
*/
input_iterator_pointer &operator=(input_iterator_pointer &&) = default;
/**
* @brief Access operator for accessing wrapped values.
* @return A pointer to the wrapped value.
*/
[[nodiscard]] pointer operator->() ENTT_NOEXCEPT {
[[nodiscard]] constexpr pointer operator->() noexcept {
return std::addressof(value);
}
/**
* @brief Dereference operator for accessing wrapped values.
* @return A reference to the wrapped value.
*/
[[nodiscard]] constexpr reference operator*() noexcept {
return value;
}
private:
Type value;
};
/**
* @brief Utility class to create an iterable object from a pair of iterators.
* @tparam It Type of iterators.
* @brief Plain iota iterator (waiting for C++20).
* @tparam Type Value type.
*/
template<typename It>
template<typename Type>
class iota_iterator final {
static_assert(std::is_integral_v<Type>, "Not an integral type");
public:
/*! @brief Value type, likely an integral one. */
using value_type = Type;
/*! @brief Invalid pointer type. */
using pointer = void;
/*! @brief Non-reference type, same as value type. */
using reference = value_type;
/*! @brief Difference type. */
using difference_type = std::ptrdiff_t;
/*! @brief Iterator category. */
using iterator_category = std::input_iterator_tag;
/*! @brief Default constructor. */
constexpr iota_iterator() noexcept
: current{} {}
/**
* @brief Constructs an iota iterator from a given value.
* @param init The initial value assigned to the iota iterator.
*/
constexpr iota_iterator(const value_type init) noexcept
: current{init} {}
/**
* @brief Pre-increment operator.
* @return This iota iterator.
*/
constexpr iota_iterator &operator++() noexcept {
return ++current, *this;
}
/**
* @brief Post-increment operator.
* @return This iota iterator.
*/
constexpr iota_iterator operator++(int) noexcept {
iota_iterator orig = *this;
return ++(*this), orig;
}
/**
* @brief Dereference operator.
* @return The underlying value.
*/
[[nodiscard]] constexpr reference operator*() const noexcept {
return current;
}
private:
value_type current;
};
/**
* @brief Comparison operator.
* @tparam Type Value type of the iota iterator.
* @param lhs A properly initialized iota iterator.
* @param rhs A properly initialized iota iterator.
* @return True if the two iterators are identical, false otherwise.
*/
template<typename Type>
[[nodiscard]] constexpr bool operator==(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
return *lhs == *rhs;
}
/**
* @brief Comparison operator.
* @tparam Type Value type of the iota iterator.
* @param lhs A properly initialized iota iterator.
* @param rhs A properly initialized iota iterator.
* @return True if the two iterators differ, false otherwise.
*/
template<typename Type>
[[nodiscard]] constexpr bool operator!=(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
return !(lhs == rhs);
}
/**
* @brief Utility class to create an iterable object from a pair of iterators.
* @tparam It Type of iterator.
* @tparam Sentinel Type of sentinel.
*/
template<typename It, typename Sentinel = It>
struct iterable_adaptor final {
/*! @brief Type of the objects returned during iteration. */
/*! @brief Value type. */
using value_type = typename std::iterator_traits<It>::value_type;
/*! @brief Iterator type. */
using iterator = It;
/*! @brief Const iterator type. */
using const_iterator = iterator;
/*! @brief Sentinel type. */
using sentinel = Sentinel;
/*! @brief Default constructor. */
iterable_adaptor() = default;
constexpr iterable_adaptor() noexcept(std::is_nothrow_default_constructible_v<iterator> &&std::is_nothrow_default_constructible_v<sentinel>)
: first{},
last{} {}
/**
* @brief Creates an iterable object from a pair of iterators.
* @param from Begin iterator.
* @param to End iterator.
*/
iterable_adaptor(It from, It to)
: first{from},
last{to} {}
constexpr iterable_adaptor(iterator from, sentinel to) noexcept(std::is_nothrow_move_constructible_v<iterator> &&std::is_nothrow_move_constructible_v<sentinel>)
: first{std::move(from)},
last{std::move(to)} {}
/**
* @brief Returns an iterator to the beginning.
* @return An iterator to the first element of the range.
*/
[[nodiscard]] const_iterator begin() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr iterator begin() const noexcept {
return first;
}
@@ -92,23 +173,23 @@ struct iterable_adaptor final {
* @return An iterator to the element following the last element of the
* range.
*/
[[nodiscard]] const_iterator end() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr sentinel end() const noexcept {
return last;
}
/*! @copydoc begin */
[[nodiscard]] const_iterator cbegin() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr iterator cbegin() const noexcept {
return begin();
}
/*! @copydoc end */
[[nodiscard]] const_iterator cend() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr sentinel cend() const noexcept {
return end();
}
private:
It first;
It last;
Sentinel last;
};
} // namespace entt

View File

@@ -4,6 +4,7 @@
#include <cstddef>
#include <limits>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
@@ -11,78 +12,23 @@
namespace entt {
/**
* @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
* @tparam Type Pointer type.
* @param ptr Fancy or raw pointer.
* @return A raw pointer that represents the address of the original pointer.
*/
template<typename Type>
[[nodiscard]] constexpr auto to_address(Type &&ptr) ENTT_NOEXCEPT {
if constexpr(std::is_pointer_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
return ptr;
} else {
return to_address(std::forward<Type>(ptr).operator->());
}
}
/**
* @brief Utility function to design allocation-aware containers.
* @tparam Allocator Type of allocator.
* @param lhs A valid allocator.
* @param rhs Another valid allocator.
*/
template<typename Allocator>
constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
lhs = rhs;
}
}
/**
* @brief Utility function to design allocation-aware containers.
* @tparam Allocator Type of allocator.
* @param lhs A valid allocator.
* @param rhs Another valid allocator.
*/
template<typename Allocator>
constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
lhs = std::move(rhs);
}
}
/**
* @brief Utility function to design allocation-aware containers.
* @tparam Allocator Type of allocator.
* @param lhs A valid allocator.
* @param rhs Another valid allocator.
*/
template<typename Allocator>
constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) ENTT_NOEXCEPT {
ENTT_ASSERT(std::allocator_traits<Allocator>::propagate_on_container_swap::value || lhs == rhs, "Cannot swap the containers");
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
using std::swap;
swap(lhs, rhs);
}
}
/**
* @brief Checks whether a value is a power of two or not.
* @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.
*/
[[nodiscard]] inline constexpr bool is_power_of_two(const std::size_t value) ENTT_NOEXCEPT {
[[nodiscard]] inline constexpr bool is_power_of_two(const std::size_t value) noexcept {
return value && ((value & (value - 1)) == 0);
}
/**
* @brief Computes the smallest power of two greater than or equal to a value.
* @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.
*/
[[nodiscard]] inline constexpr std::size_t next_power_of_two(const std::size_t value) ENTT_NOEXCEPT {
ENTT_ASSERT(value < (std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)), "Numeric limits exceeded");
[[nodiscard]] inline constexpr std::size_t next_power_of_two(const std::size_t value) noexcept {
ENTT_ASSERT_CONSTEXPR(value < (std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)), "Numeric limits exceeded");
std::size_t curr = value - (value != 0u);
for(int next = 1; next < std::numeric_limits<std::size_t>::digits; next = next * 2) {
@@ -98,11 +44,240 @@ constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[ma
* @param mod _Modulus_, it must be a power of two.
* @return The common remainder.
*/
[[nodiscard]] inline constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) ENTT_NOEXCEPT {
ENTT_ASSERT(is_power_of_two(mod), "Value must be a power of two");
[[nodiscard]] inline constexpr std::size_t fast_mod(const std::size_t value, const std::size_t mod) noexcept {
ENTT_ASSERT_CONSTEXPR(is_power_of_two(mod), "Value must be a power of two");
return value & (mod - 1u);
}
/**
* @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
* @tparam Type Pointer type.
* @param ptr Fancy or raw pointer.
* @return A raw pointer that represents the address of the original pointer.
*/
template<typename Type>
[[nodiscard]] constexpr auto to_address(Type &&ptr) noexcept {
if constexpr(std::is_pointer_v<std::decay_t<Type>>) {
return ptr;
} else {
return to_address(std::forward<Type>(ptr).operator->());
}
}
/**
* @brief Utility function to design allocation-aware containers.
* @tparam Allocator Type of allocator.
* @param lhs A valid allocator.
* @param rhs Another valid allocator.
*/
template<typename Allocator>
constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
lhs = rhs;
}
}
/**
* @brief Utility function to design allocation-aware containers.
* @tparam Allocator Type of allocator.
* @param lhs A valid allocator.
* @param rhs Another valid allocator.
*/
template<typename Allocator>
constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
lhs = std::move(rhs);
}
}
/**
* @brief Utility function to design allocation-aware containers.
* @tparam Allocator Type of allocator.
* @param lhs A valid allocator.
* @param rhs Another valid allocator.
*/
template<typename Allocator>
constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
using std::swap;
swap(lhs, rhs);
} else {
ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers");
}
}
/**
* @brief Deleter for allocator-aware unique pointers (waiting for C++20).
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Allocator>
struct allocation_deleter: private Allocator {
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Pointer type. */
using pointer = typename std::allocator_traits<Allocator>::pointer;
/**
* @brief Inherited constructors.
* @param alloc The allocator to use.
*/
constexpr allocation_deleter(const allocator_type &alloc) noexcept(std::is_nothrow_copy_constructible_v<allocator_type>)
: Allocator{alloc} {}
/**
* @brief Destroys the pointed object and deallocates its memory.
* @param ptr A valid pointer to an object of the given type.
*/
constexpr void operator()(pointer ptr) noexcept(std::is_nothrow_destructible_v<typename allocator_type::value_type>) {
using alloc_traits = std::allocator_traits<Allocator>;
alloc_traits::destroy(*this, to_address(ptr));
alloc_traits::deallocate(*this, ptr, 1u);
}
};
/**
* @brief Allows `std::unique_ptr` to use allocators (waiting for C++20).
* @tparam Type Type of object to allocate for and to construct.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the object.
* @param allocator The allocator to use.
* @param args Parameters to use to construct the object.
* @return A properly initialized unique pointer with a custom deleter.
*/
template<typename Type, typename Allocator, typename... Args>
ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) {
static_assert(!std::is_array_v<Type>, "Array types are not supported");
using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Type>;
using allocator_type = typename alloc_traits::allocator_type;
allocator_type alloc{allocator};
auto ptr = alloc_traits::allocate(alloc, 1u);
ENTT_TRY {
alloc_traits::construct(alloc, to_address(ptr), std::forward<Args>(args)...);
}
ENTT_CATCH {
alloc_traits::deallocate(alloc, ptr, 1u);
ENTT_THROW;
}
return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
}
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type>
struct uses_allocator_construction {
template<typename Allocator, typename... Params>
static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept {
if constexpr(!std::uses_allocator_v<Type, Allocator> && std::is_constructible_v<Type, Params...>) {
return std::forward_as_tuple(std::forward<Params>(params)...);
} else {
static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request");
if constexpr(std::is_constructible_v<Type, std::allocator_arg_t, const Allocator &, Params...>) {
return std::tuple<std::allocator_arg_t, const Allocator &, Params &&...>{std::allocator_arg, allocator, std::forward<Params>(params)...};
} else {
static_assert(std::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
return std::forward_as_tuple(std::forward<Params>(params)..., allocator);
}
}
}
};
template<typename Type, typename Other>
struct uses_allocator_construction<std::pair<Type, Other>> {
using type = std::pair<Type, Other>;
template<typename Allocator, typename First, typename Second>
static constexpr auto args(const Allocator &allocator, std::piecewise_construct_t, First &&first, Second &&second) noexcept {
return std::make_tuple(
std::piecewise_construct,
std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<First>(first)),
std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<Second>(second)));
}
template<typename Allocator>
static constexpr auto args(const Allocator &allocator) noexcept {
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
}
template<typename Allocator, typename First, typename Second>
static constexpr auto args(const Allocator &allocator, First &&first, Second &&second) noexcept {
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::forward<First>(first)), std::forward_as_tuple(std::forward<Second>(second)));
}
template<typename Allocator, typename First, typename Second>
static constexpr auto args(const Allocator &allocator, const std::pair<First, Second> &value) noexcept {
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(value.first), std::forward_as_tuple(value.second));
}
template<typename Allocator, typename First, typename Second>
static constexpr auto args(const Allocator &allocator, std::pair<First, Second> &&value) noexcept {
return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::move(value.first)), std::forward_as_tuple(std::move(value.second)));
}
};
} // namespace internal
/*! @endcond */
/**
* @brief Uses-allocator construction utility (waiting for C++20).
*
* Primarily intended for internal use. Prepares the argument list needed to
* create an object of a given type by means of uses-allocator construction.
*
* @tparam Type Type to return arguments for.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the object.
* @param allocator The allocator to use.
* @param args Parameters to use to construct the object.
* @return The arguments needed to create an object of the given type.
*/
template<typename Type, typename Allocator, typename... Args>
constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) noexcept {
return internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...);
}
/**
* @brief Uses-allocator construction utility (waiting for C++20).
*
* Primarily intended for internal use. Creates an object of a given type by
* means of uses-allocator construction.
*
* @tparam Type Type of object to create.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the object.
* @param allocator The allocator to use.
* @param args Parameters to use to construct the object.
* @return A newly created object of the given type.
*/
template<typename Type, typename Allocator, typename... Args>
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args) {
return std::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
}
/**
* @brief Uses-allocator construction utility (waiting for C++20).
*
* Primarily intended for internal use. Creates an object of a given type by
* means of uses-allocator construction at an uninitialized memory location.
*
* @tparam Type Type of object to create.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the object.
* @param value Memory location in which to place the object.
* @param allocator The allocator to use.
* @param args Parameters to use to construct the object.
* @return A pointer to the newly created object of the given type.
*/
template<typename Type, typename Allocator, typename... Args>
constexpr Type *uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args) {
return std::apply([value](auto &&...curr) { return new(value) Type(std::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
}
} // namespace entt
#endif

View File

@@ -25,7 +25,7 @@ struct monostate {
* @param val User data to assign to the given key.
*/
template<typename Type>
void operator=(Type val) const ENTT_NOEXCEPT {
void operator=(Type val) const noexcept {
value<Type> = val;
}
@@ -35,7 +35,7 @@ struct monostate {
* @return Stored value, if any.
*/
template<typename Type>
operator Type() const ENTT_NOEXCEPT {
operator Type() const noexcept {
return value<Type>;
}

View File

@@ -4,10 +4,36 @@
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename>
struct is_tuple_impl: std::false_type {};
template<typename... Args>
struct is_tuple_impl<std::tuple<Args...>>: std::true_type {};
} // namespace internal
/*! @endcond */
/**
* @brief Provides the member constant `value` to true if a given type is a
* tuple, false otherwise.
* @tparam Type The type to test.
*/
template<typename Type>
struct is_tuple: internal::is_tuple_impl<std::remove_cv_t<Type>> {};
/**
* @brief Helper variable template.
* @tparam Type The type to test.
*/
template<typename Type>
inline constexpr bool is_tuple_v = is_tuple<Type>::value;
/**
* @brief Utility function to unwrap tuples of a single element.
* @tparam Type Tuple type of any sizes.
@@ -16,7 +42,7 @@ namespace entt {
* element otherwise.
*/
template<typename Type>
constexpr decltype(auto) unwrap_tuple(Type &&value) ENTT_NOEXCEPT {
constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept {
if constexpr(std::tuple_size_v<std::remove_reference_t<Type>> == 1u) {
return std::get<0>(std::forward<Type>(value));
} else {
@@ -24,6 +50,46 @@ constexpr decltype(auto) unwrap_tuple(Type &&value) ENTT_NOEXCEPT {
}
}
/**
* @brief Utility class to forward-and-apply tuple objects.
* @tparam Func Type of underlying invocable object.
*/
template<typename Func>
struct forward_apply: private Func {
/**
* @brief Constructs a forward-and-apply object.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
*/
template<typename... Args>
constexpr forward_apply(Args &&...args) noexcept(std::is_nothrow_constructible_v<Func, Args...>)
: Func{std::forward<Args>(args)...} {}
/**
* @brief Forwards and applies the arguments with the underlying function.
* @tparam Type Tuple-like type to forward to the underlying function.
* @param args Parameters to forward to the underlying function.
* @return Return value of the underlying function, if any.
*/
template<typename Type>
constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(std::apply(std::declval<Func &>(), args))) {
return std::apply(static_cast<Func &>(*this), std::forward<Type>(args));
}
/*! @copydoc operator()() */
template<typename Type>
constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(std::apply(std::declval<const Func &>(), args))) {
return std::apply(static_cast<const Func &>(*this), std::forward<Type>(args));
}
};
/**
* @brief Deduction guide.
* @tparam Func Type of underlying invocable object.
*/
template<typename Func>
forward_apply(Func) -> forward_apply<std::remove_reference_t<std::remove_cv_t<Func>>>;
} // namespace entt
#endif

View File

@@ -11,22 +11,18 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
struct ENTT_API type_index final {
[[nodiscard]] static id_type next() ENTT_NOEXCEPT {
[[nodiscard]] static id_type next() noexcept {
static ENTT_MAYBE_ATOMIC(id_type) value{};
return value++;
}
};
template<typename Type>
[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT {
[[nodiscard]] constexpr auto stripped_type_name() noexcept {
#if defined ENTT_PRETTY_FUNCTION
std::string_view pretty_function{ENTT_PRETTY_FUNCTION};
auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1);
@@ -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) ENTT_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) ENTT_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) ENTT_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) ENTT_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.
@@ -81,13 +73,13 @@ struct ENTT_API type_index final {
* @brief Returns the sequential identifier of a given type.
* @return The sequential identifier of a given type.
*/
[[nodiscard]] static id_type value() ENTT_NOEXCEPT {
[[nodiscard]] static id_type value() noexcept {
static const id_type value = internal::type_index::next();
return value;
}
/*! @copydoc value */
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr operator id_type() const noexcept {
return value();
}
};
@@ -103,16 +95,16 @@ struct type_hash final {
* @return The numeric representation of the given type.
*/
#if defined ENTT_PRETTY_FUNCTION
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
[[nodiscard]] static constexpr id_type value() noexcept {
return internal::type_hash<Type>(0);
#else
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
[[nodiscard]] static constexpr id_type value() noexcept {
return type_index<Type>::value();
#endif
}
/*! @copydoc value */
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr operator id_type() const noexcept {
return value();
}
};
@@ -127,33 +119,33 @@ struct type_name final {
* @brief Returns the name of a given type.
* @return The name of the given type.
*/
[[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT {
[[nodiscard]] static constexpr std::string_view value() noexcept {
return internal::type_name<Type>(0);
}
/*! @copydoc value */
[[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr operator std::string_view() const noexcept {
return value();
}
};
/*! @brief Implementation specific information about a type. */
class type_info final {
struct type_info final {
/**
* @brief Constructs a type info object for a given type.
* @tparam Type Type for which to construct a type info object.
*/
template<typename Type>
friend const type_info &type_id() ENTT_NOEXCEPT;
constexpr type_info(std::in_place_type_t<Type>) noexcept
: seq{type_index<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
identifier{type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
alias{type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()} {}
template<typename Type>
constexpr type_info(std::in_place_type_t<Type>) ENTT_NOEXCEPT
: seq{type_index<std::remove_reference_t<std::remove_const_t<Type>>>::value()},
identifier{type_hash<std::remove_reference_t<std::remove_const_t<Type>>>::value()},
alias{type_name<std::remove_reference_t<std::remove_const_t<Type>>>::value()} {}
public:
/**
* @brief Type index.
* @return Type index.
*/
[[nodiscard]] constexpr id_type index() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr id_type index() const noexcept {
return seq;
}
@@ -161,7 +153,7 @@ public:
* @brief Type hash.
* @return Type hash.
*/
[[nodiscard]] constexpr id_type hash() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr id_type hash() const noexcept {
return identifier;
}
@@ -169,7 +161,7 @@ public:
* @brief Type name.
* @return Type name.
*/
[[nodiscard]] constexpr std::string_view name() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr std::string_view name() const noexcept {
return alias;
}
@@ -185,7 +177,7 @@ private:
* @param rhs A type info object.
* @return True if the two type info objects are identical, false otherwise.
*/
[[nodiscard]] inline constexpr bool operator==(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
[[nodiscard]] inline constexpr bool operator==(const type_info &lhs, const type_info &rhs) noexcept {
return lhs.hash() == rhs.hash();
}
@@ -195,7 +187,7 @@ private:
* @param rhs A type info object.
* @return True if the two type info objects differ, false otherwise.
*/
[[nodiscard]] inline constexpr bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
[[nodiscard]] inline constexpr bool operator!=(const type_info &lhs, const type_info &rhs) noexcept {
return !(lhs == rhs);
}
@@ -205,7 +197,7 @@ private:
* @param rhs A valid type info object.
* @return True if the first element is less than the second, false otherwise.
*/
[[nodiscard]] constexpr bool operator<(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator<(const type_info &lhs, const type_info &rhs) noexcept {
return lhs.index() < rhs.index();
}
@@ -216,7 +208,7 @@ private:
* @return True if the first element is less than or equal to the second, false
* otherwise.
*/
[[nodiscard]] constexpr bool operator<=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator<=(const type_info &lhs, const type_info &rhs) noexcept {
return !(rhs < lhs);
}
@@ -227,7 +219,7 @@ private:
* @return True if the first element is greater than the second, false
* otherwise.
*/
[[nodiscard]] constexpr bool operator>(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator>(const type_info &lhs, const type_info &rhs) noexcept {
return rhs < lhs;
}
@@ -238,30 +230,37 @@ private:
* @return True if the first element is greater than or equal to the second,
* false otherwise.
*/
[[nodiscard]] constexpr bool operator>=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator>=(const type_info &lhs, const type_info &rhs) noexcept {
return !(lhs < rhs);
}
/**
* @brief Returns the type info object associated to a given type.
*
* The returned element refers to an object with static storage duration.<br/>
* The type doesn't need to be a complete type. If the type is a reference, the
* result refers to the referenced type. In all cases, top-level cv-qualifiers
* are ignored.
*
* @tparam Type Type for which to generate a type info object.
* @return A properly initialized type info object.
* @return A reference to a properly initialized type info object.
*/
template<typename Type>
[[nodiscard]] const type_info &type_id() ENTT_NOEXCEPT {
[[nodiscard]] const type_info &type_id() noexcept {
if constexpr(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>) {
static type_info instance{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>};
static type_info instance{std::in_place_type<Type>};
return instance;
} else {
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
}
}
/*! @copydoc type_id */
template<typename Type>
[[nodiscard]] const type_info &type_id(Type &&) noexcept {
return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
}
} // namespace entt
#endif

View File

@@ -3,6 +3,7 @@
#include <cstddef>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
@@ -16,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 */
{};
@@ -55,7 +56,6 @@ using type_identity_t = typename type_identity<Type>::type;
/**
* @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains.
* @tparam Type The type of which to return the size.
* @tparam The size of the type if `sizeof` accepts it, 0 otherwise.
*/
template<typename Type, typename = void>
struct size_of: std::integral_constant<std::size_t, 0u> {};
@@ -121,22 +121,22 @@ struct type_list_element;
/**
* @brief Provides compile-time indexed access to the types of a type list.
* @tparam Index Index of the type to return.
* @tparam Type First type provided by the type list.
* @tparam First First type provided by the type list.
* @tparam Other Other types provided by the type list.
*/
template<std::size_t Index, typename Type, typename... Other>
struct type_list_element<Index, type_list<Type, Other...>>
template<std::size_t Index, typename First, typename... Other>
struct type_list_element<Index, type_list<First, Other...>>
: type_list_element<Index - 1u, type_list<Other...>> {};
/**
* @brief Provides compile-time indexed access to the types of a type list.
* @tparam Type First type provided by the type list.
* @tparam First First type provided by the type list.
* @tparam Other Other types provided by the type list.
*/
template<typename Type, typename... Other>
struct type_list_element<0u, type_list<Type, Other...>> {
template<typename First, typename... Other>
struct type_list_element<0u, type_list<First, Other...>> {
/*! @brief Searched type. */
using type = Type;
using type = First;
};
/**
@@ -147,6 +147,58 @@ struct type_list_element<0u, type_list<Type, Other...>> {
template<std::size_t Index, typename List>
using type_list_element_t = typename type_list_element<Index, List>::type;
/*! @brief Primary template isn't defined on purpose. */
template<typename, typename>
struct type_list_index;
/**
* @brief Provides compile-time type access to the types of a type list.
* @tparam Type Type to look for and for which to return the index.
* @tparam First First type provided by the type list.
* @tparam Other Other types provided by the type list.
*/
template<typename Type, typename First, typename... Other>
struct type_list_index<Type, type_list<First, Other...>> {
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
/*! @brief Compile-time position of the given type in the sublist. */
static constexpr value_type value = 1u + type_list_index<Type, type_list<Other...>>::value;
};
/**
* @brief Provides compile-time type access to the types of a type list.
* @tparam Type Type to look for and for which to return the index.
* @tparam Other Other types provided by the type list.
*/
template<typename Type, typename... Other>
struct type_list_index<Type, type_list<Type, Other...>> {
static_assert(type_list_index<Type, type_list<Other...>>::value == sizeof...(Other), "Non-unique type");
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
/*! @brief Compile-time position of the given type in the sublist. */
static constexpr value_type value = 0u;
};
/**
* @brief Provides compile-time type access to the types of a type list.
* @tparam Type Type to look for and for which to return the index.
*/
template<typename Type>
struct type_list_index<Type, type_list<>> {
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
/*! @brief Compile-time position of the given type in the sublist. */
static constexpr value_type value = 0u;
};
/**
* @brief Helper variable template.
* @tparam List Type list.
* @tparam Type Type to look for and for which to return the index.
*/
template<typename Type, typename List>
inline constexpr std::size_t type_list_index_v = type_list_index<Type, List>::value;
/**
* @brief Concatenates multiple type lists.
* @tparam Type Types provided by the first type list.
@@ -198,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::disjunction_v<std::is_same<Type, Other>...>,
typename type_list_unique<type_list<Other...>>::type,
type_list_cat_t<type_list<Type>, typename type_list_unique<type_list<Other...>>::type>>;
};
/*! @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
@@ -245,7 +300,8 @@ struct type_list_contains;
* @tparam Other Type to look for.
*/
template<typename... Type, typename Other>
struct type_list_contains<type_list<Type...>, Other>: std::disjunction<std::is_same<Type, Other>...> {};
struct type_list_contains<type_list<Type...>, Other>
: std::bool_constant<(std::is_same_v<Type, Other> || ...)> {};
/**
* @brief Helper variable template.
@@ -277,6 +333,29 @@ struct type_list_diff<type_list<Type...>, type_list<Other...>> {
template<typename... List>
using type_list_diff_t = typename type_list_diff<List...>::type;
/*! @brief Primary template isn't defined on purpose. */
template<typename, template<typename...> class>
struct type_list_transform;
/**
* @brief Applies a given _function_ to a type list and generate a new list.
* @tparam Type Types provided by the type list.
* @tparam Op Unary operation as template class with a type member named `type`.
*/
template<typename... Type, template<typename...> class Op>
struct type_list_transform<type_list<Type...>, Op> {
/*! @brief Resulting type list after applying the transform function. */
using type = type_list<typename Op<Type>::type...>;
};
/**
* @brief Helper type.
* @tparam List Type list.
* @tparam Op Unary operation as template class with a type member named `type`.
*/
template<typename List, template<typename...> class Op>
using type_list_transform_t = typename type_list_transform<List, Op>::type;
/**
* @brief A class to use to push around lists of constant values, nothing more.
* @tparam Value Values provided by the value list.
@@ -310,10 +389,20 @@ struct value_list_element<Index, value_list<Value, Other...>>
*/
template<auto Value, auto... Other>
struct value_list_element<0u, value_list<Value, Other...>> {
/*! @brief Searched type. */
using type = decltype(Value);
/*! @brief Searched value. */
static constexpr auto value = Value;
};
/**
* @brief Helper type.
* @tparam Index Index of the type to return.
* @tparam List Value list to search into.
*/
template<std::size_t Index, typename List>
using value_list_element_t = typename value_list_element<Index, List>::type;
/**
* @brief Helper type.
* @tparam Index Index of the value to return.
@@ -322,6 +411,58 @@ struct value_list_element<0u, value_list<Value, Other...>> {
template<std::size_t Index, typename List>
inline constexpr auto value_list_element_v = value_list_element<Index, List>::value;
/*! @brief Primary template isn't defined on purpose. */
template<auto, typename>
struct value_list_index;
/**
* @brief Provides compile-time type access to the values of a value list.
* @tparam Value Value to look for and for which to return the index.
* @tparam First First value provided by the value list.
* @tparam Other Other values provided by the value list.
*/
template<auto Value, auto First, auto... Other>
struct value_list_index<Value, value_list<First, Other...>> {
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
/*! @brief Compile-time position of the given value in the sublist. */
static constexpr value_type value = 1u + value_list_index<Value, value_list<Other...>>::value;
};
/**
* @brief Provides compile-time type access to the values of a value list.
* @tparam Value Value to look for and for which to return the index.
* @tparam Other Other values provided by the value list.
*/
template<auto Value, auto... Other>
struct value_list_index<Value, value_list<Value, Other...>> {
static_assert(value_list_index<Value, value_list<Other...>>::value == sizeof...(Other), "Non-unique type");
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
/*! @brief Compile-time position of the given value in the sublist. */
static constexpr value_type value = 0u;
};
/**
* @brief Provides compile-time type access to the values of a value list.
* @tparam Value Value to look for and for which to return the index.
*/
template<auto Value>
struct value_list_index<Value, value_list<>> {
/*! @brief Unsigned integer type. */
using value_type = std::size_t;
/*! @brief Compile-time position of the given type in the sublist. */
static constexpr value_type value = 0u;
};
/**
* @brief Helper variable template.
* @tparam List Value list.
* @tparam Value Value to look for and for which to return the index.
*/
template<auto Value, typename List>
inline constexpr std::size_t value_list_index_v = value_list_index<Value, List>::value;
/**
* @brief Concatenates multiple value lists.
* @tparam Value Values provided by the first value list.
@@ -373,6 +514,89 @@ struct value_list_cat<value_list<Value...>> {
template<typename... List>
using value_list_cat_t = typename value_list_cat<List...>::type;
/*! @brief Primary template isn't defined on purpose. */
template<typename>
struct value_list_unique;
/**
* @brief Removes duplicates values from a value list.
* @tparam Value One of the values provided by the given value list.
* @tparam Other The other values provided by the given value list.
*/
template<auto Value, auto... Other>
struct value_list_unique<value_list<Value, Other...>> {
/*! @brief A value list without duplicate types. */
using type = std::conditional_t<
((Value == Other) || ...),
typename value_list_unique<value_list<Other...>>::type,
value_list_cat_t<value_list<Value>, typename value_list_unique<value_list<Other...>>::type>>;
};
/*! @brief Removes duplicates values from a value list. */
template<>
struct value_list_unique<value_list<>> {
/*! @brief A value list without duplicate types. */
using type = value_list<>;
};
/**
* @brief Helper type.
* @tparam Type A value list.
*/
template<typename Type>
using value_list_unique_t = typename value_list_unique<Type>::type;
/**
* @brief Provides the member constant `value` to true if a value list contains
* a given value, false otherwise.
* @tparam List Value list.
* @tparam Value Value to look for.
*/
template<typename List, auto Value>
struct value_list_contains;
/**
* @copybrief value_list_contains
* @tparam Value Values provided by the value list.
* @tparam Other Value to look for.
*/
template<auto... Value, auto Other>
struct value_list_contains<value_list<Value...>, Other>
: std::bool_constant<((Value == Other) || ...)> {};
/**
* @brief Helper variable template.
* @tparam List Value list.
* @tparam Value Value to look for.
*/
template<typename List, auto Value>
inline constexpr bool value_list_contains_v = value_list_contains<List, Value>::value;
/*! @brief Primary template isn't defined on purpose. */
template<typename...>
class value_list_diff;
/**
* @brief Computes the difference between two value lists.
* @tparam Value Values provided by the first value list.
* @tparam Other Values provided by the second value list.
*/
template<auto... Value, auto... Other>
class value_list_diff<value_list<Value...>, value_list<Other...>> {
using v141_toolset_workaround = value_list<Other...>;
public:
/*! @brief A value list that is the difference between the two value lists. */
using type = value_list_cat_t<std::conditional_t<value_list_contains_v<v141_toolset_workaround, Value>, value_list<>, value_list<Value>>...>;
};
/**
* @brief Helper type.
* @tparam List Value lists between which to compute the difference.
*/
template<typename... List>
using value_list_diff_t = typename value_list_diff<List...>::type;
/*! @brief Same as std::is_invocable, but with tuples. */
template<typename, typename>
struct is_applicable: std::false_type {};
@@ -454,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>
@@ -468,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_const_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> {};
/**
@@ -486,33 +702,6 @@ struct is_iterator<Type, std::enable_if_t<!std::is_same_v<std::remove_const_t<st
template<typename Type>
inline constexpr bool is_iterator_v = is_iterator<Type>::value;
/**
* @brief Provides the member constant `value` to true if a given type is of the
* required iterator type, false otherwise.
* @tparam Type The type to test.
* @tparam It Required iterator type.
*/
template<typename Type, typename It, typename = void>
struct is_iterator_type: std::false_type {};
/*! @copydoc is_iterator_type */
template<typename Type, typename It>
struct is_iterator_type<Type, It, std::enable_if_t<is_iterator_v<Type> && std::is_same_v<Type, It>>>
: std::true_type {};
/*! @copydoc is_iterator_type */
template<typename Type, typename It>
struct is_iterator_type<Type, It, std::enable_if_t<!std::is_same_v<Type, It>, std::void_t<typename It::iterator_type>>>
: is_iterator_type<Type, typename It::iterator_type> {};
/**
* @brief Helper variable template.
* @tparam Type The type to test.
* @tparam It Required iterator type.
*/
template<typename Type, typename It>
inline constexpr bool is_iterator_type_v = is_iterator_type<Type, It>::value;
/**
* @brief Provides the member constant `value` to true if a given type is both
* an empty and non-final class, false otherwise.
@@ -520,7 +709,7 @@ inline constexpr bool is_iterator_type_v = is_iterator_type<Type, It>::value;
*/
template<typename Type>
struct is_ebco_eligible
: std::conjunction<std::is_empty<Type>, std::negation<std::is_final<Type>>> {};
: std::bool_constant<std::is_empty_v<Type> && !std::is_final_v<Type>> {};
/**
* @brief Helper variable template.
@@ -548,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>
@@ -569,47 +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_const_t<Type>>>, bool> maybe_equality_comparable(choice_t<2>) {
if constexpr(has_tuple_size_value<Type>::value) {
return unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
} else {
return maybe_equality_comparable<Type>(choice<1>);
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>)> {};
struct is_equality_comparable<const Type>: is_equality_comparable<Type> {};
/**
* @brief Helper variable template.
@@ -633,7 +832,7 @@ struct constness_as {
template<typename To, typename From>
struct constness_as<To, const From> {
/*! @brief The type resulting from the transcription of the constness. */
using type = std::add_const_t<To>;
using type = const To;
};
/**
@@ -673,6 +872,50 @@ public:
template<typename Member>
using member_class_t = typename member_class<Member>::type;
/**
* @brief Extracts the n-th argument of a given function or member function.
* @tparam Index The index of the argument to extract.
* @tparam Candidate A valid function, member function or data member type.
*/
template<std::size_t Index, typename Candidate>
class nth_argument {
template<typename Ret, typename... Args>
static constexpr type_list<Args...> pick_up(Ret (*)(Args...));
template<typename Ret, typename Class, typename... Args>
static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...));
template<typename Ret, typename Class, typename... Args>
static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...) const);
template<typename Type, typename Class>
static constexpr type_list<Type> pick_up(Type Class ::*);
public:
/*! @brief N-th argument of the given function or member function. */
using type = type_list_element_t<Index, decltype(pick_up(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 type.
*/
template<std::size_t Index, typename Candidate>
using nth_argument_t = typename nth_argument<Index, Candidate>::type;
} // namespace entt
template<typename... Type>
struct std::tuple_size<entt::type_list<Type...>>: std::integral_constant<std::size_t, entt::type_list<Type...>::size> {};
template<std::size_t Index, typename... Type>
struct std::tuple_element<Index, entt::type_list<Type...>>: entt::type_list_element<Index, entt::type_list<Type...>> {};
template<auto... Value>
struct std::tuple_size<entt::value_list<Value...>>: std::integral_constant<std::size_t, entt::value_list<Value...>::size> {};
template<std::size_t Index, auto... Value>
struct std::tuple_element<Index, entt::value_list<Value...>>: entt::value_list_element<Index, entt::value_list<Value...>> {};
#endif

View File

@@ -1,8 +1,8 @@
#ifndef ENTT_CORE_UTILITY_HPP
#define ENTT_CORE_UTILITY_HPP
#include <type_traits>
#include <utility>
#include "../config/config.h"
namespace entt {
@@ -17,8 +17,8 @@ struct identity {
* @param value The actual argument.
* @return The submitted value as-is.
*/
template<class Type>
[[nodiscard]] constexpr Type &&operator()(Type &&value) const ENTT_NOEXCEPT {
template<typename Type>
[[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept {
return std::forward<Type>(value);
}
};
@@ -31,7 +31,7 @@ struct identity {
* @return Pointer to the member.
*/
template<typename Type, typename Class>
[[nodiscard]] constexpr auto overload(Type Class::*member) ENTT_NOEXCEPT {
[[nodiscard]] constexpr auto overload(Type Class::*member) noexcept {
return member;
}
@@ -42,7 +42,7 @@ template<typename Type, typename Class>
* @return Pointer to the function.
*/
template<typename Func>
[[nodiscard]] constexpr auto overload(Func *func) ENTT_NOEXCEPT {
[[nodiscard]] constexpr auto overload(Func *func) noexcept {
return func;
}
@@ -50,7 +50,7 @@ template<typename Func>
* @brief Helper type for visitors.
* @tparam Func Types of function objects.
*/
template<class... Func>
template<typename... Func>
struct overloaded: Func... {
using Func::operator()...;
};
@@ -59,20 +59,20 @@ struct overloaded: Func... {
* @brief Deduction guide.
* @tparam Func Types of function objects.
*/
template<class... Func>
template<typename... Func>
overloaded(Func...) -> overloaded<Func...>;
/**
* @brief Basic implementation of a y-combinator.
* @tparam Func Type of a potentially recursive function.
*/
template<class Func>
template<typename Func>
struct y_combinator {
/**
* @brief Constructs a y-combinator from a given function.
* @param recursive A potentially recursive function.
*/
y_combinator(Func recursive)
constexpr y_combinator(Func recursive) noexcept(std::is_nothrow_move_constructible_v<Func>)
: func{std::move(recursive)} {}
/**
@@ -81,14 +81,14 @@ struct y_combinator {
* @param args Parameters to use to invoke the underlying function.
* @return Return value of the underlying function, if any.
*/
template<class... Args>
decltype(auto) operator()(Args &&...args) const {
template<typename... Args>
constexpr decltype(auto) operator()(Args &&...args) const noexcept(std::is_nothrow_invocable_v<Func, const y_combinator &, Args...>) {
return func(*this, std::forward<Args>(args)...);
}
/*! @copydoc operator()() */
template<class... Args>
decltype(auto) operator()(Args &&...args) {
template<typename... Args>
constexpr decltype(auto) operator()(Args &&...args) noexcept(std::is_nothrow_invocable_v<Func, y_combinator &, Args...>) {
return func(*this, std::forward<Args>(args)...);
}

View File

@@ -1,36 +1,55 @@
#ifndef ENTT_ENTITY_COMPONENT_HPP
#define ENTT_ENTITY_COMPONENT_HPP
#include <cstddef>
#include <type_traits>
#include "../config/config.h"
#include "fwd.hpp"
namespace entt {
/*! @brief Commonly used default traits for all types. */
struct basic_component_traits {
/*! @brief Pointer stability, default is `false`. */
static constexpr auto in_place_delete = false;
/*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */
static constexpr auto ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
/*! @brief Page size, default is `ENTT_PACKED_PAGE`. */
static constexpr auto page_size = ENTT_PACKED_PAGE;
};
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type, typename = void>
struct in_place_delete: std::bool_constant<!(std::is_move_constructible_v<Type> && std::is_move_assignable_v<Type>)> {};
template<>
struct in_place_delete<void>: std::false_type {};
template<typename Type>
struct in_place_delete<Type, std::enable_if_t<Type::in_place_delete>>
: std::true_type {};
template<typename Type, typename = void>
struct page_size: std::integral_constant<std::size_t, !std::is_empty_v<ENTT_ETO_TYPE(Type)> * ENTT_PACKED_PAGE> {};
template<>
struct page_size<void>: std::integral_constant<std::size_t, 0u> {};
template<typename Type>
struct page_size<Type, std::void_t<decltype(Type::page_size)>>
: std::integral_constant<std::size_t, Type::page_size> {};
} // namespace internal
/*! @endcond */
/**
* @brief Common way to access various properties of components.
* @tparam Type Type of component.
*/
template<typename Type, typename = void>
struct component_traits: basic_component_traits {
struct component_traits {
static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
};
/**
* @brief Helper variable template.
* @tparam Type Type of component.
*/
template<class Type>
inline constexpr bool ignore_as_empty_v = component_traits<Type>::ignore_if_empty &&std::is_empty_v<Type>;
/*! @brief Component type. */
using type = Type;
/*! @brief Pointer stability, default is `false`. */
static constexpr bool in_place_delete = internal::in_place_delete<Type>::value;
/*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */
static constexpr std::size_t page_size = internal::page_size<Type>::value;
};
} // namespace entt

View File

@@ -9,77 +9,85 @@
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
template<typename Type>
constexpr int popcount(Type value) noexcept {
return value ? (int(value & 1) + popcount(value >> 1)) : 0;
}
template<typename, typename = void>
struct entt_traits;
template<typename Type>
struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>>
: entt_traits<std::underlying_type_t<Type>> {};
: entt_traits<std::underlying_type_t<Type>> {
using value_type = Type;
};
template<typename Type>
struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>>
: entt_traits<typename Type::entity_type> {};
: entt_traits<typename Type::entity_type> {
using value_type = Type;
};
template<>
struct entt_traits<std::uint32_t> {
using value_type = std::uint32_t;
using entity_type = std::uint32_t;
using version_type = std::uint16_t;
static constexpr entity_type entity_mask = 0xFFFFF;
static constexpr entity_type version_mask = 0xFFF;
static constexpr std::size_t entity_shift = 20u;
};
template<>
struct entt_traits<std::uint64_t> {
using value_type = std::uint64_t;
using entity_type = std::uint64_t;
using version_type = std::uint32_t;
static constexpr entity_type entity_mask = 0xFFFFFFFF;
static constexpr entity_type version_mask = 0xFFFFFFFF;
static constexpr std::size_t entity_shift = 32u;
};
} // namespace internal
/*! @endcond */
/**
* Internal details not to be documented.
* @endcond
* @brief Common basic entity traits implementation.
* @tparam Traits Actual entity traits to use.
*/
template<typename Traits>
class basic_entt_traits {
static constexpr auto length = internal::popcount(Traits::entity_mask);
/**
* @brief Entity traits.
* @tparam Type Type of identifier.
*/
template<typename Type>
class entt_traits: internal::entt_traits<Type> {
using base_type = internal::entt_traits<Type>;
static_assert(Traits::entity_mask && ((typename Traits::entity_type{1} << length) == (Traits::entity_mask + 1)), "Invalid entity mask");
static_assert((typename Traits::entity_type{1} << internal::popcount(Traits::version_mask)) == (Traits::version_mask + 1), "Invalid version mask");
public:
/*! @brief Value type. */
using value_type = Type;
using value_type = typename Traits::value_type;
/*! @brief Underlying entity type. */
using entity_type = typename base_type::entity_type;
using entity_type = typename Traits::entity_type;
/*! @brief Underlying version type. */
using version_type = typename base_type::version_type;
/*! @brief Reserved identifier. */
static constexpr entity_type reserved = base_type::entity_mask | (base_type::version_mask << base_type::entity_shift);
/*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */
static constexpr auto page_size = ENTT_SPARSE_PAGE;
using version_type = typename Traits::version_type;
/*! @brief Entity mask size. */
static constexpr entity_type entity_mask = Traits::entity_mask;
/*! @brief Version mask size */
static constexpr entity_type version_mask = Traits::version_mask;
/**
* @brief Converts an entity to its underlying type.
* @param value The value to convert.
* @return The integral representation of the given value.
*/
[[nodiscard]] static constexpr entity_type to_integral(const value_type value) ENTT_NOEXCEPT {
[[nodiscard]] static constexpr entity_type to_integral(const value_type value) noexcept {
return static_cast<entity_type>(value);
}
@@ -88,8 +96,8 @@ public:
* @param value The value to convert.
* @return The integral representation of the entity part.
*/
[[nodiscard]] static constexpr entity_type to_entity(const value_type value) ENTT_NOEXCEPT {
return (to_integral(value) & base_type::entity_mask);
[[nodiscard]] static constexpr entity_type to_entity(const value_type value) noexcept {
return (to_integral(value) & entity_mask);
}
/**
@@ -97,8 +105,18 @@ public:
* @param value The value to convert.
* @return The integral representation of the version part.
*/
[[nodiscard]] static constexpr version_type to_version(const value_type value) ENTT_NOEXCEPT {
return (to_integral(value) >> base_type::entity_shift);
[[nodiscard]] static constexpr version_type to_version(const value_type value) noexcept {
return (static_cast<version_type>(to_integral(value) >> length) & version_mask);
}
/**
* @brief Returns the successor of a given identifier.
* @param value The identifier of which to return the successor.
* @return The successor of the given identifier.
*/
[[nodiscard]] static constexpr value_type next(const value_type value) noexcept {
const auto vers = to_version(value) + 1;
return construct(to_integral(value), static_cast<version_type>(vers + (vers == version_mask)));
}
/**
@@ -111,8 +129,8 @@ public:
* @param version The version part of the identifier.
* @return A properly constructed identifier.
*/
[[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) ENTT_NOEXCEPT {
return value_type{(entity & base_type::entity_mask) | (static_cast<entity_type>(version) << base_type::entity_shift)};
[[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 & version_mask) << length)};
}
/**
@@ -125,36 +143,53 @@ public:
* @param rhs The identifier from which to take the version part.
* @return A properly constructed identifier.
*/
[[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) ENTT_NOEXCEPT {
constexpr auto mask = (base_type::version_mask << base_type::entity_shift);
return value_type{(lhs & base_type::entity_mask) | (rhs & mask)};
[[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept {
return value_type{(lhs & entity_mask) | (rhs & (version_mask << length))};
}
};
/**
* @copydoc entt_traits<Entity>::to_integral
* @brief Entity traits.
* @tparam Type Type of identifier.
*/
template<typename Type>
struct entt_traits: basic_entt_traits<internal::entt_traits<Type>> {
/*! @brief Base type. */
using base_type = basic_entt_traits<internal::entt_traits<Type>>;
/*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */
static constexpr std::size_t page_size = ENTT_SPARSE_PAGE;
};
/**
* @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) ENTT_NOEXCEPT {
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_integral(const Entity value) noexcept {
return entt_traits<Entity>::to_integral(value);
}
/**
* @copydoc entt_traits<Entity>::to_entity
* @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) ENTT_NOEXCEPT {
[[nodiscard]] constexpr typename entt_traits<Entity>::entity_type to_entity(const Entity value) noexcept {
return entt_traits<Entity>::to_entity(value);
}
/**
* @copydoc entt_traits<Entity>::to_version
* @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) ENTT_NOEXCEPT {
[[nodiscard]] constexpr typename entt_traits<Entity>::version_type to_version(const Entity value) noexcept {
return entt_traits<Entity>::to_version(value);
}
@@ -166,9 +201,10 @@ struct null_t {
* @return The null representation for the given type.
*/
template<typename Entity>
[[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT {
using entity_traits = entt_traits<Entity>;
return entity_traits::combine(entity_traits::reserved, entity_traits::reserved);
[[nodiscard]] constexpr operator Entity() const noexcept {
using traits_type = entt_traits<Entity>;
constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
return value;
}
/**
@@ -176,7 +212,7 @@ struct null_t {
* @param other A null object.
* @return True in all cases.
*/
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const noexcept {
return true;
}
@@ -185,7 +221,7 @@ struct null_t {
* @param other A null object.
* @return False in all cases.
*/
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) const noexcept {
return false;
}
@@ -196,9 +232,9 @@ struct null_t {
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
using entity_traits = entt_traits<Entity>;
return entity_traits::to_entity(entity) == entity_traits::to_entity(*this);
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
using traits_type = entt_traits<Entity>;
return traits_type::to_entity(entity) == traits_type::to_entity(*this);
}
/**
@@ -208,7 +244,7 @@ struct null_t {
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
return !(entity == *this);
}
};
@@ -221,7 +257,7 @@ struct null_t {
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity, const null_t other) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator==(const Entity entity, const null_t other) noexcept {
return other.operator==(entity);
}
@@ -233,7 +269,7 @@ template<typename Entity>
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity, const null_t other) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator!=(const Entity entity, const null_t other) noexcept {
return !(other == entity);
}
@@ -245,9 +281,10 @@ struct tombstone_t {
* @return The tombstone representation for the given type.
*/
template<typename Entity>
[[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT {
using entity_traits = entt_traits<Entity>;
return entity_traits::combine(entity_traits::reserved, entity_traits::reserved);
[[nodiscard]] constexpr operator Entity() const noexcept {
using traits_type = entt_traits<Entity>;
constexpr auto value = traits_type::construct(traits_type::entity_mask, traits_type::version_mask);
return value;
}
/**
@@ -255,7 +292,7 @@ struct tombstone_t {
* @param other A tombstone object.
* @return True in all cases.
*/
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const noexcept {
return true;
}
@@ -264,7 +301,7 @@ struct tombstone_t {
* @param other A tombstone object.
* @return False in all cases.
*/
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const noexcept {
return false;
}
@@ -275,9 +312,9 @@ struct tombstone_t {
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
using entity_traits = entt_traits<Entity>;
return entity_traits::to_version(entity) == entity_traits::to_version(*this);
[[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept {
using traits_type = entt_traits<Entity>;
return traits_type::to_version(entity) == traits_type::to_version(*this);
}
/**
@@ -287,7 +324,7 @@ struct tombstone_t {
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator!=(const Entity entity) const noexcept {
return !(entity == *this);
}
};
@@ -300,7 +337,7 @@ struct tombstone_t {
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator==(const Entity entity, const tombstone_t other) noexcept {
return other.operator==(entity);
}
@@ -312,7 +349,7 @@ template<typename Entity>
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator!=(const Entity entity, const tombstone_t other) noexcept {
return !(other == entity);
}
@@ -320,7 +357,7 @@ template<typename Entity>
* @brief Compile-time constant for null entities.
*
* There exist implicit conversions from this variable to identifiers of any
* allowed type. Similarly, there exist comparision operators between the null
* allowed type. Similarly, there exist comparison operators between the null
* entity and any other identifier.
*/
inline constexpr null_t null{};
@@ -329,7 +366,7 @@ inline constexpr null_t null{};
* @brief Compile-time constant for tombstone entities.
*
* There exist implicit conversions from this variable to identifiers of any
* allowed type. Similarly, there exist comparision operators between the
* allowed type. Similarly, there exist comparison operators between the
* tombstone entity and any other identifier.
*/
inline constexpr tombstone_t tombstone{};

View File

@@ -1,31 +1,49 @@
#ifndef ENTT_ENTITY_FWD_HPP
#define ENTT_ENTITY_FWD_HPP
#include <cstdint>
#include <memory>
#include <type_traits>
#include "../core/fwd.hpp"
#include "utility.hpp"
#include "../core/type_traits.hpp"
namespace entt {
template<typename Entity, typename = std::allocator<Entity>>
/*! @brief Default entity identifier. */
enum class entity : id_type {};
/*! @brief Storage deletion policy. */
enum class deletion_policy : std::uint8_t {
/*! @brief Swap-and-pop deletion policy. */
swap_and_pop = 0u,
/*! @brief In-place deletion policy. */
in_place = 1u,
/*! @brief Swap-only deletion policy. */
swap_only = 2u
};
template<typename Entity = entity, typename = std::allocator<Entity>>
class basic_sparse_set;
template<typename, typename Type, typename = std::allocator<Type>, typename = void>
template<typename Type, typename = entity, typename = std::allocator<Type>, typename = void>
class basic_storage;
template<typename>
template<typename, typename>
class basic_sigh_mixin;
template<typename Entity = entity, typename = std::allocator<Entity>>
class basic_registry;
template<typename, typename, typename, typename = void>
template<typename, typename, typename = void>
class basic_view;
template<typename>
template<typename Type, typename = std::allocator<Type *>>
class basic_runtime_view;
template<typename, typename, typename, typename>
template<typename, typename, typename>
class basic_group;
template<typename>
template<typename, typename Mask = std::uint32_t, typename = std::allocator<Mask>>
class basic_observer;
template<typename>
@@ -43,74 +61,205 @@ class basic_snapshot_loader;
template<typename>
class basic_continuous_loader;
/*! @brief Default entity identifier. */
enum class entity : id_type {};
/*! @brief Alias declaration for the most common use case. */
using sparse_set = basic_sparse_set<>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Type Type of objects assigned to the entities.
*/
template<typename Type>
using storage = basic_storage<Type>;
/**
* @brief Alias declaration for the most common use case.
* @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 sparse_set = basic_sparse_set<entity>;
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 storage = basic_storage<entity, Args...>;
/*! @brief Alias declaration for the most common use case. */
using registry = basic_registry<entity>;
/*! @brief Alias declaration for the most common use case. */
using observer = basic_observer<entity>;
/*! @brief Alias declaration for the most common use case. */
using organizer = basic_organizer<entity>;
/*! @brief Alias declaration for the most common use case. */
using handle = basic_handle<entity>;
/*! @brief Alias declaration for the most common use case. */
using const_handle = basic_handle<const entity>;
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 handle_view = basic_handle<entity, 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 declaration for the most common use case.
* @tparam Args Other template parameters.
* @brief Alias for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
struct exclude_t final: type_list<Type...> {
/*! @brief Default constructor. */
explicit constexpr exclude_t() {}
};
/**
* @brief Variable template for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr exclude_t<Type...> exclude{};
/**
* @brief Alias for lists of observed components.
* @tparam Type List of types.
*/
template<typename... Type>
struct get_t final: type_list<Type...> {
/*! @brief Default constructor. */
explicit constexpr get_t() {}
};
/**
* @brief Variable template for lists of observed components.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr get_t<Type...> get{};
/**
* @brief Alias for lists of owned components.
* @tparam Type List of types.
*/
template<typename... Type>
struct owned_t final: type_list<Type...> {
/*! @brief Default constructor. */
explicit constexpr owned_t() {}
};
/**
* @brief Variable template for lists of owned components.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr owned_t<Type...> owned{};
/**
* @brief Applies a given _function_ to a get list and generate a new list.
* @tparam Type Types provided by the get list.
* @tparam Op Unary operation as template class with a type member named `type`.
*/
template<typename... Type, template<typename...> class Op>
struct type_list_transform<get_t<Type...>, Op> {
/*! @brief Resulting get list after applying the transform function. */
using type = get_t<typename Op<Type>::type...>;
};
/**
* @brief Applies a given _function_ to an exclude list and generate a new list.
* @tparam Type Types provided by the exclude list.
* @tparam Op Unary operation as template class with a type member named `type`.
*/
template<typename... Type, template<typename...> class Op>
struct type_list_transform<exclude_t<Type...>, Op> {
/*! @brief Resulting exclude list after applying the transform function. */
using type = exclude_t<typename Op<Type>::type...>;
};
/**
* @brief Applies a given _function_ to an owned list and generate a new list.
* @tparam Type Types provided by the owned list.
* @tparam Op Unary operation as template class with a type member named `type`.
*/
template<typename... Type, template<typename...> class Op>
struct type_list_transform<owned_t<Type...>, Op> {
/*! @brief Resulting owned list after applying the transform function. */
using type = owned_t<typename Op<Type>::type...>;
};
/**
* @brief 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 const_handle_view = basic_handle<const entity, Args...>;
using storage_type_t = typename storage_type<Args...>::type;
/*! @brief Alias declaration for the most common use case. */
using snapshot = basic_snapshot<entity>;
/**
* 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 Alias declaration for the most common use case. */
using snapshot_loader = basic_snapshot_loader<entity>;
/*! @brief Alias declaration for the most common use case. */
using continuous_loader = basic_continuous_loader<entity>;
/**
* @brief Helper type.
* @tparam Args Arguments to forward.
*/
template<typename... Args>
using storage_for_t = typename storage_for<Args...>::type;
/**
* @brief Alias declaration for the most common use case.
* @tparam Get Types of components iterated by the view.
* @tparam Exclude Types of components used to filter the view.
* @tparam Get Types of storage iterated by the view.
* @tparam Exclude Types of storage used to filter the view.
*/
template<typename Get, typename Exclude = exclude_t<>>
using view = basic_view<entity, Get, Exclude>;
/*! @brief Alias declaration for the most common use case. */
using runtime_view = basic_runtime_view<entity>;
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.
* @tparam Args Other template parameters.
* @tparam Owned Types of storage _owned_ by the group.
* @tparam Get Types of storage _observed_ by the group.
* @tparam Exclude Types of storage used to filter the group.
*/
template<typename... Args>
using group = basic_group<entity, Args...>;
template<typename Owned, typename Get, typename Exclude>
using group = basic_group<type_list_transform_t<Owned, storage_for>, type_list_transform_t<Get, storage_for>, type_list_transform_t<Exclude, storage_for>>;
} // namespace entt

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,102 @@
#ifndef ENTT_ENTITY_HANDLE_HPP
#define ENTT_ENTITY_HANDLE_HPP
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/iterator.hpp"
#include "../core/type_traits.hpp"
#include "entity.hpp"
#include "fwd.hpp"
#include "registry.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename It>
class handle_storage_iterator final {
template<typename Other>
friend class handle_storage_iterator;
using underlying_type = std::remove_reference_t<typename It::value_type::second_type>;
using entity_type = typename underlying_type::entity_type;
public:
using value_type = typename std::iterator_traits<It>::value_type;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
constexpr handle_storage_iterator() noexcept
: entt{null},
it{},
last{} {}
constexpr handle_storage_iterator(entity_type value, It from, It to) noexcept
: entt{value},
it{from},
last{to} {
while(it != last && !it->second.contains(entt)) {
++it;
}
}
constexpr handle_storage_iterator &operator++() noexcept {
while(++it != last && !it->second.contains(entt)) {}
return *this;
}
constexpr handle_storage_iterator operator++(int) noexcept {
handle_storage_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] constexpr reference operator*() const noexcept {
return *it;
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
return operator*();
}
template<typename ILhs, typename IRhs>
friend constexpr bool operator==(const handle_storage_iterator<ILhs> &, const handle_storage_iterator<IRhs> &) noexcept;
private:
entity_type entt;
It it;
It last;
};
template<typename ILhs, typename IRhs>
[[nodiscard]] constexpr bool operator==(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename ILhs, typename IRhs>
[[nodiscard]] constexpr bool operator!=(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/*! @endcond */
/**
* @brief Non-owning handle to an entity.
*
* Tiny wrapper around a registry and an entity.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Type Types to which to restrict the scope of a handle.
* @tparam Registry Basic registry type.
* @tparam Scope Types to which to restrict the scope of a handle.
*/
template<typename Entity, typename... Type>
template<typename Registry, typename... Scope>
struct basic_handle {
/*! @brief Type of registry accepted by the handle. */
using registry_type = constness_as_t<basic_registry<std::remove_const_t<Entity>>, Entity>;
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
/*! @brief Underlying version type. */
@@ -31,7 +105,7 @@ struct basic_handle {
using size_type = typename registry_type::size_type;
/*! @brief Constructs an invalid handle. */
basic_handle() ENTT_NOEXCEPT
basic_handle() noexcept
: reg{},
entt{null} {}
@@ -40,21 +114,37 @@ struct basic_handle {
* @param ref An instance of the registry class.
* @param value A valid identifier.
*/
basic_handle(registry_type &ref, entity_type value) ENTT_NOEXCEPT
basic_handle(registry_type &ref, entity_type value) noexcept
: reg{&ref},
entt{value} {}
/**
* @brief Returns an iterable object to use to _visit_ a handle.
*
* The iterable object returns a pair that contains the name and a reference
* to the current storage.<br/>
* Returned storage are those that contain the entity associated with the
* handle.
*
* @return An iterable object to use to _visit_ the handle.
*/
[[nodiscard]] auto storage() const noexcept {
auto iterable = reg->storage();
using iterator_type = internal::handle_storage_iterator<typename decltype(iterable)::iterator>;
return iterable_adaptor{iterator_type{entt, iterable.begin(), iterable.end()}, iterator_type{entt, iterable.end(), iterable.end()}};
}
/**
* @brief Constructs a const handle from a non-const one.
* @tparam Other A valid entity type (see entt_traits for more details).
* @tparam Other A valid entity type.
* @tparam Args Scope of the handle to construct.
* @return A const handle referring to the same registry and the same
* entity.
*/
template<typename Other, typename... Args>
operator basic_handle<Other, Args...>() const ENTT_NOEXCEPT {
static_assert(std::is_same_v<Other, Entity> || std::is_same_v<std::remove_const_t<Other>, Entity>, "Invalid conversion between different handles");
static_assert((sizeof...(Type) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Type)) && ... && (type_list_contains_v<type_list<Type...>, Args>))), "Invalid conversion between different handles");
operator basic_handle<Other, Args...>() const noexcept {
static_assert(std::is_same_v<Other, Registry> || std::is_same_v<std::remove_const_t<Other>, Registry>, "Invalid conversion between different handles");
static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v<type_list<Scope...>, Args>))), "Invalid conversion between different handles");
return reg ? basic_handle<Other, Args...>{*reg, entt} : basic_handle<Other, Args...>{};
}
@@ -63,7 +153,7 @@ struct basic_handle {
* @brief Converts a handle to its underlying entity.
* @return The contained identifier.
*/
[[nodiscard]] operator entity_type() const ENTT_NOEXCEPT {
[[nodiscard]] operator entity_type() const noexcept {
return entity();
}
@@ -71,7 +161,7 @@ struct basic_handle {
* @brief Checks if a handle refers to non-null registry pointer and entity.
* @return True if the handle refers to non-null registry and entity, false otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
[[nodiscard]] explicit operator bool() const noexcept {
return reg && reg->valid(entt);
}
@@ -87,7 +177,7 @@ struct basic_handle {
* @brief Returns a pointer to the underlying registry, if any.
* @return A pointer to the underlying registry, if any.
*/
[[nodiscard]] registry_type *registry() const ENTT_NOEXCEPT {
[[nodiscard]] registry_type *registry() const noexcept {
return reg;
}
@@ -95,30 +185,25 @@ struct basic_handle {
* @brief Returns the entity associated with a handle.
* @return The entity associated with the handle.
*/
[[nodiscard]] entity_type entity() const ENTT_NOEXCEPT {
[[nodiscard]] entity_type entity() const noexcept {
return entt;
}
/**
* @brief Destroys the entity associated with a handle.
* @sa basic_registry::destroy
*/
/*! @brief Destroys the entity associated with a handle. */
void destroy() {
reg->destroy(entt);
reg->destroy(std::exchange(entt, null));
}
/**
* @brief Destroys the entity associated with a handle.
* @sa basic_registry::destroy
* @param version A desired version upon destruction.
*/
void destroy(const version_type version) {
reg->destroy(entt, version);
reg->destroy(std::exchange(entt, null), version);
}
/**
* @brief Assigns the given component to a handle.
* @sa basic_registry::emplace
* @tparam Component Type of component to create.
* @tparam Args Types of arguments to use to construct the component.
* @param args Parameters to use to initialize the component.
@@ -126,13 +211,12 @@ struct basic_handle {
*/
template<typename Component, typename... Args>
decltype(auto) emplace(Args &&...args) const {
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
return reg->template emplace<Component>(entt, std::forward<Args>(args)...);
}
/**
* @brief Assigns or replaces the given component for a handle.
* @sa basic_registry::emplace_or_replace
* @tparam Component Type of component to assign or replace.
* @tparam Args Types of arguments to use to construct the component.
* @param args Parameters to use to initialize the component.
@@ -140,13 +224,12 @@ struct basic_handle {
*/
template<typename Component, typename... Args>
decltype(auto) emplace_or_replace(Args &&...args) const {
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
return reg->template emplace_or_replace<Component>(entt, std::forward<Args>(args)...);
}
/**
* @brief Patches the given component for a handle.
* @sa basic_registry::patch
* @tparam Component Type of component to patch.
* @tparam Func Types of the function objects to invoke.
* @param func Valid function objects.
@@ -154,13 +237,12 @@ struct basic_handle {
*/
template<typename Component, typename... Func>
decltype(auto) patch(Func &&...func) const {
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
return reg->template patch<Component>(entt, std::forward<Func>(func)...);
}
/**
* @brief Replaces the given component for a handle.
* @sa basic_registry::replace
* @tparam Component Type of component to replace.
* @tparam Args Types of arguments to use to construct the component.
* @param args Parameters to use to initialize the component.
@@ -168,36 +250,33 @@ struct basic_handle {
*/
template<typename Component, typename... Args>
decltype(auto) replace(Args &&...args) const {
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
return reg->template replace<Component>(entt, std::forward<Args>(args)...);
}
/**
* @brief Removes the given components from a handle.
* @sa basic_registry::remove
* @tparam Component Types of components to remove.
* @return The number of components actually removed.
*/
template<typename... Component>
size_type remove() const {
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
return reg->template remove<Component...>(entt);
}
/**
* @brief Erases the given components from a handle.
* @sa basic_registry::erase
* @tparam Component Types of components to erase.
*/
template<typename... Component>
void erase() const {
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
reg->template erase<Component...>(entt);
}
/**
* @brief Checks if a handle has all the given components.
* @sa basic_registry::all_of
* @tparam Component Components for which to perform the check.
* @return True if the handle has all the components, false otherwise.
*/
@@ -208,7 +287,6 @@ struct basic_handle {
/**
* @brief Checks if a handle has at least one of the given components.
* @sa basic_registry::any_of
* @tparam Component Components for which to perform the check.
* @return True if the handle has at least one of the given components,
* false otherwise.
@@ -220,19 +298,17 @@ struct basic_handle {
/**
* @brief Returns references to the given components for a handle.
* @sa basic_registry::get
* @tparam Component Types of components to get.
* @return References to the components owned by the handle.
*/
template<typename... Component>
[[nodiscard]] decltype(auto) get() const {
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
return reg->template get<Component...>(entt);
}
/**
* @brief Returns a reference to the given component for a handle.
* @sa basic_registry::get_or_emplace
* @tparam Component Type of component to get.
* @tparam Args Types of arguments to use to construct the component.
* @param args Parameters to use to initialize the component.
@@ -240,19 +316,18 @@ struct basic_handle {
*/
template<typename Component, typename... Args>
[[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const {
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
static_assert(((sizeof...(Scope) == 0) || ... || std::is_same_v<Component, Scope>), "Invalid type");
return reg->template get_or_emplace<Component>(entt, std::forward<Args>(args)...);
}
/**
* @brief Returns pointers to the given components for a handle.
* @sa basic_registry::try_get
* @tparam Component Types of components to get.
* @return Pointers to the components owned by the handle.
*/
template<typename... Component>
[[nodiscard]] auto try_get() const {
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
static_assert(sizeof...(Scope) == 0 || (type_list_contains_v<type_list<Scope...>, Component> && ...), "Invalid type");
return reg->template try_get<Component...>(entt);
}
@@ -264,30 +339,6 @@ struct basic_handle {
return reg->orphan(entt);
}
/**
* @brief Visits a handle and returns the pools for its components.
*
* The signature of the function should be equivalent to the following:
*
* @code{.cpp}
* void(id_type, const basic_sparse_set<entity_type> &);
* @endcode
*
* Returned pools are those that contain the entity associated with the
* handle.
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void visit(Func &&func) const {
for(auto [id, storage]: reg->storage()) {
if(storage.contains(entt)) {
func(id, storage);
}
}
}
private:
registry_type *reg;
entity_type entt;
@@ -303,7 +354,7 @@ private:
* entity, false otherwise.
*/
template<typename... Args, typename... Other>
[[nodiscard]] bool operator==(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] bool operator==(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
return lhs.registry() == rhs.registry() && lhs.entity() == rhs.entity();
}
@@ -317,24 +368,10 @@ template<typename... Args, typename... Other>
* entity, true otherwise.
*/
template<typename... Args, typename... Other>
[[nodiscard]] bool operator!=(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] bool operator!=(const basic_handle<Args...> &lhs, const basic_handle<Other...> &rhs) noexcept {
return !(lhs == rhs);
}
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
basic_handle(basic_registry<Entity> &, Entity) -> basic_handle<Entity>;
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
basic_handle(const basic_registry<Entity> &, Entity) -> basic_handle<const Entity>;
} // namespace entt
#endif

View File

@@ -1,124 +1,113 @@
#ifndef ENTT_ENTITY_HELPER_HPP
#define ENTT_ENTITY_HELPER_HPP
#include <memory>
#include <type_traits>
#include "../config/config.h"
#include <utility>
#include "../core/fwd.hpp"
#include "../core/type_traits.hpp"
#include "../signal/delegate.hpp"
#include "fwd.hpp"
#include "registry.hpp"
#include "group.hpp"
#include "storage.hpp"
#include "view.hpp"
namespace entt {
/**
* @brief Converts a registry to a view.
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Registry Basic registry type.
*/
template<typename Entity>
struct as_view {
/*! @brief Underlying entity identifier. */
using entity_type = std::remove_const_t<Entity>;
template<typename Registry>
class as_view {
template<typename... Get, typename... Exclude>
auto dispatch(get_t<Get...>, exclude_t<Exclude...>) const {
return reg.template view<constness_as_t<typename Get::value_type, Get>...>(exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{});
}
public:
/*! @brief Type of registry to convert. */
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
/**
* @brief Constructs a converter for a given registry.
* @param source A valid reference to a registry.
*/
as_view(registry_type &source) ENTT_NOEXCEPT: reg{source} {}
as_view(registry_type &source) noexcept
: reg{source} {}
/**
* @brief Conversion function from a registry to a view.
* @tparam Exclude Types of components used to filter the view.
* @tparam Component Type of components used to construct the view.
* @tparam Get Type of storage used to construct the view.
* @tparam Exclude Types of storage used to filter the view.
* @return A newly created view.
*/
template<typename Exclude, typename... Component>
operator basic_view<entity_type, get_t<Component...>, Exclude>() const {
return reg.template view<Component...>(Exclude{});
template<typename Get, typename Exclude>
operator basic_view<Get, Exclude>() const {
return dispatch(Get{}, Exclude{});
}
private:
registry_type &reg;
};
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_view(basic_registry<Entity> &) -> as_view<Entity>;
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_view(const basic_registry<Entity> &) -> as_view<const Entity>;
/**
* @brief Converts a registry to a group.
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Registry Basic registry type.
*/
template<typename Entity>
struct as_group {
/*! @brief Underlying entity identifier. */
using entity_type = std::remove_const_t<Entity>;
template<typename Registry>
class as_group {
template<typename... Owned, typename... Get, typename... Exclude>
auto dispatch(owned_t<Owned...>, get_t<Get...>, exclude_t<Exclude...>) const {
if constexpr(std::is_const_v<registry_type>) {
return reg.template group_if_exists<typename Owned::value_type...>(get_t<typename Get::value_type...>{}, exclude_t<typename Exclude::value_type...>{});
} else {
return reg.template group<constness_as_t<typename Owned::value_type, Owned>...>(get_t<constness_as_t<typename Get::value_type, Get>...>{}, exclude_t<constness_as_t<typename Exclude::value_type, Exclude>...>{});
}
}
public:
/*! @brief Type of registry to convert. */
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
/**
* @brief Constructs a converter for a given registry.
* @param source A valid reference to a registry.
*/
as_group(registry_type &source) ENTT_NOEXCEPT: reg{source} {}
as_group(registry_type &source) noexcept
: reg{source} {}
/**
* @brief Conversion function from a registry to a group.
* @tparam Get Types of components observed by the group.
* @tparam Exclude Types of components used to filter the group.
* @tparam Owned Types of components owned by the group.
* @tparam Owned Types of _owned_ by the group.
* @tparam Get Types of storage _observed_ by the group.
* @tparam Exclude Types of storage used to filter the group.
* @return A newly created group.
*/
template<typename Get, typename Exclude, typename... Owned>
operator basic_group<entity_type, owned_t<Owned...>, Get, Exclude>() const {
if constexpr(std::is_const_v<registry_type>) {
return reg.template group_if_exists<Owned...>(Get{}, Exclude{});
} else {
return reg.template group<Owned...>(Get{}, Exclude{});
}
template<typename Owned, typename Get, typename Exclude>
operator basic_group<Owned, Get, Exclude>() const {
return dispatch(Owned{}, Get{}, Exclude{});
}
private:
registry_type &reg;
};
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_group(basic_registry<Entity> &) -> as_group<Entity>;
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_group(const basic_registry<Entity> &) -> as_group<const Entity>;
/**
* @brief Helper to create a listener that directly invokes a member function.
* @tparam Member Member function to invoke on a component of the given type.
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Registry Basic registry type.
* @param reg A registry that contains the given entity and its components.
* @param entt Entity from which to get the component.
*/
template<auto Member, typename Entity = entity>
void invoke(basic_registry<Entity> &reg, const Entity entt) {
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(basic_registry<Entity> &, const Entity)> func;
delegate<void(Registry &, const typename Registry::entity_type)> func;
func.template connect<Member>(reg.template get<member_class_t<decltype(Member)>>(entt));
func(reg, entt);
}
@@ -127,23 +116,22 @@ void invoke(basic_registry<Entity> &reg, const Entity 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 Entity A valid entity type (see entt_traits for more details).
* @tparam Component Type of component.
* @param reg A registry that contains the given entity and its components.
* @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 Entity, typename Component>
Entity to_entity(const basic_registry<Entity> &reg, const Component &instance) {
const auto &storage = reg.template storage<Component>();
const typename basic_registry<Entity>::base_type &base = storage;
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 += ENTT_PACKED_PAGE) {
if(const auto dist = (addr - std::addressof(storage.get(*it))); dist >= 0 && dist < ENTT_PACKED_PAGE) {
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);
}
}
@@ -151,6 +139,135 @@ Entity to_entity(const basic_registry<Entity> &reg, const Component &instance) {
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... 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) {
return to_entity(*storage, instance);
}
return null;
}
/*! @brief Primary template isn't defined on purpose. */
template<typename...>
struct sigh_helper;
/**
* @brief Signal connection helper for registries.
* @tparam Registry Basic registry type.
*/
template<typename Registry>
struct sigh_helper<Registry> {
/*! @brief Registry type. */
using registry_type = Registry;
/**
* @brief Constructs a helper for a given registry.
* @param ref A valid reference to a registry.
*/
sigh_helper(registry_type &ref)
: bucket{&ref} {}
/**
* @brief Binds a properly initialized helper to a given signal type.
* @tparam Type Type of signal to bind the helper to.
* @param id Optional name for the underlying storage to use.
* @return A helper for a given registry and signal type.
*/
template<typename Type>
auto with(const id_type id = type_hash<Type>::value()) noexcept {
return sigh_helper<registry_type, Type>{*bucket, id};
}
/**
* @brief Returns a reference to the underlying registry.
* @return A reference to the underlying registry.
*/
[[nodiscard]] registry_type &registry() noexcept {
return *bucket;
}
private:
registry_type *bucket;
};
/**
* @brief Signal connection helper for registries.
* @tparam Registry Basic registry type.
* @tparam Type Type of signal to connect listeners to.
*/
template<typename Registry, typename Type>
struct sigh_helper<Registry, Type> final: sigh_helper<Registry> {
/*! @brief Registry type. */
using registry_type = Registry;
/**
* @brief Constructs a helper for a given registry.
* @param ref A valid reference to a registry.
* @param id Optional name for the underlying storage to use.
*/
sigh_helper(registry_type &ref, const id_type id = type_hash<Type>::value())
: sigh_helper<Registry>{ref},
name{id} {}
/**
* @brief Forwards the call to `on_construct` on the underlying storage.
* @tparam Candidate Function or member to connect.
* @tparam Args Type of class or type of payload, if any.
* @param args A valid object that fits the purpose, if any.
* @return This helper.
*/
template<auto Candidate, typename... Args>
auto on_construct(Args &&...args) {
this->registry().template on_construct<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
return *this;
}
/**
* @brief Forwards the call to `on_update` on the underlying storage.
* @tparam Candidate Function or member to connect.
* @tparam Args Type of class or type of payload, if any.
* @param args A valid object that fits the purpose, if any.
* @return This helper.
*/
template<auto Candidate, typename... Args>
auto on_update(Args &&...args) {
this->registry().template on_update<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
return *this;
}
/**
* @brief Forwards the call to `on_destroy` on the underlying storage.
* @tparam Candidate Function or member to connect.
* @tparam Args Type of class or type of payload, if any.
* @param args A valid object that fits the purpose, if any.
* @return This helper.
*/
template<auto Candidate, typename... Args>
auto on_destroy(Args &&...args) {
this->registry().template on_destroy<Type>(name).template connect<Candidate>(std::forward<Args>(args)...);
return *this;
}
private:
id_type name;
};
/**
* @brief Deduction guide.
* @tparam Registry Basic registry type.
*/
template<typename Registry>
sigh_helper(Registry &) -> sigh_helper<Registry>;
} // namespace entt
#endif

303
src/entt/entity/mixin.hpp Normal file
View File

@@ -0,0 +1,303 @@
#ifndef ENTT_ENTITY_MIXIN_HPP
#define ENTT_ENTITY_MIXIN_HPP
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/any.hpp"
#include "../signal/sigh.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Mixin type used to add signal support to storage types.
*
* The function type of a listener is equivalent to:
*
* @code{.cpp}
* void(basic_registry<entity_type> &, entity_type);
* @endcode
*
* This applies to all signals made available.
*
* @tparam Type Underlying storage type.
* @tparam Registry Basic registry 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(owner_type &, const typename underlying_type::entity_type), typename underlying_type::allocator_type>;
using underlying_iterator = typename underlying_type::base_type::basic_iterator;
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 static_cast<owner_type &>(*owner);
}
void pop(underlying_iterator first, underlying_iterator last) final {
if(auto &reg = owner_or_assert(); destruction.empty()) {
underlying_type::pop(first, last);
} else {
for(; first != last; ++first) {
const auto entt = *first;
destruction.publish(reg, entt);
const auto it = underlying_type::find(entt);
underlying_type::pop(it, it + 1u);
}
}
}
void pop_all() final {
if(auto &reg = owner_or_assert(); !destruction.empty()) {
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 {
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);
}
}
}
}
underlying_type::pop_all();
}
underlying_iterator try_emplace(const typename underlying_type::entity_type entt, const bool force_back, const void *value) final {
const auto it = underlying_type::try_emplace(entt, force_back, value);
if(auto &reg = owner_or_assert(); it != underlying_type::base_type::end()) {
construction.publish(reg, *it);
}
return it;
}
public:
/*! @brief Allocator type. */
using allocator_type = typename underlying_type::allocator_type;
/*! @brief Underlying entity identifier. */
using entity_type = typename underlying_type::entity_type;
/*! @brief Expected registry type. */
using registry_type = owner_type;
/*! @brief Default constructor. */
basic_sigh_mixin()
: basic_sigh_mixin{allocator_type{}} {}
/**
* @brief Constructs an empty storage with a given allocator.
* @param allocator The allocator to use.
*/
explicit basic_sigh_mixin(const allocator_type &allocator)
: underlying_type{allocator},
owner{},
construction{allocator},
destruction{allocator},
update{allocator} {}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_sigh_mixin(basic_sigh_mixin &&other) noexcept
: underlying_type{std::move(other)},
owner{other.owner},
construction{std::move(other.construction)},
destruction{std::move(other.destruction)},
update{std::move(other.update)} {}
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
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},
destruction{std::move(other.destruction), allocator},
update{std::move(other.update), allocator} {}
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This storage.
*/
basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept {
underlying_type::operator=(std::move(other));
owner = other.owner;
construction = std::move(other.construction);
destruction = std::move(other.destruction);
update = std::move(other.update);
return *this;
}
/**
* @brief Exchanges the contents with those of a given storage.
* @param other Storage to exchange the content with.
*/
void swap(basic_sigh_mixin &other) {
using std::swap;
underlying_type::swap(other);
swap(owner, other.owner);
swap(construction, other.construction);
swap(destruction, other.destruction);
swap(update, other.update);
}
/**
* @brief Returns a sink object.
*
* The sink returned by this function can be used to receive notifications
* whenever a new instance is created and assigned to an entity.<br/>
* Listeners are invoked after the object has been assigned to the entity.
*
* @sa sink
*
* @return A temporary sink object.
*/
[[nodiscard]] auto on_construct() noexcept {
return sink{construction};
}
/**
* @brief Returns a sink object.
*
* The sink returned by this function can be used to receive notifications
* whenever an instance is explicitly updated.<br/>
* Listeners are invoked after the object has been updated.
*
* @sa sink
*
* @return A temporary sink object.
*/
[[nodiscard]] auto on_update() noexcept {
return sink{update};
}
/**
* @brief Returns a sink object.
*
* The sink returned by this function can be used to receive notifications
* whenever an instance is removed from an entity and thus destroyed.<br/>
* Listeners are invoked before the object has been removed from the entity.
*
* @sa sink
*
* @return A temporary sink object.
*/
[[nodiscard]] auto on_destroy() noexcept {
return sink{destruction};
}
/**
* @brief Emplace elements into a storage.
*
* The behavior of this operation depends on the underlying storage type
* (for example, components vs entities).<br/>
* Refer to the specific documentation for more details.
*
* @return A return value as returned by the underlying storage.
*/
auto emplace() {
const auto entt = underlying_type::emplace();
construction.publish(owner_or_assert(), entt);
return entt;
}
/**
* @brief Emplace elements into a storage.
*
* The behavior of this operation depends on the underlying storage type
* (for example, components vs entities).<br/>
* Refer to the specific documentation for more details.
*
* @tparam Args Types of arguments to forward to the underlying storage.
* @param hint A valid identifier.
* @param args Parameters to forward to the underlying storage.
* @return A return value as returned by the underlying storage.
*/
template<typename... Args>
decltype(auto) emplace(const entity_type hint, Args &&...args) {
if constexpr(std::is_same_v<typename underlying_type::value_type, typename underlying_type::entity_type>) {
const auto entt = underlying_type::emplace(hint, std::forward<Args>(args)...);
construction.publish(owner_or_assert(), entt);
return entt;
} else {
underlying_type::emplace(hint, std::forward<Args>(args)...);
construction.publish(owner_or_assert(), hint);
return this->get(hint);
}
}
/**
* @brief Patches the given instance for an entity.
* @tparam Func Types of the function objects to invoke.
* @param entt A valid identifier.
* @param func Valid function objects.
* @return A reference to the patched instance.
*/
template<typename... Func>
decltype(auto) patch(const entity_type entt, Func &&...func) {
underlying_type::patch(entt, std::forward<Func>(func)...);
update.publish(owner_or_assert(), entt);
return this->get(entt);
}
/**
* @brief Emplace elements into a storage.
*
* The behavior of this operation depends on the underlying storage type
* (for example, components vs entities).<br/>
* Refer to the specific documentation for more details.
*
* @tparam It Iterator type (as required by the underlying storage type).
* @tparam Args Types of arguments to forward to the underlying storage.
* @param first An iterator to the first element of the range.
* @param last An iterator past the last element of the range.
* @param args Parameters to use to forward to the underlying storage.
*/
template<typename It, typename... Args>
void insert(It first, It last, Args &&...args) {
auto from = underlying_type::size();
underlying_type::insert(first, last, std::forward<Args>(args)...);
if(auto &reg = owner_or_assert(); !construction.empty()) {
for(const auto to = underlying_type::size(); from != to; ++from) {
construction.publish(reg, underlying_type::operator[](from));
}
}
}
/**
* @brief Forwards variables to derived classes, if any.
* @param value A variable wrapped in an opaque container.
*/
void bind(any value) noexcept final {
auto *reg = any_cast<basic_registry_type>(&value);
owner = reg ? reg : owner;
underlying_type::bind(std::move(value));
}
private:
basic_registry_type *owner;
sigh_type construction;
sigh_type destruction;
sigh_type update;
};
} // namespace entt
#endif

View File

@@ -6,14 +6,10 @@
#include <limits>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "../signal/delegate.hpp"
#include "entity.hpp"
#include "fwd.hpp"
#include "registry.hpp"
#include "storage.hpp"
#include "utility.hpp"
namespace entt {
@@ -47,7 +43,7 @@ struct basic_collector<> {
* @return The updated collector.
*/
template<typename... AllOf, typename... NoneOf>
static constexpr auto group(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
static constexpr auto group(exclude_t<NoneOf...> = exclude_t{}) noexcept {
return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>>{};
}
@@ -57,7 +53,7 @@ struct basic_collector<> {
* @return The updated collector.
*/
template<typename AnyOf>
static constexpr auto update() ENTT_NOEXCEPT {
static constexpr auto update() noexcept {
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>>{};
}
};
@@ -82,7 +78,7 @@ struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule
* @return The updated collector.
*/
template<typename... AllOf, typename... NoneOf>
static constexpr auto group(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
static constexpr auto group(exclude_t<NoneOf...> = exclude_t{}) noexcept {
return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>, current_type, Other...>{};
}
@@ -92,7 +88,7 @@ struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule
* @return The updated collector.
*/
template<typename AnyOf>
static constexpr auto update() ENTT_NOEXCEPT {
static constexpr auto update() noexcept {
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>, current_type, Other...>{};
}
@@ -103,7 +99,7 @@ struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule
* @return The updated collector.
*/
template<typename... AllOf, typename... NoneOf>
static constexpr auto where(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
static constexpr auto where(exclude_t<NoneOf...> = exclude_t{}) noexcept {
using extended_type = matcher<type_list<Reject..., NoneOf...>, type_list<Require..., AllOf...>, Rule...>;
return basic_collector<extended_type, Other...>{};
}
@@ -150,8 +146,7 @@ inline constexpr basic_collector<> collector{};
* * The entity currently pointed is destroyed.
*
* In all the other cases, modifying the pools of the given components in any
* way invalidates all the iterators and using them results in undefined
* behavior.
* way invalidates all the iterators.
*
* @warning
* Lifetime of an observer doesn't necessarily have to overcome that of the
@@ -159,11 +154,13 @@ inline constexpr basic_collector<> collector{};
* from the registry before being destroyed to avoid crashes due to dangling
* pointers.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Registry Basic registry type.
* @tparam Mask Mask type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Entity>
class basic_observer {
using payload_type = std::uint32_t;
template<typename Registry, typename Mask, typename Allocator>
class basic_observer: private basic_storage<Mask, typename Registry::entity_type, Allocator> {
using base_type = basic_storage<Mask, typename Registry::entity_type, Allocator>;
template<typename>
struct matcher_handler;
@@ -171,43 +168,43 @@ class basic_observer {
template<typename... Reject, typename... Require, typename AnyOf>
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
template<std::size_t Index>
static void maybe_valid_if(basic_observer &obs, basic_registry<Entity> &reg, const Entity entt) {
static void maybe_valid_if(basic_observer &obs, Registry &reg, const typename Registry::entity_type entt) {
if(reg.template all_of<Require...>(entt) && !reg.template any_of<Reject...>(entt)) {
if(!obs.storage.contains(entt)) {
obs.storage.emplace(entt);
if(!obs.contains(entt)) {
obs.emplace(entt);
}
obs.storage.get(entt) |= (1 << Index);
obs.get(entt) |= (1 << Index);
}
}
template<std::size_t Index>
static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) {
obs.storage.erase(entt);
static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) {
if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) {
obs.erase(entt);
}
}
template<std::size_t Index>
static void connect(basic_observer &obs, basic_registry<Entity> &reg) {
static void connect(basic_observer &obs, Registry &reg) {
(reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
(reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
reg.template on_update<AnyOf>().template connect<&maybe_valid_if<Index>>(obs);
reg.template on_destroy<AnyOf>().template connect<&discard_if<Index>>(obs);
}
static void disconnect(basic_observer &obs, basic_registry<Entity> &reg) {
(reg.template on_destroy<Require>().disconnect(obs), ...);
(reg.template on_construct<Reject>().disconnect(obs), ...);
reg.template on_update<AnyOf>().disconnect(obs);
reg.template on_destroy<AnyOf>().disconnect(obs);
static void disconnect(basic_observer &obs, Registry &reg) {
(reg.template on_destroy<Require>().disconnect(&obs), ...);
(reg.template on_construct<Reject>().disconnect(&obs), ...);
reg.template on_update<AnyOf>().disconnect(&obs);
reg.template on_destroy<AnyOf>().disconnect(&obs);
}
};
template<typename... Reject, typename... Require, typename... NoneOf, typename... AllOf>
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, type_list<NoneOf...>, AllOf...>> {
template<std::size_t Index, typename... Ignore>
static void maybe_valid_if(basic_observer &obs, basic_registry<Entity> &reg, const Entity entt) {
static void maybe_valid_if(basic_observer &obs, Registry &reg, const typename Registry::entity_type entt) {
auto condition = [&reg, entt]() {
if constexpr(sizeof...(Ignore) == 0) {
return reg.template all_of<AllOf..., Require...>(entt) && !reg.template any_of<NoneOf..., Reject...>(entt);
@@ -217,23 +214,23 @@ class basic_observer {
};
if(condition()) {
if(!obs.storage.contains(entt)) {
obs.storage.emplace(entt);
if(!obs.contains(entt)) {
obs.emplace(entt);
}
obs.storage.get(entt) |= (1 << Index);
obs.get(entt) |= (1 << Index);
}
}
template<std::size_t Index>
static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) {
obs.storage.erase(entt);
static void discard_if(basic_observer &obs, Registry &, const typename Registry::entity_type entt) {
if(obs.contains(entt) && !(obs.get(entt) &= (~(1 << Index)))) {
obs.erase(entt);
}
}
template<std::size_t Index>
static void connect(basic_observer &obs, basic_registry<Entity> &reg) {
static void connect(basic_observer &obs, Registry &reg) {
(reg.template on_destroy<Require>().template connect<&discard_if<Index>>(obs), ...);
(reg.template on_construct<Reject>().template connect<&discard_if<Index>>(obs), ...);
(reg.template on_construct<AllOf>().template connect<&maybe_valid_if<Index>>(obs), ...);
@@ -242,43 +239,55 @@ class basic_observer {
(reg.template on_construct<NoneOf>().template connect<&discard_if<Index>>(obs), ...);
}
static void disconnect(basic_observer &obs, basic_registry<Entity> &reg) {
(reg.template on_destroy<Require>().disconnect(obs), ...);
(reg.template on_construct<Reject>().disconnect(obs), ...);
(reg.template on_construct<AllOf>().disconnect(obs), ...);
(reg.template on_destroy<NoneOf>().disconnect(obs), ...);
(reg.template on_destroy<AllOf>().disconnect(obs), ...);
(reg.template on_construct<NoneOf>().disconnect(obs), ...);
static void disconnect(basic_observer &obs, Registry &reg) {
(reg.template on_destroy<Require>().disconnect(&obs), ...);
(reg.template on_construct<Reject>().disconnect(&obs), ...);
(reg.template on_construct<AllOf>().disconnect(&obs), ...);
(reg.template on_destroy<NoneOf>().disconnect(&obs), ...);
(reg.template on_destroy<AllOf>().disconnect(&obs), ...);
(reg.template on_construct<NoneOf>().disconnect(&obs), ...);
}
};
template<typename... Matcher>
static void disconnect(basic_registry<Entity> &reg, basic_observer &obs) {
static void disconnect(Registry &reg, basic_observer &obs) {
(matcher_handler<Matcher>::disconnect(obs, reg), ...);
}
template<typename... Matcher, std::size_t... Index>
void connect(basic_registry<Entity> &reg, std::index_sequence<Index...>) {
static_assert(sizeof...(Matcher) < std::numeric_limits<payload_type>::digits, "Too many matchers");
void connect(Registry &reg, std::index_sequence<Index...>) {
static_assert(sizeof...(Matcher) < std::numeric_limits<typename base_type::value_type>::digits, "Too many matchers");
(matcher_handler<Matcher>::template connect<Index>(*this, reg), ...);
release.template connect<&basic_observer::disconnect<Matcher...>>(reg);
}
public:
/*! Basic registry type. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
using entity_type = typename registry_type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Random access iterator type. */
using iterator = typename basic_sparse_set<Entity>::iterator;
using iterator = typename registry_type::common_type::iterator;
/*! @brief Default constructor. */
basic_observer()
: release{},
storage{} {}
: basic_observer{allocator_type{}} {}
/**
* @brief Constructs an empty storage with a given allocator.
* @param allocator The allocator to use.
*/
explicit basic_observer(const allocator_type &allocator)
: base_type{allocator},
release{} {}
/*! @brief Default copy constructor, deleted on purpose. */
basic_observer(const basic_observer &) = delete;
/*! @brief Default move constructor, deleted on purpose. */
basic_observer(basic_observer &&) = delete;
@@ -286,16 +295,14 @@ public:
* @brief Creates an observer and connects it to a given registry.
* @tparam Matcher Types of matchers to use to initialize the observer.
* @param reg A valid reference to a registry.
* @param allocator The allocator to use.
*/
template<typename... Matcher>
basic_observer(basic_registry<entity_type> &reg, basic_collector<Matcher...>)
: basic_observer{} {
basic_observer(registry_type &reg, basic_collector<Matcher...>, const allocator_type &allocator = allocator_type{})
: basic_observer{allocator} {
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
}
/*! @brief Default destructor. */
~basic_observer() = default;
/**
* @brief Default copy assignment operator, deleted on purpose.
* @return This observer.
@@ -314,10 +321,10 @@ public:
* @param reg A valid reference to a registry.
*/
template<typename... Matcher>
void connect(basic_registry<entity_type> &reg, basic_collector<Matcher...>) {
void connect(registry_type &reg, basic_collector<Matcher...>) {
disconnect();
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
storage.clear();
base_type::clear();
}
/*! @brief Disconnects an observer from the registry it keeps track of. */
@@ -332,16 +339,16 @@ public:
* @brief Returns the number of elements in an observer.
* @return Number of elements.
*/
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return storage.size();
[[nodiscard]] size_type size() const noexcept {
return base_type::size();
}
/**
* @brief Checks whether an observer is empty.
* @return True if the observer is empty, false otherwise.
*/
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return storage.empty();
[[nodiscard]] bool empty() const noexcept {
return base_type::empty();
}
/**
@@ -356,39 +363,33 @@ public:
*
* @return A pointer to the array of entities.
*/
[[nodiscard]] const entity_type *data() const ENTT_NOEXCEPT {
return storage.data();
[[nodiscard]] const entity_type *data() const noexcept {
return base_type::data();
}
/**
* @brief Returns an iterator to the first entity of the observer.
*
* The returned iterator points to the first entity of the observer. If the
* container is empty, the returned iterator will be equal to `end()`.
* If the observer is empty, the returned iterator will be equal to `end()`.
*
* @return An iterator to the first entity of the observer.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return storage.basic_sparse_set<entity_type>::begin();
[[nodiscard]] iterator begin() const noexcept {
return base_type::base_type::begin();
}
/**
* @brief Returns an iterator that is past the last entity of the observer.
*
* The returned iterator points to the entity following the last entity of
* the observer. Attempting to dereference the returned iterator results in
* undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* observer.
*/
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return storage.basic_sparse_set<entity_type>::end();
[[nodiscard]] iterator end() const noexcept {
return base_type::base_type::end();
}
/*! @brief Clears the underlying container. */
void clear() ENTT_NOEXCEPT {
storage.clear();
void clear() noexcept {
base_type::clear();
}
/**
@@ -428,7 +429,6 @@ public:
private:
delegate<void(basic_observer &)> release;
basic_storage<entity_type, payload_type> storage;
};
} // namespace entt

View File

@@ -1,32 +1,28 @@
#ifndef ENTT_ENTITY_ORGANIZER_HPP
#define ENTT_ENTITY_ORGANIZER_HPP
#include <algorithm>
#include <cstddef>
#include <type_traits>
#include <utility>
#include <vector>
#include "../container/dense_hash_map.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../core/utility.hpp"
#include "../graph/adjacency_matrix.hpp"
#include "../graph/flow.hpp"
#include "fwd.hpp"
#include "helper.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename>
struct is_view: std::false_type {};
template<typename Entity, typename... Component, typename... Exclude>
struct is_view<basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>>>: std::true_type {};
template<typename... Args>
struct is_view<basic_view<Args...>>: std::true_type {};
template<typename Type>
inline constexpr bool is_view_v = is_view<Type>::value;
@@ -34,67 +30,60 @@ inline constexpr bool is_view_v = is_view<Type>::value;
template<typename Type, typename Override>
struct unpack_type {
using ro = std::conditional_t<
type_list_contains_v<Override, std::add_const_t<Type>> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
type_list_contains_v<Override, const Type> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
type_list<std::remove_const_t<Type>>,
type_list<>>;
using rw = std::conditional_t<
type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, std::add_const_t<Type>>),
type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, const Type>),
type_list<Type>,
type_list<>>;
};
template<typename Entity, typename... Override>
struct unpack_type<basic_registry<Entity>, type_list<Override...>> {
template<typename... Args, typename... Override>
struct unpack_type<basic_registry<Args...>, type_list<Override...>> {
using ro = type_list<>;
using rw = type_list<>;
};
template<typename Entity, typename... Override>
struct unpack_type<const basic_registry<Entity>, type_list<Override...>>
: unpack_type<basic_registry<Entity>, type_list<Override...>> {};
template<typename... Args, typename... Override>
struct unpack_type<const basic_registry<Args...>, type_list<Override...>>
: unpack_type<basic_registry<Args...>, type_list<Override...>> {};
template<typename Entity, typename... Component, typename... Exclude, typename... Override>
struct unpack_type<basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>>, type_list<Override...>> {
using ro = type_list_cat_t<type_list<Exclude...>, typename unpack_type<Component, type_list<Override...>>::ro...>;
using rw = type_list_cat_t<typename unpack_type<Component, type_list<Override...>>::rw...>;
template<typename... Get, typename... Exclude, typename... Override>
struct unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {
using ro = type_list_cat_t<type_list<typename Exclude::value_type...>, typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::ro...>;
using rw = type_list_cat_t<typename unpack_type<constness_as_t<typename Get::value_type, Get>, type_list<Override...>>::rw...>;
};
template<typename Entity, typename... Component, typename... Exclude, typename... Override>
struct unpack_type<const basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>>, type_list<Override...>>
: unpack_type<basic_view<Entity, get_t<Component...>, exclude_t<Exclude...>>, type_list<Override...>> {};
template<typename... Get, typename... Exclude, typename... Override>
struct unpack_type<const basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>>
: unpack_type<basic_view<get_t<Get...>, exclude_t<Exclude...>>, type_list<Override...>> {};
template<typename, typename>
struct resource;
struct resource_traits;
template<typename... Args, typename... Req>
struct resource<type_list<Args...>, type_list<Req...>> {
struct resource_traits<type_list<Args...>, type_list<Req...>> {
using args = type_list<std::remove_const_t<Args>...>;
using ro = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::ro..., typename unpack_type<Req, type_list<>>::ro...>;
using rw = type_list_cat_t<typename unpack_type<Args, type_list<Req...>>::rw..., typename unpack_type<Req, type_list<>>::rw...>;
};
template<typename... Req, typename Ret, typename... Args>
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource(Ret (*)(Args...));
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> free_function_to_resource_traits(Ret (*)(Args...));
template<typename... Req, typename Ret, typename Type, typename... Args>
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource(Ret (*)(Type &, Args...));
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (*)(Type &, Args...));
template<typename... Req, typename Ret, typename Class, typename... Args>
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource(Ret (Class::*)(Args...));
resource_traits<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource_traits(Ret (Class::*)(Args...));
template<typename... Req, typename Ret, typename Class, typename... Args>
resource<type_list<std::remove_reference_t<Args>...>, type_list<Req...>> constrained_function_to_resource(Ret (Class::*)(Args...) const);
template<typename... Req>
resource<type_list<>, type_list<Req...>> to_resource();
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.
@@ -105,12 +94,12 @@ resource<type_list<>, type_list<Req...>> to_resource();
* goal of the tool. Instead, they are returned to the user in the form of a
* graph that allows for safe execution.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Registry Basic registry type.
*/
template<typename Entity>
template<typename Registry>
class basic_organizer final {
using callback_type = void(const void *, basic_registry<Entity> &);
using prepare_type = void(basic_registry<Entity> &);
using callback_type = void(const void *, Registry &);
using prepare_type = void(Registry &);
using dependency_type = std::size_t(const bool, const type_info **, const std::size_t);
struct vertex_data final {
@@ -125,18 +114,18 @@ class basic_organizer final {
};
template<typename Type>
[[nodiscard]] static decltype(auto) extract(basic_registry<Entity> &reg) {
if constexpr(std::is_same_v<Type, basic_registry<Entity>>) {
[[nodiscard]] static decltype(auto) extract(Registry &reg) {
if constexpr(std::is_same_v<Type, Registry>) {
return reg;
} else if constexpr(internal::is_view_v<Type>) {
return as_view{reg};
return static_cast<Type>(as_view{reg});
} else {
return reg.template ctx_or_set<std::remove_reference_t<Type>>();
return reg.ctx().template emplace<std::remove_reference_t<Type>>();
}
}
template<typename... Args>
[[nodiscard]] static auto to_args(basic_registry<Entity> &reg, type_list<Args...>) {
[[nodiscard]] static auto to_args(Registry &reg, type_list<Args...>) {
return std::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
}
@@ -146,92 +135,29 @@ class basic_organizer final {
return {};
} else {
const type_info *info[sizeof...(Type)]{&type_id<Type>()...};
const auto length = (std::min)(count, sizeof...(Type));
std::copy_n(info, length, buffer);
const auto length = count < sizeof...(Type) ? count : sizeof...(Type);
for(std::size_t pos{}; pos < length; ++pos) {
buffer[pos] = info[pos];
}
return length;
}
}
template<typename... RO, typename... RW>
void track_dependencies(std::size_t index, const bool requires_registry, type_list<RO...>, type_list<RW...>) {
dependencies[type_hash<basic_registry<Entity>>::value()].emplace_back(index, requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u));
(dependencies[type_hash<RO>::value()].emplace_back(index, false), ...);
(dependencies[type_hash<RW>::value()].emplace_back(index, true), ...);
}
[[nodiscard]] std::vector<bool> adjacency_matrix() {
const auto length = vertices.size();
std::vector<bool> edges(length * length, false);
// creates the ajacency matrix
for(const auto &deps: dependencies) {
const auto last = deps.second.cend();
auto it = deps.second.cbegin();
while(it != last) {
if(it->second) {
// rw item
if(auto curr = it++; it != last) {
if(it->second) {
edges[curr->first * length + it->first] = true;
} else {
if(const auto next = std::find_if(it, last, [](const auto &elem) { return elem.second; }); next != last) {
for(; it != next; ++it) {
edges[curr->first * length + it->first] = true;
edges[it->first * length + next->first] = true;
}
} else {
for(; it != next; ++it) {
edges[curr->first * length + it->first] = true;
}
}
}
}
} else {
// ro item, possibly only on first iteration
if(const auto next = std::find_if(it, last, [](const auto &elem) { return elem.second; }); next != last) {
for(; it != next; ++it) {
edges[it->first * length + next->first] = true;
}
} else {
it = last;
}
}
}
}
// computes the transitive closure
for(std::size_t vk{}; vk < length; ++vk) {
for(std::size_t vi{}; vi < length; ++vi) {
for(std::size_t vj{}; vj < length; ++vj) {
edges[vi * length + vj] = edges[vi * length + vj] || (edges[vi * length + vk] && edges[vk * length + vj]);
}
}
}
// applies the transitive reduction
for(std::size_t vert{}; vert < length; ++vert) {
edges[vert * length + vert] = false;
}
for(std::size_t vj{}; vj < length; ++vj) {
for(std::size_t vi{}; vi < length; ++vi) {
if(edges[vi * length + vj]) {
for(std::size_t vk{}; vk < length; ++vk) {
if(edges[vj * length + vk]) {
edges[vi * length + vk] = false;
}
}
}
}
}
return edges;
builder.bind(static_cast<id_type>(index));
builder.set(type_hash<Registry>::value(), requires_registry || (sizeof...(RO) + sizeof...(RW) == 0u));
(builder.ro(type_hash<RO>::value()), ...);
(builder.rw(type_hash<RW>::value()), ...);
}
public:
/*! Basic registry type. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
using entity_type = typename registry_type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Raw task function type. */
@@ -257,7 +183,7 @@ public:
* @param length The length of the user-supplied buffer.
* @return The number of type info objects written to the buffer.
*/
size_type ro_dependency(const type_info **buffer, const std::size_t length) const ENTT_NOEXCEPT {
size_type ro_dependency(const type_info **buffer, const std::size_t length) const noexcept {
return node.dependency(false, buffer, length);
}
@@ -268,7 +194,7 @@ public:
* @param length The length of the user-supplied buffer.
* @return The number of type info objects written to the buffer.
*/
size_type rw_dependency(const type_info **buffer, const std::size_t length) const ENTT_NOEXCEPT {
size_type rw_dependency(const type_info **buffer, const std::size_t length) const noexcept {
return node.dependency(true, buffer, length);
}
@@ -276,7 +202,7 @@ public:
* @brief Returns the number of read-only resources of a vertex.
* @return The number of read-only resources of the vertex.
*/
size_type ro_count() const ENTT_NOEXCEPT {
size_type ro_count() const noexcept {
return node.ro_count;
}
@@ -284,7 +210,7 @@ public:
* @brief Returns the number of writable resources of a vertex.
* @return The number of writable resources of the vertex.
*/
size_type rw_count() const ENTT_NOEXCEPT {
size_type rw_count() const noexcept {
return node.rw_count;
}
@@ -292,7 +218,7 @@ public:
* @brief Checks if a vertex is also a top-level one.
* @return True if the vertex is a top-level one, false otherwise.
*/
bool top_level() const ENTT_NOEXCEPT {
bool top_level() const noexcept {
return is_top_level;
}
@@ -300,7 +226,7 @@ public:
* @brief Returns a type info object associated with a vertex.
* @return A properly initialized type info object.
*/
const type_info &info() const ENTT_NOEXCEPT {
const type_info &info() const noexcept {
return *node.info;
}
@@ -308,7 +234,7 @@ public:
* @brief Returns a user defined name associated with a vertex, if any.
* @return The user defined name associated with the vertex, if any.
*/
const char *name() const ENTT_NOEXCEPT {
const char *name() const noexcept {
return node.name;
}
@@ -316,7 +242,7 @@ public:
* @brief Returns the function associated with a vertex.
* @return The function associated with the vertex.
*/
function_type *callback() const ENTT_NOEXCEPT {
function_type *callback() const noexcept {
return node.callback;
}
@@ -324,7 +250,7 @@ public:
* @brief Returns the payload associated with a vertex, if any.
* @return The payload associated with the vertex, if any.
*/
const void *data() const ENTT_NOEXCEPT {
const void *data() const noexcept {
return node.payload;
}
@@ -332,7 +258,7 @@ public:
* @brief Returns the list of nodes reachable from a given vertex.
* @return The list of nodes reachable from the vertex.
*/
const std::vector<std::size_t> &children() const ENTT_NOEXCEPT {
const std::vector<std::size_t> &children() const noexcept {
return reachable;
}
@@ -341,7 +267,7 @@ public:
* are properly instantiated before using them.
* @param reg A valid registry.
*/
void prepare(basic_registry<entity_type> &reg) const {
void prepare(registry_type &reg) const {
node.prepare ? node.prepare(reg) : void();
}
@@ -359,10 +285,10 @@ public:
*/
template<auto Candidate, typename... Req>
void emplace(const char *name = nullptr) {
using resource_type = decltype(internal::free_function_to_resource<Req...>(Candidate));
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, basic_registry<entity_type>>;
using resource_type = decltype(internal::free_function_to_resource_traits<Req...>(Candidate));
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
callback_type *callback = +[](const void *, basic_registry<entity_type> &reg) {
callback_type *callback = +[](const void *, registry_type &reg) {
std::apply(Candidate, to_args(reg, typename resource_type::args{}));
};
@@ -373,7 +299,7 @@ public:
nullptr,
callback,
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
+[](basic_registry<entity_type> &reg) { void(to_args(reg, typename resource_type::args{})); },
+[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
@@ -391,10 +317,10 @@ public:
*/
template<auto Candidate, typename... Req, typename Type>
void emplace(Type &value_or_instance, const char *name = nullptr) {
using resource_type = decltype(internal::constrained_function_to_resource<Req...>(Candidate));
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, basic_registry<entity_type>>;
using resource_type = decltype(internal::constrained_function_to_resource_traits<Req...>(Candidate));
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, registry_type>;
callback_type *callback = +[](const void *payload, basic_registry<entity_type> &reg) {
callback_type *callback = +[](const void *payload, registry_type &reg) {
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
std::apply(Candidate, std::tuple_cat(std::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{})));
};
@@ -406,7 +332,7 @@ public:
&value_or_instance,
callback,
+[](const bool rw, const type_info **buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
+[](basic_registry<entity_type> &reg) { void(to_args(reg, typename resource_type::args{})); },
+[](registry_type &reg) { void(to_args(reg, typename resource_type::args{})); },
&type_id<std::integral_constant<decltype(Candidate), Candidate>>()};
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
@@ -423,7 +349,7 @@ public:
*/
template<typename... Req>
void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) {
using resource_type = internal::resource<type_list<>, type_list<Req...>>;
using resource_type = internal::resource_traits<type_list<>, type_list<Req...>>;
track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
vertex_data vdata{
@@ -444,28 +370,19 @@ public:
* @return The adjacency list of the task graph.
*/
std::vector<vertex> graph() {
const auto edges = adjacency_matrix();
// creates the adjacency list
std::vector<vertex> adjacency_list{};
adjacency_list.reserve(vertices.size());
auto adjacency_matrix = builder.graph();
for(std::size_t col{}, length = vertices.size(); col < length; ++col) {
for(auto curr: adjacency_matrix.vertices()) {
const auto iterable = adjacency_matrix.in_edges(curr);
std::vector<std::size_t> reachable{};
const auto row = col * length;
bool is_top_level = true;
for(std::size_t next{}; next < length; ++next) {
if(edges[row + next]) {
reachable.push_back(next);
}
for(auto &&edge: adjacency_matrix.out_edges(curr)) {
reachable.push_back(edge.second);
}
for(std::size_t next{}; next < length && is_top_level; ++next) {
is_top_level = !edges[next * length + col];
}
adjacency_list.emplace_back(is_top_level, vertices[col], std::move(reachable));
adjacency_list.emplace_back(iterable.cbegin() == iterable.cend(), vertices[curr], std::move(reachable));
}
return adjacency_list;
@@ -473,13 +390,13 @@ public:
/*! @brief Erases all elements from a container. */
void clear() {
dependencies.clear();
builder.clear();
vertices.clear();
}
private:
dense_hash_map<id_type, std::vector<std::pair<std::size_t, bool>>, identity> dependencies;
std::vector<vertex_data> vertices;
flow builder;
};
} // namespace entt

File diff suppressed because it is too large Load Diff

View File

@@ -2,45 +2,46 @@
#define ENTT_ENTITY_RUNTIME_VIEW_HPP
#include <algorithm>
#include <cstddef>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "entity.hpp"
#include "fwd.hpp"
#include "sparse_set.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type>
template<typename Set>
class runtime_view_iterator final {
using iterator_type = typename Set::iterator;
[[nodiscard]] bool valid() const {
return std::all_of(pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
return (!tombstone_check || *it != tombstone)
&& std::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
}
public:
using iterator_type = typename Type::iterator;
using difference_type = typename iterator_type::difference_type;
using value_type = typename iterator_type::value_type;
using pointer = typename iterator_type::pointer;
using reference = typename iterator_type::reference;
using iterator_category = std::bidirectional_iterator_tag;
runtime_view_iterator() ENTT_NOEXCEPT = default;
constexpr runtime_view_iterator() noexcept
: pools{},
filter{},
it{},
tombstone_check{} {}
runtime_view_iterator(const std::vector<const Type *> &cpools, const std::vector<const Type *> &ignore, iterator_type curr) ENTT_NOEXCEPT
runtime_view_iterator(const std::vector<Set *> &cpools, const std::vector<Set *> &ignore, iterator_type curr) noexcept
: pools{&cpools},
filter{&ignore},
it{curr} {
it{curr},
tombstone_check{pools->size() == 1u && (*pools)[0u]->policy() == deletion_policy::in_place} {
if(it != (*pools)[0]->end() && !valid()) {
++(*this);
}
@@ -56,118 +57,178 @@ public:
return ++(*this), orig;
}
runtime_view_iterator &operator--() ENTT_NOEXCEPT {
runtime_view_iterator &operator--() {
while(--it != (*pools)[0]->begin() && !valid()) {}
return *this;
}
runtime_view_iterator operator--(int) ENTT_NOEXCEPT {
runtime_view_iterator operator--(int) {
runtime_view_iterator orig = *this;
return operator--(), orig;
}
[[nodiscard]] pointer operator->() const {
[[nodiscard]] pointer operator->() const noexcept {
return it.operator->();
}
[[nodiscard]] reference operator*() const {
[[nodiscard]] reference operator*() const noexcept {
return *operator->();
}
[[nodiscard]] bool operator==(const runtime_view_iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator==(const runtime_view_iterator &other) const noexcept {
return it == other.it;
}
[[nodiscard]] bool operator!=(const runtime_view_iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator!=(const runtime_view_iterator &other) const noexcept {
return !(*this == other);
}
private:
const std::vector<const Type *> *pools;
const std::vector<const Type *> *filter;
const std::vector<Set *> *pools;
const std::vector<Set *> *filter;
iterator_type it;
bool tombstone_check;
};
} // namespace internal
/*! @endcond */
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief Runtime view.
* @brief Generic runtime view.
*
* Runtime views iterate over those entities that have at least all the given
* components in their bags. During initialization, a runtime view looks at the
* number of entities available for each component and picks up a reference to
* the smallest set of candidate entities in order to get a performance boost
* when iterate.<br/>
* Order of elements during iterations are highly dependent on the order of the
* underlying data structures. See sparse_set and its specializations for more
* details.
* Runtime views iterate over those entities that are at least in the given
* storage. During initialization, a runtime view looks at the number of
* entities available for each component and uses the smallest set in order to
* get a performance boost when iterating.
*
* @b Important
*
* Iterators aren't invalidated if:
*
* * New instances of the given components are created and assigned to entities.
* * The entity currently pointed is modified (as an example, if one of the
* given components is removed from the entity to which the iterator points).
* * New elements are added to the storage.
* * The entity currently pointed is modified (for example, components are added
* or removed from it).
* * The entity currently pointed is destroyed.
*
* In all the other cases, modifying the pools of the given components in any
* way invalidates all the iterators and using them results in undefined
* behavior.
* In all other cases, modifying the storage iterated by the view in any way
* invalidates all the iterators.
*
* @note
* Views share references to the underlying data structures of the registry that
* generated them. Therefore any change to the entities and to the components
* made by means of the registry are immediately reflected by the views, unless
* a pool was missing when the view was built (in this case, the view won't
* have a valid reference and won't be updated accordingly).
*
* @warning
* Lifetime of a view must not overcome that of the registry that generated it.
* In any other case, attempting to use a view results in undefined behavior.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Type Common base type.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Entity>
class basic_runtime_view final {
using basic_common_type = basic_sparse_set<Entity>;
[[nodiscard]] bool valid() const {
return !pools.empty() && pools.front();
}
template<typename Type, typename Allocator>
class basic_runtime_view {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, Type *>, "Invalid value type");
using container_type = std::vector<Type *, Allocator>;
public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
using entity_type = typename Type::entity_type;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Common type among all storage types. */
using common_type = Type;
/*! @brief Bidirectional iterator type. */
using iterator = internal::runtime_view_iterator<basic_common_type>;
using iterator = internal::runtime_view_iterator<common_type>;
/*! @brief Default constructor to use to create empty, invalid views. */
basic_runtime_view() ENTT_NOEXCEPT
: pools{},
filter{} {}
basic_runtime_view() noexcept
: basic_runtime_view{allocator_type{}} {}
/**
* @brief Constructs a runtime view from a set of storage classes.
* @param cpools The storage for the types to iterate.
* @param epools The storage for the types used to filter the view.
* @brief Constructs an empty, invalid view with a given allocator.
* @param allocator The allocator to use.
*/
basic_runtime_view(std::vector<const basic_common_type *> cpools, std::vector<const basic_common_type *> epools) ENTT_NOEXCEPT
: pools{std::move(cpools)},
filter{std::move(epools)} {
auto candidate = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
});
explicit basic_runtime_view(const allocator_type &allocator)
: pools{allocator},
filter{allocator} {}
// brings the best candidate (if any) on front of the vector
std::rotate(pools.begin(), candidate, pools.end());
/*! @brief Default copy constructor. */
basic_runtime_view(const basic_runtime_view &) = default;
/**
* @brief Allocator-extended copy constructor.
* @param other The instance to copy from.
* @param allocator The allocator to use.
*/
basic_runtime_view(const basic_runtime_view &other, const allocator_type &allocator)
: pools{other.pools, allocator},
filter{other.filter, allocator} {}
/*! @brief Default move constructor. */
basic_runtime_view(basic_runtime_view &&) noexcept(std::is_nothrow_move_constructible_v<container_type>) = default;
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
basic_runtime_view(basic_runtime_view &&other, const allocator_type &allocator)
: pools{std::move(other.pools), allocator},
filter{std::move(other.filter), allocator} {}
/**
* @brief Default copy assignment operator.
* @return This container.
*/
basic_runtime_view &operator=(const basic_runtime_view &) = default;
/**
* @brief Default move assignment operator.
* @return This container.
*/
basic_runtime_view &operator=(basic_runtime_view &&) noexcept(std::is_nothrow_move_assignable_v<container_type>) = default;
/**
* @brief Exchanges the contents with those of a given view.
* @param other View to exchange the content with.
*/
void swap(basic_runtime_view &other) {
using std::swap;
swap(pools, other.pools);
swap(filter, other.filter);
}
/**
* @brief Returns the associated allocator.
* @return The associated allocator.
*/
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
return pools.get_allocator();
}
/*! @brief Clears the view. */
void clear() {
pools.clear();
filter.clear();
}
/**
* @brief Appends an opaque storage object to a runtime view.
* @param base An opaque reference to a storage object.
* @return This runtime view.
*/
basic_runtime_view &iterate(common_type &base) {
if(pools.empty() || !(base.size() < pools[0u]->size())) {
pools.push_back(&base);
} else {
pools.push_back(std::exchange(pools[0u], &base));
}
return *this;
}
/**
* @brief Adds an opaque storage object as a filter of a runtime view.
* @param base An opaque reference to a storage object.
* @return This runtime view.
*/
basic_runtime_view &exclude(common_type &base) {
filter.push_back(&base);
return *this;
}
/**
@@ -175,36 +236,29 @@ public:
* @return Estimated number of entities iterated by the view.
*/
[[nodiscard]] size_type size_hint() const {
return valid() ? pools.front()->size() : size_type{};
return pools.empty() ? size_type{} : pools.front()->size();
}
/**
* @brief Returns an iterator to the first entity that has the given
* components.
*
* The returned iterator points to the first entity that has the given
* components. If the view is empty, the returned iterator will be equal to
* `end()`.
* If the view is empty, the returned iterator will be equal to `end()`.
*
* @return An iterator to the first entity that has the given components.
*/
[[nodiscard]] iterator begin() const {
return valid() ? iterator{pools, filter, pools[0]->begin()} : iterator{};
return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->begin()};
}
/**
* @brief Returns an iterator that is past the last entity that has the
* given components.
*
* The returned iterator points to the entity following the last entity that
* has the given components. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @return An iterator to the entity following the last entity that has the
* given components.
*/
[[nodiscard]] iterator end() const {
return valid() ? iterator{pools, filter, pools[0]->end()} : iterator{};
return pools.empty() ? iterator{} : iterator{pools, filter, pools[0]->end()};
}
/**
@@ -213,7 +267,8 @@ public:
* @return True if the view contains the given entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const {
return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
return !pools.empty()
&& std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
}
@@ -221,8 +276,7 @@ public:
* @brief Iterates entities and applies the given function object to them.
*
* The function object is invoked for each entity. It is provided only with
* the entity itself. To get the components, users can use the registry with
* which the view was built.<br/>
* the entity itself.<br/>
* The signature of the function should be equivalent to the following:
*
* @code{.cpp}
@@ -240,8 +294,8 @@ public:
}
private:
std::vector<const basic_common_type *> pools;
std::vector<const basic_common_type *> filter;
container_type pools;
container_type filter;
};
} // namespace entt

View File

@@ -1,7 +1,6 @@
#ifndef ENTT_ENTITY_SNAPSHOT_HPP
#define ENTT_ENTITY_SNAPSHOT_HPP
#include <array>
#include <cstddef>
#include <iterator>
#include <tuple>
@@ -9,15 +8,31 @@
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../container/dense_hash_map.hpp"
#include "../container/dense_map.hpp"
#include "../core/type_traits.hpp"
#include "component.hpp"
#include "entity.hpp"
#include "fwd.hpp"
#include "registry.hpp"
#include "view.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Registry>
void orphans(Registry &registry) {
auto &storage = registry.template storage<typename Registry::entity_type>();
for(auto entt: storage) {
if(registry.orphan(entt)) {
storage.erase(entt);
}
}
}
} // namespace internal
/*! @endcond */
/**
* @brief Utility class to create snapshots from a registry.
*
@@ -26,125 +41,110 @@ namespace entt {
* This type can be used in both cases if provided with a correctly configured
* output archive.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Registry Basic registry type.
*/
template<typename Entity>
template<typename Registry>
class basic_snapshot {
using entity_traits = entt_traits<Entity>;
template<typename Component, typename Archive, typename It>
void get(Archive &archive, std::size_t sz, It first, It last) const {
const auto view = reg->template view<std::add_const_t<Component>>();
archive(typename entity_traits::entity_type(sz));
while(first != last) {
const auto entt = *(first++);
if(reg->template all_of<Component>(entt)) {
std::apply(archive, std::tuple_cat(std::make_tuple(entt), view.get(entt)));
}
}
}
template<typename... Component, typename Archive, typename It, std::size_t... Index>
void component(Archive &archive, It first, It last, std::index_sequence<Index...>) const {
std::array<std::size_t, sizeof...(Index)> size{};
auto begin = first;
while(begin != last) {
const auto entt = *(begin++);
((reg->template all_of<Component>(entt) ? ++size[Index] : 0u), ...);
}
(get<Component>(archive, size[Index], first, last), ...);
}
static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
using traits_type = typename Registry::traits_type;
public:
/*! Basic registry type. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
using entity_type = typename registry_type::entity_type;
/**
* @brief Constructs an instance that is bound to a given registry.
* @param source A valid reference to a registry.
*/
basic_snapshot(const basic_registry<entity_type> &source) ENTT_NOEXCEPT
basic_snapshot(const registry_type &source) noexcept
: reg{&source} {}
/*! @brief Default move constructor. */
basic_snapshot(basic_snapshot &&) = default;
basic_snapshot(basic_snapshot &&) noexcept = default;
/*! @brief Default move assignment operator. @return This snapshot. */
basic_snapshot &operator=(basic_snapshot &&) = default;
basic_snapshot &operator=(basic_snapshot &&) noexcept = default;
/**
* @brief Puts aside all the entities from the underlying registry.
*
* Entities are serialized along with their versions. Destroyed entities are
* taken in consideration as well by this function.
*
* @brief Serializes all elements of a type with associated identifiers.
* @tparam Type Type of elements to serialize.
* @tparam Archive Type of output archive.
* @param archive A valid reference to an output archive.
* @param id Optional name used to map the storage within the registry.
* @return An object of this type to continue creating the snapshot.
*/
template<typename Archive>
const basic_snapshot &entities(Archive &archive) const {
const auto sz = reg->size();
template<typename Type, typename Archive>
const basic_snapshot &get(Archive &archive, const id_type id = type_hash<Type>::value()) const {
if(const auto *storage = reg->template storage<Type>(id); storage) {
archive(static_cast<typename traits_type::entity_type>(storage->size()));
archive(typename entity_traits::entity_type(sz + 1u));
archive(reg->released());
if constexpr(std::is_same_v<Type, entity_type>) {
archive(static_cast<typename traits_type::entity_type>(storage->free_list()));
for(auto first = reg->data(), last = first + sz; first != last; ++first) {
archive(*first);
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);
}
}
} else {
archive(typename traits_type::entity_type{});
}
return *this;
}
/**
* @brief Puts aside the given components.
*
* Each instance is serialized together with the entity to which it belongs.
* Entities are serialized along with their versions.
*
* @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>
const basic_snapshot &component(Archive &archive) const {
if constexpr(sizeof...(Component) == 1u) {
const auto view = reg->template view<const Component...>();
(component<Component>(archive, view.rbegin(), view.rend()), ...);
return *this;
} else {
(component<Component>(archive), ...);
return *this;
}
}
/**
* @brief Puts aside the given components for the entities in a range.
*
* Each instance is serialized together with the entity to which it belongs.
* Entities are serialized along with their versions.
*
* @tparam Component Types of components to serialize.
* @brief Serializes all elements of a type with associated identifiers for
* the entities in a range.
* @tparam Type Type of elements to serialize.
* @tparam Archive Type of output archive.
* @tparam It Type of input iterator.
* @param archive A valid reference to an output archive.
* @param first An iterator to the first element of the range to serialize.
* @param last An iterator past the last element of the range to serialize.
* @param id Optional name used to map the storage within the registry.
* @return An object of this type to continue creating the snapshot.
*/
template<typename... Component, typename Archive, typename It>
const basic_snapshot &component(Archive &archive, It first, It last) const {
component<Component...>(archive, first, last, std::index_sequence_for<Component...>{});
template<typename Type, typename Archive, typename It>
const basic_snapshot &get(Archive &archive, It first, It last, const id_type id = type_hash<Type>::value()) const {
static_assert(!std::is_same_v<Type, entity_type>, "Entity types not supported");
if(const auto *storage = reg->template storage<Type>(id); storage && !storage->empty()) {
archive(static_cast<typename traits_type::entity_type>(std::distance(first, last)));
for(; first != last; ++first) {
if(const auto entt = *first; storage->contains(entt)) {
archive(entt);
std::apply([&archive](auto &&...args) { (archive(std::forward<decltype(args)>(args)), ...); }, storage->get_as_tuple(entt));
} else {
archive(static_cast<entity_type>(null));
}
}
} else {
archive(typename traits_type::entity_type{});
}
return *this;
}
private:
const basic_registry<entity_type> *reg;
const registry_type *reg;
};
/**
@@ -155,100 +155,82 @@ private:
* originally had.<br/>
* An example of use is the implementation of a save/restore utility.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Registry Basic registry type.
*/
template<typename Entity>
template<typename Registry>
class basic_snapshot_loader {
using entity_traits = entt_traits<Entity>;
template<typename Type, typename Archive>
void assign(Archive &archive) const {
typename entity_traits::entity_type length{};
archive(length);
entity_type entt{};
if constexpr(ignore_as_empty_v<std::remove_const_t<Type>>) {
while(length--) {
archive(entt);
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
ENTT_ASSERT(entity == entt, "Entity not available for use");
reg->template emplace<Type>(entity);
}
} else {
Type instance{};
while(length--) {
archive(entt, instance);
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
ENTT_ASSERT(entity == entt, "Entity not available for use");
reg->template emplace<Type>(entity, std::move(instance));
}
}
}
static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
using traits_type = typename Registry::traits_type;
public:
/*! Basic registry type. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
using entity_type = typename registry_type::entity_type;
/**
* @brief Constructs an instance that is bound to a given registry.
* @param source A valid reference to a registry.
*/
basic_snapshot_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
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. */
basic_snapshot_loader(basic_snapshot_loader &&) = default;
basic_snapshot_loader(basic_snapshot_loader &&) noexcept = default;
/*! @brief Default move assignment operator. @return This loader. */
basic_snapshot_loader &operator=(basic_snapshot_loader &&) = default;
basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default;
/**
* @brief Restores entities that were in use during serialization.
*
* This function restores the entities that were in use during serialization
* and gives them the versions they originally had.
*
* @brief Restores all elements of a type with associated identifiers.
* @tparam Type Type of elements to restore.
* @tparam Archive Type of input archive.
* @param archive A valid reference to an input archive.
* @param id Optional name used to map the storage within the registry.
* @return A valid loader to continue restoring data.
*/
template<typename Archive>
const basic_snapshot_loader &entities(Archive &archive) const {
typename entity_traits::entity_type length{};
template<typename Type, typename Archive>
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);
std::vector<entity_type> all(length);
for(std::size_t pos{}; pos < length; ++pos) {
archive(all[pos]);
if constexpr(std::is_same_v<Type, entity_type>) {
typename traits_type::entity_type count{};
storage.reserve(length);
archive(count);
for(entity_type entity = null; length; --length) {
archive(entity);
storage.emplace(entity);
}
storage.free_list(count);
} else {
auto &other = reg->template storage<entity_type>();
entity_type entt{null};
while(length--) {
if(archive(entt); entt != null) {
const auto entity = other.contains(entt) ? entt : other.emplace(entt);
ENTT_ASSERT(entity == entt, "Entity not available for use");
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
storage.emplace(entity);
} else {
Type elem{};
archive(elem);
storage.emplace(entity, std::move(elem));
}
}
}
}
reg->assign(++all.cbegin(), all.cend(), all[0u]);
return *this;
}
/**
* @brief Restores components and assigns them to the right entities.
*
* The template parameter list must be exactly the same used during
* serialization. In the event that the entity to which the component is
* assigned doesn't exist yet, the loader will take care to create it with
* the version it originally had.
*
* @tparam Component Types of components 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>
const basic_snapshot_loader &component(Archive &archive) const {
(assign<Component>(archive), ...);
return *this;
}
@@ -258,22 +240,17 @@ public:
* In case all the entities were serialized but only part of the components
* was saved, it could happen that some of the entities have no components
* once restored.<br/>
* This functions helps to identify and destroy those entities.
* This function helps to identify and destroy those entities.
*
* @return A valid loader to continue restoring data.
*/
const basic_snapshot_loader &orphans() const {
reg->each([this](const auto entt) {
if(reg->orphan(entt)) {
reg->release(entt);
}
});
basic_snapshot_loader &orphans() {
internal::orphans(*reg);
return *this;
}
private:
basic_registry<entity_type> *reg;
registry_type *reg;
};
/**
@@ -286,43 +263,29 @@ private:
* Identifiers that entities originally had are not transferred to the target.
* Instead, the loader maps remote identifiers to local ones while restoring a
* snapshot.<br/>
* An example of use is the implementation of a client-server applications with
* An example of use is the implementation of a client-server application with
* the requirement of transferring somehow parts of the representation side to
* side.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Registry Basic registry type.
*/
template<typename Entity>
template<typename Registry>
class basic_continuous_loader {
using entity_traits = entt_traits<Entity>;
static_assert(!std::is_const_v<Registry>, "Non-const registry type required");
using traits_type = typename Registry::traits_type;
void destroy(Entity entt) {
if(const auto it = remloc.find(entt); it == remloc.cend()) {
const auto local = reg->create();
remloc.emplace(entt, std::make_pair(local, true));
reg->destroy(local);
}
}
void restore(Entity entt) {
const auto it = remloc.find(entt);
if(it == remloc.cend()) {
const auto local = reg->create();
remloc.emplace(entt, std::make_pair(local, true));
} else {
if(!reg->valid(remloc[entt].first)) {
remloc[entt].first = reg->create();
void restore(typename Registry::entity_type entt) {
if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) {
if(!reg->valid(remloc[entity].second)) {
remloc[entity].second = reg->create();
}
// set the dirty flag
remloc[entt].second = true;
} else {
remloc.insert_or_assign(entity, std::make_pair(entt, reg->create()));
}
}
template<typename Container>
auto update(int, Container &container)
-> decltype(typename Container::mapped_type{}, void()) {
auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) {
// map like container
Container other;
@@ -340,12 +303,12 @@ class basic_continuous_loader {
}
}
std::swap(container, other);
using std::swap;
swap(container, other);
}
template<typename Container>
auto update(char, Container &container)
-> decltype(typename Container::value_type{}, void()) {
auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) {
// vector like container
static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
@@ -354,9 +317,9 @@ class basic_continuous_loader {
}
}
template<typename Other, typename Type, typename Member>
void update([[maybe_unused]] Other &instance, [[maybe_unused]] Member Type::*member) {
if constexpr(!std::is_same_v<Other, Type>) {
template<typename Component, typename Other, typename Member>
void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) {
if constexpr(!std::is_same_v<Component, Other>) {
return;
} else if constexpr(std::is_same_v<Member, entity_type>) {
instance.*member = map(instance.*member);
@@ -366,52 +329,19 @@ class basic_continuous_loader {
}
}
template<typename Component>
void remove_if_exists() {
for(auto &&ref: remloc) {
const auto local = ref.second.first;
if(reg->valid(local)) {
reg->template remove<Component>(local);
}
}
}
template<typename Other, typename Archive, typename... Type, typename... Member>
void assign(Archive &archive, [[maybe_unused]] Member Type::*...member) {
typename entity_traits::entity_type length{};
archive(length);
entity_type entt{};
if constexpr(ignore_as_empty_v<std::remove_const_t<Other>>) {
while(length--) {
archive(entt);
restore(entt);
reg->template emplace_or_replace<Other>(map(entt));
}
} else {
Other instance{};
while(length--) {
archive(entt, instance);
(update(instance, member), ...);
restore(entt);
reg->template emplace_or_replace<Other>(map(entt), std::move(instance));
}
}
}
public:
/*! Basic registry type. */
using registry_type = Registry;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
using entity_type = typename registry_type::entity_type;
/**
* @brief Constructs an instance that is bound to a given registry.
* @param source A valid reference to a registry.
*/
basic_continuous_loader(basic_registry<entity_type> &source) ENTT_NOEXCEPT
: reg{&source} {}
basic_continuous_loader(registry_type &source) noexcept
: remloc{source.get_allocator()},
reg{&source} {}
/*! @brief Default move constructor. */
basic_continuous_loader(basic_continuous_loader &&) = default;
@@ -420,87 +350,66 @@ public:
basic_continuous_loader &operator=(basic_continuous_loader &&) = default;
/**
* @brief Restores entities that were in use during serialization.
* @brief Restores all elements of a type with associated identifiers.
*
* This function restores the entities that were in use during serialization
* and creates local counterparts for them if required.
* 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 Type Type of elements to restore.
* @tparam Archive Type of input archive.
* @param archive A valid reference to an input archive.
* @return A non-const reference to this loader.
* @param id Optional name used to map the storage within the registry.
* @return A valid loader to continue restoring data.
*/
template<typename Archive>
basic_continuous_loader &entities(Archive &archive) {
typename entity_traits::entity_type length{};
entity_type entt{};
template<typename Type, typename Archive>
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};
archive(length);
// discards the head of the list of destroyed entities
archive(entt);
for(std::size_t pos{}, last = length - 1u; pos < last; ++pos) {
archive(entt);
if constexpr(std::is_same_v<Type, entity_type>) {
typename traits_type::entity_type in_use{};
if(const auto entity = entity_traits::to_entity(entt); entity == pos) {
storage.reserve(length);
archive(in_use);
for(std::size_t pos{}; pos < in_use; ++pos) {
archive(entt);
restore(entt);
} else {
destroy(entt);
}
}
return *this;
}
for(std::size_t pos = in_use; pos < length; ++pos) {
archive(entt);
/**
* @brief Restores components and assigns them to the right entities.
*
* The template parameter list must be exactly the same used during
* serialization. In the event that the entity to which the component is
* assigned doesn't exist yet, the loader will take care to create a local
* counterpart for it.<br/>
* Members can be either data members of type entity_type or containers of
* entities. In both cases, the loader will visit them and update the
* entities by replacing each one with its local counterpart.
*
* @tparam Component Type of component to restore.
* @tparam Archive Type of input archive.
* @tparam Type Types of components to update with local counterparts.
* @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... Type, typename... Member>
basic_continuous_loader &component(Archive &archive, Member Type::*...member) {
(remove_if_exists<Component>(), ...);
(assign<Component>(archive, member...), ...);
return *this;
}
if(const auto entity = to_entity(entt); remloc.contains(entity)) {
if(reg->valid(remloc[entity].second)) {
reg->destroy(remloc[entity].second);
}
/**
* @brief Helps to purge entities that no longer have a conterpart.
*
* 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.
*/
basic_continuous_loader &shrink() {
auto it = remloc.begin();
while(it != remloc.cend()) {
const auto local = it->second.first;
bool &dirty = it->second.second;
if(dirty) {
dirty = false;
++it;
} else {
if(reg->valid(local)) {
reg->destroy(local);
remloc.erase(entity);
}
}
} else {
for(auto &&ref: remloc) {
storage.remove(ref.second.second);
}
it = remloc.erase(it);
while(length--) {
if(archive(entt); entt != null) {
restore(entt);
if constexpr(std::tuple_size_v<decltype(storage.get_as_tuple({}))> == 0u) {
storage.emplace(map(entt));
} else {
Type elem{};
archive(elem);
storage.emplace(map(entt), std::move(elem));
}
}
}
}
@@ -513,17 +422,12 @@ public:
* In case all the entities were serialized but only part of the components
* was saved, it could happen that some of the entities have no components
* once restored.<br/>
* This functions helps to identify and destroy those entities.
* This function helps to identify and destroy those entities.
*
* @return A non-const reference to this loader.
*/
basic_continuous_loader &orphans() {
reg->each([this](const auto entt) {
if(reg->orphan(entt)) {
reg->release(entt);
}
});
internal::orphans(*reg);
return *this;
}
@@ -532,8 +436,9 @@ public:
* @param entt A valid identifier.
* @return True if `entity` is managed by the loader, false otherwise.
*/
[[nodiscard]] bool contains(entity_type entt) const ENTT_NOEXCEPT {
return (remloc.find(entt) != remloc.cend());
[[nodiscard]] bool contains(entity_type entt) const noexcept {
const auto it = remloc.find(to_entity(entt));
return it != remloc.cend() && it->second.first == entt;
}
/**
@@ -541,20 +446,17 @@ public:
* @param entt A valid identifier.
* @return The local identifier if any, the null entity otherwise.
*/
[[nodiscard]] entity_type map(entity_type entt) const ENTT_NOEXCEPT {
const auto it = remloc.find(entt);
entity_type other = null;
if(it != remloc.cend()) {
other = it->second.first;
[[nodiscard]] entity_type map(entity_type entt) const noexcept {
if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) {
return it->second.second;
}
return other;
return null;
}
private:
dense_hash_map<entity_type, std::pair<entity_type, bool>> remloc;
basic_registry<entity_type> *reg;
dense_map<typename traits_type::entity_type, std::pair<entity_type, entity_type>> remloc;
registry_type *reg;
};
} // namespace entt

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,52 +0,0 @@
#ifndef ENTT_ENTITY_UTILITY_HPP
#define ENTT_ENTITY_UTILITY_HPP
#include "../core/type_traits.hpp"
namespace entt {
/**
* @brief Alias for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
struct exclude_t: type_list<Type...> {};
/**
* @brief Variable template for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr exclude_t<Type...> exclude{};
/**
* @brief Alias for lists of observed components.
* @tparam Type List of types.
*/
template<typename... Type>
struct get_t: type_list<Type...> {};
/**
* @brief Variable template for lists of observed components.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr get_t<Type...> get{};
/**
* @brief Alias for lists of owned components.
* @tparam Type List of types.
*/
template<typename... Type>
struct owned_t: type_list<Type...> {};
/**
* @brief Variable template for lists of owned components.
* @tparam Type List of types.
*/
template<typename... Type>
inline constexpr owned_t<Type...> owned{};
} // namespace entt
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,9 @@
// IWYU pragma: begin_exports
#include "config/config.h"
#include "config/macro.h"
#include "config/version.h"
#include "container/dense_hash_map.hpp"
#include "container/dense_hash_set.hpp"
#include "container/dense_map.hpp"
#include "container/dense_set.hpp"
#include "core/algorithm.hpp"
#include "core/any.hpp"
#include "core/attribute.h"
@@ -21,6 +24,7 @@
#include "entity/group.hpp"
#include "entity/handle.hpp"
#include "entity/helper.hpp"
#include "entity/mixin.hpp"
#include "entity/observer.hpp"
#include "entity/organizer.hpp"
#include "entity/registry.hpp"
@@ -28,12 +32,14 @@
#include "entity/snapshot.hpp"
#include "entity/sparse_set.hpp"
#include "entity/storage.hpp"
#include "entity/utility.hpp"
#include "entity/view.hpp"
#include "graph/adjacency_matrix.hpp"
#include "graph/dot.hpp"
#include "graph/flow.hpp"
#include "locator/locator.hpp"
#include "meta/adl_pointer.hpp"
#include "meta/container.hpp"
#include "meta/ctx.hpp"
#include "meta/context.hpp"
#include "meta/factory.hpp"
#include "meta/meta.hpp"
#include "meta/node.hpp"
@@ -49,9 +55,10 @@
#include "process/process.hpp"
#include "process/scheduler.hpp"
#include "resource/cache.hpp"
#include "resource/handle.hpp"
#include "resource/loader.hpp"
#include "resource/resource.hpp"
#include "signal/delegate.hpp"
#include "signal/dispatcher.hpp"
#include "signal/emitter.hpp"
#include "signal/sigh.hpp"
// IWYU pragma: end_exports

View File

@@ -1,7 +1,11 @@
// IWYU pragma: begin_exports
#include "container/fwd.hpp"
#include "core/fwd.hpp"
#include "entity/fwd.hpp"
#include "graph/fwd.hpp"
#include "meta/fwd.hpp"
#include "poly/fwd.hpp"
#include "process/fwd.hpp"
#include "resource/fwd.hpp"
#include "signal/fwd.hpp"
// IWYU pragma: end_exports

View File

@@ -0,0 +1,341 @@
#ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP
#define ENTT_GRAPH_ADJACENCY_MATRIX_HPP
#include <cstddef>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/iterator.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename It>
class edge_iterator {
using size_type = std::size_t;
public:
using value_type = std::pair<size_type, size_type>;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
constexpr edge_iterator() noexcept
: it{},
vert{},
pos{},
last{},
offset{} {}
constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept
: it{std::move(base)},
vert{vertices},
pos{from},
last{to},
offset{step} {
for(; pos != last && !it[pos]; pos += offset) {}
}
constexpr edge_iterator &operator++() noexcept {
for(pos += offset; pos != last && !it[pos]; pos += offset) {}
return *this;
}
constexpr edge_iterator operator++(int) noexcept {
edge_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] constexpr reference operator*() const noexcept {
return *operator->();
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
return std::make_pair<size_type>(pos / vert, pos % vert);
}
template<typename Type>
friend constexpr bool operator==(const edge_iterator<Type> &, const edge_iterator<Type> &) noexcept;
private:
It it;
size_type vert;
size_type pos;
size_type last;
size_type offset{};
};
template<typename Container>
[[nodiscard]] inline constexpr bool operator==(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
return lhs.pos == rhs.pos;
}
template<typename Container>
[[nodiscard]] inline constexpr bool operator!=(const edge_iterator<Container> &lhs, const edge_iterator<Container> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/*! @endcond */
/**
* @brief Basic implementation of a directed adjacency matrix.
* @tparam Category Either a directed or undirected category tag.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Category, typename Allocator>
class adjacency_matrix {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_base_of_v<directed_tag, Category>, "Invalid graph category");
static_assert(std::is_same_v<typename alloc_traits::value_type, std::size_t>, "Invalid value type");
using container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Vertex type. */
using vertex_type = size_type;
/*! @brief Edge type. */
using edge_type = std::pair<vertex_type, vertex_type>;
/*! @brief Vertex iterator type. */
using vertex_iterator = iota_iterator<vertex_type>;
/*! @brief Edge iterator type. */
using edge_iterator = internal::edge_iterator<typename container_type::const_iterator>;
/*! @brief Out edge iterator type. */
using out_edge_iterator = edge_iterator;
/*! @brief In edge iterator type. */
using in_edge_iterator = edge_iterator;
/*! @brief Graph category tag. */
using graph_category = Category;
/*! @brief Default constructor. */
adjacency_matrix() noexcept(noexcept(allocator_type{}))
: adjacency_matrix{0u} {}
/**
* @brief Constructs an empty container with a given allocator.
* @param allocator The allocator to use.
*/
explicit adjacency_matrix(const allocator_type &allocator) noexcept
: adjacency_matrix{0u, allocator} {}
/**
* @brief Constructs an empty container with a given allocator and user
* supplied number of vertices.
* @param vertices Number of vertices.
* @param allocator The allocator to use.
*/
adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{})
: matrix{vertices * vertices, allocator},
vert{vertices} {}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
adjacency_matrix(const adjacency_matrix &other)
: adjacency_matrix{other, other.get_allocator()} {}
/**
* @brief Allocator-extended copy constructor.
* @param other The instance to copy from.
* @param allocator The allocator to use.
*/
adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator)
: matrix{other.matrix, allocator},
vert{other.vert} {}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
adjacency_matrix(adjacency_matrix &&other) noexcept
: adjacency_matrix{std::move(other), other.get_allocator()} {}
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator)
: matrix{std::move(other.matrix), allocator},
vert{std::exchange(other.vert, 0u)} {}
/**
* @brief Default copy assignment operator.
* @param other The instance to copy from.
* @return This container.
*/
adjacency_matrix &operator=(const adjacency_matrix &other) {
matrix = other.matrix;
vert = other.vert;
return *this;
}
/**
* @brief Default move assignment operator.
* @param other The instance to move from.
* @return This container.
*/
adjacency_matrix &operator=(adjacency_matrix &&other) noexcept {
matrix = std::move(other.matrix);
vert = std::exchange(other.vert, 0u);
return *this;
}
/**
* @brief Returns the associated allocator.
* @return The associated allocator.
*/
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
return matrix.get_allocator();
}
/*! @brief Clears the adjacency matrix. */
void clear() noexcept {
matrix.clear();
vert = {};
}
/**
* @brief Exchanges the contents with those of a given adjacency matrix.
* @param other Adjacency matrix to exchange the content with.
*/
void swap(adjacency_matrix &other) {
using std::swap;
swap(matrix, other.matrix);
swap(vert, other.vert);
}
/**
* @brief Returns the number of vertices.
* @return The number of vertices.
*/
[[nodiscard]] size_type size() const noexcept {
return vert;
}
/**
* @brief Returns an iterable object to visit all vertices of a matrix.
* @return An iterable object to visit all vertices of a matrix.
*/
[[nodiscard]] iterable_adaptor<vertex_iterator> vertices() const noexcept {
return {0u, vert};
}
/**
* @brief Returns an iterable object to visit all edges of a matrix.
* @return An iterable object to visit all edges of a matrix.
*/
[[nodiscard]] iterable_adaptor<edge_iterator> edges() const noexcept {
const auto it = matrix.cbegin();
const auto sz = matrix.size();
return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}};
}
/**
* @brief Returns an iterable object to visit all out edges of a vertex.
* @param vertex The vertex of which to return all out edges.
* @return An iterable object to visit all out edges of a vertex.
*/
[[nodiscard]] iterable_adaptor<out_edge_iterator> out_edges(const vertex_type vertex) const noexcept {
const auto it = matrix.cbegin();
const auto from = vertex * vert;
const auto to = from + vert;
return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}};
}
/**
* @brief Returns an iterable object to visit all in edges of a vertex.
* @param vertex The vertex of which to return all in edges.
* @return An iterable object to visit all in edges of a vertex.
*/
[[nodiscard]] iterable_adaptor<in_edge_iterator> in_edges(const vertex_type vertex) const noexcept {
const auto it = matrix.cbegin();
const auto from = vertex;
const auto to = vert * vert + from;
return {{it, vert, from, to, vert}, {it, vert, to, to, vert}};
}
/**
* @brief Resizes an adjacency matrix.
* @param vertices The new number of vertices.
*/
void resize(const size_type vertices) {
adjacency_matrix other{vertices, get_allocator()};
for(auto [lhs, rhs]: edges()) {
other.insert(lhs, rhs);
}
other.swap(*this);
}
/**
* @brief Inserts an edge into the adjacency matrix, if it does not exist.
* @param lhs The left hand vertex of the edge.
* @param rhs The right hand vertex of the edge.
* @return A pair consisting of an iterator to the inserted element (or to
* the element that prevented the insertion) and a bool denoting whether the
* insertion took place.
*/
std::pair<edge_iterator, bool> insert(const vertex_type lhs, const vertex_type rhs) {
const auto pos = lhs * vert + rhs;
if constexpr(std::is_same_v<graph_category, undirected_tag>) {
const auto rev = rhs * vert + lhs;
ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
matrix[rev] = 1u;
}
const auto inserted = !std::exchange(matrix[pos], 1u);
return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted};
}
/**
* @brief Removes the edge associated with a pair of given vertices.
* @param lhs The left hand vertex of the edge.
* @param rhs The right hand vertex of the edge.
* @return Number of elements removed (either 0 or 1).
*/
size_type erase(const vertex_type lhs, const vertex_type rhs) {
const auto pos = lhs * vert + rhs;
if constexpr(std::is_same_v<graph_category, undirected_tag>) {
const auto rev = rhs * vert + lhs;
ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong");
matrix[rev] = 0u;
}
return std::exchange(matrix[pos], 0u);
}
/**
* @brief Checks if an adjacency matrix contains a given edge.
* @param lhs The left hand vertex of the edge.
* @param rhs The right hand vertex of the edge.
* @return True if there is such an edge, false otherwise.
*/
[[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const {
const auto pos = lhs * vert + rhs;
return pos < matrix.size() && matrix[pos];
}
private:
container_type matrix;
size_type vert;
};
} // namespace entt
#endif

58
src/entt/graph/dot.hpp Normal file
View File

@@ -0,0 +1,58 @@
#ifndef ENTT_GRAPH_DOT_HPP
#define ENTT_GRAPH_DOT_HPP
#include <ostream>
#include <type_traits>
#include "fwd.hpp"
namespace entt {
/**
* @brief Outputs a graph in dot format.
* @tparam Graph Graph type, valid as long as it exposes edges and vertices.
* @tparam Writer Vertex decorator type.
* @param out A standard output stream.
* @param graph The graph to output.
* @param writer Vertex decorator object.
*/
template<typename Graph, typename Writer>
void dot(std::ostream &out, const Graph &graph, Writer writer) {
static_assert(std::is_base_of_v<directed_tag, typename Graph::graph_category>, "Invalid graph category");
if constexpr(std::is_same_v<typename Graph::graph_category, undirected_tag>) {
out << "graph{";
} else {
out << "digraph{";
}
for(auto &&vertex: graph.vertices()) {
out << vertex << "[";
writer(out, vertex);
out << "];";
}
for(auto [lhs, rhs]: graph.edges()) {
if constexpr(std::is_same_v<typename Graph::graph_category, undirected_tag>) {
out << lhs << "--" << rhs << ";";
} else {
out << lhs << "->" << rhs << ";";
}
}
out << "}";
}
/**
* @brief Outputs a graph in dot format.
* @tparam Graph Graph type, valid as long as it exposes edges and vertices.
* @param out A standard output stream.
* @param graph The graph to output.
*/
template<typename Graph>
void dot(std::ostream &out, const Graph &graph) {
return dot(out, graph, [](auto &&...) {});
}
} // namespace entt
#endif

341
src/entt/graph/flow.hpp Normal file
View File

@@ -0,0 +1,341 @@
#ifndef ENTT_GRAPH_FLOW_HPP
#define ENTT_GRAPH_FLOW_HPP
#include <algorithm>
#include <cstddef>
#include <functional>
#include <iterator>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../container/dense_map.hpp"
#include "../container/dense_set.hpp"
#include "../core/compressed_pair.hpp"
#include "../core/fwd.hpp"
#include "../core/iterator.hpp"
#include "../core/utility.hpp"
#include "adjacency_matrix.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Utility class for creating task graphs.
* @tparam Allocator Type of allocator used to manage memory and elements.
*/
template<typename Allocator>
class basic_flow {
using alloc_traits = std::allocator_traits<Allocator>;
static_assert(std::is_same_v<typename alloc_traits::value_type, id_type>, "Invalid value type");
using task_container_type = dense_set<id_type, identity, std::equal_to<id_type>, typename alloc_traits::template rebind_alloc<id_type>>;
using ro_rw_container_type = std::vector<std::pair<std::size_t, bool>, typename alloc_traits::template rebind_alloc<std::pair<std::size_t, bool>>>;
using deps_container_type = dense_map<id_type, ro_rw_container_type, identity, std::equal_to<id_type>, typename alloc_traits::template rebind_alloc<std::pair<const id_type, ro_rw_container_type>>>;
using adjacency_matrix_type = adjacency_matrix<directed_tag, typename alloc_traits::template rebind_alloc<std::size_t>>;
void emplace(const id_type res, const bool is_rw) {
ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
if(!deps.contains(res) && sync_on != vertices.size()) {
deps[res].emplace_back(sync_on, true);
}
deps[res].emplace_back(index.first(), is_rw);
}
void setup_graph(adjacency_matrix_type &matrix) const {
for(const auto &elem: deps) {
const auto last = elem.second.cend();
auto it = elem.second.cbegin();
while(it != last) {
if(it->second) {
// rw item
if(auto curr = it++; it != last) {
if(it->second) {
matrix.insert(curr->first, it->first);
} else if(const auto next = std::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
for(; it != next; ++it) {
matrix.insert(curr->first, it->first);
matrix.insert(it->first, next->first);
}
} else {
for(; it != next; ++it) {
matrix.insert(curr->first, it->first);
}
}
}
} else {
// ro item (first iteration only)
if(const auto next = std::find_if(it, last, [](const auto &value) { return value.second; }); next != last) {
for(; it != next; ++it) {
matrix.insert(it->first, next->first);
}
} else {
it = last;
}
}
}
}
}
void transitive_closure(adjacency_matrix_type &matrix) const {
const auto length = matrix.size();
for(std::size_t vk{}; vk < length; ++vk) {
for(std::size_t vi{}; vi < length; ++vi) {
for(std::size_t vj{}; vj < length; ++vj) {
if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) {
matrix.insert(vi, vj);
}
}
}
}
}
void transitive_reduction(adjacency_matrix_type &matrix) const {
const auto length = matrix.size();
for(std::size_t vert{}; vert < length; ++vert) {
matrix.erase(vert, vert);
}
for(std::size_t vj{}; vj < length; ++vj) {
for(std::size_t vi{}; vi < length; ++vi) {
if(matrix.contains(vi, vj)) {
for(std::size_t vk{}; vk < length; ++vk) {
if(matrix.contains(vj, vk)) {
matrix.erase(vi, vk);
}
}
}
}
}
}
public:
/*! @brief Allocator type. */
using allocator_type = Allocator;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Iterable task list. */
using iterable = iterable_adaptor<typename task_container_type::const_iterator>;
/*! @brief Adjacency matrix type. */
using graph_type = adjacency_matrix_type;
/*! @brief Default constructor. */
basic_flow()
: basic_flow{allocator_type{}} {}
/**
* @brief Constructs a flow builder with a given allocator.
* @param allocator The allocator to use.
*/
explicit basic_flow(const allocator_type &allocator)
: index{0u, allocator},
vertices{allocator},
deps{allocator},
sync_on{} {}
/*! @brief Default copy constructor. */
basic_flow(const basic_flow &) = default;
/**
* @brief Allocator-extended copy constructor.
* @param other The instance to copy from.
* @param allocator The allocator to use.
*/
basic_flow(const basic_flow &other, const allocator_type &allocator)
: index{other.index.first(), allocator},
vertices{other.vertices, allocator},
deps{other.deps, allocator},
sync_on{other.sync_on} {}
/*! @brief Default move constructor. */
basic_flow(basic_flow &&) noexcept = default;
/**
* @brief Allocator-extended move constructor.
* @param other The instance to move from.
* @param allocator The allocator to use.
*/
basic_flow(basic_flow &&other, const allocator_type &allocator)
: index{other.index.first(), allocator},
vertices{std::move(other.vertices), allocator},
deps{std::move(other.deps), allocator},
sync_on{other.sync_on} {}
/**
* @brief Default copy assignment operator.
* @return This flow builder.
*/
basic_flow &operator=(const basic_flow &) = default;
/**
* @brief Default move assignment operator.
* @return This flow builder.
*/
basic_flow &operator=(basic_flow &&) noexcept = default;
/**
* @brief Returns the associated allocator.
* @return The associated allocator.
*/
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
return allocator_type{index.second()};
}
/**
* @brief Returns the identifier at specified location.
* @param pos Position of the identifier to return.
* @return The requested identifier.
*/
[[nodiscard]] id_type operator[](const size_type pos) const {
return vertices.cbegin()[pos];
}
/*! @brief Clears the flow builder. */
void clear() noexcept {
index.first() = {};
vertices.clear();
deps.clear();
sync_on = {};
}
/**
* @brief Exchanges the contents with those of a given flow builder.
* @param other Flow builder to exchange the content with.
*/
void swap(basic_flow &other) {
using std::swap;
std::swap(index, other.index);
std::swap(vertices, other.vertices);
std::swap(deps, other.deps);
std::swap(sync_on, other.sync_on);
}
/**
* @brief Returns the number of tasks.
* @return The number of tasks.
*/
[[nodiscard]] size_type size() const noexcept {
return vertices.size();
}
/**
* @brief Binds a task to a flow builder.
* @param value Task identifier.
* @return This flow builder.
*/
basic_flow &bind(const id_type value) {
sync_on += (sync_on == vertices.size());
const auto it = vertices.emplace(value).first;
index.first() = size_type(it - vertices.begin());
return *this;
}
/**
* @brief Turns the current task into a sync point.
* @return This flow builder.
*/
basic_flow &sync() {
ENTT_ASSERT(index.first() < vertices.size(), "Invalid node");
sync_on = index.first();
for(const auto &elem: deps) {
elem.second.emplace_back(sync_on, true);
}
return *this;
}
/**
* @brief Assigns a resource to the current task with a given access mode.
* @param res Resource identifier.
* @param is_rw Access mode.
* @return This flow builder.
*/
basic_flow &set(const id_type res, bool is_rw = false) {
emplace(res, is_rw);
return *this;
}
/**
* @brief Assigns a read-only resource to the current task.
* @param res Resource identifier.
* @return This flow builder.
*/
basic_flow &ro(const id_type res) {
emplace(res, false);
return *this;
}
/**
* @brief Assigns a range of read-only resources to the current task.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of elements.
* @param last An iterator past the last element of the range of elements.
* @return This flow builder.
*/
template<typename It>
std::enable_if_t<std::is_same_v<std::remove_const_t<typename std::iterator_traits<It>::value_type>, id_type>, basic_flow &>
ro(It first, It last) {
for(; first != last; ++first) {
emplace(*first, false);
}
return *this;
}
/**
* @brief Assigns a writable resource to the current task.
* @param res Resource identifier.
* @return This flow builder.
*/
basic_flow &rw(const id_type res) {
emplace(res, true);
return *this;
}
/**
* @brief Assigns a range of writable resources to the current task.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of elements.
* @param last An iterator past the last element of the range of elements.
* @return This flow builder.
*/
template<typename It>
std::enable_if_t<std::is_same_v<std::remove_const_t<typename std::iterator_traits<It>::value_type>, id_type>, basic_flow &>
rw(It first, It last) {
for(; first != last; ++first) {
emplace(*first, true);
}
return *this;
}
/**
* @brief Generates a task graph for the current content.
* @return The adjacency matrix of the task graph.
*/
[[nodiscard]] graph_type graph() const {
graph_type matrix{vertices.size(), get_allocator()};
setup_graph(matrix);
transitive_closure(matrix);
transitive_reduction(matrix);
return matrix;
}
private:
compressed_pair<size_type, allocator_type> index;
task_container_type vertices;
deps_container_type deps;
size_type sync_on;
};
} // namespace entt
#endif

27
src/entt/graph/fwd.hpp Normal file
View File

@@ -0,0 +1,27 @@
#ifndef ENTT_GRAPH_FWD_HPP
#define ENTT_GRAPH_FWD_HPP
#include <cstddef>
#include <memory>
#include "../core/fwd.hpp"
namespace entt {
/*! @brief Undirected graph category tag. */
struct directed_tag {};
/*! @brief Directed graph category tag. */
struct undirected_tag: directed_tag {};
template<typename, typename = std::allocator<std::size_t>>
class adjacency_matrix;
template<typename = std::allocator<id_type>>
class basic_flow;
/*! @brief Alias declaration for the most common use case. */
using flow = basic_flow<>;
} // namespace entt
#endif

View File

@@ -10,95 +10,136 @@ namespace entt {
/**
* @brief Service locator, nothing more.
*
* A service locator can be used to do what it promises: locate services.<br/>
* A service locator is used to do what it promises: locate services.<br/>
* Usually service locators are tightly bound to the services they expose and
* thus it's hard to define a general purpose class to do that. This template
* based implementation tries to fill the gap and to get rid of the burden of
* defining a different specific locator for each application.
* thus it's hard to define a general purpose class to do that. This tiny class
* tries to fill the gap and to get rid of the burden of defining a different
* specific locator for each application.
*
* @tparam Service Type of service managed by the locator.
* @note
* Users shouldn't retain references to a service. The recommended way is to
* retrieve the service implementation currently set each and every time the
* need for it arises. The risk is to incur in unexpected behaviors otherwise.
*
* @tparam Service Service type.
*/
template<typename Service>
struct service_locator {
/*! @brief Type of service offered. */
using service_type = Service;
class locator final {
class service_handle {
friend class locator<Service>;
std::shared_ptr<Service> value{};
};
public:
/*! @brief Service type. */
using type = Service;
/*! @brief Service node type. */
using node_type = service_handle;
/*! @brief Default constructor, deleted on purpose. */
service_locator() = delete;
locator() = delete;
/*! @brief Default destructor, deleted on purpose. */
~service_locator() = delete;
~locator() = delete;
/**
* @brief Tests if a valid service implementation is set.
* @return True if the service is set, false otherwise.
* @brief Checks whether a service locator contains a value.
* @return True if the service locator contains a value, false otherwise.
*/
[[nodiscard]] static bool empty() ENTT_NOEXCEPT {
return !static_cast<bool>(service);
[[nodiscard]] static bool has_value() noexcept {
return (service != nullptr);
}
/**
* @brief Returns a weak pointer to a service implementation, if any.
*
* Clients of a service shouldn't retain references to it. The recommended
* way is to retrieve the service implementation currently set each and
* every time the need of using it arises. Otherwise users can incur in
* unexpected behaviors.
*
* @return A reference to the service implementation currently set, if any.
*/
[[nodiscard]] static std::weak_ptr<Service> get() ENTT_NOEXCEPT {
return service;
}
/**
* @brief Returns a weak reference to a service implementation, if any.
*
* Clients of a service shouldn't retain references to it. The recommended
* way is to retrieve the service implementation currently set each and
* every time the need of using it arises. Otherwise users can incur in
* unexpected behaviors.
* @brief Returns a reference to a valid service, if any.
*
* @warning
* In case no service implementation has been set, a call to this function
* results in undefined behavior.
* Invoking this function can result in undefined behavior if the service
* hasn't been set yet.
*
* @return A reference to the service implementation currently set, if any.
* @return A reference to the service currently set, if any.
*/
[[nodiscard]] static Service &ref() ENTT_NOEXCEPT {
[[nodiscard]] static Service &value() noexcept {
ENTT_ASSERT(has_value(), "Service not available");
return *service;
}
/**
* @brief Returns a service if available or sets it from a fallback type.
*
* Arguments are used only if a service doesn't already exist. In all other
* cases, they are discarded.
*
* @tparam Args Types of arguments to use to construct the fallback service.
* @tparam Type Fallback service type.
* @param args Parameters to use to construct the fallback service.
* @return A reference to a valid service.
*/
template<typename Type = Service, typename... Args>
[[nodiscard]] static Service &value_or(Args &&...args) {
return service ? *service : emplace<Type>(std::forward<Args>(args)...);
}
/**
* @brief Sets or replaces a service.
* @tparam Impl Type of the new service to use.
* @tparam Type Service type.
* @tparam Args Types of arguments to use to construct the service.
* @param args Parameters to use to construct the service.
* @return A reference to a valid service.
*/
template<typename Impl = Service, typename... Args>
static void set(Args &&...args) {
service = std::make_shared<Impl>(std::forward<Args>(args)...);
template<typename Type = Service, typename... Args>
static Service &emplace(Args &&...args) {
service = std::make_shared<Type>(std::forward<Args>(args)...);
return *service;
}
/**
* @brief Sets or replaces a service.
* @param ptr Service to use to replace the current one.
* @brief Sets or replaces a service using a given allocator.
* @tparam Type Service type.
* @tparam Allocator Type of allocator used to manage memory and elements.
* @tparam Args Types of arguments to use to construct the service.
* @param alloc The allocator to use.
* @param args Parameters to use to construct the service.
* @return A reference to a valid service.
*/
static void set(std::shared_ptr<Service> ptr) {
ENTT_ASSERT(static_cast<bool>(ptr), "Null service not allowed");
service = std::move(ptr);
template<typename Type = Service, typename Allocator, typename... Args>
static Service &emplace(std::allocator_arg_t, Allocator alloc, Args &&...args) {
service = std::allocate_shared<Type>(alloc, std::forward<Args>(args)...);
return *service;
}
/**
* @brief Resets a service.
*
* The service is no longer valid after a reset.
* @brief Returns a handle to the underlying service.
* @return A handle to the underlying service.
*/
static void reset() {
service.reset();
static node_type handle() noexcept {
node_type node{};
node.value = service;
return node;
}
/**
* @brief Resets or replaces a service.
* @param other Optional handle with which to replace the service.
*/
static void reset(const node_type &other = {}) noexcept {
service = other.value;
}
/**
* @brief Resets or replaces a service.
* @tparam Type Service type.
* @tparam Deleter Deleter type.
* @param elem A pointer to a service to manage.
* @param deleter A deleter to use to destroy the service.
*/
template<typename Type, typename Deleter = std::default_delete<Type>>
static void reset(Type *elem, Deleter deleter = {}) {
service = std::shared_ptr<Service>{elem, std::move(deleter)};
}
private:
inline static std::shared_ptr<Service> service = nullptr;
// std::shared_ptr because of its type erased allocator which is useful here
inline static std::shared_ptr<Service> service{};
};
} // namespace entt

View File

@@ -2,272 +2,384 @@
#define ENTT_META_CONTAINER_HPP
#include <array>
#include <deque>
#include <iterator>
#include <list>
#include <map>
#include <set>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "../container/dense_hash_map.hpp"
#include "../container/dense_hash_set.hpp"
#include "../container/dense_map.hpp"
#include "../container/dense_set.hpp"
#include "context.hpp"
#include "meta.hpp"
#include "type_traits.hpp"
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::reserve)>>: 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) ENTT_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 bool clear([[maybe_unused]] any &container) {
if constexpr(is_dynamic_sequence_container<Type>::value) {
if(auto *const cont = any_cast<Type>(&container); cont) {
cont->clear();
return true;
}
}
return false;
}
[[nodiscard]] static iterator begin(any &container) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return iterator{std::begin(*cont)};
}
return iterator{std::begin(any_cast<const Type &>(container))};
}
[[nodiscard]] static iterator end(any &container) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return iterator{std::end(*cont)};
}
return iterator{std::end(any_cast<const Type &>(container))};
}
[[nodiscard]] static iterator insert([[maybe_unused]] any &container, [[maybe_unused]] iterator it, [[maybe_unused]] meta_any &value) {
if constexpr(is_dynamic_sequence_container<Type>::value) {
if(auto *const cont = any_cast<Type>(&container); cont) {
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
if(value.allow_cast<typename Type::const_reference>() || value.allow_cast<typename Type::value_type>()) {
const auto *element = value.try_cast<std::remove_reference_t<typename Type::const_reference>>();
return iterator{cont->insert(any_cast<const typename Type::iterator &>(it.base()), element ? *element : value.cast<typename Type::value_type>())};
}
}
}
return {};
}
[[nodiscard]] static iterator erase([[maybe_unused]] any &container, [[maybe_unused]] iterator it) {
if constexpr(is_dynamic_sequence_container<Type>::value) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return iterator{cont->erase(any_cast<const typename Type::iterator &>(it.base()))};
}
}
return {};
}
[[nodiscard]] static meta_any get(any &container, size_type pos) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return meta_any{std::in_place_type<typename Type::reference>, (*cont)[pos]};
}
return meta_any{std::in_place_type<typename Type::const_reference>, any_cast<const Type &>(container)[pos]};
}
};
template<typename, 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) ENTT_NOEXCEPT {
return any_cast<const Type &>(container).size();
}
[[nodiscard]] static bool clear(any &container) {
if(auto *const cont = any_cast<Type>(&container); cont) {
cont->clear();
return true;
}
return false;
}
[[nodiscard]] static iterator begin(any &container) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return iterator{std::integral_constant<bool, key_only>{}, cont->begin()};
}
return iterator{std::integral_constant<bool, key_only>{}, std::begin(any_cast<const Type &>(container))};
}
[[nodiscard]] static iterator end(any &container) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return iterator{std::integral_constant<bool, key_only>{}, cont->end()};
}
return iterator{std::integral_constant<bool, key_only>{}, std::end(any_cast<const Type &>(container))};
}
[[nodiscard]] static bool insert(any &container, meta_any &key, [[maybe_unused]] meta_any &value) {
if(auto *const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
if constexpr(is_key_only_meta_associative_container<Type>::value) {
return cont->insert(key.cast<const typename Type::key_type &>()).second;
} else {
if(value.allow_cast<const typename Type::mapped_type &>()) {
return cont->emplace(key.cast<const typename Type::key_type &>(), value.cast<const typename Type::mapped_type &>()).second;
}
}
}
return false;
}
[[nodiscard]] static bool erase(any &container, meta_any &key) {
if(auto *const cont = any_cast<Type>(&container); cont && key.allow_cast<const typename Type::key_type &>()) {
return (cont->erase(key.cast<const typename Type::key_type &>()) != cont->size());
}
return false;
}
[[nodiscard]] static iterator find(any &container, meta_any &key) {
if(key.allow_cast<const typename Type::key_type &>()) {
if(auto *const cont = any_cast<Type>(&container); cont) {
return iterator{std::integral_constant<bool, key_only>{}, cont->find(key.cast<const typename Type::key_type &>())};
}
return iterator{std::integral_constant<bool, key_only>{}, any_cast<const Type &>(container).find(key.cast<const typename Type::key_type &>())};
}
return {};
}
};
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.
* @tparam Type The type of elements.
* @tparam Args Other arguments.
* @tparam Args Template arguments for the container.
*/
template<typename Type, typename... Args>
struct meta_sequence_container_traits<std::vector<Type, Args...>>
: internal::basic_meta_sequence_container_traits<std::vector<Type, Args...>> {};
template<typename... Args>
struct 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.
* @tparam Type The type of elements.
* @tparam N The number of elements.
* @tparam Type Template arguments for the container.
* @tparam N Template arguments for the container.
*/
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.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_sequence_container_traits<std::list<Args...>>
: basic_meta_sequence_container_traits<std::list<Args...>> {};
/**
* @brief Meta sequence container traits for `std::deque`s of any type.
* @tparam Args Template arguments for the container.
*/
template<typename... Args>
struct meta_sequence_container_traits<std::deque<Args...>>
: basic_meta_sequence_container_traits<std::deque<Args...>> {};
/**
* @brief Meta associative container traits for `std::map`s of any type.
* @tparam Key The key type of elements.
* @tparam Value The value type of elements.
* @tparam Args Other arguments.
* @tparam Args Template arguments for the container.
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::map<Key, Value, Args...>>
: internal::basic_meta_associative_container_traits<std::map<Key, Value, Args...>> {};
template<typename... Args>
struct meta_associative_container_traits<std::map<Args...>>
: basic_meta_associative_container_traits<std::map<Args...>> {};
/**
* @brief Meta associative container traits for `std::unordered_map`s of any
* type.
* @tparam Key The key type of elements.
* @tparam Value The value type of elements.
* @tparam Args Other arguments.
* @tparam Args Template arguments for the container.
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
: internal::basic_meta_associative_container_traits<std::unordered_map<Key, Value, Args...>> {};
template<typename... Args>
struct meta_associative_container_traits<std::unordered_map<Args...>>
: basic_meta_associative_container_traits<std::unordered_map<Args...>> {};
/**
* @brief Meta associative container traits for `std::set`s of any type.
* @tparam Key The type of elements.
* @tparam Args Other arguments.
* @tparam Args Template arguments for the container.
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::set<Key, Args...>>
: internal::basic_meta_associative_container_traits<std::set<Key, Args...>> {};
template<typename... Args>
struct meta_associative_container_traits<std::set<Args...>>
: basic_meta_associative_container_traits<std::set<Args...>> {};
/**
* @brief Meta associative container traits for `std::unordered_set`s of any
* type.
* @tparam Key The type of elements.
* @tparam Args Other arguments.
* @tparam Args Template arguments for the container.
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
: internal::basic_meta_associative_container_traits<std::unordered_set<Key, Args...>> {};
template<typename... Args>
struct meta_associative_container_traits<std::unordered_set<Args...>>
: basic_meta_associative_container_traits<std::unordered_set<Args...>> {};
/**
* @brief Meta associative container traits for `dense_hash_map`s of any type.
* @tparam Key The key type of the elements.
* @tparam Type The value type of the elements.
* @tparam Args Other arguments.
* @brief Meta associative container traits for `dense_map`s of any type.
* @tparam Args Template arguments for the container.
*/
template<typename Key, typename Type, typename... Args>
struct meta_associative_container_traits<dense_hash_map<Key, Type, Args...>>
: internal::basic_meta_associative_container_traits<dense_hash_map<Key, Type, Args...>> {};
template<typename... Args>
struct meta_associative_container_traits<dense_map<Args...>>
: basic_meta_associative_container_traits<dense_map<Args...>> {};
/**
* @brief Meta associative container traits for `dense_hash_set`s of any type.
* @tparam Type The value type of the elements.
* @tparam Args Other arguments.
* @brief Meta associative container traits for `dense_set`s of any type.
* @tparam Args Template arguments for the container.
*/
template<typename Type, typename... Args>
struct meta_associative_container_traits<dense_hash_set<Type, Args...>>
: internal::basic_meta_associative_container_traits<dense_hash_set<Type, Args...>> {};
template<typename... Args>
struct meta_associative_container_traits<dense_set<Args...>>
: basic_meta_associative_container_traits<dense_set<Args...>> {};
} // namespace entt

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