Compare commits

..

1340 Commits

Author SHA1 Message Date
Michele Caini
7a949dd328 updated single include file 2021-01-09 16:45:27 +01:00
Michele Caini
3982217b67 Update README.md 2021-01-08 11:59:08 +01:00
Michele Caini
8cb61da9c2 *: minor changes 2021-01-08 11:43:26 +01:00
Michele Caini
375c780d3b doc: updated links (close #630) 2021-01-07 09:23:09 +01:00
Michele Caini
f3b6c2ce5d doc: updated links (close #628) 2021-01-06 14:41:27 +01:00
Michele Caini
a7a2c96382 registry: added ::reserve_pools 2021-01-05 09:35:41 +01:00
Michele Caini
99336ef746 doc: dark mode friendly header 2021-01-04 16:33:26 +01:00
Michele Caini
72d2adfe1c *: updated copyright 2021-01-04 14:09:53 +01:00
Michele Caini
707574e294 meta: avoid warnings for unused variables 2021-01-04 12:25:55 +01:00
Michele Caini
18ffbd0027 registry: group -> group_if_exists (close #626) 2021-01-04 08:34:56 +01:00
reworks
68a0e4f39a doc: update links.md (#627) 2021-01-03 16:35:16 +01:00
Michele Caini
ddb99ced34 storage: storage type check 2021-01-02 16:42:49 +01:00
Michele Caini
cb2782bc71 registry: ::remove requires at least a component now (close #623) 2021-01-01 23:55:13 +01:00
Alex Perry
52cade9267 doc: fixed missing prefix "L" (#622) 2021-01-01 23:46:24 +01:00
Michele Caini
ec600eb2f4 any: use feature tests to get around an issue with clang 6.0.0 2020-12-31 11:40:08 +01:00
Michele Caini
61e96e2dab *: get around an issue with entt::integral_constant on (very) old compilers 2020-12-30 18:04:57 +01:00
Michele Caini
9f5433053d poly: minor changes 2020-12-30 17:18:43 +01:00
Michele Caini
d2489a57b7 doc: updated links 2020-12-30 13:12:54 +01:00
Michele Caini
e5841cd467 poly: suppress warnings for unused variables 2020-12-29 18:15:33 +01:00
Michele Caini
820d52428f doc: updated references 2020-12-29 16:51:38 +01:00
Michele Caini
ae6931b046 any: avoid unreachable code 2020-12-28 16:14:05 +01:00
Michele Caini
90a97b90bb doc: minor changes 2020-12-28 16:07:36 +01:00
Michele Caini
4b38d81f00 algorithm: use plain for rather than for_each 2020-12-27 23:07:37 +01:00
Michele Caini
8c27ca9e36 *: suppress some warnings (see #620) 2020-12-27 00:12:28 +01:00
Michele Caini
4b89fc390d poly: renaming to avoid conflicts with libraries that redefine words randomly (close #615) 2020-12-26 17:00:51 +01:00
Michele Caini
29c1766714 registry: const poly storage function 2020-12-24 16:48:07 +01:00
Michele Caini
2e5a9f117c *: cleanup 2020-12-23 19:09:31 +01:00
Michele Caini
2abcbcd30f meta: support for pointer-like types with a custom dereference operator other than operator* 2020-12-23 19:00:05 +01:00
Michele Caini
ac8bde4ea8 doc: get around an issue with doxygen 2020-12-23 17:31:08 +01:00
Michele Caini
78a13efc6c any: minor changes 2020-12-23 12:28:07 +01:00
Michele Caini
c99e859978 meta: container traits not required for const T 2020-12-23 12:27:46 +01:00
Michele Caini
ed448cb99f doc: filled some todos here and there 2020-12-23 11:30:43 +01:00
Michele Caini
5d472a1f2e test: suppress warnings 2020-12-23 09:42:40 +01:00
Michele Caini
92a938db0e meta: reduced instantiations from meta iterators 2020-12-23 09:42:38 +01:00
Michele Caini
aa979b2046 any/meta:
* added alias constructor to any
* added alias constructor to meta_any
* added alias constructor to poly
* added support for const containers, const deref operator and const views to meta_any
2020-12-23 09:42:36 +01:00
Michele Caini
2daaf899d3 any: comparison functions (==, !=) 2020-12-23 09:42:33 +01:00
Michele Caini
fa4c6bccbc meta_any: make ref to pointer-like types work in all cases 2020-12-23 09:42:31 +01:00
Michele Caini
bedea4b11a *: added error messages to static asserts 2020-12-23 09:42:29 +01:00
Michele Caini
bc415242f2 test:
* support for pointer-like to const
* internal meta_range coverage
* fully tested meta_handle
* references as arguments for meta_ctor
* invoke const function on const reference for meta_func
* references as arguments for meta_func
* as_cref_t return type for meta_func
* setter and getter on const reference for meta_data
* as_cref_t getter for meta_data
* set by const and non-const reference for meta_data
* const invoke for meta_any
* const get for meta_any
* aob
2020-12-23 09:42:26 +01:00
Michele Caini
2eeb7552d6 test:
* more on any const and non-const reference support
* poly support for const and non-const references
* poly as_ref overloads
2020-12-23 09:42:24 +01:00
Michele Caini
3a6ecb10a7 meta_sequence_container: extended support for const iterators 2020-12-23 09:42:22 +01:00
Michele Caini
f55004d1e4 test: any::as_ref for const references 2020-12-23 09:42:19 +01:00
Michele Caini
1a3304a886 meta_any:
* set is necessarily non-const
* added non-const overloads for get and invoke
2020-12-23 09:42:17 +01:00
Michele Caini
58bcbe75b7 meta: minor changes 2020-12-23 09:42:14 +01:00
Michele Caini
753df6decf poly: updated doc (const references) 2020-12-23 09:42:11 +01:00
Michele Caini
c32f947c18 meta:
* support for pointers to const types
* use std::reference_wrapper instead of std::ref to let pass constness
2020-12-23 09:42:09 +01:00
Michele Caini
6123e4ac8a any/meta/poly: as_ref const and non-const overloads 2020-12-23 09:42:07 +01:00
Michele Caini
c52f16f5b8 meta:
* meta_any: convert -> allow_cast
* support for const references
* as_cref_t policy
2020-12-23 09:42:04 +01:00
Michele Caini
3dac65a012 *: minor changes 2020-12-23 09:42:01 +01:00
Michele Caini
bc089bc4c1 any_cast: review any_cast for better support to const references 2020-12-23 09:41:58 +01:00
Michele Caini
1075ded4dc test: minor changes 2020-12-23 09:41:55 +01:00
Michele Caini
5578ea2f30 meta_any: added support for const references, reviewed meta_any::cast (T vs T &) 2020-12-23 09:41:52 +01:00
Michele Caini
ade3e58829 any: added support to const references 2020-12-23 09:41:49 +01:00
Michele Caini
ee2e88476c any: instance type is now const void * instead of void * 2020-12-23 09:41:44 +01:00
Michele Caini
1726e983ad doc: added Minecraft Earth to the list :) 2020-12-23 09:38:27 +01:00
Michele Caini
44341f0bcc doc: cleaned up example in the README 2020-12-21 13:44:50 +01:00
Michele Caini
366da3d0fe type_info: use remove_cv_t rather than remove_const_t 2020-12-17 10:17:31 +01:00
Michele Caini
f7fa2f605b poly: minor changes 2020-12-17 10:17:23 +01:00
Michele Caini
6854dea47e delegate: use type_list rather than tuple internally 2020-12-17 10:17:11 +01:00
Michele Caini
9d7e1cd99d registry: use type_list rather than tuple internally 2020-12-17 10:17:04 +01:00
Michele Caini
330f3dff77 core: updated ident, removed dependency on <tuple> 2020-12-17 10:16:54 +01:00
Michele Caini
073c46e7bf any: const void * return type for the fake vtable 2020-12-17 10:14:43 +01:00
Michele Caini
9950b2ea34 type_traits: added type_list_element[_t] and value_list_element[_v] 2020-12-17 10:13:02 +01:00
Michele Caini
a7c2a5c49b doc: updated links 2020-12-17 10:12:47 +01:00
Michele Caini
c2c39cd0d0 doc: suppress a warning from doxygen 2020-12-14 11:19:04 +01:00
Michele Caini
b6e7c36b11 delegate: use constness_as_t internally 2020-12-14 11:17:24 +01:00
Michele Caini
002f92fe1e organizer: fixed an issue for free functions with payload (close #613) 2020-12-14 11:17:10 +01:00
Michele Caini
d6d0cdf9aa build system: avoid enabling tests by default when EnTT is the top dir project 2020-12-14 08:43:23 +01:00
Martin Stump
7d002df94f build system: add MAIN_PROJECT check for test option (#610)
* Add MAIN_PROJECT check for test option
* Set MAIN_PROJECT=OFF initially
2020-12-14 08:43:18 +01:00
Michele Caini
f0d7408f94 doc: minor changes 2020-12-13 23:52:16 +01:00
Keith Rosenberg
7154678347 doc: mention aggregate initialization usage in registry::emplace, refs #592 (#593)
* update example to explain aggregate initialization usage, refs #592
* cleanup example; add details about parameterized constructors and aggregate initialization

Co-authored-by: kthrose <kthrose@netpoetica.com>
2020-12-13 23:29:01 +01:00
Fahmi Akbar Wildana
68f0743c40 doc: add @javelin/ecs in references.md (#611) 2020-12-13 23:26:22 +01:00
Michele Caini
3d5905c878 doc: added more details 2020-12-12 16:39:45 +01:00
Michele Caini
a344a1ca59 doc: typo 2020-12-12 15:37:11 +01:00
Michele Caini
5f539ddfb7 doc: updated documentation (core, entity, poly) 2020-12-12 15:13:46 +01:00
Michele Caini
a974235d10 core/entity/meta/poly:
* updated poly (static vtable, design review)
* .ref -> as_ref (any, meta_any, poly)
* poly storage
2020-12-12 15:09:29 +01:00
Michele Caini
2d17ef5c7e meta: removed as_ref tag 2020-12-12 14:58:31 +01:00
Michele Caini
dda8c209df type_traits: added type_identity trait (waiting for C++20) 2020-12-12 14:55:30 +01:00
Michele Caini
be88d5dfb8 type_info: minor changes 2020-12-12 14:51:41 +01:00
Michele Caini
4a537d82d3 minor changes 2020-12-08 19:38:31 +01:00
Michele Caini
6f36723097 runtime_view: public constructor (close #597) 2020-12-06 15:37:51 +01:00
Michele Caini
35bce924f8 handle: added support for destroy (close #598) 2020-12-03 12:17:49 +01:00
Michele Caini
9356e8ccb5 config: reintroduce ENTT_DISABLE_ASSERT (close #599) 2020-12-03 11:18:27 +01:00
Michele Caini
1ffde24ef6 *: updated TODO 2020-12-03 10:55:08 +01:00
Michele Caini
2f52bef882 poly: first implementation 2020-12-02 15:49:40 +01:00
Michele Caini
b1369582e1 type_traits: added value_list 2020-12-02 15:49:05 +01:00
Michele Caini
cf176719a8 *: minor changes here and there 2020-12-02 15:48:36 +01:00
Michele Caini
d7ed72ac06 meta_any: single vtable function to reduce instantiations and storage requirements 2020-12-02 11:10:04 +01:00
Michele Caini
83322664f1 any: doc + more tests 2020-12-02 11:10:04 +01:00
Michele Caini
5af7e96f70 meta/*: removed meta_storage, meta_any uses any internally 2020-12-02 11:10:04 +01:00
Michele Caini
c95041d7c3 core: standalone any class 2020-12-02 11:10:04 +01:00
Michele Caini
62f40dcb21 meta_storage: internal review for better memory usage 2020-12-02 11:10:04 +01:00
Michele Caini
b4f88e303a meta_storage: branchless implementation 2020-12-02 11:10:04 +01:00
Michele Caini
cd0ec69446 meta: reduced instantiations due to meta any, use a fake vtable function 2020-12-02 11:10:04 +01:00
Michele Caini
909415d167 organizer: bug fixing/tests (thanks to @Green-Sky) 2020-12-02 11:09:52 +01:00
Michele Caini
337bc6d97a view_pack: support for multiple views of the same type 2020-12-02 11:09:51 +01:00
Michele Caini
6c9fab7da1 type_traits: minor changes 2020-12-02 11:09:51 +01:00
Michele Caini
315b1f5913 type traits: added is_complete[_v] 2020-12-02 11:09:51 +01:00
Michele Caini
c2d1859858 emitter: truly const emitter, no lazy initialization 2020-12-02 11:09:51 +01:00
Michele Caini
37ba7316e0 doc: fixed typo 2020-12-02 11:09:51 +01:00
Michele Caini
fc1292b1d1 test: get around the best bug ever of msvc, toolset v141 2020-12-02 11:09:51 +01:00
Michele Caini
0507680cc1 view/group: try to get around an issue of gcc v7.5 + suppress some warnings here and there 2020-12-02 11:09:51 +01:00
Michele Caini
60475d3354 view/group: safe invalid views/groups (close #470) 2020-12-02 11:09:51 +01:00
Michele Caini
b1cd794b2c registry: truly const registry 2020-12-02 11:09:51 +01:00
Michele Caini
cd98ecff88 view: default constructible views 2020-12-02 11:09:51 +01:00
Michele Caini
f8ec4027ee group: default constructible groups 2020-12-02 11:09:51 +01:00
Michele Caini
d980a5cf44 build system: use asan on the CI 2020-12-02 11:05:00 +01:00
Michele Caini
761604d044 config: favor detection of clang over that of msvc, otherwise clang-cl will fail 2020-12-02 11:04:21 +01:00
Michele Caini
0f4161f616 build system: added older compiler versions to the CI 2020-12-02 10:46:05 +01:00
Michele Caini
4a668c97a3 type_info: get around a nasty bug of clang < 9 when using libstdc++ 2020-12-02 10:45:41 +01:00
Michele Caini
9d687c25b3 storage: safe self-move to support standard containers (close #601) 2020-12-01 22:59:14 +01:00
Michele Caini
0b73082aa0 build system: minor changes to make it work again with the CI 2020-11-20 17:05:20 +01:00
Gnik
085e1ae157 build system: prefix cmake variables with ENTT_. (#585) 2020-11-20 16:30:22 +01:00
Tom Yaxley
7c0db3203b meta: allow checking meta_any for nullptr (#591) 2020-11-20 09:43:39 +01:00
Michele Caini
bc987ed03f *: force add the version to the single include file 2020-11-20 09:43:36 +01:00
Michele Caini
57e1bf3afd doc: fixed typo 2020-11-20 09:43:34 +01:00
Michele Caini
90606bd410 hashed_string: literals are now enclosed within entt::literals, ENTT_HS_SUFFIX and ENTT_HWS_SUFFIX no longer exist (close #590) 2020-11-20 09:43:28 +01:00
Michele Caini
9744a3745c doc: updated references 2020-11-20 09:43:21 +01:00
Zoltán Kurucz
14e051f970 Fixed const, non-const types section intro in entity.md (#589) 2020-11-14 16:49:11 +01:00
Michele Caini
2396c9b6da snapshot: avoid setting the wrong version for entities during a restore (close #588) 2020-11-14 16:48:11 +01:00
Michele Caini
c386a9d140 runtime_view: removed ::empty, misleading information (breaking change) 2020-11-11 17:03:48 +01:00
Michele Caini
12847593c2 runtime_view: size -> size_hint, misleading name (breaking change) 2020-11-11 17:03:44 +01:00
Michele Caini
6cfa024ea2 doc: small changes 2020-11-11 13:15:46 +01:00
Michele Caini
4b43d99660 group: removed/reduced scope for ::raw, misleading information (breaking change) 2020-11-11 13:15:44 +01:00
Michele Caini
c1bfc29e7f group: removed ::data<T>, misleading information (breaking change) 2020-11-11 13:15:42 +01:00
Michele Caini
7e91e27f14 group: removed ::empty<T...>, misleading information (breaking change) 2020-11-11 13:15:39 +01:00
Michele Caini
f8015036a9 group: removed ::size<T>, misleading information (breaking change) 2020-11-11 13:15:37 +01:00
Michele Caini
b7ef1607dc view: public constructors and deduction guides 2020-11-09 10:31:51 +01:00
Michele Caini
b93a31dd5b helper: removed Const template parameter, used the same model of the handle class (const/non-const entity) 2020-11-08 23:34:32 +01:00
Michele Caini
fa09964f10 storage: a better iterator 2020-11-08 23:03:27 +01:00
Michele Caini
0038728be3 storage: removed const T specialization for storage_traits 2020-11-08 01:06:06 +01:00
Michele Caini
ec56651959 doc: fixed typo in core.md 2020-11-08 00:58:48 +01:00
Michele Caini
8259371d6a handle: minor changes 2020-11-08 00:46:34 +01:00
Michele Caini
d8623991c0 constness_as: updated doc 2020-11-08 00:46:03 +01:00
Michele Caini
0c205431b0 doc: updated documentation for the core classes 2020-11-08 00:37:06 +01:00
Michele Caini
58dbaf4a51 type_traits: added constness_as[_t] 2020-11-08 00:36:41 +01:00
Michele Caini
3b50ebae83 delegate: updated doc 2020-11-07 23:55:53 +01:00
Michele Caini
8b895eff7a *: minor changes to get around some nasty bugs of compilers 2020-11-06 17:29:48 +01:00
Michele Caini
70af0365bf entity:*: removed broken references to the old actor class 2020-11-06 15:00:01 +01:00
Michele Caini
bb3e3bfa1f meta: containers traits are no longer internal details only 2020-11-06 14:58:22 +01:00
Michele Caini
54aa98a752 entity/*: remove the requirement for get_as_tuple from storage classes 2020-11-06 14:49:39 +01:00
Michele Caini
3bff0aa1ea sigh_storage_mixin: don't use get_as_tuple anymore 2020-11-06 12:37:10 +01:00
Michele Caini
b012231635 registry: don't use get_as_tuple and assume that users know what they are doing 2020-11-06 11:32:39 +01:00
Michele Caini
6c6f05fc91 snapshot: cleanup 2020-11-06 11:21:46 +01:00
Michele Caini
3338d5e105 storage_traits: small review 2020-11-06 11:20:10 +01:00
Michele Caini
390ec2f0c1 entity/*: merged storage.hpp and pool.hpp 2020-11-05 18:53:22 +01:00
Michele Caini
4ebdf7a6e8 pool: pool_traits/pool_t -> storage_traits/storage_t 2020-11-05 18:48:52 +01:00
Michele Caini
6f1366dbb5 entity/*: use pool introspection rather than is_empty for filtering 2020-11-05 17:23:39 +01:00
Michele Caini
503791d3c0 view: removed chunked iteration, no real benefits so far and there is no way to make it consistent across all views in future 2020-11-05 15:10:23 +01:00
Michele Caini
902dc49de2 storage: added .get_as_tuple(entity) 2020-11-05 14:29:45 +01:00
Michele Caini
2d299f31e5 storage: removed the requirement to expose try_get 2020-11-05 12:55:34 +01:00
Michele Caini
df298587b8 type_info: suppress warnings for uninitialized members 2020-11-05 12:46:24 +01:00
Michele Caini
b9c33008d8 sparse_set: faster remove/range-remove 2020-11-05 12:21:42 +01:00
Michele Caini
ca97f1c4a3 test: oops, re-enable all bench 2020-11-05 11:10:33 +01:00
Michele Caini
effed56653 sparse_set: a better swap 2020-11-05 10:00:00 +01:00
Michele Caini
7b501aa89b sparse_set/storage: virtual sort 2020-11-04 23:52:48 +01:00
Michele Caini
6c0d0d465b storage: minor changes 2020-11-04 17:19:40 +01:00
Michele Caini
a52bd20912 registry: minor changes 2020-11-04 17:05:22 +01:00
Michele Caini
aabcc445ee *: minor changes 2020-11-04 16:59:35 +01:00
Michele Caini
d491e504cc type_info: small review 2020-11-04 10:49:30 +01:00
Michele Caini
3142e430e7 hashed_string: constexpr ::value suitable for uses with string views 2020-11-04 10:48:40 +01:00
Michele Caini
b784d80a50 pool: minor changes 2020-11-04 00:08:04 +01:00
Michele Caini
7344654308 doc: cleanup 2020-11-03 23:24:59 +01:00
Michele Caini
e01b35c39c config: update default page size 2020-11-03 00:45:46 +01:00
Michele Caini
b8b2c4ee73 handle: get around an issue of VS, toolkit v141 2020-11-03 00:45:24 +01:00
Michele Caini
8cd1ce97f7 handle: it's now possible to convert a handle to a handle view and a handle view to a more restricted one (see #583) 2020-11-03 00:36:11 +01:00
Michele Caini
05b514b743 Revert "entity: minor changes"
This reverts commit af69a0a1fd.
2020-11-02 14:05:07 +01:00
Michele Caini
22596e0f5b entity: added handle_view (close #583) 2020-11-02 13:05:38 +01:00
Michele Caini
e7031794df registry: suppress some warnings (close #582) 2020-11-01 21:49:09 +01:00
Michele Caini
af69a0a1fd entity: minor changes 2020-11-01 00:29:04 +01:00
Michele Caini
52fa690764 view: added use<T> to set explicitly the type that should drive all iterations in a multi type view 2020-10-29 00:03:26 +01:00
Michele Caini
4ad411e320 traits: is_eto_eligible[_v] -> is_empty[_v], internal version 2020-10-28 22:58:26 +01:00
Michele Caini
09da190e93 entity/*: rollback erase -> remove (no longer a breaking change :) 2020-10-28 16:24:44 +01:00
Michele Caini
797dd56bb7 test: removed temporary multi storage example, added a note to the todo list for a refined example 2020-10-28 16:16:52 +01:00
Michele Caini
5e1d77fcd5 doc: updated documentation for registry remove/erase 2020-10-28 13:03:15 +01:00
Michele Caini
2820f2658b entity/: differentiate between remove and erase to avoid name clashing on the custom path (breaking changes) 2020-10-28 12:21:35 +01:00
Michele Caini
f3fc32660b *: updated TODO 2020-10-28 08:43:43 +01:00
Michele Caini
2d4b00ec24 registry: added ::destroyed, made ::assign much faster (breaking changes, close #522) 2020-10-27 23:01:28 +01:00
Michele Caini
86808f5035 doc: minor changes 2020-10-27 09:06:18 +01:00
Michele Caini
82946e2372 pool: storage_adapter -> storage_adapter_mixin 2020-10-27 00:09:32 +01:00
Michele Caini
22d117a397 doc: fixed typo (close #578) 2020-10-26 22:35:49 +01:00
Michele Caini
662cfc9fdc *: cleanup 2020-10-26 15:41:54 +01:00
Michele Caini
a3e73909cf group/view/view_pack: review 2020-10-26 15:31:00 +01:00
Michele Caini
95bafc8ced *: try to get around an issue of gcc v7.5 2020-10-26 15:29:58 +01:00
Michele Caini
05f1906f77 *: get around an issue with clang 2020-10-26 12:43:55 +01:00
Michele Caini
dbbb131424 view_pack: added more functionalities 2020-10-26 12:38:45 +01:00
Michele Caini
fc7ec35242 doc/test: minor changes 2020-10-26 12:29:45 +01:00
Michele Caini
7ac10472dc view/group: small review 2020-10-26 10:50:17 +01:00
Michele Caini
d255889c5c group: added reverse iterators, rbegin and rend to iterable groups 2020-10-26 08:55:17 +01:00
Michele Caini
7662da22fc view: added reverse iterators, rbegin and rend to iterable views 2020-10-25 23:19:56 +01:00
Michele Caini
64cc200df0 test: code coverage 2020-10-25 15:13:13 +01:00
Michele Caini
63c983683c meta: avoid shadow warnings 2020-10-25 15:13:13 +01:00
Michele Caini
92f79c99f7 meta: review overloaded meta functions 2020-10-25 15:13:13 +01:00
Innokentiy Alaytsev
24f937fe4f [meta] Meta-function overload support (#538)
Now meta-functions can be overloaded. When a function with a duplicate
identifier is registered, it's added into the meta-type function list after the
first meta-function with the same id. During the invocation, the meta-functions
with the requested id are iterated, and the best matching one is chosen. The
overload that doesn't require any type conversions or the minimal number of
those is considered the best match. If none of the overloads matches the given
arguments or if there are multiple matching overloads requiring the same number
of type casts then the invocation will fail the same way it happens in C++.

Signed-off-by: Innokentiy Alaytsev <alaitsev@gmail.com>
2020-10-25 15:13:13 +01:00
Michele Caini
47bb682890 doc: updated links 2020-10-23 21:16:38 +02:00
codylico
9ab674ef9a doc: add a note on registry::try_get (#576) 2020-10-23 23:12:35 +02:00
Michele Caini
83eb0de916 doc: updated links 2020-10-22 09:11:52 +02:00
Koward
6359a12dbb doc: Unreal Engine 4 usage instructions (#574) 2020-10-22 09:09:00 +02:00
Michele Caini
eb8e96f413 example: multi instance storage 2020-10-21 08:40:03 +02:00
Michele Caini
138bd96167 doc: updated links 2020-10-21 08:34:22 +02:00
Michele Caini
0d5ea4711d pool/storage: split storage_adapter from basic_storage 2020-10-20 09:45:11 +02:00
Michele Caini
fa4212f07b storage_adapter: extended ::remove 2020-10-20 08:54:58 +02:00
Michele Caini
c7635a7e3d *: updated todo list 2020-10-20 08:23:21 +02:00
Michele Caini
3923c4cfd2 test: more tests, suppress warnings 2020-10-19 22:46:37 +02:00
Michele Caini
6ad884080c meta_func/meta_ctor: support for registering external member functions 2020-10-19 22:38:08 +02:00
Michele Caini
c578a43611 doc: updated doxy file 2020-10-19 12:24:35 +02:00
Michele Caini
aebfa7161f registry: extended ::remove 2020-10-19 12:01:04 +02:00
Michele Caini
682bc502e2 view_pack: minor changes 2020-10-19 09:08:49 +02:00
Michele Caini
cf018ff74c entity: updated operator==/operator!= (close #573) 2020-10-18 23:37:18 +02:00
Michele Caini
5a9cb251ad doc: updated links 2020-10-18 23:24:48 +02:00
Jan Niklas Hasse
bbbf5a5edf Allow compilation for Windows with GNU-like compilers (#566)
Besides MSVC (and compatible compilers like clang-cl) there's also GCC
(MinGW) and GNU-like Clang on Windows. Therefore setting command line
flags in CMake should check for MSVC instead of $<PLATFORM_ID:Windows>.
2020-10-17 18:26:50 +02:00
Michele Caini
7df0449100 view_pack: suppress a shadow warning caused by an unused variable 2020-10-17 18:22:26 +02:00
Michele Caini
820add87ea test: gtest is now working as expected (close #571) 2020-10-17 18:19:49 +02:00
Michele Caini
9a574aa00c doc: more on view_pack 2020-10-17 18:11:09 +02:00
Michele Caini
10da82a331 view_pack: ::each allows to remove the entity from the callback 2020-10-17 18:08:43 +02:00
Michele Caini
26c816e78c type_traits: is_applicable[_v] and is_applicable_r[_v] for tuples 2020-10-17 17:51:58 +02:00
Michele Caini
808e238384 view/group: full callback is tested first now (breaking changes) 2020-10-17 17:19:38 +02:00
Michele Caini
ff068e032b test: code coverage 2020-10-17 00:30:15 +02:00
Michele Caini
5072e96277 view_pack: get around an issue of VS2017 2020-10-17 00:19:27 +02:00
Michele Caini
c55c1c0615 *: view_pack class and tests 2020-10-16 23:59:44 +02:00
Michele Caini
9983faef70 view/group: consistent ::get without template arguments (breaking changes) 2020-10-16 16:15:04 +02:00
Michele Caini
70a264e939 view: updated noexcept-ness for iterators 2020-10-16 09:55:09 +02:00
Michele Caini
9ef6008c67 doc: updated links 2020-10-16 08:29:09 +02:00
Michele Caini
5a3e816544 view/groups: extended get (breaking changes) 2020-10-15 17:02:50 +02:00
Michele Caini
3e385fb884 view/group: minor changes 2020-10-15 16:41:06 +02:00
Michele Caini
fa5cce7477 pool/registry: rename to avoid name clash with virtual functions 2020-10-15 16:13:41 +02:00
Michele Caini
b2de76e8a0 test: temporary workaround for an upstream regression in googletest (see #571) 2020-10-15 15:27:40 +02:00
Michele Caini
edb363b236 sparse_set: avoid comparisons between different types 2020-10-15 15:23:56 +02:00
Michele Caini
12dcfdb5e1 view: candidate selection happens on construction only 2020-10-15 15:23:32 +02:00
Michele Caini
86c1dd7f32 test: suppress some warnings here and there 2020-10-15 15:11:15 +02:00
Michele Caini
d8ff4285da registry: suppress warnings for uninitialized variable 2020-10-15 15:11:05 +02:00
Michele Caini
7effde0478 view: minor changes 2020-10-15 12:52:16 +02:00
Michele Caini
559ee931fb view/group: proxy() -> each() (breaking changes - I know, I shouldn't have changed it before) 2020-10-15 10:06:00 +02:00
Michele Caini
cb27a7fe3e pool: storage adapter and signal mixin are now independent from each other 2020-10-15 09:03:14 +02:00
Michele Caini
c33a8dc2c8 doc: typo 2020-10-14 23:54:58 +02:00
Michele Caini
11fcf88b88 *: some final here and there 2020-10-14 23:54:49 +02:00
Michele Caini
4f0baa80d7 *: object_type -> value_type (breaking changes) 2020-10-14 19:50:00 +02:00
Michele Caini
ddea97bc88 storage: emplace returns the newly created object 2020-10-14 19:44:17 +02:00
Michele Caini
102c9891a0 test: code coverage for sparse set and storage range-erase 2020-10-14 19:37:28 +02:00
Michele Caini
fb4784b695 test: minor changes 2020-10-14 19:18:02 +02:00
Michele Caini
9a0650c703 pool/storage/sparse_set: pushed range-erase at the bottom of the hierarchy 2020-10-14 19:08:23 +02:00
Michele Caini
a62b93acec storage: updated except specification 2020-10-14 17:06:07 +02:00
Michele Caini
2d11bdc736 doc: minor changes 2020-10-14 16:47:39 +02:00
Michele Caini
7d263d36a0 storage: split basic_storage and storage 2020-10-14 16:44:11 +02:00
Michele Caini
4965fd5888 sparse_set: split basic_sparse_set and sparse_set 2020-10-14 16:35:16 +02:00
Michele Caini
36db8b6f59 group: use operator+ for type lists 2020-10-14 16:08:58 +02:00
Michele Caini
9e69f62a39 doc: updated doc for multi component views 2020-10-14 16:08:09 +02:00
Michele Caini
f307021cf1 view: removed multi component view ::raw and ::data (breaking changes) 2020-10-14 16:04:57 +02:00
Michele Caini
0709c402f8 test: reduced the amount of madness by a few degrees :) 2020-10-14 15:54:20 +02:00
Michele Caini
df5deb8b88 view: removed multi component view ::size (breaking changes) 2020-10-14 15:54:08 +02:00
Michele Caini
111dd40097 view: removed multi component view ::empty (breaking changes) 2020-10-14 15:54:00 +02:00
Michele Caini
c83e7d7995 view: removed multi component view ::size<T> (breaking changes) 2020-10-14 15:53:40 +02:00
Michele Caini
718f964de7 type traits: make type_list_cat work with vs2017 2020-10-14 15:37:19 +02:00
Michele Caini
ce0db9b968 type_list: removed type_list_size[_v] in favor of type_list::size (breaking changes) and added operator+ for type lists 2020-10-14 15:36:52 +02:00
Michele Caini
3f0d602353 doc: typo 2020-10-14 15:35:55 +02:00
Michele Caini
5364d778b0 doc: updated links 2020-10-14 15:30:18 +02:00
Michele Caini
0ddec227fa test: minor changes 2020-10-13 14:29:36 +02:00
Michele Caini
a5ea35ee56 meta: use type info objects rather than plain hashes (breaking changes) 2020-10-13 13:48:52 +02:00
Michele Caini
a3e03fb889 type_info: a better operator== 2020-10-13 13:48:18 +02:00
Michele Caini
b7711f0182 doc: updated documentation for meta (clost #569) 2020-10-13 12:52:38 +02:00
Michele Caini
aae199ff1c test: updated plugin examples 2020-10-13 12:41:07 +02:00
Michele Caini
8d0611a188 meta: meta_handle accepts only lvalue references as it ought to be 2020-10-08 14:08:44 +02:00
Michele Caini
958b245c3d doc: typos 2020-10-07 16:05:16 +02:00
Michele Caini
fbb77092eb doc: updated links (engine.... vrooooommm) 2020-10-06 09:32:11 +02:00
Michele Caini
ebc8328712 meta: added size_of to meta type (close #565) 2020-10-06 09:08:50 +02:00
Michele Caini
7967c6dfc8 traits: added size_of[_v] 2020-10-06 09:08:11 +02:00
Michele Caini
fca08a5162 view/group: minor changes 2020-10-05 16:12:27 +02:00
Michele Caini
49f65d6762 registry: internal rework (close #564 among the other things) 2020-10-05 12:52:55 +02:00
Michele Caini
7684e1bad5 doc: minor changes 2020-10-05 11:21:21 +02:00
Michele Caini
46e974d201 registry/pool: removed internal <pool>::patch overload 2020-10-05 08:03:36 +02:00
Michele Caini
ab55d0abc8 doc: updated links 2020-10-03 23:44:00 +02:00
Michele Caini
ed668d5144 view: updated value_type for view_proxy 2020-10-02 10:42:22 +02:00
Michele Caini
dec0f28a2b organizer: added new type to entt/entity 2020-10-02 10:41:56 +02:00
Michele Caini
de7d79f1f4 doc: added a reference to ENTT_USE_ATOMIC where it matters (close #562) 2020-10-02 10:10:55 +02:00
Michele Caini
d204d580dd type info: minor changes 2020-09-29 14:06:09 +02:00
Michele Caini
e4e38edf24 type_info: updated documentation 2020-09-29 08:52:45 +02:00
Michele Caini
3721a1f90b handle: fixed an issue with the comparison operators + minor changes 2020-09-29 08:47:14 +02:00
Vennor
897850c3eb Truly invalid entt::handle (#551) 2020-09-28 22:45:40 +02:00
Michele Caini
a22efb25c6 sparse_set/storage: avoid virtual erase 2020-09-25 17:09:07 +02:00
Michele Caini
f7e80879ae type_info: comparison operators 2020-09-25 16:43:05 +02:00
Michele Caini
bf902e6398 doc: updated links 2020-09-24 17:08:27 +02:00
Michele Caini
aed817f724 doc: updated links (entt topic on GH) 2020-09-24 09:00:01 +02:00
Michele Caini
5ac76d29fc doc: minor changes 2020-09-24 08:44:41 +02:00
Michele Caini
81311ddd03 registry: visit/ctx return type info objects and not only the hash values (breaking changes) 2020-09-24 08:25:49 +02:00
Michele Caini
3c52070243 type_info/type_id: minor changes 2020-09-24 08:25:49 +02:00
Michele Caini
9070f50658 meta_range: minor changes 2020-09-24 08:25:49 +02:00
Michele Caini
ecc3c56cb1 doc: removed all references to old type_info class template 2020-09-24 08:25:49 +02:00
Michele Caini
a86191f6e0 type traits: added type_list_contains[_v] 2020-09-24 08:25:49 +02:00
Michele Caini
aa5fdac522 type_info: it's now copyable and moveable as it ought be 2020-09-24 08:25:49 +02:00
Michele Caini
3cd32c74a1 type info: updated documentation 2020-09-24 08:25:49 +02:00
Michele Caini
2e2f6a03d9 type info: untyped type_info class and type_id functions 2020-09-24 08:25:49 +02:00
Michele Caini
25a073f20b type info: revised to support opaque type info objects (contains breaking changes) 2020-09-24 08:25:49 +02:00
Michele Caini
0fb244e381 type info: removed has_type_index[_v] utility 2020-09-24 08:25:49 +02:00
Michele Caini
631ba70b72 signal: removed unused functions 2020-09-24 08:25:49 +02:00
Michele Caini
0a1d6b2a6f doc: removed reference to ENTT_STANDALONE 2020-09-24 08:25:48 +02:00
Michele Caini
94bfa5ea25 test: get around an issue of toolset v141 2020-09-24 08:25:48 +02:00
Michele Caini
118c14bf1e lib: standalone mode is now the default 2020-09-24 08:25:48 +02:00
Michele Caini
cf395f707a doc: minor changes 2020-09-24 00:13:58 +02:00
Michele Caini
6e040fa87c doc: more on hashed strings (close #559) 2020-09-24 00:09:45 +02:00
Michele Caini
c0a7f84382 doc: correct definition for ranges (close #560) 2020-09-23 23:55:48 +02:00
Michele Caini
826d7b7c26 registry: reintroduce old function type for signals, the registry is now provided to listeners 2020-09-23 23:02:49 +02:00
Michele Caini
91e63d0f19 pool: doc related changes 2020-09-22 08:07:29 +02:00
Michele Caini
2d69e5f6ff doc: updated documentation about signals from a registry 2020-09-22 08:07:14 +02:00
Michele Caini
23f0fcd024 registry: suppress some warnings 2020-09-22 08:06:56 +02:00
Michele Caini
3fcd82abad test: suppress a warning 2020-09-22 08:06:45 +02:00
Michele Caini
d766c39791 *: minor changes 2020-09-22 08:06:41 +02:00
Michele Caini
a76c3b3baa updated TODO file 2020-09-22 08:06:35 +02:00
Michele Caini
9290b4eecc view: size -> size_hint for multi component views (close #553) 2020-09-22 08:06:30 +02:00
Michele Caini
eccfec4b4f registry: use pool_t instead of default_pool 2020-09-22 08:06:24 +02:00
Michele Caini
80aadd3874 registry/pool: split the default pool from the registry class, allow for custom pools 2020-09-22 08:06:16 +02:00
Michele Caini
9da15826db registry: component signals return only the entity 2020-09-22 08:06:04 +02:00
Michele Caini
8c403f8795 bench: added a couple of tests for recycling entities 2020-09-22 08:05:56 +02:00
Michele Caini
b010824dbd registry: faster ::create 2020-09-22 08:05:51 +02:00
Michele Caini
3340f8864f entt/entity: removed deprecated stuff 2020-09-22 08:05:23 +02:00
Michele Caini
9fb3cdfc4c now working on version 2.6 2020-09-22 08:05:04 +02:00
Michele Caini
3a3a2c2702 doc: updated links and references to similar projects 2020-09-22 08:03:55 +02:00
Michele Caini
be38919758 doc: removed references to entt::component (close #557) 2020-09-22 08:03:44 +02:00
Michele Caini
a816ccf6ee meta_any: support for pointer-like types to non-const, non-copyable types (close #556) 2020-09-22 08:03:39 +02:00
Michele Caini
5e85068e35 meta: @Innokentiy-Alaytsev was right and I was not :) 2020-09-22 08:03:33 +02:00
Michele Caini
77865ab4a1 meta: update doc + minor stylistic changes 2020-09-22 08:03:28 +02:00
Innokentiy Alaytsev
5fc6ee27f6 Fixed trailing spaces
Signed-off-by: Innokentiy Alaytsev <alaitsev@gmail.com>
2020-09-22 08:03:21 +02:00
Innokentiy Alaytsev
5995adf8b6 Implemented shortcuts for meta-functions and meta-data
The shortcut for meta-functions allows invoking them directly from an instance
of meta_type or meta_any. If the meta-function was not found or the arguments
don't match its signature an invalid meta_any object is returned.

The shortcut for meta-data allows getting and setting meta-data directly from an
instance of meta_type of meta_any. If the meta_data was not found or
getting/setting it failed and invalid meta_any object is returned.

Signed-off-by: Innokentiy Alaytsev <alaitsev@gmail.com>
2020-09-22 08:03:12 +02:00
Michele Caini
c9f47ed89a sparse_set: minor changes 2020-09-22 08:02:23 +02:00
Michele Caini
d6325ffcfa now working on v3.5.2 2020-09-22 08:02:04 +02:00
Michele Caini
9d72472114 entity: updated difference type for 32b identifiers 2020-09-03 16:22:05 +02:00
Michele Caini
102350a125 entity: removed support for 16b identifiers 2020-09-03 16:22:00 +02:00
Michele Caini
1c650cb136 observer: fixed an issue with exclusion lists (close #549) 2020-09-03 16:21:52 +02:00
Michele Caini
625e74653d test: get around comdat folding 2020-09-03 16:17:11 +02:00
Michele Caini
5bad762293 now working on version 3.5.1 2020-09-03 14:34:34 +02:00
Michele Caini
fc1ff11352 updated single include file 2020-08-31 22:47:23 +02:00
Michele Caini
0595ba384e *: suppress some warnings 2020-08-29 21:59:44 +02:00
Michele Caini
f80f5e9955 doc: updated links 2020-08-29 16:14:11 +02:00
Michele Caini
f689014c3e emitter: the event isn't const by default anymore (close #547) 2020-08-21 18:09:05 +02:00
Michele Caini
9b24655bbf dispatcher: the event isn't const by default anymore (see #547) 2020-08-21 18:02:41 +02:00
Michele Caini
c3201070a1 doc: updated FAQs (close #543) 2020-08-21 16:16:40 +02:00
Michele Caini
8a146209e4 sigh: updated documentation 2020-08-21 15:59:56 +02:00
Michele Caini
2b719726cd view: suppress warnings 2020-08-21 12:24:34 +02:00
Michele Caini
27209e4836 doc: updated links 2020-08-19 16:39:24 +02:00
Michele Caini
0497762f94 doc: typo 2020-08-19 10:41:01 +02:00
Michele Caini
b38f1e744b doc: updated README - EnTT runs everywhere 2020-08-19 10:15:16 +02:00
Michele Caini
481c49e18e doc: added a new link to similar projects 2020-08-19 10:06:38 +02:00
Michele Caini
69cf9115b5 doc: added a new link to the list of showcases (close #546) 2020-08-19 10:02:31 +02:00
Michele Caini
3eedd89efe config/core/entity: added is_eto_eligible[_v] and used it where it makes sense 2020-08-17 18:21:21 +02:00
Michele Caini
ad262ea624 entity/*: suppress some warnings here and there 2020-08-16 12:10:55 +02:00
Michele Caini
08cd8c95f7 updated todo list 2020-08-16 11:25:28 +02:00
Michele Caini
c86790c6b8 test: minor changes 2020-08-16 11:24:57 +02:00
Michele Caini
e466d9252f view: rebind the view only when possible 2020-08-14 12:12:57 +02:00
Michele Caini
02f8a0baa6 view: stable candidate computed on construction 2020-08-14 11:58:10 +02:00
Michele Caini
9f7bbe3f9d doc: updated links 2020-08-14 11:02:37 +02:00
Michele Caini
e81e0e97e0 meta: workaround for an issue of VS2019 (see #314) 2020-08-12 09:05:20 +02:00
Michele Caini
52554c3972 test: suppress a bunch of warnings 2020-08-11 16:53:03 +02:00
Michele Caini
48b6c4876a runtime view: suppress warnings for shadow variables 2020-08-11 16:52:24 +02:00
Michele Caini
99e89c2540 registry: suppress warnings for shadow variables 2020-08-11 16:52:06 +02:00
Michele Caini
0e8453d4ed entt_traits: updated difference types 2020-08-11 15:27:41 +02:00
Michele Caini
c750b746b3 meta: explicit return type to get around an issue with VS2017 2020-08-10 18:16:26 +02:00
Michele Caini
0ac07e2e83 meta: reset is now part of meta_type 2020-08-10 18:15:11 +02:00
Michele Caini
ead6cb9ca3 test: suppress warnings 2020-08-10 10:04:14 +02:00
Michele Caini
c401f9211d test: minor changes 2020-08-10 10:04:14 +02:00
Michele Caini
abb72c0a9a view: rbegin/rend 2020-08-10 10:04:13 +02:00
Michele Caini
bc9172bd43 doc: updated links 2020-08-10 10:04:13 +02:00
Michele Caini
b205a5e49d group: rbegin/rend 2020-08-10 10:04:13 +02:00
Michele Caini
fccf9642d8 view: prepare multi component views for reverse iterators 2020-08-10 10:04:13 +02:00
Michele Caini
96dd68f52b doc: typo 2020-08-10 10:04:12 +02:00
Michele Caini
7f923bb389 doc: added more details about observers (close #536) 2020-08-10 10:04:12 +02:00
Michele Caini
7ab7ebb3f6 doc: added a note about in-place sorting 2020-08-10 10:04:12 +02:00
Michele Caini
4eacb58a3e doc: minor changes 2020-08-10 10:04:12 +02:00
Michele Caini
24248832d1 group/view: explicit proxy object 2020-08-10 10:04:11 +02:00
Michele Caini
a53f0900bd view/group: make range return types explicit in preparation for faster/unsafe reverse iterators 2020-08-10 10:04:11 +02:00
Michele Caini
6a1a5a0f74 sparse set: minor changes 2020-08-10 10:04:10 +02:00
Michele Caini
65aa4e145e registry: minor changes 2020-08-10 10:04:10 +02:00
Michele Caini
cf903aa082 storage: added reverse iterators 2020-08-10 10:04:09 +02:00
Michele Caini
75dd86e8ef sparse set: added reverse iterators 2020-08-10 10:04:09 +02:00
Michele Caini
70a3d62c14 doc: udpated links 2020-08-10 10:04:08 +02:00
Michele Caini
291e3cd229 view: minor changes 2020-08-10 10:04:08 +02:00
Michele Caini
9b28c1fdd2 runtime view: suppress warning (close #540) 2020-08-10 10:01:09 +02:00
Michele Caini
d1d73da039 doc: fixed typo (close #534) 2020-07-28 21:51:59 +02:00
Michele Caini
59f041b9a9 view: minor changes 2020-07-27 10:50:11 +02:00
Michele Caini
fbf3b9ce4d doc: help doxygen not to go crazy (thanks to @erez-o for pointing this out) 2020-07-27 00:07:11 +02:00
Michele Caini
9be2e1c4c9 sigh: don't use std::forward with fake forwarding references 2020-07-26 01:09:58 +02:00
Michele Caini
a06c9f890c meta: cleanup 2020-07-25 23:35:52 +02:00
cugone
fc8e8874a9 *: fix C4003 NOMINMAX issue (#531) 2020-07-25 23:09:26 +02:00
Michele Caini
09e0f68616 view: suppress shadow warnings 2020-07-25 23:02:52 +02:00
Michele Caini
0e7e36f80d view: chunked iteration for multi-component views (close #462) 2020-07-25 18:47:20 +02:00
Michele Caini
8484dcd332 doc: updated links 2020-07-24 11:00:33 +02:00
Michele Caini
8a46296b48 meta: simplified iterators for meta containers 2020-07-24 11:00:33 +02:00
Michele Caini
b748a910b2 meta: fix an issue with meta_associative_container::meta_iterator::value 2020-07-24 11:00:33 +02:00
Michele Caini
932603eea3 *: minor changes 2020-07-24 11:00:33 +02:00
Michele Caini
5056972f79 meta: ctors and funcs also accept a meta_any * + size pair (close #528) 2020-07-24 11:00:33 +02:00
Michele Caini
d99ccca291 meta: minor changes 2020-07-24 11:00:33 +02:00
Sackhorn
1d9b26d9ec doc: backslash typo in FAQ (#532) 2020-07-24 11:00:12 +02:00
Michele Caini
3a64707c6e doc: updated links 2020-07-21 15:43:58 +02:00
Michele Caini
6f4071bd75 view: check filter array correctly (close #527) 2020-07-21 13:12:51 +02:00
Michele Caini
1354fdc613 *: suppress some warnings here and there (close #525) 2020-07-20 00:20:55 +02:00
Michele Caini
991244655a dispatcher: opaque disconnect (close #523) 2020-07-19 12:18:15 +02:00
Michele Caini
0d07d935bf *: removed redundant namespace names 2020-07-19 12:13:51 +02:00
Michele Caini
bd56b642a7 doc: updated links 2020-07-19 11:03:06 +02:00
Sackhorn
d989f0edf2 Update entity.md (#524)
Small typo fix in wiki
2020-07-19 10:20:52 +02:00
Michele Caini
f561cf9c8f build system: suppress wrong warning 2020-07-16 18:03:16 +02:00
Michele Caini
13502e5467 entity: explicit casts to suppress misleading warnings 2020-07-16 17:48:29 +02:00
Michele Caini
045c2a6f05 delegate: removed redundant calls to delegate constructor 2020-07-15 18:13:44 +02:00
Michele Caini
725e9feb68 entity: removed unused constructors from range iterators (being default constructible isn't a requirement for input iterators) 2020-07-15 17:33:21 +02:00
Michele Caini
6e45126f53 test: added explicit test for ENTT_NO_ETO 2020-07-15 16:09:41 +02:00
Michele Caini
6ebc39e038 entity: added sfinae-friendly utility for component-to-pool conversions 2020-07-14 18:25:01 +02:00
Michele Caini
8b0a7c302b storage: workaround for an issue of vs2017 2020-07-14 17:46:08 +02:00
Michele Caini
0c3e50da2f build system: try to reproduce an issue of vs2019, toolset v141 2020-07-14 15:11:39 +02:00
Michele Caini
d220cf4acc platform: minor changes 2020-07-13 23:56:01 +02:00
Innokentiy Alaytsev
eb1ce7e927 meta: Deduplicate the STL-compatible container traits (#518) 2020-07-13 23:55:19 +02:00
Michele Caini
46f6f41a6b entity: remove asserts from to_entity, it's potentially UB as from the standard 2020-07-12 23:53:20 +02:00
Michele Caini
2fa59fc43c entity: added debug asserts to to_entity 2020-07-12 16:45:00 +02:00
Michele Caini
b7763b3887 test: minor changes 2020-07-11 17:59:23 +02:00
Michele Caini
8c002b67d5 runtime view: support for excluded components (close #512) 2020-07-11 17:26:20 +02:00
Michele Caini
7692c4a377 test: ENTT_ID_TYPE -> entt::id_type 2020-07-11 15:56:30 +02:00
Michele Caini
1f0acec06c doc: minor changes 2020-07-11 15:07:23 +02:00
Michele Caini
1b5295a8fe helper: added to_entity function that returns the entity associated with a given component 2020-07-11 12:32:58 +02:00
Michele Caini
0b699a3f20 view: fixed the constrained range-each 2020-07-10 17:54:07 +02:00
Michele Caini
409d7a499d test: code coverage 2020-07-10 17:45:17 +02:00
Michele Caini
ba7428f3d6 group: small changes to get around an issue of g++ v7.5 2020-07-10 17:35:57 +02:00
Michele Caini
c12c32d26e view/group: updated range iterators (thanks to @Lawrencemm for pointing this out) 2020-07-10 15:37:43 +02:00
Michele Caini
0ca5ea0150 test: minor changes 2020-07-10 15:09:40 +02:00
Michele Caini
11ca7c7b3e group: get around an issue with g++ 2020-07-09 19:20:09 +02:00
Michele Caini
8f6c47527d doc: added a note about ranges for views and groups (close #502) 2020-07-09 18:40:41 +02:00
Michele Caini
dd28882b27 group: optimized ranges 2020-07-09 18:18:07 +02:00
Michele Caini
1b93a449b2 view: improved view ranges 2020-07-09 18:09:38 +02:00
Michele Caini
7cf2ec09b7 group: added iterable object to visit entities and components at once 2020-07-09 16:58:26 +02:00
Michele Caini
4d1952a406 view: added iterable object to visit entities and components at once 2020-07-09 16:58:07 +02:00
Michele Caini
b8d25e2327 doc: typos 2020-07-08 18:07:26 +02:00
Michele Caini
89d7c7e572 handle: better API 2020-07-06 09:39:23 +02:00
Michele Caini
75b19230eb entity: make null_t public 2020-07-06 09:24:56 +02:00
Indiana Kernick
7889ca1ca7 Non-owning entt::handle (#513) 2020-07-04 18:00:44 +02:00
Michele Caini
cec1b932bd example: custom identifier (and some fixes for the purpose) 2020-07-02 16:56:49 +02:00
Michele Caini
2c7455ea2b benchmark: use entt::id_type instead of ENTT_ID_TYPE 2020-07-02 15:07:20 +02:00
Michele Caini
edc9cc9278 type_traits: removed ENTT_OPAQUE_TYPE 2020-07-01 18:41:20 +02:00
Michele Caini
51eafaeb4f doc: mention custom types for entity identifiers 2020-07-01 18:41:00 +02:00
Michele Caini
556373d331 registry: better support for integral entity identifiers (even if not recommended) 2020-07-01 18:39:34 +02:00
Michele Caini
804cfb7482 test: use entt::to_integral instead of std::underlying_type_t for entity identifiers 2020-07-01 17:17:33 +02:00
Michele Caini
143eae0729 test: avoid using underlying_type_t with entt_traits 2020-07-01 17:10:42 +02:00
Michele Caini
29d4846de7 entity: bind to_integral to entt_traits instead of a specific enum class 2020-07-01 16:28:56 +02:00
Michele Caini
306178f371 doc: minor changes 2020-07-01 16:06:08 +02:00
Michele Caini
371b541fbc entity: make entt_traits sfinae-friendly and avoid using std::underlying_type_t to define the entity traits types 2020-07-01 15:32:04 +02:00
Oortonaut
902658fd21 Properly case entity version for 64-bit support. (#516) 2020-07-01 10:51:26 +02:00
Michele Caini
0ca8dff974 test: code coverage 2020-06-30 17:50:36 +02:00
Michele Caini
a212b054e7 platform: added support file for android ndk r17 2020-06-30 16:47:27 +02:00
Michele Caini
cccd1baa2f meta: minor changes 2020-06-26 16:04:09 +02:00
Michele Caini
5dd25aed4d meta: assoc container's ::erase/::find accept also convertible keys 2020-06-26 14:59:35 +02:00
Michele Caini
6ddc725b75 meta: minor changes 2020-06-26 12:51:44 +02:00
Michele Caini
36ab7444a0 meta: removed some deprecated functions (semantics had changed, it was already a breaking change in itself) 2020-06-26 12:43:51 +02:00
Michele Caini
a8d004334a meta: minor changes 2020-06-26 12:24:28 +02:00
Michele Caini
900398a632 resource: added prefix resource_ to all classes 2020-06-25 23:37:50 +02:00
Michele Caini
f24bb8737d deprecate actor 2020-06-25 22:55:35 +02:00
Michele Caini
cb5e9b197a doc: added links to docsforge (close #510) 2020-06-24 09:44:54 +02:00
Michele Caini
450e20ae78 meta: minor changes 2020-06-23 11:31:04 +02:00
Michele Caini
5d42a76fe5 meta: added support for convertible types to meta containers ::insert functions 2020-06-23 10:55:40 +02:00
Michele Caini
c5075a3db0 doc: minor changes (see #510) 2020-06-23 08:49:17 +02:00
Michele Caini
ad5bb5198b meta: fixed key_only member function for meta associative containers 2020-06-22 17:02:45 +02:00
Michele Caini
d306bc4a9a test: code coverage 2020-06-22 12:47:10 +02:00
Michele Caini
5c3b956542 doc: fixed some problems with doxygen (see #510) 2020-06-22 12:11:36 +02:00
Michele Caini
ade8533f28 meta: dedicate iterators for different types of meta containers 2020-06-22 11:07:57 +02:00
Michele Caini
ad3413d6ad meta: added is_key_only_meta_associative_container[_v] to type traits 2020-06-22 10:19:06 +02:00
skypjack
f3d0e3f4dd test: fixed tests for meta containers 2020-06-22 09:32:00 +02:00
Michele Caini
6e2e030ba7 meta: updated documentation 2020-06-22 01:05:48 +02:00
Michele Caini
613f993638 core/type_traits: removed is_dereferenceable[_v] 2020-06-21 23:42:07 +02:00
Michele Caini
2566e3631b meta: support for pointer-like types 2020-06-21 23:39:26 +02:00
Michele Caini
4ad6c0a8a9 meta: meta_sequence_container_traits_t -> meta_sequence_container_traits 2020-06-21 23:13:20 +02:00
Michele Caini
0369ac450e meta: added meta sequence container resize + [[nodiscard]] here and there 2020-06-21 23:08:14 +02:00
Michele Caini
ab16680cc8 type_traits: removed container detectors 2020-06-20 01:20:22 +02:00
Michele Caini
8a344cd9b2 meta: meta container support review 2020-06-20 01:17:14 +02:00
Michele Caini
4e66fb4589 test: minor changes, code coverage 2020-06-19 11:52:47 +02:00
Michele Caini
0043e3d623 meta: breaking change, meta_any::operator* dereferences the internal pointer (if any) 2020-06-19 00:15:01 +02:00
Michele Caini
ed168015bf meta: review meta_handle 2020-06-18 18:49:52 +02:00
Michele Caini
1d450ef27e meta: deprecate meta_[any|handle]::operator*, use ::ref instead 2020-06-18 18:21:12 +02:00
Michele Caini
932e681d22 meta: get rid of meta_dtor_node 2020-06-18 16:44:04 +02:00
Michele Caini
032bcd9fbe meta: minor changes 2020-06-18 16:02:26 +02:00
Michele Caini
e113fa53a4 meta: split meta_storage from meta_any 2020-06-18 14:31:06 +02:00
Michele Caini
da212dc2a4 meta: added meta_type::is_dereferenceable 2020-06-18 11:34:44 +02:00
Michele Caini
d1c5a62a9d core: type_traits, added is_dereferenceable[_v] 2020-06-18 11:30:55 +02:00
Michele Caini
0c777e10e5 doc: meta, container support 2020-06-18 10:17:50 +02:00
Michele Caini
b919b172b1 *: suppress some warnings here and there 2020-06-16 23:36:31 +02:00
Michele Caini
5dd8d05114 meta: get around an issue of msvc 2020-06-16 23:29:50 +02:00
Michele Caini
3400b32015 meta: containers support (close #499) 2020-06-16 23:21:45 +02:00
Michele Caini
2e4becad60 type_traits: sequence/associative container traits 2020-06-16 23:18:55 +02:00
Michele Caini
3d485858d5 meta: get around a bug of gcc-7, meta factory has no longer only static members 2020-06-15 00:08:46 +02:00
Michele Caini
be93643808 view: non-const excluded types are always accepted (close #507) 2020-06-14 23:42:15 +02:00
Michele Caini
f704352bae type_traits: unpack_as_t/unpack_as_v 2020-06-14 23:28:35 +02:00
Michele Caini
6683b46b07 meta: factory<Type> has now only static functions 2020-06-14 17:32:28 +02:00
Michele Caini
a1fe458338 meta: removed dependency on <algorithm> from internal.hpp 2020-06-14 16:37:38 +02:00
Michele Caini
e6328e3207 meta: minor changes 2020-06-12 17:47:39 +02:00
Michele Caini
8b1f703397 doc: updated missing description 2020-06-12 16:18:12 +02:00
Michele Caini
583c8add7e meta: make meta_handle copyable 2020-06-12 11:42:05 +02:00
Michele Caini
0266cc8e99 meta: make instances meta handles all around the codebase 2020-06-12 11:36:13 +02:00
Michele Caini
fac4132cb1 meta: meta_type rank/extent 2020-06-12 10:10:43 +02:00
Michele Caini
bf3864b2da meta: arrays are no longer indexable via meta_type::set/get 2020-06-12 09:30:29 +02:00
Michele Caini
7c21042858 sparse_set: improved performance (see #506) - thanks @Kerndog73 2020-06-12 08:19:44 +02:00
Michele Caini
d0fd9e4618 meta: range_iterator are now part of ranges 2020-06-11 19:50:32 +02:00
Michele Caini
9b53230f83 meta: cleanup 2020-06-11 17:59:29 +02:00
Michele Caini
d814b7b11e test: code coverage 2020-06-11 17:03:45 +02:00
Michele Caini
9f5421d3d4 build system: solved an issue with codecov 2020-06-11 16:48:25 +02:00
Michele Caini
6b9e5db3bf meta: updated resolve function(s) 2020-06-11 15:40:16 +02:00
Michele Caini
9eac3faf3d meta: added meta_range and meta_iterator 2020-06-11 15:27:56 +02:00
Michele Caini
252de444fc test: meta, minor changes 2020-06-11 11:00:20 +02:00
Michele Caini
c29b9cc937 test: updated tests for meta 2020-06-11 10:46:40 +02:00
Michele Caini
6ac582a771 test: more on meta_type 2020-06-11 10:10:07 +02:00
Michele Caini
04b0c9f2cf test: more on meta_func 2020-06-11 09:55:49 +02:00
Michele Caini
6b2468f033 test: more on meta_data 2020-06-11 09:53:35 +02:00
Michele Caini
2737acb114 test: added meta_type 2020-06-11 09:45:55 +02:00
Michele Caini
d03e9c48c5 tests: minor changes 2020-06-11 09:01:33 +02:00
Michele Caini
08d9cfe82c test: added meta_func 2020-06-10 17:37:21 +02:00
Michele Caini
e8ea8f91c3 test: added meta_data 2020-06-10 17:22:48 +02:00
Michele Caini
e7cfa7fda5 test: added meta_ctor 2020-06-10 16:43:02 +02:00
Michele Caini
b0b504d002 test: added meta_conv 2020-06-10 15:59:12 +02:00
Michele Caini
1da07ba60b test: added meta_base 2020-06-10 15:51:10 +02:00
Michele Caini
cedebf8145 test: added meta_prop 2020-06-10 15:42:47 +02:00
Michele Caini
29832bb2c0 test: added meta_any 2020-06-10 15:32:30 +02:00
Michele Caini
320d815d60 test: added meta_basic 2020-06-10 15:05:26 +02:00
Michele Caini
9f18401581 meta: split fixture and tests 2020-06-10 14:56:01 +02:00
Michele Caini
b3a2f0e3a3 meta: internal range/iterator support 2020-06-10 11:34:45 +02:00
Michele Caini
c00dcd31d6 meta: small review 2020-06-09 16:41:12 +02:00
Michele Caini
b836be2c84 doc: minor changes 2020-06-09 16:13:47 +02:00
Michele Caini
f89c5cc072 doc: added section pool to entity.md (close #505) 2020-06-09 09:57:57 +02:00
Michele Caini
ab7fa56bb3 doc: updated documentation for groups and nested groups 2020-06-09 09:32:36 +02:00
Michele Caini
7e624159ee registry/group: pool<T>::super is no longer required 2020-06-09 00:55:48 +02:00
Michele Caini
857a791d68 registry: sort/sortable no longer requires pool<T>::super 2020-06-08 00:44:02 +02:00
Michele Caini
171463faf5 [[nodiscard]]: try to get around an issue with VS2017 (see #501) 2020-06-07 17:34:38 +02:00
Michele Caini
2cafb49ffe entity: [[nodiscard]] (close #501) 2020-06-07 00:51:45 +02:00
Michele Caini
ae12fed5fe meta: [[nodiscard]] (see #501) 2020-06-07 00:13:20 +02:00
Michele Caini
be5547de53 core: [[nodiscard]] (see #501) 2020-06-06 23:51:08 +02:00
Michele Caini
cac50ef566 locator: [[nodiscard]] (see #501) 2020-06-06 23:43:56 +02:00
Michele Caini
57a5736942 process: [[nodiscard]] (see #501) 2020-06-06 23:42:48 +02:00
Michele Caini
167eadf699 resource: [[nodiscard]] (see #501) 2020-06-06 23:39:56 +02:00
Michele Caini
5676e420a6 signal: [[nodiscard]] (see #501) 2020-06-06 23:36:31 +02:00
Michele Caini
f5edc9e973 doc: core, type_info<T>::name 2020-06-05 14:57:24 +02:00
Michele Caini
4a305e1568 type_info: added ::name 2020-06-05 00:32:15 +02:00
Michele Caini
748ab221dd delegate: renaming of exported types 2020-06-03 23:59:58 +02:00
Michele Caini
7d786cea8f test: pass ENTT_STANDALONE definition to all targets 2020-06-03 23:42:05 +02:00
Michele Caini
1bf734338d doc: suppress a couple of warnings from doxygen 2020-06-03 17:17:10 +02:00
Michele Caini
98df1d6004 config: type index based lookup as opt-in alternative (close #490) 2020-06-03 17:13:11 +02:00
Michele Caini
290e942f3e doc: updated documentation for meta 2020-06-01 19:38:07 +02:00
Michele Caini
46d54f7e01 factory: try to get around an issue of GCC 2020-05-31 17:23:56 +02:00
Michele Caini
16e1715d06 factory: extended ::data support (close #496) 2020-05-31 17:13:21 +02:00
Michele Caini
52faa1bec5 meta: allow read-only data registration in meta (close #496) 2020-05-29 00:54:39 +02:00
Michele Caini
c8a6465688 meta: reduce instantiations 2020-05-29 00:30:20 +02:00
Alex Ames
0273b7606e snapshot: components no longer need to be copyable (#498)
Replaced calls to std::as_const with std::move so that components can
be moved into place instead of copied when reading them in from a
snapshot.
2020-05-27 23:56:48 +02:00
Michele Caini
51022cb132 meta: reduce instantiations 2020-05-27 00:51:42 +02:00
Michele Caini
78f9d87ac3 test: suppress shadow warnings 2020-05-25 23:03:28 +02:00
Michele Caini
e57135eaab delegate: support for non-capturing lambda functions (see #495) 2020-05-25 22:59:02 +02:00
Michele Caini
5fbb663529 *: added meaningful messages (?) to static asserts (close #493) 2020-05-24 00:32:08 +02:00
Michele Caini
7db0f540bd dispatcher: enqueue works fine with aggregates now (close #491) 2020-05-23 00:40:42 +02:00
Michele Caini
c8f0afb775 test: ugly workaround for an ICE of VS2017 that fails to compile valid C++ code when combined with ENTT_API 2020-05-22 00:33:17 +02:00
Michele Caini
51a5815098 registry: suppress shadow warnings 2020-05-21 22:50:38 +02:00
Michele Caini
18bd2eb729 doc: removed references to patreon account 2020-05-21 08:44:24 +02:00
Michele Caini
f04fd61879 doc: added config section 2020-05-19 00:36:45 +02:00
Michele Caini
c1527cc4c8 doc: more details on the order of components and entities when iterating through pointers returned from raw/data (close #489) 2020-05-17 23:48:43 +02:00
Michele Caini
cf1c1ed126 group: const correctness for constructor arguments 2020-05-17 22:57:16 +02:00
Michele Caini
c4ba8f96e6 view: try to get around a bug in MSVC 2020-05-17 00:44:06 +02:00
Michele Caini
350884c627 view: const correctness for constructor arguments 2020-05-17 00:18:52 +02:00
Michele Caini
aa756f6d68 doc: minor changes 2020-05-17 00:12:43 +02:00
Michele Caini
1a77bf49f5 registry: const correctness 2020-05-16 00:52:28 +02:00
Michele Caini
1b509c56fe meta: cleanup 2020-05-16 00:52:23 +02:00
Joël Lamotte
038b10c74d Added build2 package info (#484) 2020-05-14 00:38:36 +02:00
Michele Caini
39baa59625 registry: remove_if_exists returns the number of components actually removed (close #483) 2020-05-13 00:20:44 +02:00
Michele Caini
3fc091ebb2 view: removed deprecated functions 2020-05-12 00:24:39 +02:00
Michele Caini
a557e133d3 group: removed deprecated functions 2020-05-12 00:18:42 +02:00
Michele Caini
7d4f10ccc6 registry: removed deprecated functions 2020-05-12 00:12:49 +02:00
Michele Caini
39a15bef12 snapshot: removed deprecated functions 2020-05-11 16:38:12 +02:00
Michele Caini
92c59f3ea1 registry: removed the dependency on the snapshot stuff 2020-05-11 16:38:12 +02:00
Michele Caini
226bd44e2c meta: removed deprecated functions 2020-05-11 16:38:12 +02:00
Michele Caini
78d43a49c6 observer: removed deprecated functions 2020-05-11 16:38:12 +02:00
Michele Caini
471651ac5a storage: removed deprecated functions 2020-05-11 16:38:12 +02:00
Michele Caini
89515b0e30 sparse set: removed deprecated functions 2020-05-11 16:38:12 +02:00
Michele Caini
1d61c0d970 build system: updated version, now working on v3.5.0 2020-05-11 16:38:12 +02:00
Michele Caini
35c3acbade doc: added a link to the discord server 2020-05-11 16:37:18 +02:00
Michele Caini
58a2c6a13a updated single include file 2020-05-10 16:14:27 +02:00
Michele Caini
bf0160adbd registry: removed useless check 2020-05-08 23:27:53 +02:00
Michele Caini
dfbc92dd3e test: code coverage 2020-05-08 23:17:36 +02:00
Michele Caini
85b0bbfd55 snapshot: suppress shadow warnings 2020-05-07 17:20:25 +02:00
Michele Caini
fb2a93dc05 snapshot: updated documentation 2020-05-07 16:25:51 +02:00
Michele Caini
4ac46bf19d snapshot: registry friendship is no longer required 2020-05-07 16:02:49 +02:00
Michele Caini
4d73adb540 snapshot: cleanup 2020-05-07 16:02:49 +02:00
Michele Caini
bdfeb1ae22 registry: destroy with suggested version 2020-05-07 16:02:49 +02:00
Michele Caini
3fc116ab53 minor changes 2020-05-07 16:02:49 +02:00
Michele Caini
8db61a38cc sparse set: review 2020-05-07 16:02:49 +02:00
Michele Caini
0a70979934 observer: deprecated .replace, use .update instead 2020-05-07 16:02:49 +02:00
Michele Caini
1a2ccdf991 Update README.md 2020-05-07 16:01:12 +02:00
Michele Caini
0adee56d76 meta: as_alias[_t] -> as_ref[_t] (see #479) 2020-04-30 23:59:17 +02:00
Michele Caini
fedd50efe4 meta: added meta_any::ref as an alias to meta_any operator* (close #479) 2020-04-30 23:53:02 +02:00
Michele Caini
d7de7dbe6b build system: minor changes (close #478) 2020-04-30 23:24:50 +02:00
Michele Caini
9fb8939efd meta: removed redundant assert 2020-04-30 14:28:54 +02:00
Michele Caini
fe8f671137 build system: USE_LIBCPP option is set to ON by default (see #478) 2020-04-30 14:28:34 +02:00
Michele Caini
1a4de1482b build system: minor changes (close #478) 2020-04-29 23:10:42 +02:00
Michele Caini
090a2595e1 config/type_id: minor changes 2020-04-29 01:05:17 +02:00
Michele Caini
89dc7f817f meta: added resolve_type utility 2020-04-25 17:36:57 +02:00
Michele Caini
fe0f26ce9c meta: workaround for an issue of clang 7 (close #472) 2020-04-25 16:48:21 +02:00
Michele Caini
11349629f4 meta: get around an issue of VS2017 2020-04-23 14:56:39 +02:00
Michele Caini
9a67652c0c meta: separate resolve.hpp file 2020-04-22 20:05:24 +02:00
Michele Caini
b35521dfcb meta: deprecated resolve by id, added entt::resolve_id 2020-04-21 18:32:35 +02:00
Michele Caini
9faf306d1e meta: added entt::resolve_if 2020-04-20 23:25:10 +02:00
Michele Caini
d8393dace6 meta: deprecated *::alias(), use ::id() instead 2020-04-20 22:34:30 +02:00
Michele Caini
692e5275a3 entity: the null entity works fine also with C++20 (close #467) 2020-04-20 22:34:30 +02:00
Michele Caini
1cfe517db8 meta: meta_type::id -> meta_type::type_id 2020-04-20 22:34:30 +02:00
Michele Caini
e99e1dc2ac meta: factory::alias -> factory::type (with type_info<T>::id as a default identifier) 2020-04-20 22:34:30 +02:00
Michele Caini
1bf4ebcabb suppress warnings for shadow parameters 2020-04-20 22:34:30 +02:00
Michele Caini
ec4b264868 meta: export also the meta_node class template (close #464) 2020-04-20 22:34:30 +02:00
Michele Caini
efb125b2d5 updated list of contributors 2020-04-20 22:34:16 +02:00
Elias Daler
1c0fdbed59 Fix typo in docs (s/comp/velocity) (#468) 2020-04-20 22:32:52 +02:00
Michele Caini
37bb10e564 doc: updated examples (close #463) 2020-04-17 00:23:04 +02:00
Michele Caini
1507d5d85f updated single include file (close #461) 2020-04-14 18:37:59 +02:00
Michele Caini
2a86acfc50 doc: updated documentation for the core part 2020-04-14 18:35:03 +02:00
Michele Caini
e0ee01b92e doc: fixed typo 2020-04-14 18:29:25 +02:00
Michele Caini
6006917622 storage: assert on requirements (see #458) 2020-04-09 19:42:45 +02:00
Michele Caini
4ffcf6bf3b meta: added the possibility to detach meta types from contexts 2020-04-09 00:26:02 +02:00
Michele Caini
49cde59c4e meta: minor changes 2020-04-08 23:45:48 +02:00
Michele Caini
ed7382995c registry: added ::remove_all to orphan entities (close #446) 2020-04-07 23:48:07 +02:00
Michele Caini
a7faab53b9 basic_continuous_loader: deprecated ::has, use ::contains instead 2020-04-07 00:00:57 +02:00
Michele Caini
a6aad25117 sparse_set/storage: deprecated ::destroy, use ::erase instead 2020-04-06 23:57:20 +02:00
Michele Caini
5f06084b19 sparse_set: deprecated ::has, use ::contains instead 2020-04-06 23:51:59 +02:00
Michele Caini
8151fbcb2e core: tag is no longer deprecated (close #457) 2020-04-06 23:21:17 +02:00
Michele Caini
5a8e46a6b8 doc: updated documentation for the resource module 2020-04-06 23:20:46 +02:00
Michele Caini
c4997c52e2 doc: updated documentation for the entity module 2020-04-06 23:20:28 +02:00
Michele Caini
ff12c22f50 test: cleanup 2020-04-05 23:36:00 +02:00
Michele Caini
ed7f09ab80 registry: updated tests (lib) 2020-04-05 23:32:10 +02:00
Michele Caini
f68941992a emitter: updated tests (lib) 2020-04-05 23:22:16 +02:00
Michele Caini
afcd9285e6 dispatcher: updated tests (lib) 2020-04-05 23:16:16 +02:00
Michele Caini
22f78d5b33 doc: updated documentation for making EnTT work nicely across boundaries 2020-04-05 22:58:07 +02:00
Michele Caini
5259142eb6 registry: use fast path if available, standard path otherwise 2020-04-05 22:07:35 +02:00
Michele Caini
dc403ce8ab emitter: use fast path if available, standard path otherwise 2020-04-05 22:07:23 +02:00
Michele Caini
a6fddd6a2c dispatcher: use fast path if available, standard path otherwise 2020-04-05 22:07:12 +02:00
Michele Caini
819cd623f9 multiple modules: minor changes 2020-04-05 22:04:57 +02:00
Michele Caini
f185494de3 type info: added has_type_index[_v] 2020-04-05 22:03:52 +02:00
Michele Caini
628a17ae72 config: fixed ENTT_IS_EMPTY macro definition 2020-04-03 00:49:47 +02:00
Michele Caini
08169b9180 emitter: reintroduced type_id for the internal pool 2020-04-03 00:22:01 +02:00
Michele Caini
1e79f2441c dispatcher: reintroduced type_id for the internal pool 2020-04-03 00:21:53 +02:00
Michele Caini
8680c0ba39 config: ENTT_DISABLE_ETO -> ENTT_NO_ETO 2020-04-02 18:21:42 +02:00
Michele Caini
8a78b0dbd6 registry: use only sequential indexes for component types now 2020-04-01 22:17:10 +02:00
Michele Caini
0232035e34 emitter: use only sequential indexes now 2020-04-01 21:27:59 +02:00
Michele Caini
74f3df83db dispatcher: use only sequential indexes now 2020-04-01 21:19:38 +02:00
Michele Caini
53fa0d2fe8 registry: ::assure sets a constraint on the type 2020-04-01 00:16:35 +02:00
Michele Caini
52aa9ab761 type_info: split type_info::index to type_index::value 2020-04-01 00:14:28 +02:00
Michele Caini
92cf6195b2 iterators: standard-ish names for better integration 2020-03-30 16:11:10 +02:00
Michele Caini
86a392991a test: type_info::index 2020-03-28 17:05:23 +01:00
Michele Caini
30d426d667 doc: updated core section 2020-03-28 17:01:04 +01:00
Michele Caini
5702c50680 type_info: added ::index to generate type indexes 2020-03-28 17:00:48 +01:00
Michele Caini
e38d2e156d doc: updated list of showcases 2020-03-27 00:25:30 +01:00
Michele Caini
dfc18619a2 build system: updated installation process (close #451) 2020-03-27 00:04:48 +01:00
Michele Caini
9e8f2c52a0 doc: updated section for on_update/on_replace (close #452) 2020-03-25 15:11:14 +01:00
Michele Caini
1c8f5b98f1 build system: updated installation process (close #451) 2020-03-25 00:56:43 +01:00
Michele Caini
972470ad42 benchmark: minor changes 2020-03-24 22:40:39 +01:00
Michele Caini
f7e3a055fb registry: minor changes 2020-03-21 23:35:45 +01:00
Michele Caini
34f05fb8dc doc: updated wiki for meta (close #448) 2020-03-21 16:56:29 +01:00
Michele Caini
709fd34264 registry/storage: ::insert supports all types of iterators 2020-03-21 16:48:31 +01:00
Michele Caini
b888757092 entity/*: iterators review 2020-03-20 23:53:43 +01:00
Michele Caini
0f42827047 entity/*: stop using deprecated functions internally 2020-03-20 16:50:04 +01:00
Michele Caini
e69d1556e1 config: renamed ENTT_ENABLE_ETO to ENTT_IS_EMPTY 2020-03-20 00:04:26 +01:00
Michele Caini
141fbf7472 type_traits: deprecated entt::tag because of the more general purpose alternative entt::integral_constant 2020-03-19 23:41:49 +01:00
Michele Caini
c9a3ae8149 type_traits: added shortcut entt::integral_constant 2020-03-19 23:38:10 +01:00
Michele Caini
e16a8d29ea links: added the Vim of game engines (close #447) 2020-03-19 16:05:31 +01:00
Michele Caini
fff50d0e50 registry: workaround for an issue with MSVC 2020-03-19 16:00:11 +01:00
Michele Caini
360734b447 doc: workaround for some idiosyncracies of doxygen 2020-03-19 00:49:49 +01:00
Michele Caini
7e5edad32b registry: workaround for an issue of gcc7 2020-03-19 00:33:14 +01:00
Michele Caini
fc47b47850 doc: updated doc for empty types 2020-03-18 23:59:44 +01:00
Michele Caini
c7de058e1d storage/registry: empty types are no longer a thing 2020-03-18 00:11:53 +01:00
Michele Caini
0fff3c905c view: deprecated ::less, ::each returns only non-empty types now 2020-03-16 00:30:33 +01:00
Michele Caini
2fcb055c43 group: deprecated ::less, ::each returns only non-empty types now 2020-03-15 23:50:02 +01:00
Michele Caini
97e0d63102 storage: consume args for empty types in all cases 2020-03-13 23:08:59 +01:00
Michele Caini
5e04f0accd registry: strict check on ::insert (see #438) 2020-03-13 00:02:05 +01:00
Michele Caini
16835e3928 registry: get_or_assign -> get_or_emplace 2020-03-12 23:41:58 +01:00
Michele Caini
22e0ef1354 doc: updated examples, wiki and inline documentation 2020-03-12 23:33:08 +01:00
Michele Caini
0141dc519c doc: added similar projects (close #443) 2020-03-11 17:57:36 +01:00
Michele Caini
9aadc30b94 registry: disambiguate calls to ::assign and ::assign_or_replace (close #438) 2020-03-11 16:19:41 +01:00
Michele Caini
23a73fcb7c doc: suppressed some warnings due to missing parameters 2020-03-11 15:36:14 +01:00
Michele Caini
9a3b585110 registry: disambiguate calls to pool_handler<T>::construct (see #438) 2020-03-11 14:34:47 +01:00
Michele Caini
09ee46860a sparse_set: disambiguate calls to ::construct (see #438) 2020-03-11 00:07:41 +01:00
Michele Caini
d8f289182d storage: disambiguate calls to ::construct (see #438) 2020-03-11 00:05:04 +01:00
Michele Caini
dc8fa2153b registry: on_replace becomes on_update 2020-03-09 14:46:38 +01:00
Michele Caini
32fb335832 registry: added ::patch, reintroduced ::replace from arguments (close #437) 2020-03-09 14:34:28 +01:00
Michele Caini
58885854f1 doc: added a warning to registry::replace 2020-03-08 23:36:18 +01:00
Michele Caini
3e87788541 registry: ::replace always returns the component, no matter what 2020-03-08 16:42:17 +01:00
Michele Caini
5746df4d74 doc: added a note on registry::assign 2020-03-08 15:54:07 +01:00
Michele Caini
71d86c44e0 registry: cleanup 2020-03-08 00:56:00 +01:00
Michele Caini
c5e50289e1 workflow: unlock deploy to homebrew-entt (close #397) 2020-03-07 23:26:47 +01:00
Michele Caini
e62f1edada registry: minor changes 2020-03-07 23:26:39 +01:00
Michele Caini
50e8db28b8 minor changes all over the codebase (final) 2020-03-07 00:41:21 +01:00
Michele Caini
ef7c572018 core: define entt::id_type alias for ENTT_ID_TYPE (close #416) 2020-03-07 00:41:21 +01:00
Michele Caini
1e962754cc entity module: added utility.hpp, cleaned up fwd.hpp 2020-03-07 00:41:21 +01:00
Michele Caini
0240453b07 registry: review context variables 2020-03-07 00:41:21 +01:00
Michele Caini
38a80a95f2 registry: reduce instantiations 2020-03-07 00:41:21 +01:00
Michele Caini
b5e411d251 registry: removed deprecated functions 2020-03-07 00:41:21 +01:00
Michele Caini
71a623276e registry: removed deprecated overload for replace 2020-03-07 00:41:21 +01:00
Michele Caini
1e76703144 meta: removed deprecated functions 2020-03-07 00:41:21 +01:00
Michele Caini
6ffaf11226 helper: added a shortcut to invoke members on components from callbacks (close #385) 2020-03-07 00:41:21 +01:00
Michele Caini
fc0caec1a4 build system: updated version, now working on v3.4.0 2020-03-07 00:41:21 +01:00
Michele Caini
043f9a5025 updated single include file 2020-03-07 00:41:15 +01:00
Michele Caini
822264a65e workflow: --dry-run for the deploy.yml debut (see #397) 2020-03-07 00:30:24 +01:00
Michele Caini
8e9a6a4f06 registry: fixed a bug that affects late group initialization (close #440) 2020-03-07 00:30:21 +01:00
Michele Caini
76f3909ec9 workflow: update homebrew-entt (see #397) 2020-03-07 00:30:19 +01:00
Michele Caini
23e839b40e build system: updated install process (close #421) 2020-03-07 00:30:16 +01:00
Michele Caini
6a560fc7bf observer: use any<T...> rather than a fold expression with has<T> 2020-03-07 00:30:08 +01:00
Michele Caini
709d1c93a4 registry: fixed a bug that affects late group initialization (close #436) 2020-03-07 00:29:57 +01:00
Michele Caini
8d4b5f4bb7 sparse_set: remove copy ctor/assignment operator (use range-construct instead) 2020-03-07 00:11:30 +01:00
Paul Gruenbacher
9eb5a85e9e doc: update clone example to handle empty types (#441) 2020-03-07 00:09:19 +01:00
Paul Gruenbacher
e7521445e9 doc: update stamp example (#442) 2020-03-07 00:09:15 +01:00
Michele Caini
bb050e2660 actor: (has<T>(e) && ...) -> has<T...>(e) 2020-03-07 00:07:56 +01:00
Michele Caini
bc3b0eb491 links: added references to Chrysalis (project and blog post) 2020-03-07 00:06:39 +01:00
Michele Caini
7cea05d376 doc: updated documentation for snapshot archives (close #431) 2020-03-07 00:06:32 +01:00
Michele Caini
b8a3bdf6b5 build system: minor changes 2020-03-07 00:06:25 +01:00
Michele Caini
638b6dba17 build system: updated version, now working on v3.3.2 2020-03-06 23:56:55 +01:00
Michele Caini
50ba8c6c39 updated single include file 2020-02-28 23:27:20 +01:00
Michele Caini
94d15ebbef config: being empty isn't enough for ETO, type must be default constructible 2020-02-28 23:18:12 +01:00
Michele Caini
e150882231 doc: udpated doc (see #431) 2020-02-28 23:18:09 +01:00
Michele Caini
80a659c90c doc: typo 2020-02-28 23:18:03 +01:00
Michele Caini
17d96427ea registry: assign_or_replace works also with aggregates now (close #429) 2020-02-28 23:17:58 +01:00
Michele Caini
7fdda788af registry: minor changes (close #424) 2020-02-28 23:17:53 +01:00
Ezekiel Warren
182adbd9d9 Re-added bazel support (#430) 2020-02-28 23:17:45 +01:00
Michele Caini
4931c9cd9b build system: updated version, now working on v3.3.1 2020-02-28 23:17:24 +01:00
Michele Caini
a112409735 updated single include file (close #425) 2020-02-23 16:54:02 +01:00
Michele Caini
7aaa6dd986 build system: suppress a few other warnings here and there 2020-02-19 16:12:36 +01:00
Michele Caini
3c39cfe645 build system: trigger more warnings (at least with MSVC) and suppress as many as possible (close #420, close #394) 2020-02-19 15:01:13 +01:00
Michele Caini
6a46325e7e registry: deprecate ::clone/::stamp 2020-02-18 12:51:19 +01:00
Michele Caini
15c9688a5a entity module: minor changes 2020-02-18 11:50:33 +01:00
Michele Caini
d9f93ccc11 moved tags from entity/helper to core/type_traits (see #419) 2020-02-18 09:58:51 +01:00
Michele Caini
652e569afc registry: cleanup 2020-02-17 13:36:57 +01:00
Michele Caini
c55372459f view: cleanup 2020-02-17 13:36:46 +01:00
Michele Caini
09f36e32f7 type traits: added member_class and member_class_t 2020-02-17 08:18:58 +01:00
Michele Caini
688d435d8e meta: fixed a bug on meta_type::construct with no arguments (close #413) 2020-02-16 21:54:48 +01:00
Michele Caini
e7403d8551 registry: in-place ::replace, the signal no longer receives an extra argument (close #406) 2020-02-15 22:32:50 +01:00
Indiana Kernick
60039441a1 Remove UTF-8 BOM (#414) 2020-02-15 15:40:09 +01:00
Michele Caini
97f4414cc4 minor changes 2020-02-15 00:54:40 +01:00
Michele Caini
df9595bc0d build system: clean up 2020-02-14 23:15:26 +01:00
Michele Caini
93533b7bc6 build system: make it work properly (again) with clang-cl 2020-02-14 23:06:46 +01:00
Michele Caini
a99afa2ddf build system: make gtest compile (again) on macos 2020-02-14 22:56:37 +01:00
Michele Caini
1e651a5145 tests: code coverage 2020-02-14 17:32:05 +01:00
Michele Caini
79ecfa2573 build system: suppress deprecated warnings 2020-02-14 16:43:27 +01:00
Michele Caini
e2b676d54c cleanup 2020-02-13 12:30:01 +01:00
Michele Caini
2b73bf35b6 meta: meta_type_node::id -> meta_type_node::type_id 2020-02-13 12:05:45 +01:00
Michele Caini
2137b3a879 doc: added DungeonSlayer to links 2020-02-11 23:29:50 +01:00
Michele Caini
e52b3fd5bc meta: ::identifier renamed to ::alias, added meta_type::id to get the id of the underlying type (close #412) 2020-02-11 12:30:55 +01:00
Michele Caini
0dfd2aa714 build system: minor changes to make tests compile with VS 2020-02-10 22:57:48 +01:00
Michele Caini
5d63c4c981 storage: basic_storage no longer exists (close #411) 2020-02-10 22:49:23 +01:00
Michele Caini
84d3f9ab9a registry: added missing assert (close #409) 2020-02-10 22:46:49 +01:00
Michele Caini
1133dba9d8 attribute: correct include guard (close #410) 2020-02-10 22:45:30 +01:00
Michele Caini
cd2fdc2ffe build system: use cmake fetch content rather than external add 2020-02-10 22:43:42 +01:00
Michele Caini
57d017ed8e build system: the version is read from cmake rather than written 2020-02-10 22:25:35 +01:00
Michele Caini
3ad2c559f1 build system: better support for IDEs 2020-02-09 23:16:59 +01:00
Michele Caini
c3facfa925 build system: minor changes 2020-02-09 20:07:32 +01:00
Michele Caini
db8d9ebc72 suppress shadow warnings 2020-02-08 16:31:01 +01:00
Michele Caini
3aef00af18 registry: suppress warnings on ::replace for empty components (close #407, close #408) 2020-02-08 15:56:01 +01:00
Michele Caini
a4d576bae8 registry: visit functionality for context variables (close #390) 2020-02-08 15:34:32 +01:00
Michele Caini
9320365ef6 registry: const-correctness for ::visit 2020-02-08 15:34:28 +01:00
Michele Caini
0be7494042 group: added front/back (close #393) 2020-02-08 15:34:22 +01:00
Michele Caini
df55f338ca view: added front/back (see #393) 2020-02-08 15:34:18 +01:00
Michele Caini
8210efb548 delegate: suppress warnings on parameters used for tag dispatching 2020-02-08 15:34:14 +01:00
Michele Caini
43503e2fc9 test: enforce requirements for non default constructible components (close #405) 2020-02-08 15:34:08 +01:00
Michele Caini
448c3ae425 registry/storage: assign review 2020-02-08 15:34:03 +01:00
Michele Caini
f7684a8a3e cleanup/minor changes 2020-02-08 15:33:59 +01:00
Michele Caini
4f200ac71e cleanup 2020-02-08 15:32:09 +01:00
Michele Caini
4772559e8b test: code coverage 2020-02-02 22:12:41 +01:00
Michele Caini
a984ce5bba registry: temporary changes to remove args from assure 2020-02-02 21:51:13 +01:00
Michele Caini
eee8a338e2 doc: updated examples (close #401) 2020-02-02 20:52:14 +01:00
Michele Caini
8894c0ef48 typo 2020-02-01 01:01:03 +01:00
Michele Caini
c5b8577d94 meta: redefined constructors where it matters (close #404) 2020-02-01 00:59:23 +01:00
Michele Caini
ce9def4a56 registry: avoid redundant instantiations 2020-02-01 00:50:13 +01:00
Michele Caini
894601aad2 cleanup/suppress warnings 2020-01-31 23:40:52 +01:00
Michele Caini
285c91e81b config: ENTT_DISABLE_ASSERT no longer exists, ENTT_ASSERT can be redefined now (close #403) 2020-01-31 23:39:37 +01:00
Michele Caini
ba8ca93afc doc: updated the doc for the ecs part (close #390) 2020-01-31 23:32:09 +01:00
Michele Caini
ad0dab2493 registry: added ::visit to get all components in a registry of owned by an entity 2020-01-31 22:43:25 +01:00
Michele Caini
8b66316180 doc: updated README file 2020-01-31 22:42:36 +01:00
Michele Caini
da4ee38914 type_info: minor changes 2020-01-30 20:03:51 +01:00
Michele Caini
62fde229e2 cleanup 2020-01-29 00:26:38 +01:00
Michele Caini
676115d214 delegate/sigh: reduced number of instantiations, moved instantiations out of the way from sigh::publish 2020-01-28 12:20:52 +01:00
Michele Caini
f36d838df1 hashed_string: non-recursive helper (close #400) 2020-01-27 22:46:24 +01:00
Michele Caini
f32f3ab895 config: avoid using pretty function with gcc < 9 (see #396) 2020-01-25 23:19:38 +01:00
Michele Caini
fc0432df8c registry: minor changes 2020-01-24 23:52:39 +01:00
Michele Caini
797b5bcb53 type_info: force constexpr-ness (close #396) 2020-01-24 23:29:12 +01:00
Michele Caini
b816f203cd doc: minor changes (close #398) 2020-01-24 23:29:06 +01:00
Michele Caini
714e2f86a1 cleanup 2020-01-24 16:02:45 +01:00
Michele Caini
ff75085f15 doc: updated links 2020-01-23 22:55:03 +01:00
Michele Caini
dbc8b18b80 registry: added any<T...> (close #371) 2020-01-21 12:52:59 +01:00
Michele Caini
efb2bbe8b2 cleanup: removed entity/utility.hpp 2020-01-21 12:33:37 +01:00
Michele Caini
8278c8eedd doc: minor changes 2020-01-21 12:24:02 +01:00
Michele Caini
6f696a026b registry: callbacks receive the registry as first argument (better dependencies) 2020-01-20 16:09:25 +01:00
Michele Caini
f558797246 workaround for an issue of clang 6 2020-01-20 00:01:10 +01:00
Michele Caini
c8671d1c2b doc: updated signal.md (see #385) 2020-01-19 23:43:57 +01:00
Michele Caini
7fd41e48b9 sigh: support for unbound members 2020-01-19 19:18:33 +01:00
Michele Caini
409d5f5966 delegate: support for unbound members 2020-01-19 15:16:38 +01:00
Michele Caini
5d1802faf7 doc: updated links 2020-01-18 23:05:42 +01:00
Michele Caini
a580bac385 registry: range-assign with optional init function(s) 2020-01-18 01:11:30 +01:00
Michele Caini
c43214543f storage: removed batch construct by copy 2020-01-18 00:57:27 +01:00
Michele Caini
b3c568fb6f registry: faster group initialization 2020-01-16 00:02:22 +01:00
Michele Caini
b34fe3200c storage: batch construct by copy 2020-01-15 23:55:28 +01:00
Michele Caini
dada8dbdeb storage/registry: batch add no longer returns an iterator 2020-01-15 23:21:34 +01:00
Michele Caini
e7d4077065 storage/registry: batch add default-constructs the component 2020-01-15 23:07:35 +01:00
Michele Caini
b1e54bfd86 storage: minor changes 2020-01-15 22:42:17 +01:00
Michele Caini
85ad4c4766 registry (and a few others): callbacks no longer receive components, see #386 2020-01-13 23:11:24 +01:00
Michele Caini
3dce560759 test: updated benchmarks 2020-01-13 23:08:42 +01:00
Michele Caini
969b8f0a7a test: minor changes 2020-01-13 00:27:15 +01:00
Michele Caini
ba8e738f40 doc: updated ecs part 2020-01-13 00:12:22 +01:00
Michele Caini
4bc80fae8d storage: minor changes 2020-01-13 00:06:17 +01:00
Michele Caini
ee5156704d registry: ::assign to assign entities to an empty registry 2020-01-12 00:31:53 +01:00
Michele Caini
986cd03732 registry: added ::data() to get the list of entities of a registry 2020-01-11 23:56:50 +01:00
Michele Caini
937fdabaa9 algorithm: missing include (close #389) 2020-01-11 23:56:11 +01:00
Michele Caini
c0fa97510e minor changes that are aimed mainly at suppressing warnings 2020-01-11 23:06:30 +01:00
Michele Caini
2fc6fe442d workaround of an bug of gcc-7 2020-01-11 21:56:08 +01:00
Michele Caini
7ba14f5a57 registry: only opaque stamp is allowed, use assign/assign_or_replace for components 2020-01-11 01:23:57 +01:00
Michele Caini
352e4576fc registry: ::reset doesn't exist anymore, use ::remove and ::clear instead 2020-01-11 01:11:48 +01:00
Michele Caini
210eebc0dc sparse_set/storage: ::reset is now ::clear 2020-01-09 22:51:35 +01:00
Michele Caini
5904941361 registry: stable assign (close #386) 2020-01-09 22:06:33 +01:00
Michele Caini
b352815cf8 registry: minor chages 2020-01-07 23:58:23 +01:00
Michele Caini
38a2751cd9 tests: code coverage back to 100% 2020-01-07 00:16:46 +01:00
Michele Caini
6388607d11 doc: added PopHead to the list of showcases (close #384) 2020-01-06 23:54:05 +01:00
Michele Caini
469276b8be registry: create no longer accepts a list of default constructible types to assign to entities 2020-01-06 23:46:58 +01:00
Michele Caini
2a863ee851 registry: minor changes 2020-01-06 00:50:03 +01:00
Michele Caini
b6dae2fe57 doc: updated entity.md 2020-01-06 00:40:45 +01:00
Michele Caini
d202bd3e50 registry: create with hint (close #303) 2020-01-06 00:40:22 +01:00
Michele Caini
dc2e44b2c0 doc: added sequentity to the list of showcases 2020-01-06 00:39:33 +01:00
Michele Caini
32c481c28c doc: stomp -> stamp 2020-01-04 22:59:46 +01:00
Michele Caini
8519c99706 updated copyright 2020-01-04 00:17:16 +01:00
Michele Caini
5b1bac4c19 doc: more details on entt::null (close #375) 2020-01-02 23:58:12 +01:00
Michele Caini
0a95a0674b build system: the conan-center-index makes the custom deploy step useless (close #380) 2020-01-02 22:25:12 +01:00
Michele Caini
2f11f6dc37 workaround for an issue of MSVC 2020-01-01 22:39:01 +01:00
Michele Caini
af66274c72 registry: const/non-const review (close #381) 2020-01-01 22:29:13 +01:00
Michele Caini
c5679b208f registry: improved ::group 2019-12-31 16:45:49 +01:00
Michele Caini
020fc179a5 traits: to_integral uses static_cast now 2019-12-31 15:45:36 +01:00
Michele Caini
dc9c1fc762 doc: minor changes 2019-12-31 15:21:53 +01:00
Michele Caini
f0938d70b2 registry: stomp -> stamp 2019-12-31 00:54:10 +01:00
Michele Caini
072761c5ba updated doc 2019-12-31 00:37:52 +01:00
Michele Caini
8aacd4d022 aob: removed mod stuff 2019-12-29 15:53:52 +01:00
Michele Caini
b6f9ca0021 updated TODO 2019-12-29 15:36:36 +01:00
Michele Caini
a43f354511 doc: minor changes 2019-12-29 15:18:20 +01:00
Michele Caini
43766406ae registry/dispatcher/emitter: removed ::discard, updated test and doc 2019-12-29 15:16:12 +01:00
Michele Caini
37dd1ae363 registry: group reworking 2019-12-29 15:16:12 +01:00
Michele Caini
5a3effaef5 group: faster contains 2019-12-29 15:16:12 +01:00
Michele Caini
cd4bcce70f view: faster contains 2019-12-29 15:16:12 +01:00
Michele Caini
c1e7549b61 registry: group reworking 2019-12-29 15:16:12 +01:00
Michele Caini
036ef25da9 registry: uses views to initialize groups 2019-12-29 15:16:12 +01:00
Michele Caini
9884c37ef4 view: gets rid of filter tuple 2019-12-29 15:16:12 +01:00
Michele Caini
23069d76eb registry: minor changes 2019-12-29 15:16:12 +01:00
Michele Caini
b2d0e7fae2 registry: assure returns a reference now 2019-12-29 15:16:12 +01:00
Michele Caini
30a039a031 minor changes: shadow variables, dead doc, todo list 2019-12-29 15:16:12 +01:00
Michele Caini
8d67bb726c test: guarantee that entt::entity{} != entt::null (close #375) 2019-12-29 15:16:12 +01:00
Michele Caini
c4dec4cd4d meta: test review 2019-12-29 15:16:12 +01:00
Michele Caini
f17b975fb9 meta: meta_any support for non-copyable types (close #336) 2019-12-29 15:16:12 +01:00
Michele Caini
7a3b7593d0 doc: updated documentation 2019-12-29 15:16:12 +01:00
Michele Caini
bad342b840 test: lib plugin std cpp 2019-12-29 15:16:12 +01:00
Michele Caini
e3968a8f9d test: lib std cpp 2019-12-29 15:16:12 +01:00
Michele Caini
f577183c24 build system: BUILD_PLUGIN is no longer required, plugins are libs 2019-12-29 15:16:12 +01:00
Michele Caini
be58f2e68a minor changes 2019-12-29 15:16:12 +01:00
Michele Caini
99f81e82d5 build system: removed support for bazel (no longer maintained) 2019-12-29 15:16:12 +01:00
Michele Caini
7cfd3957de test_info:🆔 make the family-like fallback work across boundaries 2019-12-29 15:16:12 +01:00
Michele Caini
c51c88a17c include guards and macros in general: removed superfluous comments 2019-12-29 15:16:12 +01:00
Michele Caini
e09af98dc5 test: minor changes 2019-12-29 15:16:12 +01:00
Michele Caini
89635f6583 type_info:🆔 family-like fallback 2019-12-29 15:16:12 +01:00
Michele Caini
14034642f1 test: review 2019-12-29 15:16:12 +01:00
Michele Caini
4af7d975c1 type_id -> type info + allow also fully runtime ids 2019-12-29 15:16:12 +01:00
Michele Caini
d9884917fb registry: added discard to free explicitly a pool 2019-12-29 15:16:12 +01:00
Michele Caini
95fd4e4c99 emitter: added discard to free explicitly a pool 2019-12-29 15:16:12 +01:00
Michele Caini
9457a55910 dispatcher: added discard to free explicitly a pool 2019-12-29 15:16:12 +01:00
Michele Caini
56e7dd0de0 dispatcher::discard becomes dispatcher::clear 2019-12-29 15:16:12 +01:00
Michele Caini
f0dc882ae9 minor changes here and there 2019-12-29 15:16:12 +01:00
Michele Caini
acb70d4440 meta: uses type_id_v rather than other techniques 2019-12-29 15:16:12 +01:00
Michele Caini
167721bf8c removed ENTT_API from ENTT_OPAQUE_ID 2019-12-29 15:16:12 +01:00
Michele Caini
4f438e5228 family: back to the old-fashioned model 2019-12-29 15:16:12 +01:00
Michele Caini
0f0aeb6d47 meta: prepare migration to entt::type_id 2019-12-29 15:16:12 +01:00
Michele Caini
d1a6edad8a ENTT_OPAQUE_TYPE: to_integer -> to_integral 2019-12-29 15:16:12 +01:00
Michele Caini
388feb7edb docs: updated doxy.in 2019-12-29 15:16:12 +01:00
Michele Caini
962b068c92 test: pass NOMINMAX where cr.h is included 2019-12-29 15:16:12 +01:00
Michele Caini
a32373bc3a meta: updated tests, CR_UNLOAD isn't passed on close 2019-12-29 15:16:12 +01:00
Michele Caini
94a5a4ac1e doc: minor changes 2019-12-29 15:16:12 +01:00
Michele Caini
ed8eea12bd entt::component no longer exists 2019-12-29 15:16:12 +01:00
Michele Caini
83bea8b654 registry: uses type_id_v rather than families 2019-12-29 15:16:12 +01:00
Michele Caini
d4d2db228e minor changes: noexcept-ness review (close #372) 2019-12-29 15:16:12 +01:00
Michele Caini
f8b8c91fe8 type_id: sfinae friendly version to allow extreme customization 2019-12-29 15:16:12 +01:00
Michele Caini
8451301a5a dispatcher/emitter: constrained assure 2019-12-29 15:16:12 +01:00
Michele Caini
449b03f6bd type_id: built-in variadic accepts only single types 2019-12-29 15:16:12 +01:00
Michele Caini
3853ff725f dispatcher/emitter: better assure 2019-12-29 15:16:12 +01:00
Michele Caini
ee66e3ef9e added missing include 2019-12-29 15:16:12 +01:00
Michele Caini
2643500957 type_id: removed redundant check 2019-12-29 15:16:12 +01:00
Michele Caini
88467a87a4 emitter: uses type_id_v rather than a family 2019-12-29 15:16:12 +01:00
Michele Caini
d1cdeb4a2d dispatcher: uses type_id_v rather than a family 2019-12-29 15:16:12 +01:00
Michele Caini
f5ced7fe39 core: (customizable) type_id[_v] 2019-12-29 15:16:12 +01:00
Michele Caini
023267ecab static hashed_string::to_value -> hashed_string::value 2019-12-29 15:16:12 +01:00
Michele Caini
3d515a760c attribute.h: lib -> core 2019-12-29 15:16:12 +01:00
Michele Caini
026c5987dd suppress some warnings here and there 2019-12-29 15:16:12 +01:00
Michele Caini
84fb3694f2 test: meta and plugins 2019-12-29 15:16:12 +01:00
Michele Caini
169dcbcd74 coverage: enabled plugins 2019-12-29 15:16:12 +01:00
Michele Caini
d28b6fbf1e test: use MODULE rather than SHARED for plugins 2019-12-29 15:16:12 +01:00
Michele Caini
9f7a2ef84e updated TODO 2019-12-29 15:16:12 +01:00
Michele Caini
cc5ea60d2b test: minor changes (for code coverage) 2019-12-29 15:16:12 +01:00
Michele Caini
8bc63494bc hashed string: added missing include 2019-12-29 15:16:12 +01:00
Michele Caini
9acdeeed04 CI: enabled plugins 2019-12-29 15:16:12 +01:00
Michele Caini
d2cdb2a209 build system: refine macro SETUP_PLUGIN_TEST 2019-12-29 15:16:12 +01:00
Michele Caini
36bad31355 signal: updated fwd.hpp 2019-12-29 15:16:12 +01:00
Michele Caini
427587e591 test: ENTT_API_* definitions are set by means of cmake 2019-12-29 15:16:12 +01:00
Michele Caini
4f028d8201 test: prepare plugin stuff 2019-12-29 15:16:12 +01:00
Michele Caini
d59c052554 build system: added fungos/cr to the list of dependencies required to compile lib tests 2019-12-29 15:16:12 +01:00
Michele Caini
93ebe91bc5 test: removed useless FAIL() 2019-12-29 15:16:12 +01:00
Michele Caini
fadb8f695e tests: minor changes 2019-12-29 15:16:12 +01:00
Michele Caini
8bb1518d09 registry: (almost) transparent dll/.so support with ENTT_API 2019-12-29 15:16:12 +01:00
Michele Caini
e8d9d663a7 registry: removed superfluous friend declaration 2019-12-29 15:16:12 +01:00
Michele Caini
2d2648cf57 emitter: : (almost) transparent dll/.so support with ENTT_API 2019-12-29 15:16:12 +01:00
Michele Caini
231036784d dispatcher: (almost) transparent dll/.so support with ENTT_API 2019-12-29 15:16:12 +01:00
Michele Caini
882b91b221 family: review to make it work with dllimport/dllexport 2019-12-29 15:16:12 +01:00
Michele Caini
df346ab380 lib, test: minor changes 2019-12-29 15:16:12 +01:00
Michele Caini
c7b8e82ada meta: (almost) transparent dll/.so support with ENTT_API 2019-12-29 15:16:12 +01:00
Michele Caini
b8784863f2 meta: context no longer exists 2019-12-29 15:16:12 +01:00
Michele Caini
3f67054f03 meta: compare function shouldn't be static 2019-12-29 15:16:12 +01:00
Michele Caini
36d1b0a4bc emitter: updated inline doc 2019-12-29 15:16:12 +01:00
Michele Caini
748777b8eb registry: removed superfluous ::template from unset() 2019-12-29 15:16:12 +01:00
Michele Caini
acd8e0bce5 registry: updated ::prepare 2019-12-29 15:16:12 +01:00
Michele Caini
d2d068edff registry: removed superfluous ::template from type() 2019-12-29 15:16:12 +01:00
Michele Caini
e2a7a7ce20 test: cleanup 2019-12-29 15:16:12 +01:00
Michele Caini
b25b1c45fb named types (traits and macros) are no longer available 2019-12-29 15:16:12 +01:00
Michele Caini
c3b0fa6c93 registry no longer uses named types 2019-12-29 15:16:12 +01:00
Michele Caini
63a4e67174 cleanup 2019-12-29 15:16:12 +01:00
Michele Caini
88e37438fa emitter: const/non-const assure 2019-12-29 15:16:12 +01:00
Michele Caini
5be1bf7d82 meta no longer uses named types 2019-12-29 15:16:12 +01:00
Michele Caini
eb4689d2f1 dispatcher no longer uses named types 2019-12-29 15:16:12 +01:00
Michele Caini
e81549e5fd emitter no longer uses named types 2019-12-29 15:16:12 +01:00
Michele Caini
becaef36ff disabled tests for shared objects/named types 2019-12-29 15:16:12 +01:00
Michele Caini
6aefa40ca2 updated TODO (changes requried to get rid of named types) 2019-12-29 15:16:12 +01:00
Michele Caini
250ef50361 added attribute.h 2019-12-29 15:16:12 +01:00
Michele Caini
5a1af60357 view/group: all iterators are at least bidirectional (close #370) 2019-12-29 15:16:12 +01:00
Michele Caini
46db75308c test: modularized lib tests 2019-12-29 15:16:12 +01:00
Michele Caini
33f5e13b29 use std::for_each instead of std::for_each_n (the latter isn't supported by older compilers) 2019-12-29 15:16:12 +01:00
Michele Caini
54bb4797db cleanup 2019-12-29 15:16:12 +01:00
Michele Caini
7a14fbb221 registry: stomp doesn't work anymore with foreign registries 2019-12-29 15:16:12 +01:00
Michele Caini
18349f5ee4 small improvements 2019-12-29 15:16:12 +01:00
Michele Caini
22b93cdd0a meta: updated doc (see #361) 2019-12-29 15:16:12 +01:00
Michele Caini
63bc0b2ba1 entity: updated doc (close #364) 2019-12-29 15:16:12 +01:00
Michele Caini
c57a7c745d meta: improved perf and compilation time, reduced loc 2019-12-29 15:16:12 +01:00
Michele Caini
f2831b5f5c updated doc (close #363) 2019-12-29 15:16:12 +01:00
Michele Caini
96f793f91b meta_any: unifying assignment operator 2019-12-29 15:16:12 +01:00
Michele Caini
4e2a0d6e58 noexcept-ness review (close #362) 2019-12-29 15:16:12 +01:00
Michele Caini
442c7f1f09 meta: review 2019-12-29 15:16:12 +01:00
Michele Caini
dbff4af7c6 cleanup 2019-12-29 15:16:12 +01:00
Michele Caini
93b09836da updated workflow (close #359) 2019-12-29 15:16:12 +01:00
Michele Caini
1782dc1565 emitter: cleanup (close #360) 2019-12-29 15:16:12 +01:00
Michele Caini
cc16874d58 cleanup 2019-12-29 15:16:12 +01:00
Michele Caini
c8925b2ae3 using atomics is no longer the default: ENTT_NO_ATOMIC -> ENTT_USE_ATOMIC 2019-12-29 15:16:12 +01:00
Michele Caini
fc043b9fcd small perf improvements 2019-12-29 15:16:12 +01:00
Michele Caini
ea86d33bc1 meta: removed reset-all function (it was logically broken across boundaries) 2019-12-29 15:16:12 +01:00
Michele Caini
82f33b82e3 meta: allow assigning properties to opaque meta types 2019-12-29 15:16:12 +01:00
Michele Caini
c645cb83a2 meta: reset-all functionality (see #358) 2019-12-29 15:16:12 +01:00
Michele Caini
d6d79a2aa5 code coverage 2019-12-29 15:16:12 +01:00
Michele Caini
786568fd2f updated workflow 2019-12-29 15:16:12 +01:00
Michele Caini
434f77a058 sigh: review connection/scoped_connection 2019-12-29 15:16:12 +01:00
Michele Caini
02f777a143 cleanup 2019-12-29 15:16:12 +01:00
Michele Caini
8025a84aeb updated workflow 2019-12-29 15:16:12 +01:00
Innokentiy Alaytsev
c37a50d3b8 updated faq.md (#351) - close #348 2019-12-29 15:16:12 +01:00
Michele Caini
6dbbb265d1 registry: added range remove 2019-12-29 15:16:12 +01:00
Michele Caini
02ce2ff74c registry: multi component remove 2019-12-29 15:16:12 +01:00
Michele Caini
28e5267132 registry::stomp supports foreign registries (close #315) 2019-12-29 15:16:12 +01:00
Michele Caini
f498b8a049 registry::prepare: strictier check 2019-12-29 15:16:12 +01:00
Michele Caini
b31afe5c8c safer registry::prepare 2019-12-29 15:16:12 +01:00
Michele Caini
eac944dbea get rid of registry::skip_family_pools 2019-12-29 15:16:12 +01:00
Michele Caini
965b20c37a review: dispatcher::assure/emitter::assure 2019-12-29 15:16:12 +01:00
Michele Caini
fba85754d7 review: registry::clone 2019-12-29 15:16:12 +01:00
Michele Caini
3c69f98451 range registry::stomp is no longer available 2019-12-29 15:16:12 +01:00
Michele Caini
cad8a90124 spawning registry::create is no longer available 2019-12-29 15:16:12 +01:00
Michele Caini
b8d888b17f minor changes 2019-12-29 15:16:12 +01:00
Michele Caini
942d783e4e cleanup 2019-12-29 15:16:12 +01:00
Michele Caini
0e352cb466 single component registry::prepare with arguments (suitable for custom pools) 2019-12-29 15:16:12 +01:00
Michele Caini
50af38b952 registry::clone/stomp review (close #350) 2019-12-29 15:16:12 +01:00
Michele Caini
1459c59cd0 updated TODO 2019-12-29 15:16:12 +01:00
Michele Caini
e74f5b2991 cleanup/refactoring 2019-12-29 15:16:12 +01:00
Michele Caini
0dec05fd70 no longer _each (it was too ugly for me) 2019-12-29 15:16:12 +01:00
Michele Caini
3cff21b4d0 updated doc (close #349) 2019-12-29 15:16:12 +01:00
Michele Caini
c380da7214 range stomp is now named stomp_each for consistency 2019-12-29 15:16:12 +01:00
Michele Caini
e2bf903c49 registry::assign_each validates entities 2019-12-29 15:16:12 +01:00
Michele Caini
9cf64ba881 range destroy is now named destroy_each for consistency 2019-12-29 15:16:12 +01:00
Michele Caini
74d901b7ae registry: range assign 2019-12-29 15:16:12 +01:00
Michele Caini
b15cb46a6d now working on v3.3.0 2019-12-29 15:16:12 +01:00
Michele Caini
89dc76e3b2 doc: added SgOgl to the EnTT in Action list (close #378) 2019-12-29 15:12:13 +01:00
Michele Caini
000b7d2651 updated single include file 2019-12-19 15:14:33 +01:00
Michele Caini
9ffa372ba2 workaround for an issue of MSVC (close #373) 2019-12-19 09:19:37 +01:00
Michele Caini
510cfcf1fc now working on v3.2.2 2019-12-19 09:18:41 +01:00
Michele Caini
e7f6d93a1e cleanup 2019-12-01 15:59:25 +01:00
Michele Caini
a17c449075 observer: minor changes 2019-12-01 15:58:05 +01:00
Michele Caini
c4da7a87f9 typo 2019-12-01 15:57:51 +01:00
Michele Caini
4a8b2f826d cleanup 2019-12-01 15:46:28 +01:00
Stefano Fiorentino
4901e4fb80 adding git_shallow to cmake deps helps reducing building time from scratch (#367)
very useful in CI/CD pipelines
2019-12-01 15:45:20 +01:00
Michele Caini
ce3a0157cb updated version.h to v3.2.1 2019-11-26 11:20:54 +01:00
Michele Caini
a146b06e4b updated single include file to v3.2.1 (close #366) 2019-11-26 11:18:41 +01:00
Michele Caini
dc78a3e56d version: 3.2.1 2019-11-26 11:17:13 +01:00
Michele Caini
86c524dade fix: sorting empty types (close #365) 2019-11-26 11:16:02 +01:00
Innokentiy Alaytsev
6889edcfc4 meta, fix: meta_prop::next lazy initialization 2019-11-26 11:11:42 +01:00
Michele Caini
3cd5934bad typo 2019-11-26 11:11:26 +01:00
Michele Caini
064104f23a suppress **all** shadow warnings (close #346) 2019-11-26 11:11:19 +01:00
Michele Caini
e80b1c264c family: it no longer dacays types 2019-11-26 11:11:13 +01:00
Michele Caini
03c3ee514b updated doc 2019-10-25 00:03:58 +02:00
Michele Caini
c93d0f0d59 registry::prepare to force create pools explicitly 2019-10-24 23:10:03 +02:00
Michele Caini
85793d38bc meta: a static assertion forbids using non-copyable types with meta_any (close #336) 2019-10-24 22:55:07 +02:00
David Demelier
49b4a85d55 FAQ: add note about non-copyable objects (#344) 2019-10-24 14:59:22 +02:00
Michele Caini
5e8a9340f1 meta: added meta_type::remove_extent (close #345) 2019-10-23 23:29:25 +02:00
Michele Caini
2b97c01bd6 named_type_traits<Type>::value -> named_type_traits_v<Type> 2019-10-21 22:52:49 +02:00
Michele Caini
39e3a5a708 make macros require a trailing semicolon 2019-10-21 14:23:22 +02:00
Michele Caini
df13d993f7 test: more on type_traits 2019-10-21 13:43:51 +02:00
Michele Caini
36c62763e5 updated TODO 2019-10-20 18:45:49 +02:00
Michele Caini
ad5651ffb2 ENTT_DISABLE_ETO to disable empty type optimization (close #330) 2019-10-20 17:32:10 +02:00
Michele Caini
717b091b49 meta: internal and external indexing to disambiguate property overloads 2019-10-20 15:44:53 +02:00
Michele Caini
4376bbe40b workaround for an issue with clang 6 2019-10-19 22:08:11 +02:00
Michele Caini
2382d2e21c meta: invocable properties (aka annotations - see #299) 2019-10-19 16:25:35 +02:00
Michele Caini
520ccfcd06 meta: support tuple as properties 2019-10-19 16:09:03 +02:00
Michele Caini
0bdc5dfe95 minor changes: make_index_sequence -> index_sequence_for 2019-10-19 15:54:32 +02:00
Michele Caini
6a656a1b0a type_traits: updated choice utility (template variable) 2019-10-19 15:51:27 +02:00
Michele Caini
5ad4079dbf meta: std::get<1>-table properties are no longer accepted, only std::pair is supported 2019-10-19 15:19:58 +02:00
Innokentiy Alaytsev
bfa46b795f Property list (#338)
* Fix typo in comment
* Implemented a function for adding a list of properties to meta-item
2019-10-19 15:13:43 +02:00
Michele Caini
ecaa9c275c typo 2019-10-18 21:45:17 +02:00
Michele Caini
93fd1757f8 meta: more on properties (close #341) 2019-10-18 17:30:32 +02:00
Michele Caini
71d0958398 type_traits: added support for the choice trick 2019-10-18 16:38:23 +02:00
Michele Caini
ed89d94d7a meta: support for key-only properties 2019-10-17 17:23:25 +02:00
Stephan Z
135132e5f0 Snapshot loader can auto-update entities stored in maps now (#335) - close #334
* Detect if member variable is of type map and update the contained entities if needed
* issue 334: tests for identifier update on maps in snapshots
2019-10-16 23:35:29 +02:00
Michele Caini
1ad75f5c1b meta: updated doc (close #324) 2019-10-16 13:43:29 +02:00
Michele Caini
21c6f9e394 meta: updated documentation 2019-10-16 13:43:29 +02:00
Michele Caini
5a7e954aee meta: context review 2019-10-16 13:43:29 +02:00
Michele Caini
c1117e260c meta: meta_node<>::ctx -> meta_node<>::global 2019-10-16 13:43:29 +02:00
Michele Caini
b0ea150e94 meta: properties can be also runtime objects 2019-10-16 13:43:29 +02:00
Michele Caini
0e3bdc02ea meta: meta_factory::type supports named types (the identifier isn't required in this case) 2019-10-16 13:43:29 +02:00
Michele Caini
e5a075a329 meta: minor changes 2019-10-16 13:43:29 +02:00
Michele Caini
30c7a64619 meta: simplified T::prop 2019-10-16 13:43:29 +02:00
Michele Caini
ab12f29ebf meta: introduce extended meta factory 2019-10-16 13:43:29 +02:00
Michele Caini
a0c3a82c76 meta: cleanup and renaming 2019-10-16 13:43:29 +02:00
Michele Caini
085a281f8a meta: some tests across boundaries 2019-10-16 13:43:29 +02:00
Michele Caini
1f871c24b9 meta: plug-and-play mode 2019-10-16 13:43:29 +02:00
Michele Caini
9f46b51985 minor changes 2019-10-16 13:43:29 +02:00
Michele Caini
fc572b8717 updated TODO 2019-10-16 13:43:29 +02:00
Michele Caini
4404601fa3 meta: tests 2019-10-16 13:43:29 +02:00
Michele Caini
faf7e28119 meta: added meta context object 2019-10-16 13:43:29 +02:00
Michele Caini
0303facfd9 updated TODO 2019-10-16 13:43:29 +02:00
Michele Caini
86e056a736 meta: added underlying context 2019-10-16 13:43:29 +02:00
Michele Caini
75105dc1fc meta: cleanup 2019-10-16 13:43:29 +02:00
Michele Caini
14b4979c98 added is_equality_comparable[_v] trait 2019-10-16 13:43:29 +02:00
Michele Caini
f956c64765 meta: doc 2019-10-16 13:43:29 +02:00
Michele Caini
8b3f954ad8 meta: cleanup 2019-10-16 13:43:29 +02:00
Michele Caini
a013cfcd1e meta_type::meta is no longer available 2019-10-16 13:43:29 +02:00
Michele Caini
65553e6c43 meta_type::remove_pointer returns a pointer to an underlying node now 2019-10-16 13:43:29 +02:00
Michele Caini
401c881c00 meta_prop::meta is no longer available 2019-10-16 13:43:29 +02:00
Michele Caini
cf0e4d24a1 meta_func::meta is no longer available 2019-10-16 13:43:29 +02:00
Michele Caini
21810f3b39 meta_data::meta is no longer available 2019-10-16 13:43:29 +02:00
Michele Caini
0b211ab0ba meta_dtor::meta is no longer available 2019-10-16 13:43:29 +02:00
Michele Caini
30c7cf3512 meta_ctor::meta is no longer available 2019-10-16 13:43:29 +02:00
Michele Caini
bf8839a560 meta_base::meta is no longer available 2019-10-16 13:43:29 +02:00
Michele Caini
818998c532 meta_conv::meta is no longer available 2019-10-16 13:43:29 +02:00
Michele Caini
98f54029d0 some consts here and there 2019-10-16 13:43:29 +02:00
Michele Caini
d41f2c138b minor changes 2019-10-16 13:43:29 +02:00
Michele Caini
50f07a6a0d meta: cleanup 2019-10-16 13:43:29 +02:00
Michele Caini
b10116febb review: cache resource_type and id_type 2019-10-16 13:43:29 +02:00
Michele Caini
17b5d732e4 cleanup 2019-10-16 13:43:29 +02:00
Michele Caini
5b16b1d827 entt::resource_cache -> entt::cache 2019-10-16 13:43:29 +02:00
Michele Caini
e5fe962130 entt::resource_handle -> entt::handle 2019-10-16 13:43:29 +02:00
Michele Caini
00f03d9bb7 entt::resource_loader -> entt::loader 2019-10-16 13:43:29 +02:00
Michele Caini
f7c285af20 minor changes 2019-10-16 09:14:08 +02:00
Michele Caini
f6e3121c76 GH sponsorship 2019-10-08 22:56:26 +02:00
Michele Caini
a95aa81850 utility: overloaded and y_combinator 2019-10-01 15:02:18 +02:00
Michele Caini
ffa5825658 cleanup 2019-10-01 15:01:56 +02:00
Michele Caini
df5b90cc7c nested groups: documentation 2019-09-30 00:20:02 +02:00
Michele Caini
9dde644fd0 nested groups: impl + tests 2019-09-30 00:19:17 +02:00
Michele Caini
d525a1536c sink::[before|disconnect]: const void * -> Type * 2019-09-30 00:11:07 +02:00
Michele Caini
54f18f3f0d delegate/sink: pointer payload 2019-09-29 23:40:03 +02:00
Michele Caini
ce4f26a5d5 minor changes 2019-09-29 21:43:30 +02:00
Guillaume Haerinck
177a7429f1 [doc] Add link to Mirror lasers & Robots project (#329) 2019-09-29 21:31:49 +02:00
Michele Caini
f672d734f9 delegate: built-in support for pointer payload 2019-09-29 00:46:29 +02:00
Michele Caini
faf5a38f1c sink: before/disconnect and const void * 2019-09-28 22:56:47 +02:00
Michele Caini
03c4267b84 process: tests with both a complex data type and a fundamental type (close #326) 2019-09-28 00:25:25 +02:00
Michele Caini
ab08621808 updated .gitignore 2019-09-28 00:17:41 +02:00
Michele Caini
d06c0e5c5d updated doc 2019-09-28 00:12:47 +02:00
Griffin Downs
32e76298e4 Add vcpkg installation instructions (#327) 2019-09-28 00:08:38 +02:00
Michele Caini
752163a5c0 workaround for an issue of VS2019 (close #314) 2019-09-27 23:49:43 +02:00
Michele Caini
6568fa23f8 updated TODO 2019-09-27 23:06:26 +02:00
Michele Caini
9c69288304 added more showcases (close #328) 2019-09-27 23:03:45 +02:00
Michele Caini
3a3346e750 typo 2019-09-26 23:32:25 +02:00
Michele Caini
47ab73d9a4 updated doc 2019-09-26 23:03:44 +02:00
Michele Caini
9555385325 updated list of contributors 2019-09-26 16:11:19 +02:00
xiss burg
f80a03afc7 This should allow any type to be used as Delta... (#325)
* This should allow any type to be used as Delta, beyond native numerical types.
* Why write more code than you have to?
2019-09-26 16:09:56 +02:00
Michele Caini
c1b64770d1 updated tests 2019-09-25 23:54:53 +02:00
Michele Caini
400f106d62 updated coverage.yml 2019-09-25 13:52:39 +02:00
Michele Caini
1cc20716ae codecov badge 2019-09-25 12:58:43 +02:00
Michele Caini
fc7d123871 tests: review 2019-09-25 12:54:17 +02:00
Michele Caini
2a8a014ad0 tests: review 2019-09-25 12:37:20 +02:00
Michele Caini
861f452d26 remove coveralls 2019-09-25 11:57:48 +02:00
Michele Caini
64a7d5e4fd codecov 2019-09-25 11:57:29 +02:00
Michele Caini
7c45423969 GH actions: reattach HEAD (workaround for an issue with the checkout action) 2019-09-25 10:13:13 +02:00
Michele Caini
480f70d7e2 GH actions: badges 2019-09-24 17:10:43 +02:00
Michele Caini
7f182896ca deleted appveyor/travis files 2019-09-24 17:01:45 +02:00
Michele Caini
1319fe2eb5 GH actions: conan 2019-09-24 16:45:26 +02:00
Michele Caini
f5c231aa80 GH actions: split CI and coveralls 2019-09-24 11:41:22 +02:00
Michele Caini
84d468333a github actions 2019-09-24 11:36:33 +02:00
Michele Caini
dfdbb0a061 class -> struct 2019-09-24 00:12:49 +02:00
Michele Caini
27365abbe3 registry: always assure and mutable list of pools 2019-09-23 23:44:14 +02:00
Michele Caini
f3aed46c94 minor changes 2019-09-23 23:16:29 +02:00
Michele Caini
7e0ea176cf cleanup 2019-09-23 22:58:47 +02:00
Michele Caini
791e13e7bf updated README 2019-09-23 16:01:50 +02:00
Michele Caini
9dff3ac749 sigh::disconnect and sigh::before support for pointers to instances 2019-09-22 23:42:04 +02:00
Michele Caini
45f207164d minor changes 2019-09-22 16:11:09 +02:00
Michele Caini
bea6f3ec14 sigh: filter out null opaque pointers 2019-09-22 15:19:27 +02:00
Michele Caini
1edc883ca2 cleanup 2019-09-21 17:00:44 +02:00
Michele Caini
116825d604 slightly faster sparse_set::arrange (apply permutation in O(N) now) 2019-09-21 15:29:11 +02:00
Michele Caini
26bc5ef091 workaround for an issue of VS 2019-09-20 17:27:52 +02:00
Michele Caini
8c228287aa doc: sink::before 2019-09-20 15:22:19 +02:00
Michele Caini
5c7c682d41 test: sink::before 2019-09-20 15:20:31 +02:00
Michele Caini
bfc2eca041 sink::before (overloaded function) 2019-09-20 14:53:10 +02:00
Michele Caini
b043b48e6e sparse_set::arrange: more tests (see #323) 2019-09-20 08:33:31 +02:00
Michele Caini
d7c03d7356 fixed an issue with sparse_set::arrange (close #323) 2019-09-19 23:50:30 +02:00
Michele Caini
c41f6aebf4 sorting: more tests 2019-09-19 22:39:13 +02:00
Michele Caini
5e6cda7c5e registry: fixed signal race on groups (close #320) 2019-09-19 14:09:53 +02:00
Carl Findahl
9c71b53abc Add namespace qualifier in CMake (close #321) (#322) 2019-09-19 13:28:33 +02:00
Michele Caini
3f96e04a7b workaround for an issue with clang 6 2019-09-18 23:16:45 +02:00
Michele Caini
90eeeedf52 view supports exclusion list 2019-09-18 14:32:58 +02:00
Michele Caini
6649362fec minor changes 2019-09-18 00:04:45 +02:00
Michele Caini
39c8889585 cleanup 2019-09-18 00:04:22 +02:00
Michele Caini
b5b1a64f0c typo 2019-09-18 00:04:07 +02:00
Michele Caini
cd108b5f57 prepare view for exclusion list 2019-09-17 23:26:54 +02:00
Michele Caini
780f3f8552 updated TODO list 2019-09-17 16:53:52 +02:00
Michele Caini
afea5eb69e added @suVrik to the list of contributors 2019-09-17 16:49:36 +02:00
Michele Caini
b72cf5d364 review: observer 2019-09-17 16:48:54 +02:00
Andrej Suvoraŭ
c133686dde Fix entt::collector::where (#319)
* fix observer
* add chained entt::collector::where test
2019-09-17 16:02:11 +02:00
Michele Caini
e216fa98ef cleanup 2019-09-16 22:37:38 +02:00
Michele Caini
8f9d8e188f updated README 2019-09-16 15:51:00 +02:00
Michele Caini
800751cbe0 sorting no longer requires allocations and is much faster 2019-09-16 15:38:34 +02:00
Michele Caini
14bc73cde9 swap accepts entities, no longer raw positions 2019-09-14 17:49:30 +02:00
Michele Caini
41307046be updated doc 2019-09-14 17:47:24 +02:00
Michele Caini
c259c79384 typo 2019-09-12 23:01:49 +02:00
Michele Caini
49f69facaf cleanup 2019-09-12 22:52:41 +02:00
Michele Caini
da2b6acf91 minor changes - code coverage 2019-09-12 22:34:03 +02:00
Michele Caini
fbdbe848c5 workaround for an issue of VS2017 (close #316) 2019-09-12 22:11:08 +02:00
Michele Caini
cc41caede9 multi-component [registry|view|group]::empty 2019-09-12 14:16:06 +02:00
Michele Caini
ee373eb6fb multi-component registry::shrink_to_fit 2019-09-11 23:12:14 +02:00
Michele Caini
d4b18b1e27 multi-component registry::reserve 2019-09-11 23:10:24 +02:00
Michele Caini
94e2fe2cbb make empty components eat arguments on construction 2019-09-11 22:56:35 +02:00
Michał Janiszewski
c93658ee04 Use Ninja on AppVeyor (#310)
This brings up improved compilation speed and saner error messages.
2019-09-11 22:24:05 +02:00
Michele Caini
ad7ee0b716 mark cmake project explicitly as C++ (see #309) 2019-09-10 23:02:22 +02:00
Michele Caini
b2fad7a567 added dispatch::discard to clear pools of events (close #312) 2019-09-10 22:55:03 +02:00
Michele Caini
e80adc2799 cmake support for clang users on Windows (see #311) 2019-09-10 16:38:38 +02:00
Michele Caini
ac111224ae meta: all function arguments are taken by alias (close #301) 2019-09-10 16:10:09 +02:00
Michele Caini
0813bb1a28 updated doc 2019-09-10 16:10:09 +02:00
Michele Caini
4d1ad8f749 meta_handle no longer exposes try_cast 2019-09-10 16:10:09 +02:00
Michele Caini
80b444e531 added meta_any constructor for the unmanaged object taken from a meta_handle 2019-09-10 16:10:09 +02:00
Michele Caini
3a6468cd0a disable BUILD_MOD for the CI 2019-09-10 15:18:28 +02:00
Michele Caini
c9fdb215f3 C language required for duktape (see BUILD_MOD option for more details) 2019-09-10 15:12:59 +02:00
Michał Janiszewski
85ff5f2d10 Mark CMake project explicitly as C++ (#309)
This prevents checking of C compiler
2019-09-10 14:31:12 +02:00
Michele Caini
be3597524f added a static_assert in a test to suppress a warning from GCC 2019-09-08 22:53:48 +02:00
Michele Caini
5717dbda4f added [[maybe_unused]] to suppress a warning from GCC 2019-09-08 22:50:51 +02:00
Michele Caini
588eec4672 added meta_type::compare, meta_any no longer has to store aside comparison functions 2019-09-08 22:44:06 +02:00
Michele Caini
cc3d0d8211 no more references to the prototype class (close #307) 2019-09-08 00:11:44 +02:00
Michele Caini
1550efaf7e stomp & spawn: const source registry (close #308) 2019-09-08 00:09:43 +02:00
Michele Caini
007300b881 sigh: ordered calls 2019-09-08 00:05:26 +02:00
Michele Caini
454f072f13 review stomp & spawn (close #306) 2019-09-06 17:21:07 +02:00
Michele Caini
b3be6c75c3 cleanup 2019-09-06 16:42:42 +02:00
Michele Caini
f8774f314b sink::disconnect accepts also opaque pointers 2019-09-06 08:19:28 +02:00
Michele Caini
3db35ad343 added openblack to the links 2019-09-06 08:19:28 +02:00
Michele Caini
0e42a779e2 meta_any uses reference_wrapper instead of as_alias_t for aliasing 2019-09-06 08:19:28 +02:00
Michele Caini
d34e829811 perf improvement 2019-09-06 08:19:28 +02:00
Michele Caini
ebd988702e relaxed constraints on the order of types in the group definition 2019-09-06 08:19:28 +02:00
Michele Caini
1232398742 now working on EnTT v3.2.0 2019-09-06 08:19:28 +02:00
Michele Caini
6dbcd47143 updated single file 2019-09-06 08:18:34 +02:00
Michele Caini
0e07482e26 ready to cut v3.1.1 2019-09-05 15:24:08 +02:00
Michele Caini
6bb4800ecd fix batch creation (close #305) 2019-09-05 15:24:03 +02:00
Michele Caini
37e1ac71b0 minor changes 2019-09-05 15:22:24 +02:00
Michele Caini
869f96816c updated doc 2019-09-05 15:21:45 +02:00
Michele Caini
35a7008444 added noexcept specifier 2019-09-03 23:39:38 +02:00
Michele Caini
67f80ee111 the default ctor of entt::meta_factory should be public 2019-09-03 23:31:43 +02:00
Michele Caini
083a58753b typo 2019-09-03 23:31:39 +02:00
Michele Caini
b652357a5c review: group::sort 2019-09-02 16:48:47 +02:00
Michele Caini
49a52140b0 minor changes 2019-09-02 16:34:38 +02:00
Michele Caini
e37f84a227 avoid taking the position twice 2019-09-02 16:23:11 +02:00
Nicki
50fc83d478 Update AUTHORS (#302)
He's one of contributors to the idea of nested groups!! :)
2019-08-30 09:49:46 +02:00
Michele Caini
a3da1c54eb updated single file 2019-08-29 16:01:26 +02:00
Michele Caini
b8471e3cf1 algorithm: radix sort 2019-08-27 23:42:58 +02:00
Michele Caini
4bd645d5c6 updated links 2019-08-26 16:57:30 +02:00
Michele Caini
83446c0694 updated sparse_set interface 2019-08-26 15:01:50 +02:00
Michele Caini
b4c30fc07b cleanup 2019-08-26 14:54:15 +02:00
Michele Caini
8325f5bbae runtime_view no longer uses sparse_set<...>::extent() 2019-08-26 14:54:15 +02:00
Michele Caini
9eb1196526 multi-component view no longer uses sparse_set<...>::extent() 2019-08-26 14:54:15 +02:00
Michele Caini
5fe5d4b6fc runtime_view doesn't use sparse_set<...>::data() anymore 2019-08-26 14:54:15 +02:00
Michele Caini
34af44b8d3 updated doc (close #298) 2019-08-26 14:53:21 +02:00
Michele Caini
643a20fec3 minor changes 2019-08-25 16:52:59 +02:00
Michele Caini
576b931090 meta: updated doc (close #297) 2019-08-25 14:50:12 +02:00
Michele Caini
2cc1f044df constructor to create actors from existing entities (close #296) 2019-08-23 15:54:53 +02:00
Michele Caini
c651392643 removed prototype and dependency (with connect/disconnect) 2019-08-23 15:02:55 +02:00
Michele Caini
9a669176ac workaround for an ICE with VS2019 2019-08-22 23:53:34 +02:00
Michele Caini
b902831db8 cleanup 2019-08-22 23:31:28 +02:00
Michele Caini
90a1de383a more tests 2019-08-22 18:35:23 +02:00
Michele Caini
83f9d42d31 registry: stomp and spawn 2019-08-22 18:03:29 +02:00
Michele Caini
94136531a5 added type_list_size and type_list_size_v 2019-08-22 17:59:15 +02:00
Michele Caini
b8b1e6ba62 registry::stomp: registry & -> basic_registry & 2019-08-21 23:27:35 +02:00
Michele Caini
d6911337f3 added storage::batch overload for copy construction 2019-08-21 23:23:21 +02:00
Michele Caini
d2cbb72490 cleanup 2019-08-21 23:22:32 +02:00
Michele Caini
c835b4d363 updated doc 2019-08-21 17:44:11 +02:00
Michele Caini
ece4480200 batch creation returns iterators and no longer raw pointers 2019-08-21 17:36:56 +02:00
Michele Caini
57f8d90e38 updated README 2019-08-21 17:30:56 +02:00
Michele Caini
da2b2701fe minor changes 2019-08-21 16:57:38 +02:00
Michele Caini
6d7fba3abf updated README 2019-08-21 15:27:29 +02:00
Ezekiel Warren
90798c161b Bazel Support (#287) (#291) 2019-08-21 15:11:29 +02:00
Michele Caini
65e270ff57 minor changes 2019-08-21 14:52:58 +02:00
Michele Caini
4912e19281 workaround for an issue of VS2019 2019-08-20 17:14:09 +02:00
Michele Caini
6402564f44 minor changes 2019-08-20 16:59:49 +02:00
Michele Caini
a06d5dd7bb registry: updated signatures for callbacks, deprecated dependency 2019-08-20 16:52:30 +02:00
Michele Caini
15e7486ca3 appveyor: support for VS2019 2019-08-19 17:58:22 +02:00
Michele Caini
ac462cfce9 workaround for an issue of VS2019 2019-08-19 17:56:28 +02:00
Michele Caini
d921306dd8 workaround for an issue of VS2019 2019-08-19 17:49:55 +02:00
Michele Caini
05417705ed removed useless move(s) 2019-08-19 17:39:46 +02:00
Michele Caini
1c7d9e3d75 signals meet references (close #289) 2019-08-18 15:21:29 +02:00
Ezekiel Warren
97dd928ca4 benchmark to use entt::component (#290)
* benchmark to use entt::component
* updated list of contributors
2019-08-18 15:04:10 +02:00
Michele Caini
03949f7d60 fixed registry::loader, destroyed is set to null as expected 2019-08-17 16:13:28 +02:00
Michele Caini
effe477351 perf improvement 2019-08-17 15:51:22 +02:00
Michele Caini
12ac858242 cleanup 2019-08-17 15:26:04 +02:00
Michele Caini
eec1937f52 updated entt::null comparison functions 2019-08-17 14:51:14 +02:00
Michele Caini
906cd48fb7 version-less entt::null (close #288) 2019-08-16 15:26:36 +02:00
Michele Caini
78beecf6f1 meta: removed wrong noexcept 2019-08-16 00:41:54 +02:00
Michele Caini
06a0646541 registry::stomp: tests + bug fixing 2019-08-15 15:38:47 +02:00
Michele Caini
0499a6c6f9 deprecated prototype/documented registry::stomp 2019-08-14 15:39:49 +02:00
Michele Caini
0e62f2ee85 updated list of showcases 2019-08-14 15:30:54 +02:00
Michele Caini
2ba4c36af0 registry::stomp (to be tested yet) 2019-08-13 15:58:26 +02:00
Michele Caini
688e6ad79f minor changes 2019-08-12 17:52:13 +02:00
Michele Caini
f8ee0ce185 fixed typo 2019-08-12 17:20:20 +02:00
Michele Caini
a226e06ae8 fixed typo 2019-08-12 15:57:59 +02:00
Michele Caini
e0e51b51b7 added exclusion list to registry::clone (close #286) 2019-08-12 15:43:28 +02:00
Michele Caini
9e9e3d43a8 updated doc 2019-08-11 23:46:20 +02:00
Michele Caini
7691a9bdad entt::component is now available 2019-08-11 17:21:30 +02:00
Michele Caini
22020cae49 doc: minor changes 2019-08-11 15:57:45 +02:00
Michele Caini
6cd910b0f6 added a test to meta to show how to set/get plain variables (close #284) 2019-08-11 15:37:48 +02:00
Michele Caini
b5e9811063 updated doc 2019-08-10 23:42:12 +02:00
Michele Caini
7668c7dd00 updated TODO 2019-08-09 16:12:55 +02:00
Michele Caini
d71f743e85 meta: updated documentation 2019-08-09 16:06:50 +02:00
Michele Caini
73ef0222ac tests for meta policies 2019-08-09 00:40:37 +02:00
Michele Caini
6152387096 meta: policies 2019-08-08 23:45:19 +02:00
Michele Caini
b93ffe3b44 workaround for a bug of clang (close #281) 2019-08-08 23:42:28 +02:00
Michele Caini
478eb7c5b5 minor changes 2019-08-08 17:04:45 +02:00
Michele Caini
6c40d8bd8b updated links 2019-08-08 15:28:33 +02:00
Michele Caini
7026fe4d5a meta: review dtor policy 2019-08-06 00:32:29 +02:00
Michele Caini
9a4491dc50 workaround for a bug of gcc7 2019-08-05 14:40:11 +02:00
Michele Caini
0d835e5014 workaround for an issue of gcc7 2019-08-05 14:29:55 +02:00
Michele Caini
29b5ffb58d rewritten self-contained lambda 2019-08-05 14:19:56 +02:00
Michele Caini
a179ec485b minor changes 2019-08-05 09:50:52 +02:00
Michele Caini
f220a577e0 meta: review 2019-08-05 09:50:45 +02:00
Michele Caini
b22b1d4794 meta: prevent aliasing on prop with future changes 2019-08-04 23:03:31 +02:00
Michele Caini
d2d19e3fbc fixed typo 2019-08-04 23:03:00 +02:00
Michele Caini
19ef290499 minor changes 2019-08-01 14:52:28 +02:00
Michele Caini
f6584b45ed doc: fixed typo 2019-07-31 14:17:24 +02:00
Michele Caini
bad97a8b5b meta system:
* perf improvements
* meta_any::try_cast
* meta_any is void-friendly
* meta_any support for unmanaged objects
* general cleanup
2019-07-28 17:08:56 +02:00
Michele Caini
7116df15d6 FAQ: fixed typo - thanks @huwpascoe and @Kerndog73 2019-07-28 17:08:31 +02:00
Michele Caini
ffbb018d12 updated FAQ 2019-07-22 14:47:08 +02:00
Michele Caini
a4dcdfc403 updated FAQ 2019-07-13 00:14:33 +02:00
Michele Caini
87d901b1ae is now possible to sort non-owning groups using a custom comparison function 2019-07-12 15:41:07 +02:00
Michele Caini
9126651cb9 added the possibility to sort free instances for owned types 2019-07-11 14:46:25 +02:00
Michele Caini
3996ce8ce5 test: storage::sort for ranges 2019-07-10 15:00:00 +02:00
Michele Caini
6340423b32 updated doc 2019-07-10 14:35:38 +02:00
Michele Caini
0d921dc1fc added support for free/member functions to meta_conv 2019-07-10 14:29:17 +02:00
Michele Caini
25afea4f9c meta: setters and getters receive instances as references now 2019-07-10 14:26:40 +02:00
Michele Caini
ba46bf3af5 review: sort/respect 2019-07-09 17:26:31 +02:00
Michele Caini
416b4885f9 updated doc (close #277) 2019-07-09 15:15:26 +02:00
Michele Caini
9a10ee0efa updated doc (see #277) 2019-07-09 14:56:32 +02:00
Michele Caini
d63b78f0e7 minor changes 2019-07-09 14:01:56 +02:00
Michele Caini
99411241f6 fixed typo 2019-07-09 13:59:28 +02:00
Michele Caini
941fb1349b added cache::each (close #275) 2019-07-09 13:58:44 +02:00
Michele Caini
a470925305 typo 2019-07-06 15:23:40 +02:00
Michele Caini
e3ac292af1 return types for meta_func are no longer ambiguous (close #274) 2019-07-06 00:10:37 +02:00
Michele Caini
260b9a8d0d meta_any meets void 2019-07-05 23:03:01 +02:00
Michele Caini
530407f9b2 minor changes 2019-07-05 14:13:10 +02:00
Michele Caini
52e7b50e9b sigh: more tests 2019-07-05 13:36:47 +02:00
Michele Caini
23aa097d0a fixed the clone functionality (close #273) 2019-07-05 08:41:24 +02:00
Michele Caini
0bea153aa0 more on sigh, connection and scoped_connection 2019-07-04 15:04:17 +02:00
Michele Caini
00be58e65d cleanup - thanks @Kerndog73 2019-07-03 15:28:11 +02:00
Michele Caini
a5cc985bc2 fixed doc for sigh - thanks @Kerndog73 2019-07-03 15:18:36 +02:00
Michele Caini
afba54fb5e updated doc for delegate/sigh (close #267) 2019-07-02 15:31:55 +02:00
Michele Caini
46150a2da4 delegate works now also with move only types (close #272) 2019-07-02 14:49:49 +02:00
Michele Caini
842988c2ad workaround for an issue of MSVC 2019-07-01 16:21:07 +02:00
Michele Caini
ebad34ae51 sigh: more tests 2019-07-01 15:26:11 +02:00
Michele Caini
bceb359438 minor changes 2019-07-01 15:16:38 +02:00
Michele Caini
19a32134ab tests: sigh connection/scoped_connection 2019-07-01 15:09:55 +02:00
Michele Caini
e44a71daf2 delegate::operator==/!= test the instance as a whole now 2019-06-30 22:19:44 +02:00
Michele Caini
573750a43d added connection/scoped_connection (#267 - test required) 2019-06-30 21:32:45 +02:00
Michele Caini
dd4c73b41f review: signal/sink 2019-06-30 21:32:45 +02:00
Michele Caini
094326220f cleanup 2019-06-30 21:32:45 +02:00
Michele Caini
729a071284 sigh: a more modern approach (as in modern C++) for collectors 2019-06-30 21:32:45 +02:00
Michele Caini
ee7857a560 sigh: removed invoker class 2019-06-30 21:32:45 +02:00
Michele Caini
4cba604712 updated list of projects (close #270) 2019-06-30 20:49:11 +02:00
Michele Caini
18a62797d9 updated FAQ 2019-06-30 17:11:40 +02:00
Michele Caini
5d4ac62c9e removed superfluous base class 2019-06-28 10:35:35 +02:00
Michele Caini
2ef8c41b48 updated list of contributors 2019-06-27 08:52:30 +02:00
Michele Caini
891831a96a Merge pull request #269 from Lawrencemm/conan_editable
Conan: Support package in editable mode
2019-06-27 08:51:38 +02:00
Michele Caini
11d18fa1af entity identifiers as enum classes (close #256) 2019-06-23 16:09:07 +02:00
Lawrence Millar-Madigan
ad69cbc681 Conan: Support package in editable mode
Add a method to the recipe that maps the include path to "src" when the package is put into "editable mode". See:
https://docs.conan.io/en/latest/developing_packages/editable_packages.html
2019-06-22 14:55:02 +10:00
Michele Caini
10995de7bd cleanup - thanks to @Kerndog73 (see #267) 2019-06-19 17:32:32 +02:00
Michele Caini
c4d78c06eb fixed group::sort with components 2019-06-19 15:25:30 +02:00
Michele Caini
eb252321a7 minor changes 2019-06-18 23:23:42 +02:00
Michele Caini
04dd1447ee minor changes 2019-06-17 16:14:20 +02:00
Michele Caini
b14edbe1f4 review: observer 2019-06-16 18:39:56 +02:00
Michele Caini
c697e52c0c fixed range destroy - it's probably slightly slower now but it works also with views and groups (close #261) 2019-06-16 17:14:32 +02:00
Michele Caini
b6911da8f0 CI runs now in debug mode (close #263) 2019-06-16 17:12:41 +02:00
Michele Caini
038448865b workaround for an issue with VS (close #264) 2019-06-16 17:10:25 +02:00
Michele Caini
9e44fdbc55 review: test 2019-06-16 17:08:37 +02:00
Michele Caini
e088f0f31e observer: when -> where (close #265) 2019-06-16 15:16:04 +02:00
Michele Caini
6101feda10 added default constructor to actor 2019-06-13 06:52:01 +02:00
Michele Caini
7a3fa68468 added actor::operator bool() + minor changes 2019-06-12 17:36:26 +02:00
Michele Caini
16a11638a7 updated observer (close #260) 2019-06-11 17:49:08 +02:00
Michele Caini
43932492a7 meta: overall improvements 2019-06-10 23:19:19 +02:00
Michele Caini
8d08ffc4ae slightly faster destroy 2019-06-10 00:24:19 +02:00
Michele Caini
a5a4ee4bfe doc: observer/reactive systems 2019-06-10 00:24:08 +02:00
Michele Caini
e66f3a80e8 observer (they call me reactive system) 2019-06-08 16:59:22 +02:00
Michele Caini
e69efacb47 updated links (close #258) 2019-06-08 14:06:54 +02:00
Michele Caini
528b361e34 meta any: in place construction/emplace 2019-06-08 14:03:31 +02:00
Michele Caini
a77bb3d341 Update FUNDING.yml 2019-06-07 09:52:53 +02:00
Michele Caini
6b17385ad7 updated tests 2019-06-06 14:58:25 +02:00
Michele Caini
33fc01ef4b Create FUNDING.yml 2019-06-06 12:08:59 +02:00
Michele Caini
482324c0bd avoid forcing conversions because of an issue with VS2019 (close #257) 2019-06-04 15:02:30 +02:00
Michele Caini
0ab13a3a70 test coverage 2019-06-03 23:50:09 +02:00
Michele Caini
699fb73726 bug fixing 2019-06-01 15:18:58 +02:00
Michele Caini
ddba29cc09 more on sigh/sink 2019-05-31 22:49:37 +02:00
Michele Caini
1cdb9ef47c updated TODO 2019-05-31 15:11:02 +02:00
Michele Caini
ade3305b4c removed useless references to components from dependencies 2019-05-31 15:10:46 +02:00
Michele Caini
bd2bd37bc4 updated sigh: instances and payload matter now 2019-05-31 15:10:06 +02:00
Michele Caini
ee6f55193e updated doc 2019-05-31 15:09:27 +02:00
Michele Caini
1868df61ea fixed typo 2019-05-31 15:08:49 +02:00
Michele Caini
dfa1fc7b09 review: group handler 2019-05-31 00:14:47 +02:00
Michele Caini
a52b0495f1 minor changes 2019-05-31 00:11:00 +02:00
Michele Caini
ce00eee29f the delegate accepts now also functions with a shorter list of parameters 2019-05-31 00:10:42 +02:00
Michele Caini
858bfade6a a more flexible delegate 2019-05-30 21:54:12 +02:00
Michele Caini
4535cf9274 perf improvement 2019-05-29 22:50:34 +02:00
Michele Caini
84d1fa54ec added the excluded components to the list of template parameters of a group 2019-05-28 15:03:28 +02:00
Michele Caini
7cf4721efa review: as_group 2019-05-27 22:05:16 +02:00
Michele Caini
6578838587 fixed include 2019-05-27 21:49:19 +02:00
Michele Caini
46b7c4717f workaround for an issue in clang 6 2019-05-27 12:08:25 +02:00
Michele Caini
52bcf63554 more on hashed strings and unique identifiers 2019-05-27 00:07:40 +02:00
Michele Caini
37ec97550e fixed typo 2019-05-26 15:38:37 +02:00
Michele Caini
55e20abea8 cleanup 2019-05-25 23:51:16 +02:00
Michele Caini
ec7d81dc7a added support for wstring to hashed_string 2019-05-25 23:42:06 +02:00
Michele Caini
e93387b719 maybe_atomic_t no longer exists 2019-05-25 22:21:44 +02:00
Michele Caini
050b476fc3 suppress warnings 2019-05-25 22:08:56 +02:00
Michele Caini
5b5ffd7eaf Remove superfluous inlines (was PR #249) 2019-05-25 22:03:34 +02:00
Michele Caini
39bf5fdc05 minor changes 2019-05-25 21:43:58 +02:00
Michele Caini
09ff43ef0a updated doc 2019-05-22 08:44:49 +02:00
Michele Caini
5a02aeaa89 raw() is no longer in use 2019-05-22 08:44:43 +02:00
Martin Hammerchmidt
2a3a91af42 Fix: remove garbage unicode U+FEFF failing compilation on Macos (#248, close #247) 2019-05-22 00:19:04 +02:00
Michele Caini
d4a64e93e0 mutable handle 2019-05-21 15:02:30 +02:00
Michele Caini
c126b64892 updated doc 2019-05-21 15:01:55 +02:00
Michele Caini
526814b9ed added registry::ctx_or_set 2019-05-19 23:40:15 +02:00
Michele Caini
bc3b790f13 removed wrong ENTT_NOEXCEPT 2019-05-19 23:25:05 +02:00
Michele Caini
1fb0765443 registry: internal changes 2019-05-19 00:23:48 +02:00
Michele Caini
c4b85f9bda minor changes 2019-05-18 23:53:10 +02:00
Michele Caini
161b5530b9 added [view|group]::less 2019-05-18 14:11:12 +02:00
Michele Caini
e03979ebdc cleanup 2019-05-18 14:05:04 +02:00
Michele Caini
356c0ab594 now working on v3.1.0 2019-05-18 14:04:41 +02:00
187 changed files with 65146 additions and 24068 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# 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

82
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,82 @@
name: build
on: [push, pull_request]
jobs:
linux:
timeout-minutes: 10
strategy:
matrix:
compiler: [
g++-8, g++-9, g++,
clang++-8, clang++-9, clang++
]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
env:
CXX: ${{ matrix.compiler }}
run: |
cmake -DENTT_USE_ASAN=ON -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 5 -C Debug -j4
windows:
timeout-minutes: 10
strategy:
matrix:
os: [windows-latest, windows-2016]
toolset: [clang-cl, default, v141]
include:
- toolset: clang-cl
toolset_option: -T"ClangCl"
- toolset: v141
toolset_option: -T"v141"
exclude:
- os: windows-2016
toolset: clang-cl
- os: windows-2016
toolset: v141
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
run: |
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.toolset_option }} ..
cmake --build . -j 4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 5 -C Debug -j4
macos:
timeout-minutes: 10
runs-on: macOS-latest
steps:
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
run: |
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 5 -C Debug -j4

33
.github/workflows/coverage.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
name: coverage
on: [push, pull_request]
jobs:
codecov:
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
env:
CXXFLAGS: "-O0 --coverage -fno-inline -fno-inline-small-functions -fno-default-inline"
CXX: g++
run: |
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 5 -C Debug -j4
- name: Upload coverage to Codecov
working-directory: build
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
run: |
wget https://codecov.io/bash -O codecov
chmod +x codecov
./codecov -t $CODECOV_TOKEN -B $GITHUB_REF -s .

40
.github/workflows/deploy.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: deploy
on:
release:
types: published
jobs:
homebrew-entt:
timeout-minutes: 5
runs-on: ubuntu-latest
env:
GH_REPO: homebrew-entt
FORMULA: entt.rb
steps:
- uses: actions/checkout@v2
- name: Clone repository
working-directory: build
env:
PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
run: |
git clone https://$GITHUB_ACTOR:$PERSONAL_ACCESS_TOKEN@github.com/$GITHUB_ACTOR/$GH_REPO.git
- name: Prepare formula
working-directory: build
run: |
cd $GH_REPO
curl "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" --location --fail --silent --show-error --output archive.tar.gz
sed -i -e '/url/s/".*"/"'$(echo "https://github.com/${{ github.repository }}/archive/${{ github.ref }}.tar.gz" | sed -e 's/[\/&]/\\&/g')'"/' $FORMULA
sed -i -e '/sha256/s/".*"/"'$(openssl sha256 archive.tar.gz | cut -d " " -f 2)'"/' $FORMULA
- name: Update remote
working-directory: build
run: |
cd $GH_REPO
git config --local user.email "action@github.com"
git config --local user.name "$GITHUB_ACTOR"
git add $FORMULA
git commit -m "Update to ${{ github.ref }}"
git push origin master

9
.gitignore vendored
View File

@@ -1,5 +1,12 @@
*.user
# Conan
conan/test_package/build
# IDEs
*.user
.idea
.vscode
.vs
CMakeSettings.json
# Bazel
/bazel-*

View File

@@ -1,97 +0,0 @@
language: cpp
dist: trusty
sudo: false
env:
global:
- CONAN_USERNAME="skypjack"
- CONAN_PACKAGE_NAME="entt"
- CONAN_HEADER_ONLY="True"
- NON_CONAN_DEPLOYMENT="True"
conan-buildsteps: &conan-buildsteps
before_install:
# use this step if you desire to manipulate CONAN variables programmatically
- NON_CONAN_DEPLOYMENT="False"
install:
- chmod +x ./conan/ci/install.sh
- ./conan/ci/install.sh
script:
- chmod +x ./conan/ci/build.sh
- ./conan/ci/build.sh
# the following are dummies to overwrite default build steps
before_script:
- true
after_success:
- true
if: tag IS present
conan-linux: &conan-linux
os: linux
sudo: required
language: python
python: "3.6"
services:
- docker
<<: *conan-buildsteps
matrix:
include:
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-7']
env: COMPILER=g++-7
- os: linux
compiler: clang
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
packages: ['clang-6.0', 'g++-7']
env: COMPILER=clang++-6.0
- os: osx
osx_image: xcode10
compiler: clang
env: COMPILER=clang++
- os: linux
compiler: gcc
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-7']
env:
- COMPILER=g++-7
- CXXFLAGS="-O0 --coverage -fno-inline -fno-inline-small-functions -fno-default-inline"
before_script:
- pip install --user cpp-coveralls
after_success:
- coveralls --gcov gcov-7 --gcov-options '\-lp' --root ${TRAVIS_BUILD_DIR} --build-root ${TRAVIS_BUILD_DIR}/build --extension cpp --extension hpp --exclude deps --include src
# Conan testing and uploading
- <<: *conan-linux
env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=conanio/gcc8
notifications:
email:
on_success: never
on_failure: always
install:
- echo ${PATH}
- cmake --version
- export CXX=${COMPILER}
- echo ${CXX}
- ${CXX} --version
- ${CXX} -v
script:
- mkdir -p build && cd build
- cmake -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Release .. && make -j4
- CTEST_OUTPUT_ON_FAILURE=1 ctest -j4
deploy:
provider: script
script: scripts/update_packages.sh $TRAVIS_TAG
on:
tags: true
condition: “$NON_CONAN_DEPLOYMENT = “True”

26
AUTHORS
View File

@@ -4,34 +4,48 @@ skypjack
# Contributors
alexames
BenediktConze
bjadamson
ceeac
ColinH
corystegel
Croydon
cugone
dbacchet
dBagrat
djarek
DonKult
drglove
eliasdaler
erez-o
eugeneko
gale83
ghost
grdowns
Green-Sky
Innokentiy-Alaytsev
Kerndog73
Koward
Lawrencemm
markand
mhammerc
Milerius
morbo84
m-waka
Kerndog73
netpoetica
NixAJ
Oortonaut
Paolo-Oliverio
pgruenbacher
prowolf
stefanofiorentino
suVrik
szunhammer
The5-1
vblanco20-1
willtunnels
WizardIke
w1th0utnam3
# Special thanks for patrons
Arn
tpisto
xissburg
zaucy

15
BUILD.bazel Normal file
View File

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

View File

@@ -2,7 +2,7 @@
# EnTT
#
cmake_minimum_required(VERSION 3.7.2)
cmake_minimum_required(VERSION 3.12.4)
#
# Building in-tree is not allowed (we take care of your craziness).
@@ -12,37 +12,44 @@ 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 VERSION 3.0.0)
include(GNUInstallDirs)
project(
EnTT
VERSION ${ENTT_VERSION}
DESCRIPTION "Gaming meets modern C++ - a fast and reliable entity-component system (ECS) and much more"
HOMEPAGE_URL "https://github.com/skypjack/entt"
LANGUAGES CXX
)
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
set(SETTINGS_ORGANIZATION "Michele Caini")
set(SETTINGS_APPLICATION ${PROJECT_NAME})
set(PROJECT_AUTHOR "Michele Caini")
set(PROJECT_AUTHOR_EMAIL "michele.caini@gmail.com")
message(VERBOSE "*")
message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
message(VERBOSE "* Copyright (c) 2017-2021 Michele Caini <michele.caini@gmail.com>")
message(VERBOSE "*")
message("*")
message("* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
message("* Copyright (c) 2017-2019 ${PROJECT_AUTHOR} <${PROJECT_AUTHOR_EMAIL}>")
message("*")
option(USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if availbale." ON)
option(USE_ASAN "Use address sanitizer by adding -fsanitize=address -fno-omit-frame-pointer flags" OFF)
option(USE_COMPILE_OPTIONS "Use compile options from EnTT." ON)
option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if availbale." ON)
option(ENTT_USE_ASAN "Use address sanitizer by adding -fsanitize=address -fno-omit-frame-pointer flags" OFF)
#
# Compiler stuff
#
if(NOT MSVC AND USE_LIBCPP)
if(NOT WIN32 AND ENTT_USE_LIBCPP)
include(CheckCXXSourceCompiles)
include(CMakePushCheckState)
@@ -52,11 +59,11 @@ if(NOT MSVC AND USE_LIBCPP)
check_cxx_source_compiles("
#include<type_traits>
int main() { return std::is_same_v<int, int> ? 0 : 1; }
" HAS_LIBCPP)
int main() { return std::is_same_v<int, char>; }
" ENTT_HAS_LIBCPP)
if(NOT HAS_LIBCPP)
message(WARNING "The option USE_LIBCPP is set (by default) but libc++ is not available. The flag will not be added to the target.")
if(NOT ENTT_HAS_LIBCPP)
message(VERBOSE "The option ENTT_USE_LIBCPP is set (by default) but libc++ is not available. The flag will not be added to the target.")
endif()
cmake_pop_check_state()
@@ -66,39 +73,24 @@ endif()
# Add EnTT target
#
add_library(EnTT INTERFACE)
include(GNUInstallDirs)
configure_file(${EnTT_SOURCE_DIR}/cmake/in/version.h.in ${EnTT_SOURCE_DIR}/src/entt/config/version.h @ONLY)
add_library(EnTT INTERFACE)
add_library(EnTT::EnTT ALIAS EnTT)
target_include_directories(
EnTT INTERFACE
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_compile_definitions(
EnTT
INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:DEBUG>
INTERFACE $<$<AND:$<CONFIG:Release>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:RELEASE>
INTERFACE
$<BUILD_INTERFACE:${EnTT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
if(USE_ASAN)
target_compile_options(EnTT INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:-fsanitize=address -fno-omit-frame-pointer>)
target_link_libraries(EnTT INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:-fsanitize=address -fno-omit-frame-pointer>)
if(ENTT_USE_ASAN)
target_compile_options(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer>)
endif()
if(USE_COMPILE_OPTIONS)
target_compile_options(
EnTT
INTERFACE $<$<AND:$<CONFIG:Debug>,$<NOT:$<CXX_COMPILER_ID:MSVC>>>:-O0 -g>
# it seems that -O3 ruins a bit the performance when using clang ...
INTERFACE $<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:Clang>>:-O2>
# ... on the other side, GCC is incredibly comfortable with it.
INTERFACE $<$<AND:$<CONFIG:Release>,$<CXX_COMPILER_ID:GNU>>:-O3>
)
endif()
if(HAS_LIBCPP)
if(ENTT_HAS_LIBCPP)
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
endif()
@@ -108,89 +100,64 @@ target_compile_features(EnTT INTERFACE cxx_std_17)
# Install EnTT
#
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(CUSTOM_INSTALL_CONFIGDIR cmake)
else()
set(CUSTOM_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/entt)
endif()
install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(TARGETS EnTT EXPORT EnTTTargets)
export(EXPORT EnTTTargets FILE ${EnTT_BINARY_DIR}/EnTTTargets.cmake)
install(
EXPORT EnTTTargets
FILE EnTTTargets.cmake
DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
)
#
# Build tree package config file
#
configure_file(cmake/in/EnTTBuildConfig.cmake.in EnTTConfig.cmake @ONLY)
include(CMakePackageConfigHelpers)
#
# Install tree package config file
#
configure_package_config_file(
cmake/in/EnTTConfig.cmake.in
${CUSTOM_INSTALL_CONFIGDIR}/EnTTConfig.cmake
INSTALL_DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
PATH_VARS CMAKE_INSTALL_INCLUDEDIR
install(
TARGETS EnTT
EXPORT EnTTTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
write_basic_package_version_file(
${EnTT_BINARY_DIR}/EnTTConfigVersion.cmake
EnTTConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(
${EnTT_SOURCE_DIR}/cmake/in/EnTTConfig.cmake.in
EnTTConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
)
export(
EXPORT EnTTTargets
FILE ${CMAKE_CURRENT_BINARY_DIR}/EnTTTargets.cmake
NAMESPACE EnTT::
)
install(
EXPORT EnTTTargets
FILE EnTTTargets.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
NAMESPACE EnTT::
)
install(
FILES
${EnTT_BINARY_DIR}/${CUSTOM_INSTALL_CONFIGDIR}/EnTTConfig.cmake
${EnTT_BINARY_DIR}/EnTTConfigVersion.cmake
DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
${PROJECT_BINARY_DIR}/EnTTConfig.cmake
${PROJECT_BINARY_DIR}/EnTTConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
)
install(DIRECTORY src/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
export(PACKAGE EnTT)
#
# Tests
#
option(BUILD_TESTING "Enable testing with ctest." OFF)
option(ENTT_BUILD_TESTING "Enable building tests." OFF)
if(BUILD_TESTING)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
option(FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
if(FIND_GTEST_PACKAGE)
find_package(GTest REQUIRED)
else()
# gtest, gtest_main, gmock and gmock_main targets are available from now on
set(GOOGLETEST_DEPS_DIR ${EnTT_SOURCE_DIR}/deps/googletest)
configure_file(${EnTT_SOURCE_DIR}/cmake/in/googletest.in ${GOOGLETEST_DEPS_DIR}/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${GOOGLETEST_DEPS_DIR})
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
add_subdirectory(${GOOGLETEST_DEPS_DIR}/src ${GOOGLETEST_DEPS_DIR}/build)
target_compile_features(gmock_main PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>)
target_compile_features(gmock PRIVATE $<TARGET_PROPERTY:EnTT,INTERFACE_COMPILE_FEATURES>)
add_library(GTest::Main ALIAS gtest_main)
endif()
option(BUILD_BENCHMARK "Build benchmark." OFF)
option(BUILD_LIB "Build lib example." OFF)
option(BUILD_MOD "Build mod example." OFF)
option(BUILD_SNAPSHOT "Build snapshot example." OFF)
if(ENTT_BUILD_TESTING)
option(ENTT_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
option(ENTT_BUILD_BENCHMARK "Build benchmark." OFF)
option(ENTT_BUILD_EXAMPLE "Build examples." OFF)
option(ENTT_BUILD_LIB "Build lib tests." OFF)
option(ENTT_BUILD_SNAPSHOT "Build snapshot test with Cereal." OFF)
include(CTest)
enable_testing()
add_subdirectory(test)
endif()
@@ -199,9 +166,9 @@ endif()
# Documentation
#
option(BUILD_DOCS "Enable building with documentation." OFF)
option(ENTT_BUILD_DOCS "Enable building with documentation." OFF)
if(BUILD_DOCS)
if(ENTT_BUILD_DOCS)
find_package(Doxygen 1.8)
if(DOXYGEN_FOUND)
@@ -214,12 +181,15 @@ endif()
#
add_custom_target(
entt_aob
aob
SOURCES
appveyor.yml
.github/workflows/build.yml
.github/workflows/coverage.yml
.github/workflows/deploy.yml
.github/FUNDING.yml
AUTHORS
CONTRIBUTING.md
LICENSE
README.md
TODO
.travis.yml
)

View File

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

289
README.md
View File

@@ -1,36 +1,48 @@
![EnTT: Gaming meets modern C++](https://user-images.githubusercontent.com/1812216/42513718-ee6e98d0-8457-11e8-9baf-8d83f61a3097.png)
![EnTT: Gaming meets modern C++](https://user-images.githubusercontent.com/1812216/103550016-90752280-4ea8-11eb-8667-12ed2219e137.png)
<!--
@cond TURN_OFF_DOXYGEN
-->
[![GitHub version](https://badge.fury.io/gh/skypjack%2Fentt.svg)](http://badge.fury.io/gh/skypjack%2Fentt)
[![LoC](https://tokei.rs/b1/github/skypjack/entt)](https://github.com/skypjack/entt)
[![Build Status](https://travis-ci.org/skypjack/entt.svg?branch=master)](https://travis-ci.org/skypjack/entt)
[![Build status](https://ci.appveyor.com/api/projects/status/rvhaabjmghg715ck?svg=true)](https://ci.appveyor.com/project/skypjack/entt)
[![Coverage Status](https://coveralls.io/repos/github/skypjack/entt/badge.svg?branch=master)](https://coveralls.io/github/skypjack/entt?branch=master)
[![GitHub version](https://badge.fury.io/gh/skypjack%2Fentt.svg)](https://github.com/skypjack/entt/releases)
[![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/cOUcm1)
[![Documentation](https://img.shields.io/badge/docs-docsforge-blue)](http://entt.docsforge.com/)
[![Gitter chat](https://badges.gitter.im/skypjack/entt.png)](https://gitter.im/skypjack/entt)
[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.me/skypjack)
[![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` is a header-only, tiny and easy to use library for game programming and
much more written in **modern C++**, mainly known for its innovative
**entity-component-system (ECS)** model.<br/>
much more written in **modern C++**.<br/>
[Among others](https://github.com/skypjack/entt/wiki/EnTT-in-Action), it's used
in [**Minecraft**](https://minecraft.net/en-us/attribution/) by Mojang, the
[**ArcGIS Runtime SDKs**](https://developers.arcgis.com/arcgis-runtime/) by Esri
and [**The Forge**](https://github.com/ConfettiFX/The-Forge) by Confetti. Read
on to find out what it can offer you.
and the amazing [**Ragdoll**](https://ragdolldynamics.com/) Autodesk Maya
plugin.<br/>
If you don't see your project in the list, please open an issue, submit a PR or
add the [#entt](https://github.com/topics/entt) tag to your _topics_! :+1:
---
Do you want to **keep up with changes** or do you have a **question** that
doesn't require you to open an issue?<br/>
Join the [gitter channel](https://gitter.im/skypjack/entt) and meet other users
like you. The more we are, the better for everyone.
Join the [gitter channel](https://gitter.im/skypjack/entt) or the
[discord server](https://discord.gg/5BjPWBd) and meet other users like you. The
more we are, the better for everyone.
Wondering why your **debug build** is so slow on Windows or how to represent a
**hierarchy** with components?<br/>
Check out the
[FAQ](https://github.com/skypjack/entt/wiki/Frequently-Asked-Questions) and the
[wiki](https://github.com/skypjack/entt/wiki) if you have these or other doubts,
your answers may already be there.
If you use `EnTT` and you want to say thanks or support the project, please
**consider becoming a patron**:
[![Patreon](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/bePatron?c=1772573)
**consider becoming a
[sponsor](https://github.com/users/skypjack/sponsorship)**.<br/>
You can help me make the difference.
[Many thanks](https://skypjack.github.io/sponsorship/) to those who supported me
and still support me today.
# Table of Contents
@@ -48,9 +60,6 @@ If you use `EnTT` and you want to say thanks or support the project, please
* [Contributors](#contributors)
* [License](#license)
* [Support](#support)
* [Patreon](#patreon)
* [Donation](#donation)
* [Hire me](#hire-me)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@@ -68,25 +77,25 @@ This project started off as a pure entity-component system. Over time the
codebase has grown as more and more classes and functionalities were added.<br/>
Here is a brief, yet incomplete list of what it offers today:
* Statically generated integer **identifiers for types** (assigned either at
* Statically generated integer **identifiers** for types (assigned either at
compile-time or at runtime).
* A `constexpr` utility for **human readable resource identifiers**.
* A `constexpr` utility for human readable **resource names**.
* A minimal **configuration system** built using the monostate pattern.
* An incredibly fast **entity-component system** based on sparse sets, with its
own _pay for what you use_ policy to adjust performance and memory usage
according to the users' requirements.
* 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 support
the users and avoid reinventing the wheel (dependencies, snapshot, actor class
for those who aren't confident with the architecture and so on).
* A lot of **facilities** built on top of the entity-component system to help
the users and avoid reinventing the wheel (dependencies, snapshot, handles,
support for **reactive systems** and so on).
* The smallest and most basic implementation of a **service locator** ever seen.
* A built-in, non-intrusive and macro-free **runtime reflection system**.
* A built-in, non-intrusive and macro-free runtime **reflection system**.
* **Static polymorphism** made simple and within everyone's reach.
* A **cooperative scheduler** for processes of any type.
* All that is needed for **resource management** (cache, loaders, handles).
* **Delegates**, **signal handlers** (with built-in support for collectors) and
a tiny **event dispatcher** for immediate and delayed events to integrate in
loops.
* Delegates, **signal handlers** (with built-in support for collectors) and a
tiny event dispatcher for immediate and delayed events to integrate in loops.
* A general purpose **event emitter** as a CRTP idiom based class template.
* And **much more**! Check out the
[**wiki**](https://github.com/skypjack/entt/wiki).
@@ -94,16 +103,15 @@ Here is a brief, yet incomplete list of what it offers today:
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.
Currently, `EnTT` is tested on Linux, Microsoft Windows and OSX. It has proven
to work also on both Android and iOS.<br/>
Most likely it won't be problematic on other systems as well, but it hasn't been
sufficiently tested so far.
It is also known that `EnTT` (version 3) is 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.
## Code Example
```cpp
#include <entt/entt.hpp>
#include <cstdint>
struct position {
float x;
@@ -116,45 +124,36 @@ struct velocity {
};
void update(entt::registry &registry) {
auto view = registry.view<position, velocity>();
auto view = registry.view<const position, velocity>();
for(auto entity: view) {
// gets only the components that are going to be used ...
// use a callback
view.each([](const auto &pos, auto &vel) { /* ... */ });
auto &vel = view.get<velocity>(entity);
vel.dx = 0.;
vel.dy = 0.;
// use an extended callback
view.each([](const auto entity, const auto &pos, auto &vel) { /* ... */ });
// use a range-for
for(auto [entity, pos, vel]: view.each()) {
// ...
}
}
void update(std::uint64_t dt, entt::registry &registry) {
registry.view<position, velocity>().each([dt](auto &pos, auto &vel) {
// gets all the components of the view at once ...
pos.x += vel.dx * dt;
pos.y += vel.dy * dt;
// use forward iterators and get only the components of interest
for(auto entity: view) {
auto &vel = view.get<velocity>(entity);
// ...
});
}
}
int main() {
entt::registry registry;
std::uint64_t dt = 16;
for(auto i = 0; i < 10; ++i) {
auto entity = registry.create();
registry.assign<position>(entity, i * 1.f, i * 1.f);
if(i % 2 == 0) { registry.assign<velocity>(entity, i * .1f, i * .1f); }
for(auto i = 0u; i < 10u; ++i) {
const auto entity = registry.create();
registry.emplace<position>(entity, i * 1.f, i * 1.f);
if(i % 2 == 0) { registry.emplace<velocity>(entity, i * .1f, i * .1f); }
}
update(dt, registry);
update(registry);
// ...
}
```
@@ -174,48 +173,30 @@ amazing set of features. And even more, of course.
## Performance
As it stands right now, `EnTT` is just fast enough for my requirements when
compared to my first choice (it was already amazingly fast actually).<br/>
Below is a comparison between the two (both of them compiled with GCC 7.3.0 on a
Dell XPS 13 from mid 2014):
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.
| Benchmark | EntityX (compile-time) | EnTT |
|-----------|-------------|-------------|
| Create 1M entities | 0.0147s | **0.0046s** |
| Destroy 1M entities | 0.0053s | **0.0045s** |
| 1M entities, one component | 0.0012s | **1.9e-07s** |
| 1M entities, two components | 0.0012s | **3.8e-07s** |
| 1M entities, two components<br/>Half of the entities have all the components | 0.0009s | **3.8e-07s** |
| 1M entities, two components<br/>One of the entities has all the components | 0.0008s | **1.0e-06s** |
| 1M entities, five components | 0.0010s | **7.0e-07s** |
| 1M entities, ten components | 0.0011s | **1.2e-06s** |
| 1M entities, ten components<br/>Half of the entities have all the components | 0.0010s | **1.2e-06s** |
| 1M entities, ten components<br/>One of the entities has all the components | 0.0008s | **1.2e-06s** |
| Sort 150k entities, one component<br/>Arrays are in reverse order | - | **0.0036s** |
| Sort 150k entities, enforce permutation<br/>Arrays are in reverse order | - | **0.0005s** |
| Sort 150k entities, one component<br/>Arrays are almost sorted, std::sort | - | **0.0035s** |
| Sort 150k entities, one component<br/>Arrays are almost sorted, insertion sort | - | **0.0007s** |
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.
Note: The default version of `EntityX` (`master` branch) wasn't added to the
comparison because it's already much slower than its compile-time counterpart.
Pretty interesting results, aren't them? In fact, these benchmarks are the ones
used by `EntityX` to show _how fast it is_. To be honest, they aren't so good
and these results shouldn't be taken too seriously (indeed they are completely
unrealistic).<br/>
The proposed entity-component system is incredibly fast to iterate entities,
this is a fact. The compiler can make a lot of optimizations because of how
`EnTT` works, even more when components aren't used at all. This is exactly the
case for these benchmarks. On the other hand, if we consider real world cases,
`EnTT` is somewhere between a bit and much faster than the other solutions
around when users also access the components and not just the entities, although
it isn't as fast as reported by these benchmarks.<br/>
This is why they are completely wrong and cannot be used to evaluate any of the
entity-component-system libraries out there.
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
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.
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/>
@@ -231,8 +212,13 @@ supports at least C++17.<br/>
The requirements below are mandatory to compile the tests and to extract the
documentation:
* CMake version 3.2 or later.
* Doxygen version 1.8 or later.
* `CMake` version 3.7 or later.
* `Doxygen` version 1.8 or later.
Alternatively, [Bazel](https://bazel.build) is also supported as a build system
(credits to [zaucy](https://github.com/zaucy) who offered to maintain it).<br/>
In the documentation below I'll still refer to `CMake`, this being the official
build system of the library.
If you are looking for a C++14 version of `EnTT`, check out the git tag `cpp14`.
@@ -263,7 +249,7 @@ The documentation is based on [doxygen](http://www.doxygen.nl/).
To build it:
$ cd build
$ cmake .. -DBUILD_DOCS=ON
$ cmake .. -DENTT_BUILD_DOCS=ON
$ make
The API reference will be created in HTML format within the directory
@@ -275,9 +261,12 @@ The API reference will be created in HTML format within the directory
<!--
@cond TURN_OFF_DOXYGEN
-->
It's also available [online](https://skypjack.github.io/entt/) for the latest
version.<br/>
Finally, there exists a [wiki](https://github.com/skypjack/entt/wiki) dedicated
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/>
Moreover, there exists a [wiki](https://github.com/skypjack/entt/wiki) dedicated
to the project where users can find all related documentation pages.
<!--
@endcond TURN_OFF_DOXYGEN
@@ -287,12 +276,12 @@ to the project where users can find all related documentation pages.
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 `BUILD_TESTING` to `ON`.
In order to build the tests, set the CMake option `ENTT_BUILD_TESTING` to `ON`.
To build the most basic set of tests:
* `$ cd build`
* `$ cmake -DBUILD_TESTING=ON ..`
* `$ cmake -DENTT_BUILD_TESTING=ON ..`
* `$ make`
* `$ make test`
@@ -302,16 +291,60 @@ Note that benchmarks are not part of this set.
`EnTT` is available for some of the most known packaging tools. In particular:
* [`Conan`](https://bintray.com/skypjack/conan/entt%3Askypjack/_latestVersion),
the C/C++ Package Manager for Developers.
* [`Conan`](https://github.com/conan-io/conan-center-index), the C/C++ Package
Manager for Developers.
* [`vcpkg`](https://github.com/Microsoft/vcpkg), Microsoft VC++ Packaging
Tool.<br/>
You can download and install `EnTT` in just a few simple steps:
```
$ git clone https://github.com/Microsoft/vcpkg.git
$ cd vcpkg
$ ./bootstrap-vcpkg.sh
$ ./vcpkg integrate install
$ vcpkg install entt
```
The `EnTT` port in `vcpkg` is kept up to date by Microsoft team members and
community contributors.<br/>
If the version is out of date, please
[create an issue or pull request](https://github.com/Microsoft/vcpkg) on the
`vcpkg` repository.
* [`Homebrew`](https://github.com/skypjack/homebrew-entt), the missing package
manager for macOS.<br/>
Available as a homebrew formula. Just type the following to install it:
```
brew install skypjack/entt/entt
```
* [`vcpkg`](https://github.com/Microsoft/vcpkg/tree/master/ports/entt),
Microsoft VC++ Packaging Tool.
* [`build2`](https://build2.org), build toolchain for developing and packaging C
and C++ code.<br/>
In order to use the [`entt`](https://cppget.org/entt) package in a `build2`
project, add the following line or a similar one to the `manifest` file:
```
depends: entt ^3.0.0
```
Also check that the configuration refers to a valid repository, so that the
package can be found by `build2`:
* [`cppget.org`](https://cppget.org), the open-source community central
repository, accessible as `https://pkg.cppget.org/1/stable`.
* [Package source repository](https://github.com/build2-packaging/entt):
accessible as either `https://github.com/build2-packaging/entt.git` or
`ssh://git@github.com/build2-packaging/entt.git`.
Feel free to [report issues](https://github.com/build2-packaging/entt) with
this package.
Both can be used with `bpkg add-repo` or added in a project
`repositories.manifest`. See the official
[documentation](https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml#guide-repositories)
for more details.
Consider this list a work in progress and help me to make it longer.
@@ -349,7 +382,7 @@ I can't promise that each and every contribution will be accepted, but I can
assure that I'll do my best to take them all seriously.
If you decide to participate, please see the guidelines for
[contributing](docs/md/CONTRIBUTING.md) before to create issues or pull
[contributing](CONTRIBUTING.md) before to create issues or pull
requests.<br/>
Take also a look at the
[contributors list](https://github.com/skypjack/entt/blob/master/AUTHORS) to
@@ -360,14 +393,14 @@ know who has participated so far.
# License
Code and documentation Copyright (c) 2017-2019 Michele Caini.<br/>
Logo Copyright (c) 2018-2019 Richard Caseres.
Code and documentation Copyright (c) 2017-2021 Michele Caini.<br/>
Colorful logo Copyright (c) 2018-2021 Richard Caseres.
Code released under
[the MIT license](https://github.com/skypjack/entt/blob/master/LICENSE).
[the MIT license](https://github.com/skypjack/entt/blob/master/LICENSE).<br/>
Documentation released under
[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).<br/>
Logo released under
All logos released under
[CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
<!--
@@ -375,34 +408,10 @@ Logo released under
-->
# Support
## Patreon
Become a [patron](https://www.patreon.com/bePatron?c=1772573) and get access to
extra content, help me spend more time on the projects you love and create new
ones for you. Your support will help me to continue the work done so far and
make it more professional and feature-rich every day.<br/>
It takes very little to
[become a patron](https://www.patreon.com/bePatron?c=1772573) and thus help the
software you use every day. Don't miss the chance.
## Donation
Developing and maintaining `EnTT` takes some time and lots of coffee. I'd like
to add more and more functionalities in future and turn it in a full-featured
solution.<br/>
If you want to support this project, you can offer me an espresso. I'm from
Italy, we're used to turning the best coffee ever in code. If you find that
it's not enough, feel free to support me the way you prefer.<br/>
Take a look at the donation button at the top of the page for more details or
just click [here](https://www.paypal.me/skypjack).
## Hire me
If you start using `EnTT` and need help, if you want a new feature and want me
to give it the highest priority, if you have any other reason to contact me:
do not hesitate. I'm available for hiring.<br/>
Feel free to take a look at my [profile](https://github.com/skypjack) and
contact me by mail.
If you want to support this project, you can
[offer me](https://github.com/users/skypjack/sponsorship) an espresso.<br/>
If you find that it's not enough, feel free to
[help me](https://www.paypal.me/skypjack) the way you prefer.
<!--
@endcond TURN_OFF_DOXYGEN
-->

62
TODO
View File

@@ -1,28 +1,40 @@
* long term feature: templated generic vm
* long term feature: shared_ptr less locator
* long term feature: shared_ptr less resource cache
* long term feature: shared_ptr less locator and resource cache
* custom allocators and EnTT allocator-aware in general (long term feature, I don't actually need it at the moment) - see #22
* debugging tools (#60): the issue online already contains interesting tips on this, look at it
* runner proposal: https://en.wikipedia.org/wiki/Fork%E2%80%93join_model https://slide-rs.github.io/specs/03_dispatcher.html
* work stealing job system (see #100)
* meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects
* allow for built-in parallel each if possible
* work stealing job system (see #100) + mt scheduler based on const awareness for types
* allow to replace std:: with custom implementations
* remove runtime views, welcome reflection and what about snapshot?
* empty components model allows for shared components and prefabs unity-like
- each with entity return the shared component multiple times, one per entity that refers to it
- each components only return actual component, so shared components are returned only once
* types defined at runtime that refer to the same compile-time type (but to different pools) are possible, the library is almost there
* add take functionality, eg registry.take(entity, other); where it takes the entity and all its components from registry and move them to other
* add opaque input iterators to views and groups that return tuples <entity, T &...> (proxy), multi-pass guaranteed
* add fast lane for raw iterations, extend mt doc to describe allowed add/remove with pre-allocations on fast lanes
* review sparse set to allow customization (mix pack in the spec, base is position only)
- non-owning groups can iterate pages and skip empty ones, this should mitigate the lack of the packed array
* review 64 bit id: user defined area + dedicated member on the registry to set it
* early out in views using bitmasks with bloom filter like access based on modulus
- standard each, use bitmask to speed up the whole thing and avoid accessing the pools to test for the page
- iterator based each with a couple of iterators passed from outside (use bitmask + has)
* stable component handle that isn't affected by reallocations
* multi component registry::remove and some others?
* move CONTRIBUTING.md within doc (for GitHub)
* reactive systems
* add examples (and credits) from @alanjfs :)
* static reflection, hint: template<> meta_type_t<Type>: meta_descriptor<name, func..., props..., etc...> (see #342)
* update documentation for meta, it contains less than half of the actual feature
* custom pools example:
- lockless fully concurrent ro/rw pool with free lists
- multi instance
- tables
- enable/disable component
- spatial query
- runtime types pool
- off-line/off-memory/remote
- ...
WIP:
* HP: paginate pools
* HP: headless (sparse set only) view
* HP: pass the registry to pools, basic poly storage should have only component member
* HP: make view pack work also with groups, make packs input iterator only, add view adapter for external sources
* HP: write documentation for custom storages and views!!
* HP: any/poly: configurable sbo size, compile-time policies like sbo-required.
* HP: registry: use a poly object for pools, no more pool_data type.
* HP: make runtime views use opaque storage and therefore return also elements.
* HP: poly: support for data members
* add exclude-only views to combine with packs
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
* view pack: plain function as an alias for operator|, reverse iterators, rbegin and rend
* pagination doesn't work nicely across boundaries probably, give it a look. RO operations are fine, adding components maybe not.
* add observer functions aside observer class
* snapshot: support for range-based archives
* update snapshot documentation to describe alternatives
* page size 0 -> page less mode
* add example: 64 bit ids with 32 bits reserved for users' purposes
* add meta dynamic cast (search base for T in parent, we have the meta type already)
* make meta base/conv node work with storage/any and deprecate/remove meta_base, meta_conv, ...

1
WORKSPACE Normal file
View File

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

View File

@@ -1,25 +0,0 @@
# can use variables like {build} and {branch}
version: 1.0.{build}
image: Visual Studio 2017
environment:
BUILD_DIR: "%APPVEYOR_BUILD_FOLDER%\\build"
platform:
- Win32
configuration:
- Release
before_build:
- cd %BUILD_DIR%
- cmake .. -DBUILD_TESTING=ON -DBUILD_LIB=ON -DCMAKE_CXX_FLAGS=/W1 -G"Visual Studio 15 2017"
after_build:
- ctest -C Release -j4
build:
parallel: true
project: build/entt.sln
verbosity: minimal

View File

@@ -1,6 +0,0 @@
set(ENTT_VERSION "@PROJECT_VERSION@")
set(ENTT_INCLUDE_DIRS "@CMAKE_CURRENT_SOURCE_DIR@/src")
if(NOT CMAKE_VERSION VERSION_LESS "3.0")
include("${CMAKE_CURRENT_LIST_DIR}/EnTTTargets.cmake")
endif()

View File

@@ -1,11 +1,5 @@
set(ENTT_VERSION "@PROJECT_VERSION@")
@PACKAGE_INIT@
set_and_check(ENTT_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
if(NOT CMAKE_VERSION VERSION_LESS "3.0")
include("${CMAKE_CURRENT_LIST_DIR}/EnTTTargets.cmake")
endif()
set(EnTT_VERSION "@PROJECT_VERSION@")
include("${CMAKE_CURRENT_LIST_DIR}/EnTTTargets.cmake")
check_required_components("@PROJECT_NAME@")

View File

@@ -1,19 +0,0 @@
project(cereal-download NONE)
cmake_minimum_required(VERSION 3.2)
include(ExternalProject)
ExternalProject_Add(
cereal
GIT_REPOSITORY https://github.com/USCiLab/cereal.git
GIT_TAG v1.2.2
DOWNLOAD_DIR ${CEREAL_DEPS_DIR}
TMP_DIR ${CEREAL_DEPS_DIR}/tmp
STAMP_DIR ${CEREAL_DEPS_DIR}/stamp
SOURCE_DIR ${CEREAL_DEPS_DIR}/src
BINARY_DIR ${CEREAL_DEPS_DIR}/build
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

View File

@@ -1,19 +0,0 @@
project(duktape-download NONE)
cmake_minimum_required(VERSION 3.2)
include(ExternalProject)
ExternalProject_Add(
duktape
GIT_REPOSITORY https://github.com/svaarala/duktape-releases.git
GIT_TAG v2.2.0
DOWNLOAD_DIR ${DUKTAPE_DEPS_DIR}
TMP_DIR ${DUKTAPE_DEPS_DIR}/tmp
STAMP_DIR ${DUKTAPE_DEPS_DIR}/stamp
SOURCE_DIR ${DUKTAPE_DEPS_DIR}/src
BINARY_DIR ${DUKTAPE_DEPS_DIR}/build
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

View File

@@ -1,19 +0,0 @@
project(googletest-download NONE)
cmake_minimum_required(VERSION 3.2)
include(ExternalProject)
ExternalProject_Add(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG master
DOWNLOAD_DIR ${GOOGLETEST_DEPS_DIR}
TMP_DIR ${GOOGLETEST_DEPS_DIR}/tmp
STAMP_DIR ${GOOGLETEST_DEPS_DIR}/stamp
SOURCE_DIR ${GOOGLETEST_DEPS_DIR}/src
BINARY_DIR ${GOOGLETEST_DEPS_DIR}/build
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
TEST_COMMAND ""
)

View File

@@ -1,11 +0,0 @@
#ifndef ENTT_CONFIG_VERSION_H
#define ENTT_CONFIG_VERSION_H
#define ENTT_VERSION "@PROJECT_VERSION@"
#define ENTT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define ENTT_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define ENTT_VERSION_PATCH @PROJECT_VERSION_PATCH@
#endif // ENTT_CONFIG_VERSION_H

View File

@@ -4,24 +4,19 @@ from cpt.packager import ConanMultiPackager
import os
if __name__ == "__main__":
username = os.getenv("GITHUB_ACTOR")
tag_version = os.getenv("GITHUB_REF")
tag_package = os.getenv("GITHUB_REPOSITORY")
login_username = os.getenv("CONAN_LOGIN_USERNAME")
username = os.getenv("CONAN_USERNAME")
tag_version = os.getenv("CONAN_PACKAGE_VERSION", os.getenv("TRAVIS_TAG"))
package_version = tag_version.replace("v", "")
package_name_unset = "SET-CONAN_PACKAGE_NAME-OR-CONAN_REFERENCE"
package_name = os.getenv("CONAN_PACKAGE_NAME", package_name_unset)
package_version = tag_version.replace("refs/tags/v", "")
package_name = tag_package.replace("skypjack/", "")
reference = "{}/{}".format(package_name, package_version)
channel = os.getenv("CONAN_CHANNEL", "stable")
upload = os.getenv("CONAN_UPLOAD")
stable_branch_pattern = os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+.*")
test_folder = os.getenv("CPT_TEST_FOLDER", os.path.join("conan", "test_package"))
upload_only_when_stable = os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True)
header_only = os.getenv("CONAN_HEADER_ONLY", False)
pure_c = os.getenv("CONAN_PURE_C", False)
disable_shared = os.getenv("CONAN_DISABLE_SHARED_BUILD", "False")
if disable_shared == "True" and package_name == package_name_unset:
raise Exception("CONAN_DISABLE_SHARED_BUILD: True is only supported when you define CONAN_PACKAGE_NAME")
builder = ConanMultiPackager(username=username,
reference=reference,
@@ -31,10 +26,7 @@ if __name__ == "__main__":
stable_branch_pattern=stable_branch_pattern,
upload_only_when_stable=upload_only_when_stable,
test_folder=test_folder)
if header_only == "False":
builder.add_common_builds(pure_c=pure_c)
else:
builder.add()
builder.add()
filtered_builds = []
for settings, options, env_vars, build_requires, reference in builder.items:

View File

@@ -43,8 +43,8 @@ int main() {
for(auto i = 0; i < 10; ++i) {
auto entity = registry.create();
registry.assign<position>(entity, i * 1.f, i * 1.f);
if(i % 2 == 0) { registry.assign<velocity>(entity, i * .1f, i * .1f); }
registry.emplace<position>(entity, i * 1.f, i * 1.f);
if(i % 2 == 0) { registry.emplace<velocity>(entity, i * .1f, i * .1f); }
}
update(dt, registry);

View File

@@ -19,5 +19,9 @@ class EnttConan(ConanFile):
self.copy(pattern="LICENSE", dst="licenses")
self.copy(pattern="*", dst="include", src="src", keep_path=True)
def package_info(self):
if not self.in_local_cache:
self.cpp_info.includedirs = ["src"]
def package_id(self):
self.info.header_only()

2
deps/.gitignore vendored
View File

@@ -1,2 +0,0 @@
*
!.gitignore

View File

@@ -2,6 +2,7 @@
# Doxygen configuration (documentation)
#
set(DOXY_DEPS_DIRECTORY ${EnTT_SOURCE_DIR}/deps)
set(DOXY_SOURCE_DIRECTORY ${EnTT_SOURCE_DIR}/src)
set(DOXY_DOCS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
set(DOXY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
@@ -13,18 +14,9 @@ add_custom_target(
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxy.cfg
WORKING_DIRECTORY ${EnTT_SOURCE_DIR}
VERBATIM
SOURCES doxy.in
)
install(
DIRECTORY ${DOXY_OUTPUT_DIRECTORY}/html
DESTINATION share/${PROJECT_NAME}-${PROJECT_VERSION}/
)
add_custom_target(
docs_aob
SOURCES
md/CONTRIBUTING.md
dox/extra.dox
md/config.md
md/core.md
md/entity.md
md/faq.md
@@ -33,7 +25,14 @@ add_custom_target(
md/locator.md
md/meta.md
md/process.md
md/references.md
md/resource.md
md/signal.md
dox/extra.dox
md/unreal.md
doxy.in
)
install(
DIRECTORY ${DOXY_OUTPUT_DIRECTORY}/html
DESTINATION share/${PROJECT_NAME}-${PROJECT_VERSION}/
)

View File

@@ -1,4 +1,4 @@
# Doxyfile 1.8.13
# Doxyfile 1.8.20
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -17,11 +17,11 @@
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
# that follow. The default is UTF-8 which is also the encoding used for all text
# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
# for the list of possible encodings.
# This tag specifies the encoding used for all characters in the configuration
# file that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See
# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
@@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all generated output in the proper direction.
# Possible values are: None, LTR, RTL and Context.
# The default value is: None.
OUTPUT_TEXT_DIRECTION = None
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
@@ -179,6 +187,16 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
# such as
# /***************
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
# Javadoc-style will behave just like regular comments and it will not be
# interpreted by doxygen.
# The default value is: NO.
JAVADOC_BANNER = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
@@ -199,6 +217,14 @@ QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
# By default Python docstrings are displayed as preformatted text and doxygen's
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
# doxygen's special commands can be used and the contents of the docstring
# documentation blocks is shown as doxygen documentation.
# The default value is: YES.
PYTHON_DOCSTRING = YES
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
@@ -226,16 +252,15 @@ TAB_SIZE = 4
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines.
# newlines (in the resulting output). You can put ^^ in the value part of an
# alias to insert a newline as if a physical newline was in the original file.
# When you need a literal { or } or , in the value part of an alias you have to
# escape them by means of a backslash (\), this can lead to conflicts with the
# commands \{ and \} for these it is advised to use the version @{ and @} or use
# a double escape (\\{ and \\})
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
# A mapping has the form "name=value". For example adding "class=itcl::class"
# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
@@ -264,17 +289,26 @@ OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
# sources only. Doxygen will then generate output that is more tailored for that
# language. For instance, namespaces will be presented as modules, types will be
# separated into more groups, etc.
# The default value is: NO.
OPTIMIZE_OUTPUT_SLICE = NO
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
# Fortran. In the later case the parser tries to guess whether the code is fixed
# or free formatted code, this is the default for Fortran type files), VHDL. For
# instance to make doxygen treat .inc files as Fortran files (default is PHP),
# and .f files as C (default is Fortran), use: inc=Fortran f=C.
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran type files). For instance to make doxygen treat .inc files
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
@@ -285,7 +319,7 @@ EXTENSION_MAPPING =
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
# documentation. See https://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
@@ -297,10 +331,10 @@ MARKDOWN_SUPPORT = YES
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
# Minimum value: 0, maximum value: 99, default value: 0.
# Minimum value: 0, maximum value: 99, default value: 5.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
TOC_INCLUDE_HEADINGS = 4
TOC_INCLUDE_HEADINGS = 5
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
@@ -327,7 +361,7 @@ BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
# will parse them like normal C++ but will assume all classes use public instead
# of private inheritance when no explicit protection keyword is present.
# The default value is: NO.
@@ -413,6 +447,19 @@ TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
# speed. At this moment only the input processing can be done using multiple
# threads. Since this is still an experimental feature the default is set to 1,
# which efficively disables parallel processing. Please report any issues you
# encounter. Generating dot graphs in parallel is controlled by the
# DOT_NUM_THREADS setting.
# Minimum value: 0, maximum value: 32, default value: 1.
NUM_PROC_THREADS = 1
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
@@ -433,6 +480,12 @@ EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
# methods of a class will be included in the documentation.
# The default value is: NO.
EXTRACT_PRIV_VIRTUAL = NO
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
@@ -487,8 +540,8 @@ HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# (class|struct|union) declarations. If set to NO, these declarations will be
# included in the documentation.
# declarations. If set to NO, these declarations will be included in the
# documentation.
# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
@@ -511,7 +564,7 @@ INTERNAL_DOCS = NO
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
# (including Cygwin) and Mac users are advised to set this option to NO.
# The default value is: system dependent.
CASE_SENSE_NAMES = YES
@@ -698,7 +751,7 @@ LAYOUT_FILE =
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
@@ -743,7 +796,8 @@ WARN_IF_DOC_ERROR = YES
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation.
# parameter documentation, but not about the absence of documentation. If
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
# The default value is: NO.
WARN_NO_PARAMDOC = YES
@@ -781,13 +835,13 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched.
INPUT = @DOXY_SOURCE_DIRECTORY@ \
@DOXY_DOCS_DIRECTORY@ \
@PROJECT_SOURCE_DIR@/README.md
@DOXY_DOCS_DIRECTORY@ \
@PROJECT_SOURCE_DIR@/README.md
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: http://www.gnu.org/software/libiconv) for the list of
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# The default value is: UTF-8.
@@ -804,8 +858,10 @@ INPUT_ENCODING = UTF-8
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf.
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen
# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,
# *.vhdl, *.ucf, *.qsf and *.ice.
FILE_PATTERNS = *.h \
*.hpp \
@@ -825,7 +881,7 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
EXCLUDE = @DOXY_DEPS_DIRECTORY@
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@@ -963,7 +1019,7 @@ INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
# function all documented functions referencing it will be listed.
# entity all documented functions referencing it will be listed.
# The default value is: NO.
REFERENCED_BY_RELATION = NO
@@ -995,12 +1051,12 @@ SOURCE_TOOLTIPS = YES
# If the USE_HTAGS tag is set to YES then the references to source code will
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
# source browser. The htags tool is part of GNU's global source tagging system
# (see http://www.gnu.org/software/global/global.html). You will need version
# (see https://www.gnu.org/software/global/global.html). You will need version
# 4.8.6 or higher.
#
# To use it do the following:
# - Install the latest version of global
# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
@@ -1028,7 +1084,7 @@ VERBATIM_HEADERS = YES
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse-libclang=ON option for CMake.
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
@@ -1041,6 +1097,19 @@ CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the directory containing a file called compile_commands.json. This
# file is the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
# options used when the source files were built. This is equivalent to
# specifying the "-p" option to a clang tool, such as clang-check. These options
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
# will be added as well.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
CLANG_DATABASE_PATH =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
@@ -1159,7 +1228,7 @@ HTML_EXTRA_FILES =
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
@@ -1195,6 +1264,17 @@ HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will
# consists of multiple levels of tabs that are statically embedded in every HTML
# page. Disable this option to support browsers that do not have JavaScript,
# like the Qt help browser.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_DYNAMIC_MENUS = YES
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
@@ -1218,13 +1298,13 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: http://developer.apple.com/tools/xcode/), introduced with
# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
@@ -1263,7 +1343,7 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
@@ -1294,7 +1374,7 @@ CHM_FILE =
HHC_LOCATION =
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the master .chm file (NO).
# (YES) or that it should be included in the main .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
@@ -1339,7 +1419,7 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1347,7 +1427,7 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
# folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1356,7 +1436,7 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1364,7 +1444,7 @@ QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1372,7 +1452,7 @@ QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
@@ -1456,6 +1536,17 @@ TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
# the HTML output. These images will generally look nicer at scaled resolutions.
# Possible values are: png (the default) and svg (looks nicer but requires the
# pdf2svg or inkscape tool).
# The default value is: png.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FORMULA_FORMAT = png
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
@@ -1465,7 +1556,7 @@ EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
@@ -1476,8 +1567,14 @@ FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
FORMULA_MACROFILE =
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# http://www.mathjax.org) which uses client side Javascript for the rendering
# https://www.mathjax.org) which uses client side JavaScript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
@@ -1504,11 +1601,11 @@ MATHJAX_FORMAT = HTML-CSS
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from http://www.mathjax.org before deployment.
# The default value is: http://cdn.mathjax.org/mathjax/latest.
# MathJax from https://www.mathjax.org before deployment.
# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
@@ -1547,7 +1644,7 @@ MATHJAX_CODEFILE =
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
# implemented using a web server instead of a web client using JavaScript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
@@ -1566,7 +1663,7 @@ SERVER_BASED_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/).
# Xapian (see: https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@@ -1579,7 +1676,7 @@ EXTERNAL_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: http://xapian.org/). See the section "External Indexing and
# Xapian (see: https://xapian.org/). See the section "External Indexing and
# Searching" for details.
# This tag requires that the tag SEARCHENGINE is set to YES.
@@ -1631,21 +1728,35 @@ LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
# Note that when enabling USE_PDFLATEX this option is only used for generating
# bitmaps for formulas in the HTML output, but not in the Makefile that is
# written to the output directory.
# The default file is: latex.
# Note that when not enabling USE_PDFLATEX the default is latex when enabling
# USE_PDFLATEX the default is pdflatex and when in the later case latex is
# chosen this is overwritten by pdflatex. For specific output languages the
# default can have been set differently, this depends on the implementation of
# the output language.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
LATEX_CMD_NAME =
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
# Note: This tag is used in the Makefile / make.bat.
# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
# (.tex).
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
# generate index for LaTeX. In case there is no backslash (\) as first character
# it will be automatically added in the LaTeX code.
# Note: This tag is used in the generated output file (.tex).
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
# The default value is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_MAKEINDEX_CMD = makeindex
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
@@ -1730,9 +1841,11 @@ LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
# the PDF file directly from the LaTeX files. Set this option to YES, to get a
# higher quality PDF documentation.
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
# files. Set this option to YES, to get a higher quality PDF documentation.
#
# See also section LATEX_CMD_NAME for selecting the engine.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1766,7 +1879,7 @@ LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
@@ -1780,6 +1893,14 @@ LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the
# LATEX_OUTPUT directory will be used.
# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_EMOJI_DIRECTORY =
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
@@ -1819,9 +1940,9 @@ COMPACT_RTF = NO
RTF_HYPERLINKS = NO
# Load stylesheet definitions from file. Syntax is similar to doxygen's config
# file, i.e. a series of assignments. You only have to provide replacements,
# missing definitions are set to their default value.
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# configuration file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
@@ -1830,8 +1951,8 @@ RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
# Set optional variables used in the generation of an RTF document. Syntax is
# similar to doxygen's config file. A template extensions file can be generated
# using doxygen -e rtf extensionFile.
# similar to doxygen's configuration file. A template extensions file can be
# generated using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
@@ -1917,6 +2038,13 @@ XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
# namespace members in file scope as well, matching the HTML output.
# The default value is: NO.
# This tag requires that the tag GENERATE_XML is set to YES.
XML_NS_MEMB_FILE_SCOPE = NO
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
@@ -1949,9 +2077,9 @@ DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sf.net) file that captures the
# structure of the code including all documentation. Note that this feature is
# still experimental and incomplete at the moment.
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
# the structure of the code including all documentation. Note that this feature
# is still experimental and incomplete at the moment.
# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
@@ -2011,7 +2139,7 @@ ENABLE_PREPROCESSING = YES
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = NO
MACRO_EXPANSION = YES
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
@@ -2118,12 +2246,6 @@ EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
# The PERL_PATH should be the absolute path and name of the perl script
# interpreter (i.e. the result of 'which perl').
# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
@@ -2137,15 +2259,6 @@ PERL_PATH = /usr/bin/perl
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
# command. Doxygen will then run the mscgen tool (see:
# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
@@ -2164,7 +2277,7 @@ HIDE_UNDOC_RELATIONS = YES
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
# The default value is: YES.
# The default value is: NO.
HAVE_DOT = YES
@@ -2320,9 +2433,7 @@ DIRECTORY_GRAPH = YES
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
# png:gdiplus:gdiplus.
# The default value is: png.

101
docs/md/config.md Normal file
View File

@@ -0,0 +1,101 @@
# Crash Course: configuration
<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents
* [Introduction](#introduction)
* [Definitions](#definitions)
* [ENTT_NOEXCEPT](#entt_noexcept)
* [ENTT_USE_ATOMIC](#entt_use_atomic)
* [ENTT_ID_TYPE](#entt_id_type)
* [ENTT_PAGE_SIZE](#entt_page_size)
* [ENTT_ASSERT](#entt_assert)
* [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/>
In the vast majority of cases, users will have no interest in changing the
default parameters. For all other cases, the list of possible configurations
with which it's possible to adjust the behavior of the library at runtime can be
found below.
# Definitions
All options are intended as parameters to the compiler (or user-defined macros
within the compilation units, if preferred).<br/>
Each parameter can result in internal library definitions. It's not recommended
to try to also modify these definitions, since there is no guarantee that they
will remain stable over time unlike the options below.
## ENTT_NOEXCEPT
The purpose of this parameter is to suppress the use of `noexcept` by this
library.<br/>
To do this, simply define the variable without assigning any value to it.
## 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
thread-safe by means of this definition.
## ENTT_ID_TYPE
`entt::id_type` is directly controlled by this definition and widely used within
the library.<br/>
By default, its type is `std::uint32_t`. However, users can define a different
default type if necessary.
## ENTT_PAGE_SIZE
As is known, the ECS module of `EnTT` is based on _sparse sets_. What is less
known perhaps is that these are paged to reduce memory consumption in some
corner cases.<br/>
The default size of a page is 32kB but users can adjust it if appropriate. In
all case, the chosen value **must** be a power of 2.
## ENTT_ASSERT
For performance reasons, `EnTT` doesn't use exceptions or any other control
structures. In fact, it offers many features that result in undefined behavior
if not used correctly.<br/>
To get around this, the library relies on a lot of asserts for the purpose of
detecting errors in debug builds. By default, it uses `assert` internally, but
users are allowed to overwrite its behavior by setting this variable.
### 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_NO_ETO
In order to reduce memory consumption and increase performance, empty types are
never stored by the ECS module of `EnTT`.<br/>
Use this variable to treat these types like all others and therefore to create a
dedicated storage for them.
## ENTT_STANDARD_CPP
`EnTT` mixes non-standard language features with others that are perfectly
compliant to offer some of its functionalities.<br/>
This definition will prevent 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

@@ -6,11 +6,25 @@
# Table of Contents
* [Introduction](#introduction)
* [Compile-time identifiers](#compile-time-identifiers)
* [Runtime identifiers](#runtime-identifiers)
* [Unique sequential identifiers](#unique-sequential-identifiers)
* [Compile-time generator](#compile-time-generator)
* [Runtime generator](#runtime-generator)
* [Hashed strings](#hashed-strings)
* [Wide characters](wide-characters)
* [Conflicts](#conflicts)
* [Monostate](#monostate)
* [Any as in any type](#any-as-in-any-type)
* [Type support](#type-support)
* [Type info](#type-info)
* [Almost unique identifiers](#almost-unique-identifiers)
* [Type traits](#type-traits)
* [Size of](#size-of)
* [Is applicable](#is-applicable)
* [Constness as](#constness-as)
* [Member class type](#member-class-type)
* [Integral constant](#integral-constant)
* [Tag](#tag)
* [Utilities](#utilities)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@@ -22,19 +36,20 @@ of the library itself.<br/>
Hardly users will include these features in their code, but it's worth
describing what `EnTT` offers so as not to reinvent the wheel in case of need.
# Compile-time identifiers
# Unique sequential identifiers
Sometimes it's useful to be able to give unique identifiers to types at
compile-time.<br/>
There are plenty of different solutions out there and I could have used one of
them. However, I decided to spend my time to define a compact and versatile tool
Sometimes it's useful to be able to give unique, sequential numeric identifiers
to types either at compile-time or runtime.<br/>
There are plenty of different solutions for this out there and I could have used
one of them. However, I decided to spend my time to define a couple of tools
that fully embraces what the modern C++ has to offer.
The _result of my efforts_ is the `identifier` class template:
## Compile-time generator
To generate sequential numeric identifiers at compile-time, `EnTT` offers the
`identifier` class template:
```cpp
#include <ident.hpp>
// defines the identifiers for the given types
using id = entt::identifier<a_type, another_type>;
@@ -52,14 +67,14 @@ default:
}
```
This is all what the class template has to offer: a `type` inline variable that
contains a numerical identifier for the given type. It can be used in any
context where constant expressions are required.
This is all what this class template has to offer: a `type` inline variable that
contains a numeric identifier for the given type. It can be used in any context
where constant expressions are required.
As long as the list remains unchanged, identifiers are also guaranteed to be the
same for every run. In case they have been used in a production environment and
a type has to be removed, one can just use a placeholder to left the other
identifiers unchanged:
As long as the list remains unchanged, identifiers are also guaranteed to be
stable across different runs. In case they have been used in a production
environment and a type has to be removed, one can just use a placeholder to left
the other identifiers unchanged:
```cpp
template<typename> struct ignore_type {};
@@ -71,35 +86,30 @@ using id = entt::identifier<
>;
```
A bit ugly to see, but it works at least.
Perhaps a bit ugly to see in a codebase but it gets the job done at least.
# Runtime identifiers
## Runtime generator
Sometimes it's useful to be able to give unique identifiers to types at
runtime.<br/>
There are plenty of different solutions out there and I could have used one of
them. In fact, I adapted the most common one to my requirements and used it
extensively within the entire library.
It's the `family` class. Here is an example of use directly from the
entity-component system:
To generate sequential numeric identifiers at runtime, `EnTT` offers the
`family` class template:
```cpp
using component_family = entt::family<struct internal_registry_component_family>;
// defines a custom generator
using id = entt::family<struct my_tag>;
// ...
template<typename Component>
component_type component() const noexcept {
return component_family::type<Component>;
}
const auto a_type_id = id::type<a_type>;
const auto another_type_id = id::type<another_type>;
```
This is all what a _family_ has to offer: a `type` inline variable that contains
a numerical identifier for the given type.
a numeric identifier for the given type.<br/>
The generator is customizable, so as to get different _sequences_ for different
purposes if needed.
Please, note that identifiers aren't guaranteed to be the same for every run.
Indeed it mostly depends on the flow of execution.
Please, note that identifiers aren't guaranteed to be stable across different
runs. Indeed it mostly depends on the flow of execution.
# Hashed strings
@@ -108,7 +118,8 @@ human-readable identifiers in the codebase while using their numeric
counterparts at runtime, thus without affecting performance.<br/>
The class has an implicit `constexpr` constructor that chews a bunch of
characters. Once created, all what one can do with it is getting back the
original string or converting it into a number.<br/>
original string through the `data` member function or converting the instance
into a number.<br/>
The good part is that a hashed string can be used wherever a constant expression
is required and no _string-to-number_ conversion will take place at runtime if
used carefully.
@@ -127,9 +138,47 @@ There is also a _user defined literal_ dedicated to hashed strings to make them
more user-friendly:
```cpp
using namespace entt::literals;
constexpr auto str = "text"_hs;
```
To use it, remember that all user defined literals in `EnTT` are enclosed in the
`entt::literals` namespace. Therefore, the entire namespace or selectively the
literal of interest must be explicitly included before each use, a bit like
`std::literals`.<br/>
Finally, in case users need to create hashed strings at runtime, this class also
offers the necessary functionalities:
```cpp
std::string orig{"text"};
// create a full-featured hashed string...
entt::hashed_string str{orig.c_str()};
// ... or compute only the unique identifier
const auto hash = entt::hashed_string::value(orig.c_str());
```
This possibility shouldn't be exploited in tight loops, since the computation
takes place at runtime and no longer at compile-time and could therefore impact
performance to some degrees.
## Wide characters
The hashed string has a design that is close to that of an `std::basic_string`.
It means that `hashed_string` is nothing more than an alias for
`basic_hashed_string<char>`. For those who want to use the C++ type for wide
character representation, there exists also the alias `hashed_wstring` for
`basic_hashed_string<wchar_t>`.<br/>
In this case, the user defined literal to use to create hashed strings on the
fly is `_hws`:
```cpp
constexpr auto str = L"text"_hws;
```
Note that the hash type of the `hashed_wstring` is the same of its counterpart.
## Conflicts
The hashed string class uses internally FNV-1a to compute the numeric
@@ -165,3 +214,430 @@ entt::monostate<"mykey"_hs>{} = 42;
const bool b = entt::monostate<"mykey"_hs>{};
const int i = entt::monostate<entt::hashed_string{"mykey"}>{};
```
# Any as in any type
`EnTT` comes with its own `any` type. It may seem redundant considering that
C++17 introduced `std::any`, but it is not (hopefully).<br/>
In fact, the _type_ returned by an `std::any` is a const reference to an
`std::type_info`, an implementation defined class that's not something everyone
wants to see in a software. Furthermore, there is no way to connect it with the
type system of the library and therefore with its integrated RTTI support.<br/>
Note that this class is largely used internally by the library itself.
The API is very similar to that of its most famous counterpart, mainly because
this class serves the same purpose of being an opaque container for any type of
value.<br/>
Instances of `any` also minimize the number of allocations by relying on a well
known technique called _small buffer optimization_ and a fake vtable.
Creating an object of the `any` type, whether empty or not, is trivial:
```cpp
// an empty container
entt::any empty{};
// a container for an int
entt::any any{0};
// in place construction
entt::any in_place{std::in_place_type<int>, 42};
```
The `any` class takes the burden of destroying the contained element when
required, regardless of the storage strategy used for the specific object.<br/>
Furthermore, an instance of `any` is not tied to an actual type. Therefore, the
wrapper will be reconfigured by assigning it an object of a different type than
the one contained, so as to be able to handle the new instance.<br/>
When in doubt about the type of object contained, the `type` member function of
`any` returns an instance of `type_info` associated with its element, or an
invalid `type_info` object if the container is empty. The type is also used
internally when comparing two `any` objects:
```cpp
if(any == empty) { /* ... */ }
```
In this case, before proceeding with a comparison, it's verified that the _type_
of the two objects is actually the same.<br/>
Refer to the `EnTT` type system documentation for more details on how
`type_info` works and on possible risks of a comparison.
A particularly interesting feature of this class is that it can also be used as
an opaque container for const and non-const references:
```cpp
int value = 42;
// reference construction
entt::any any{std::ref(value)};
entt::any cany{std::cref(value)};
// alias construction
int value = 42;
entt::any in_place{std::in_place_type<int &>, &value};
```
In other words, whenever `any` intercepts a `reference_wrapper` or is explicitly
told that users want to construct an alias, it acts as a pointer to the original
instance rather than making a copy of it or moving it internally. The contained
object is never destroyed and users must ensure that its lifetime exceeds that
of the container.<br/>
Similarly, it's possible to create non-owning copies of `any` from an existing
object:
```cpp
// aliasing constructor
entt::any ref = as_ref(other);
```
In this case, it doesn't matter if the original container actually holds an
object or acts already as a reference for unmanaged elements, the new instance
thus created won't create copies and will only serve as a reference for the
original item.<br/>
This means that, starting from the example above, both `ref` and` other` will
point to the same object, whether it's initially contained in `other` or already
an unmanaged element.
As a side note, it's worth mentioning that, while everything works transparently
when it comes to non-const references, there are some exceptions when it comes
to const references.<br/>
In particular, the `data` member function invoked on a non-const instance of
`any` that wraps a const reference will return a null pointer in all cases.
To cast an instance of `any` to a type, the library offers a set of `any_cast`
functions in all respects similar to their most famous counterparts.<br/>
The only difference is that, in the case of `EnTT`, these won't raise exceptions
but will only trigger an assert in debug mode, otherwise resulting in undefined
behavior in case of misuse in release mode.
# Type support
`EnTT` provides some basic information about types of all kinds.<br/>
It also offers additional features that are not yet available in the standard
library or that will never be.
## Type info
The `type_info` class isn't a drop-in replacement for `std::type_info` but can
provide similar information which are not implementation defined and don't
require to enable RTTI.<br/>
Therefore, they can sometimes be even more reliable than those obtained
otherwise.
A type info object is an opaque class that is also copy and move constructible.
This class is returned by the `type_id` function template:
```cpp
auto info = entt::type_id<a_type>();
```
These are the information made available by this object:
* The unique, sequential identifier associated with a given type:
```cpp
auto index = entt::type_id<a_type>().seq();
```
This is also an alias for the following:
```cpp
auto index = entt::type_seq<a_type>::value();
```
The returned value isn't guaranteed to be stable across different runs.
However, it can be very useful as index in associative and unordered
associative containers or for positional accesses in a vector or an array.
So as not to conflict with the other tools available, the `family` class isn't
used to generate these indexes. Therefore, the numeric identifiers returned by
the two tools may differ.<br/>
On the other hand, this leaves users with full powers over the `family` class
and therefore the generation of custom runtime sequences of indices for their
own purposes, if necessary.
An external generator can also be used if needed. In fact, `type_seq` can be
specialized by type and is also _sfinae-friendly_ in order to allow more
refined specializations such as:
```cpp
template<typename Type>
struct entt::type_seq<Type, std::void_d<decltype(Type::index())>> {
static entt::id_type value() ENTT_NOEXCEPT {
return Type::index();
}
};
```
Note that indexes **must** still be generated sequentially in this case.<br/>
The tool is widely used within `EnTT`. Generating indices not sequentially
would break an assumption and would likely lead to undesired behaviors.
* The hash value associated with a given type:
```cpp
auto hash = entt::type_id<a_type>().hash();
```
This is also an alias for the following:
```cpp
auto hash = entt::type_hash<a_type>::value();
```
In general, the `value` function exposed by `type_hash` is also `constexpr`
but this isn't guaranteed for all compilers and platforms (although it's valid
with the most well-known and popular ones).<br/>
The `hash` function offered by the type info object isn't `constexpr` in any
case instead.
This function **can** use non-standard features of the language for its own
purposes. This makes it possible to provide compile-time identifiers that
remain stable across different runs.<br/>
In all cases, users can prevent the library from using these features by means
of the `ENTT_STANDARD_CPP` definition. In this case, there is no guarantee
that identifiers remain stable across executions. Moreover, they are generated
at runtime and are no longer a compile-time thing.
As for `type_seq`, also `type_hash` is a _sfinae-friendly_ class that can be
specialized in order to customize its behavior globally or on a per-type or
per-traits basis.
* The name associated with a given type:
```cpp
auto name = entt::type_id<my_type>().name();
```
This is also an alias for the following:
```cpp
auto name = entt::type_name<a_type>::value();
```
The name associated with a type is extracted from some information generally
made available by the compiler in use. Therefore, it may differ depending on
the compiler and may be empty in the event that this information isn't
available.<br/>
For example, given the following class:
```cpp
struct my_type { /* ... */ };
```
The name is `my_type` when compiled with GCC or CLang and `struct my_type`
when MSVC is in use.<br/>
Most of the time the name is also retrieved at compile-time and is therefore
always returned through an `std::string_view`. Users can easily access it and
modify it as needed, for example by removing the word `struct` to standardize
the result. `EnTT` won't do this for obvious reasons, since it requires
copying and creating a new string potentially at runtime.
This function **can** use non-standard features of the language for its own
purposes. Users can prevent the library from using non-standard features by
means of the `ENTT_STANDARD_CPP` definition. In this case, the name will be
empty by default.
As for `type_seq`, also `type_name` is a _sfinae-friendly_ class that can be
specialized in order to customize its behavior globally or on a per-type or
per-traits basis.
### Almost unique identifiers
Since the default non-standard, compile-time implementation of `type_hash` makes
use of hashed strings, it may happen that two types are assigned the same hash
value.<br/>
In fact, although this is quite rare, it's not entirely excluded.
Another case where two types are assigned the same identifier is when classes
from different contexts (for example two or more libraries loaded at runtime)
have the same fully qualified name. In this case, also `type_name` will return
the same value for the two types.<br/>
Fortunately, there are several easy ways to deal with this:
* The most trivial one is to define the `ENTT_STANDARD_CPP` macro. Runtime
identifiers don't suffer from the same problem in fact. However, this solution
doesn't work well with a plugin system, where the libraries aren't linked.
* Another possibility is to specialize the `type_name` class for one of the
conflicting types, in order to assign it a custom identifier. This is probably
the easiest solution that also preserves the feature of the tool.
* A fully customized identifier generation policy (based for example on enum
classes or preprocessing steps) may represent yet another option.
These are just some examples of possible approaches to the problem but there are
many others. As already mentioned above, since users have full control over
their types, this problem is in any case easy to solve and should not worry too
much.<br/>
In all likelihood, it will never happen to run into a conflict anyway.
## Type traits
A handful of utilities and traits not present in the standard template library
but which can be useful in everyday life.<br/>
This list **is not** exhaustive and contains only some of the most useful
classes. Refer to the inline documentation for more information on the features
offered by this module.
### Size of
The standard operator `sizeof` complains when users provide it for example with
function or incomplete types. On the other hand, it's guaranteed that its result
is always nonzero, even if applied to an empty class type.<br/>
This small class combines the two and offers an alternative to `sizeof` that
works under all circumstances, returning zero if the type isn't supported:
```cpp
const auto size = entt::size_of_v<void>;
```
### Is applicable
The standard library offers the great `std::is_invocable` trait in several
forms. This takes a function type and a series of arguments and returns true if
the condition is satisfied.<br/>
Moreover, users are also provided with `std::apply`, a tool for combining
invocable elements and tuples of arguments.
It would therefore be a good idea to have a variant of `std::is_invocable` that
also accepts its arguments in the form of a tuple-like type, so as to complete
the offer:
```cpp
constexpr bool result = entt::is_applicable<Func, std::tuple<a_type, another_type>>;
```
This trait is built on top of `std::is_invocable` and does nothing but unpack a
tuple-like type and simplify the code at the call site.
### Constness as
An utility to easily transfer the constness of a type to another type:
```cpp
// type is const dst_type because of the constness of src_type
using type = entt::constness_as_t<dst_type, const src_type>;
```
The trait is subject to the rules of the language. Therefore, for example,
transferring constness between references won't give the desired effect.
### Member class type
The `auto` template parameter introduced with C++17 made it possible to simplify
many class templates and template functions but also made the class type opaque
when members are passed as template arguments.<br/>
The purpose of this utility is to extract the class type in a few lines of code:
```cpp
template<typename Member>
using clazz = entt::member_class_t<Member>;
```
### Integral constant
Since `std::integral_constant` may be annoying because of its form that requires
to specify both a type and a value of that type, there is a more user-friendly
shortcut for the creation of integral constants.<br/>
This shortcut is the alias template `entt::integral_constant`:
```cpp
constexpr auto constant = entt::integral_constant<42>;
```
Among the other uses, when combined with a hashed string it helps to define tags
as human-readable _names_ where actual types would be required otherwise:
```cpp
constexpr auto enemy_tag = entt::integral_constant<"enemy"_hs>;
registry.emplace<enemy_tag>(entity);
```
### Tag
Since `id_type` is very important and widely used in `EnTT`, there is a more
user-friendly shortcut for the creation of integral constants based on it.<br/>
This shortcut is the alias template `entt::tag`.
If used in combination with hashed strings, it helps to use human-readable names
where types would be required otherwise. As an example:
```cpp
registry.emplace<entt::tag<"enemy"_hs>>(entity);
```
However, this isn't the only permitted use. Literally any value convertible to
`id_type` is a good candidate, such as the named constants of an unscoped enum.
# Utilities
It's not possible to escape the temptation to add utilities of some kind to a
library. In fact, `EnTT` also provides a handful of tools to simplify the
life of developers:
* `entt::identity`: the identity function object that will be available with
C++20. It returns its argument unchanged and nothing more. It's useful as a
sort of _do nothing_ function in template programming.
* `entt::overload`: a tool to disambiguate different overloads from their
function type. It works with both free and member functions.<br/>
Consider the following definition:
```cpp
struct clazz {
void bar(int) {}
void bar() {}
};
```
This utility can be used to get the _right_ overload as:
```cpp
auto *member = entt::overload<void(int)>(&clazz::bar);
```
The line above is literally equivalent to:
```cpp
auto *member = static_cast<void(clazz:: *)(int)>(&clazz::bar);
```
Just easier to read and shorter to type.
* `entt::overloaded`: a small class template used to create a new type with an
overloaded `operator()` from a bunch of lambdas or functors.<br/>
As an example:
```cpp
entt::overloaded func{
[](int value) { /* ... */ },
[](char value) { /* ... */ }
};
func(42);
func('c');
```
Rather useful when doing metaprogramming and having to pass to a function a
callable object that supports multiple types at once.
* `entt::y_combinator`: this is a C++ implementation of **the** _y-combinator_.
If it's not clear what it is, there is probably no need for this utility.<br/>
Below is a small example to show its use:
```cpp
entt::y_combinator gauss([](const auto &self, auto value) -> unsigned int {
return value ? (value + self(value-1u)) : 0;
});
const auto result = gauss(3u);
```
Maybe convoluted at a first glance but certainly effective. Unfortunately,
the language doesn't make it possible to do much better.
This is a rundown of the (actually few) utilities made available by `EnTT`. The
list will probably grow over time but the size of each will remain rather small,
as has been the case so far.

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,12 @@
* [Introduction](#introduction)
* [FAQ](#faq)
* [Why is my debug build on Windows so slow?](#why-is-my-debug-build-on-windows-so-slow)
* [How can I represent hierarchies with my components?](#how-can-i-represent-hierarchies-with-my-components)
* [Custom entity identifiers: yay or nay?](#custom-entity-identifiers-yay-or-nay)
* [Warning C4307: integral constant overflow](#warning-C4307-integral-constant-overflow)
* [Warning C4003: the min, the max and the macro](#warning-C4003-the-min-the-max-and-the-macro)
* [The standard and the non-copyable types](#the-standard-and-the-non-copyable-types)
* [Which functions trigger which signals](#which-functions-trigger-which-signals)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@@ -45,11 +51,168 @@ First of all, there are two things to do in a Windows project:
* 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_DISABLE_ASSERT` should be defined to disable internal
checks made by `EnTT` in debug. These are asserts introduced to help the users,
but require to access to the underlying containers and therefore risk ruining
the performance in some cases.
Moreover, the macro `ENTT_ASSERT` should be redefined to disable internal checks
made by `EnTT` in debug:
```cpp
#define ENTT_ASSERT(...) ((void)0)
```
These asserts are introduced to help the users but they require to access to the
underlying containers and therefore risk ruining the performance in some cases.
With these changes, debug performance should increase enough for most cases. If
you want something more, you can 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.
I tried to describe some of the techniques that fit well with the model of
`EnTT`. [Here](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) is the
first post of a series that tries to explore the problem. More will probably
come in future.
Long story short, you can always define a tree where the nodes expose implicit
lists of children by means of the following type:
```cpp
struct relationship {
std::size_t children{};
entt::entity first{entt::null};
entt::entity prev{entt::null};
entt::entity next{entt::null};
entt::entity parent{entt::null};
// ... other data members ...
};
```
The sort functionalities of `EnTT`, the groups and all the other features of the
library can help then to get the best in terms of data locality and therefore
performance from this component.
## Custom entity identifiers: yay or nay?
Custom entity identifiers are definitely a good idea in two cases at least:
* If `std::uint32_t` is too large or isn't large enough for your purposes, since
this is the underlying type of `entt::entity`.
* If you want to avoid conflicts when using multiple registries.
Identifiers can be defined through enum classes and custom types for which a
specialization of `entt_traits` exists. For this purpose, `entt_traits` is also
defined as a _sfinae-friendly_ class template.<br/>
In fact, this is a definition equivalent to that of `entt::entity`:
```cpp
enum class entity: std::uint32_t {};
```
In theory, integral types can also be used as entity identifiers, even though
this may break in future and isn't recommended in general.
## 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/>
First of all, I want to reassure you: it's expected and harmless. However, it
can be annoying.
To suppress it and if you don't want to suppress all the other warnings as well,
here is a workaround in the form of a macro:
```cpp
#if defined(_MSC_VER)
#define HS(str) __pragma(warning(suppress:4307)) entt::hashed_string{str}
#else
#define HS(str) entt::hashed_string{str}
#endif
```
With an example of use included:
```cpp
constexpr auto identifier = HS("my/resource/identifier");
```
Thanks to [huwpascoe](https://github.com/huwpascoe) for the courtesy.
## Warning C4003: the min, the max and the macro
On Windows, a header file defines two macros `min` and `max` which may result in
conflicts with their counterparts in the standard library and therefore in
errors during compilation.
It's a pretty big problem but fortunately it's not a problem of `EnTT` and there
is a fairly simple solution to it.<br/>
It consists in defining the `NOMINMAX` macro before to include any other header
so as to get rid of the extra definitions:
```cpp
#define NOMINMAX
```
Please refer to [this](https://github.com/skypjack/entt/issues/96) issue for
more details.
## The standard and the non-copyable types
`EnTT` uses internally the trait `std::is_copy_constructible_v` to check if a
component is actually copyable. 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.
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:
```cpp
struct type {
std::vector<std::unique_ptr<action>> vec;
};
```
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:
```cpp
struct type {
type(const type &) = delete;
type & operator=(const type &) = delete;
std::vector<std::unique_ptr<action>> vec;
};
```
Unfortunately, this will also disable aggregate initialization.
## Which functions trigger which signals
The `registry` class offers three signals that are emitted following specific
operations. Maybe not everyone knows what these operations are, though.<br/>
If this isn't clear, below you can find a _vademecum_ for this purpose:
* `on_created` is invoked when a component is first added (neither modified nor
replaced) to an entity.
* `on_update` is called whenever an existing component is modified or replaced.
* `on_destroyed` is called when a component is explicitly or implicitly removed
from an entity.
Among the most controversial functions can be found `emplace_or_replace` and
`destroy`. However, following the above rules, it's quite simple to know what
will happen.<br/>
In the first case, `on_created` is invoked if the entity has not the component,
otherwise the latter is replaced and therefore `on_update` is triggered. As for
the second case, components are removed from their entities and thus freed when
they are recycled. It means that `on_destroyed` is triggered for every component
owned by the entity that is destroyed.

View File

@@ -5,151 +5,123 @@
-->
# Table of Contents
* [Introduction](#introduction)
* [Named types and traits class](#named-types-and-traits-class)
* [Do not mix types](#do-not-mix-types)
* [Macros, macros everywhere](#macros-macros-everywhere)
* [Conflicts](#conflicts)
* [Allocations: the dark side of the force](#allocations-the-dark-side-of-the-force)
* [Working across boundaries](#working-across-boundaries)
* [The EnTT way](#the-entt-way)
* [Meta context](#meta-context)
* [Memory management](#memory-management)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
# Working across boundaries
`EnTT` has historically had a limit when used across boundaries on Windows in
general and on GNU/Linux when default visibility was set to _hidden_. The
limitation is due mainly to a custom utility used to assign unique, sequential
identifiers to different types. Unfortunately, this tool is used by several core
classes (the `registry` among the others) that are thus almost unusable across
boundaries.<br/>
The reasons for that are beyond the purposes of this document. However, the good
news is that `EnTT` also offers now a way to overcome this limit and to push
things across boundaries without problems when needed.
general and on GNU/Linux when default visibility was set to hidden. The
limitation was mainly due to a custom utility used to assign unique, sequential
identifiers with different types.<br/>
Fortunately, nowadays using `EnTT` across boundaries is easier. However, use in
standalone applications is favored and user intervention is otherwise required.
# Named types and traits class
## The EnTT way
To allow a type to work properly across boundaries when used by a class that
requires to assign unique identifiers to types, users must specialize a class
template to literally give a compile-time name to the type itself.<br/>
The name of the class template is `name_type_traits` and the specialization must
be such that it exposes a static constexpr data member named `value` having type
either `ENTT_ID_TYPE` or `entt::hashed_string::hash_type`. Its value is the user
defined unique identifier assigned to the specific type.<br/>
Identifiers are not to be sequentially generated in this case.
Many classes in `EnTT` make extensive use of type erasure for their purposes.
This isn't a problem in itself (in fact, it's the basis of an API so convenient
to use). However, a way is needed to recognize the objects whose type has been
erased on the other side of a boundary.<br/>
The `type_hash` class template is how identifiers are generated and thus made
available to the rest of the library. The `type_seq` class template makes all
types _indexable_ instead, so as to speed up the lookup.
As an example:
In general, these classes don't arouse much interest. The only exceptions are:
* When a conflict between identifiers occurs (definitely uncommon though) or
when the default solution proposed by `EnTT` isn't suitable for the user's
purposes.<br/>
The section dedicated to `type_info` contains all the details to get around
the problem in a concise and elegant way. Please refer to the specific
documentation.
* When working with linked libraries that also export all required symbols.<br/>
Compile definitions `ENTT_API_EXPORT` and `ENTT_API_IMPORT` should be passed
respectively where there is a need to import or export the symbols defined by
`EnTT`, so as to make everything work nicely across boundaries.
* When working with plugins or shared libraries that don't export any symbol. In
this case, `type_seq` confuses the other classes by giving potentially wrong
information to them.<br/>
To avoid problems, it's required to provide a custom generator. Briefly, it's
necessary to specialize the `type_seq` class and make it point to a context
that is also shared between the main application and the dynamically loaded
libraries or plugins.<br/>
This will make the type system available to the whole application, not just to
a particular tool such as the registry or the dispatcher. It means that a call
to `type_seq::value()` will return the same identifier for the same type from
both sides of a boundary and can be used reliably for any purpose.
For anyone who needs more details, the test suite contains multiple examples
covering the most common cases (see the `lib` directory for all details).<br/>
It goes without saying that it's impossible to cover all the possible cases.
However, what is offered should hopefully serve as a basis for all of them.
## Meta context
The runtime reflection system deserves a special mention when it comes to using
it across boundaries.<br/>
Since it's linked already to a static context to which the 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.
Sharing a context is trivial though. First of all, the local one must be
acquired in the main space:
```cpp
struct my_type { /* ... */ };
template<>
struct entt::named_type_traits<my_type> {
static constexpr auto value = "my_type"_hs;
};
entt::meta_ctx ctx{};
```
Because of the rules of the language, the specialization must reside in the
global namespace or in the `entt` namespace. There is no way to change this rule
unfortunately, because it doesn't depend on the library itself.
The good aspect of this approach is that it's not intrusive at all. The other
way around was in fact forcing users to inherit all their classes from a common
base. Something to avoid, at least from my point of view.<br/>
However, despite the fact that it's not intrusive, it would be great if it was
also easier to use and a bit less error-prone. This is why a bunch of macros
exist to ease defining named types.
## Do not mix types
Someone might think that this trick is valid only for the types to push across
boundaries. This isn't how things work. In fact, the problem is more complex
than that.<br/>
As a rule of thumb, users should never mix named and non-named types. Whenever
a type is given a name, all the types must be given a name. As an example,
consider the `registry` class template: in case it is pushed across boundaries,
all the types of components should be assigned a name to avoid subtle bugs.
Indeed, this constraint can be relaxed in many cases. However, it is difficult
to define a general rule to follow that is not the most stringent, unless users
know exactly what they are doing. Therefore, I won't elaborate on giving further
details on the topic.
# Macros, macros everywhere
The library comes with a set of predefined macros to use to declare named types
or export already existing ones. In particular:
* `ENTT_NAMED_TYPE` can be used to assign a name to already existing types. This
macro must be used in the global namespace even when the types to be named are
not.
```cpp
ENTT_NAMED_TYPE(my_type)
ENTT_NAMED_TYPE(ns::another_type)
```
* `ENTT_NAMED_STRUCT` can be used to define and export a struct at the same
time. It accepts also an optional namespace in which to define the given type.
This macro must be used in the global namespace.
```cpp
ENTT_NAMED_STRUCT(my_type, { /* struct definition */})
ENTT_NAMED_STRUCT(ns, another_type, { /* struct definition */})
```
* `ENTT_NAMED_CLASS` can be used to define and export a class at the same
time. It accepts also an optional namespace in which to define the given type.
This macro must be used in the global namespace.
```cpp
ENTT_NAMED_CLASS(my_type, { /* class definition */})
ENTT_NAMED_CLASS(ns, another_type, { /* class definition */})
```
Nested namespaces are supported out of the box as well in all cases. As an
example:
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:
```cpp
ENTT_NAMED_STRUCT(nested::ns, my_type, { /* struct definition */})
entt::meta_ctx::bind(ctx);
```
These macros can be used to avoid specializing the `named_type_traits` class
template. In all cases, the name of the class is used also as a seed to generate
the compile-time unique identifier.
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:
## Conflicts
```cpp
entt::meta_ctx::bind{entt::meta_ctx{});
```
When using macros, unique identifiers are 32/64 bit integers generated by
hashing strings during compilation. Therefore, conflicts are rare but still
possible. In case of conflicts, everything simply will get broken at runtime and
the strangest things will probably take place.<br/>
Unfortunately, there is no safe way to prevent it. If this happens, it will be
enough to give a different value to one of the conflicting types to solve the
problem. To do this, users can either assign a different name to the class or
directly define a specialization for the `named_type_traits` class template.
This is allowed because local and global contexts are separated. Therefore, it's
always possible to make the local context the current one again.
# Allocations: the dark side of the force
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.
As long as `EnTT` won't support custom allocators, another problem with
allocations will remain alive instead. This is in fact easily solved, or at
least it is if one knows it.
## Memory Management
To allow users to add types dynamically, the library makes extensive use of type
erasure techniques and dynamic allocations for pools (whether they are for
components, events or anything else). The problem occurs when, for example, a
registry is created on one side of a boundary and a pool is dynamically created
on the other side. In the best case, everything will crash at the exit, while at
worst it will do so at runtime.<br/>
To avoid problems, the pools must be generated from the same side of the
boundary where the object that owns them is also created. As an example, when
the registry is created in the main executable and used across boundaries for a
given type of component, the pool for that type must be created before passing
around the registry itself. To do this is fortunately quite easy, since it is
sufficient to invoke any of the methods that involve the given type (continuing
the example with the registry, a call to `reserve` or `size` is more than
enough).
There is another subtle problem due to memory management that can lead to
headaches.<br/>
It can occur where there are pools of objects (such as components or events)
dynamically created on demand. This is usually not a problem when working with
linked libraries that rely on the same dynamic runtime. However, it can occur in
the case of plugins or statically linked runtimes.
Maybe one day some dedicated methods will be added that do nothing but create a
pool for a given type. Until now it has been preferred to keep the API cleaner
as they are not strictly necessary.
As an example, imagine creating an instance of `registry` in the main executable
and sharing it with a plugin. If the latter starts working with a component that
is unknown to the former, a dedicated pool is created within the registry on
first use.<br/>
As one can guess, this pool is instantiated on a different side of the boundary
from the `registry`. Therefore, the instance is now managing memory from
different spaces and this can quickly lead to crashes if not properly addressed.
To overcome the risk, it's recommended to use well-defined interfaces that make
fundamental types pass through the boundaries, isolating the instances of the
`EnTT` classes from time to time and as appropriate.<br/>
Refer to the test suite for some examples, read the documentation available
online about this type of issues or consult someone who has already had such
experiences to avoid problems.

View File

@@ -3,8 +3,8 @@
`EnTT` is widely used in private and commercial applications. I cannot even
mention most of them because of some signatures I put on some documents time
ago. Fortunately, there are also people who took the time to implement open
source projects based on `EnTT` and did not hold back when it came to
documenting them.
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
@@ -17,48 +17,118 @@ I hope this list can grow much more in the future:
* [Minecraft](https://minecraft.net/en-us/attribution/) by
[Mojang](https://mojang.com/): of course, **that** Minecraft, see the
open source attributions page for more details.
* [Minecraft 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.
* [TiltedOnline](https://github.com/tiltedphoques/TiltedOnline) by
[Tilted Phoques](https://github.com/tiltedphoques): Skyrim and Fallout 4 mod
to play online.
* [Antkeeper](https://github.com/antkeeper/antkeeper-source): an ant colony
simulation [game](https://antkeeper.com/).
* [War of Rights](https://store.steampowered.com/app/424030/War_of_Rights/): a
multiplayer game set during the perilous days of the American Civil War, by
Campfire Games.
* [Openblack](https://github.com/openblack/openblack): open source
reimplementation of the game _Black & White_ (2001).
* [Land of the Rair](https://github.com/LandOfTheRair/core2): the new backend
of [a retro-style MUD](https://rair.land/) for the new age.
* [Face Smash](https://play.google.com/store/apps/details?id=com.gamee.facesmash):
a game to play with your face.
* [EnTT Pacman](https://github.com/Kerndog73/EnTT-Pacman): an example of how
to make Pacman with `EnTT`.
* [Wacman](https://github.com/carlfindahl/wacman): a pacman clone with OpenGL.
* [Classic Tower Defence](https://github.com/kerndog73/Classic-Tower-Defence):
a tiny little tower defence game featuring a homemade font.
[Check it out](https://indi-kernick.itch.io/classic-tower-defence).
* [The Machine](https://github.com/Kerndog73/The-Machine): a box pushing
puzzler with logic gates and other cool stuff.
[Check it out](https://indi-kernick.itch.io/the-machine-web-version).
* [EnttPong](https://github.com/reworks/EnttPong): an example of how to make
Pong with `EnTT`.
* [EnttPong 2.0](https://github.com/DomRe/EnttPong): a basic game made to
showcase different parts of EnTT and C++17.
* [Randballs](https://github.com/gale93/randballs): simple `SFML` and `EnTT`
playground.
* [EnTT Tower Defense](https://github.com/Daivuk/tddod): a data oriented tower
defense example.
* [EnTT Breakout](https://github.com/vblanco20-1/entt-breakout): simple
example of a breakout game, using `SDL` and `EnTT`.
* [Arcade puzzle game with EnTT](https://github.com/MasonRG/ArcadePuzzleGame):
arcade puzzle game made in C++ using the `SDL2` and `EnTT` libraries.
* [Snake with EnTT](https://github.com/MasonRG/SnakeGame): simple snake game
made in C++ with the `SDL2` and `EnTT` libraries.
* [Mirrors lasers and robots](https://github.com/guillaume-haerinck/imac-tower-defense):
a small tower defense game based on mirror orientation.
* [PopHead](https://github.com/SPC-Some-Polish-Coders/PopHead/): 2D, Zombie,
RPG game made from scratch in C++.
* [Robotligan](https://github.com/Trisslotten/robotligan): multiplayer
football game.
* [DungeonSlayer](https://github.com/alohaeee/DungeonSlayer): 2D game made
from scratch in C++.
* [3DGame](https://github.com/kwarkGorny/3DGame): 2.5D top-down space shooter.
* Engines/Frameworks:
* [The Forge](https://github.com/ConfettiFX/The-Forge) by
[Confett](http://www.confettispecialfx.com/): a cross-platform rendering
framework.
* Engines and the like:
* [Aether Engine](https://hadean.com/spatial-simulation/)
[v1.1+](https://docs.hadean.com/v1.1/Licenses/) by
[Hadean](https://hadean.com/): a library designed for spatially partitioning
agent-based simulations.
* [Fling Engine](https://github.com/flingengine/FlingEngine): a Vulkan game
engine with a focus on data oriented design.
* [NovusCore](https://github.com/novuscore/NovusCore): a modern take on World
of Warcraft emulation.
* [Chrysalis](https://github.com/ivanhawkes/Chrysalis): action RPG SDK for
CRYENGINE games.
* [LM-Engine](https://github.com/Lawrencemm/LM-Engine): the Vim of game
engines.
* [Edyn](https://github.com/xissburg/edyn): a real-time physics engine
organized as an ECS.
* [MushMachine](https://github.com/MadeOfJelly/MushMachine): engine...
vrooooommm.
* [Antara Gaming SDK](https://github.com/KomodoPlatform/antara-gaming-sdk):
the Komodo Gaming Software Development Kit.
* [Apparently](https://teamwisp.github.io/credits/)
[Wisp](https://teamwisp.github.io/product/) by
[Team Wisp](https://teamwisp.github.io/): an advanced real-time ray tracing
renderer built for the demands of video game artists.
* [starlight](https://github.com/DomRe/starlight): game programming framework
using `Allegro`, `Lua` and modern C++.
* [Apparently](https://github.com/JosiahWI/qub3d-libdeps)
[Qub3d](https://qub3d.org/): because blocks should be open source.
* [shiva](https://github.com/Milerius/shiva): modern C++ engine with
modularity.
* [ImGui/EnTT editor](https://github.com/Green-Sky/imgui_entt_entity_editor):
a drop-in, single-file entity editor for `EnTT` that uses `ImGui` as
graphical backend (with
[demo code](https://github.com/Green-Sky/imgui_entt_entity_editor_demo)).
* [SgOgl](https://github.com/stwe/SgOgl): a game engine library for OpenGL
developed for educational purposes.
* [Lumos](https://github.com/jmorton06/Lumos): game engine written in C++
using OpenGL and Vulkan.
* [Silvanus](https://github.com/hobbyistmaker/silvanus): Silvanus Fusion 360
Box Generator.
* [Lina Engine](https://github.com/inanevin/LinaEngine): an open-source,
modular, tiny and fast C++ game engine, aimed to develop 3D desktop games.
* Emulators:
* [NovusCore](https://github.com/novuscore/NovusCore): A modern take on World
of Warcraft emulation.
* Articles 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.
* [Game Engine series](https://www.youtube.com/c/TheChernoProject/videos) by
[The Cherno](https://github.com/TheCherno) (not only about `EnTT` but also
on the use of an ECS in general):
- [Intro to EnTT](https://www.youtube.com/watch?v=D4hz0wEB978).
- [Entities and Components](https://www.youtube.com/watch?v=-B1iu4QJTUc).
- [The ENTITY Class](https://www.youtube.com/watch?v=GfSzeAcsBb0).
- [Camera Systems](https://www.youtube.com/watch?v=ubZn7BlrnTU).
- [Scene Camera](https://www.youtube.com/watch?v=UKVFRRufKzo).
- [Native Scripting](https://www.youtube.com/watch?v=iIUhg88MK5M).
- [Native Scripting (now with virtual functions!)](https://www.youtube.com/watch?v=1cHEcrIn8IQ).
- [Scene Hierarchy Panel](https://www.youtube.com/watch?v=wziDnE8guvI).
- [Properties Panel](https://www.youtube.com/watch?v=NBpB0qscF3E).
- [Camera Component UI](https://www.youtube.com/watch?v=RIMt_6agUiU).
- [Drawing Component UI](https://www.youtube.com/watch?v=u3yq8s3KuSE).
- [Transform Component UI](https://www.youtube.com/watch?v=8JqcXYbzPJc).
- [Adding/Removing Entities and Components UI](https://www.youtube.com/watch?v=PsyGmsIgp9M).
- [Saving and Loading Scenes](https://www.youtube.com/watch?v=IEiOP7Y-Mbc).
- ... And so on.
[Check out](https://www.youtube.com/channel/UCQ-W1KE9EYfdxhL6S4twUNw) the
_Game Engine Series_ by The Cherno for more videos.
* [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
@@ -69,20 +139,52 @@ I hope this list can grow much more in the future:
giant space battle.
* [Conan Adventures (SFML and EnTT in C++)](https://leinnan.github.io/blog/conan-adventuressfml-and-entt-in-c.html):
create projects in modern C++ using `SFML`, `EnTT`, `Conan` and `CMake`.
* [Adding EnTT ECS to Chrysalis](https://www.tauradius.com/post/adding-an-ecs-to-chrysalis/):
a blog entry (and its
[follow-up](https://www.tauradius.com/post/chrysalis-update-2020-08-02/))
about the integration of `EnTT` into `Chrysalis`, an action RPG SDK for
CRYENGINE games.
* [Creating Minecraft in One Week with C++ and Vulkan](https://vazgriz.com/189/creating-minecraft-in-one-week-with-c-and-vulkan/):
a crack at recreating Minecraft in one week using a custom C++ engine and
Vulkan ([code included](https://github.com/vazgriz/VoxelGame)).
* [Ability Creator](https://www.erichildebrand.net/blog/ability-creator-project-retrospect).
project retrospect by [Eric Hildebrand](https://www.erichildebrand.net/).
* Any Other Business:
* The [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
* [ArcGIS Runtime SDKs](https://developers.arcgis.com/arcgis-runtime/) by
[Esri](https://www.esri.com/): they use `EnTT` for the internal ECS and the
cross platform C++ rendering engine. The SDKs are utilized by a lot of
enterprise custom apps, as well as by Esri for its own public applications
such as
[Explorer](https://play.google.com/store/apps/details?id=com.esri.explorer),
[Collector](https://play.google.com/store/apps/details?id=com.esri.arcgis.collector)
and
[Navigator](https://play.google.com/store/apps/details?id=com.esri.navigator).
* [FASTSUITE Edition 2](https://www.fastsuite.com/en_EN/fastsuite/fastsuite-edition-2.html)
by [Cenit](http://www.cenit.com/en_EN/about-us/overview.html): they use
`EnTT` to drive their simulation, that is, the communication between robot
controller emulator and renderer.
* [Ragdoll](https://ragdolldynamics.com/): real-time physics for Autodesk Maya
2020.
* [AtomicDEX](https://github.com/KomodoPlatform/atomicDEX-Desktop): a secure
wallet and non-custodial decentralized exchange rolled into one application.
* [Apparently](https://www.linkedin.com/in/skypjack/)
[NIO](https://www.nio.io/): there was a collaboration to make some changes
to `EnTT`, at the time used for internal projects.
* [Apparently](https://www.linkedin.com/jobs/view/architekt-c%2B%2B-at-tieto-1219512333/)
[Tieto](https://www.tieto.com/): they published a job post where `EnTT` was
listed on their software stack.
* [Sequentity](https://github.com/alanjfs/sequentity): A MIDI-like
sequencer/tracker for C++ and `ImGui` (with `Magnum` and `EnTT`).
* [EnTT meets Sol2](https://github.com/skaarj1989/entt-meets-sol2): freely
available examples of how to combine `EnTT` and `Sol2`.
* [Godot meets EnTT](https://github.com/portaloffreedom/godot_entt_example/):
a simple example on how to use `EnTT` within
[`Godot`](https://godotengine.org/).
* [Godot and GameNetworkingSockets meet EnTT](https://github.com/portaloffreedom/godot_entt_net_example):
a simple example on how to use `EnTT` and
[`GameNetworkingSockets`](https://github.com/ValveSoftware/GameNetworkingSockets)
within [`Godot`](https://godotengine.org/).
* [MatchOneEntt](https://github.com/mhaemmerle/MatchOneEntt): port of
[Match One](https://github.com/sschmid/Match-One) for `Entitas-CSharp`.
* GitHub contains also

View File

@@ -1,4 +1,4 @@
# Crash Course: reflection system
# Crash Course: runtime reflection system
<!--
@cond TURN_OFF_DOXYGEN
@@ -6,12 +6,16 @@
# Table of Contents
* [Introduction](#introduction)
* [Names and identifiers](#names-and-identifiers)
* [Reflection in a nutshell](#reflection-in-a-nutshell)
* [Any as in any type](#any-as-in-any-type)
* [Enjoy the runtime](#enjoy-the-runtime)
* [Named constants and enums](#named-constants-and-enums)
* [Properties and meta objects](#properties-and-meta-objects)
* [Unregister types](#unregister-types)
* [Any to the rescue](#any-to-the-rescue)
* [Enjoy the runtime](#enjoy-the-runtime)
* [Container support](#container-support)
* [Pointer-like types](#pointer-like-types)
* [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)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@@ -26,30 +30,71 @@ allocations. In one word: unsatisfactory.<br/>
I finally decided to write a built-in, non-intrusive and macro-free runtime
reflection system for `EnTT`. Maybe I didn't do better than others or maybe yes,
time will tell me, but at least I can model this tool around the library to
which it belongs and not vice versa.
which it belongs and not the opposite.
# Names and identifiers
The meta system doesn't force users to rely on the tools provided by the library
when it comes to working with names and identifiers. It does this by offering an
API that works with opaque identifiers that may or may not be generated by means
of a hashed string.<br/>
This means that users can assign any type of identifier to the meta objects, as
long as they are numeric. It doesn't matter if they are generated at runtime, at
compile-time or with custom functions.
That being said, the examples in the following sections are all based on the
`hashed_string` class as provided by this library. Therefore, where an
identifier is required, it's likely that a user defined literal is used as
follows:
```cpp
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
```
For what it's worth, this is likely completely equivalent to:
```cpp
auto factory = entt::meta<my_type>().type(42);
```
Obviously, human-readable identifiers are more convenient to use and highly
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 _reflect_ a type, the library provides the `reflect` function:
To create a meta node, the library provides the `meta` function that accepts a
type to reflect as a template parameter:
```cpp
auto factory = entt::reflect<my_type>("reflected_type");
auto factory = entt::meta<my_type>();
```
It accepts the type to reflect as a template parameter and an optional name as
an argument. Names are important because users can retrieve meta types at
runtime by searching for them by name. However, 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 allow
searching the type by name.<br/>
In both cases, the returned value is a factory object to use to continue
building the meta 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:
A factory is such that all its member functions returns the factory itself.
It can be used to extend the reflected type and add the following:
```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:
```cpp
auto factory = entt::meta<my_type>().type();
```
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 returns 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
@@ -59,7 +104,7 @@ It can be used to extend the reflected type and add the following:
Use the `ctor` member function for this purpose:
```cpp
entt::reflect<my_type>("reflected").ctor<int, char>().ctor<&factory>();
entt::meta<my_type>().ctor<int, char>().ctor<&factory>();
```
* _Destructors_. Free functions can be set as destructors of reflected types.
@@ -68,46 +113,55 @@ It can be used to extend the reflected type and add the following:
Use the `dtor` member function for this purpose:
```cpp
entt::reflect<my_type>("reflected").dtor<&destroy>();
entt::meta<my_type>().dtor<&destroy>();
```
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 a client's point of view, all the variables associated with the
reflected type will appear as if they were part of the type itself.<br/>
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:
```cpp
entt::reflect<my_type>("reflected")
.data<&my_type::static_variable>("static")
.data<&my_type::data_member>("member")
.data<&global_variable>("global");
entt::meta<my_type>()
.data<&my_type::static_variable>("static"_hs)
.data<&my_type::data_member>("member"_hs)
.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_. 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:
```cpp
entt::meta<my_type>().data<nullptr, &my_type::data_member>("member"_hs);
```
This function requires as an argument the name 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 be set also by means of a couple of functions, namely a
setter and a getter. Setters and getters can be either free functions, member
functions or mixed ones, as long as they respect the required signatures.<br/>
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 a client's point of view, all
the functions associated with the reflected type will appear as if they were
part of the type itself.<br/>
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:
```cpp
entt::reflect<my_type>("reflected")
.func<&my_type::static_function>("static")
.func<&my_type::member_function>("member")
.func<&free_function>("free");
entt::meta<my_type>()
.func<&my_type::static_function>("static"_hs)
.func<&my_type::member_function>("member"_hs)
.func<&free_function>("free"_hs);
```
This function requires as an argument the name to give to the meta function
once created. Users can then access meta functions at runtime by searching for
them by name.
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_.
* _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
@@ -115,7 +169,7 @@ It can be used to extend the reflected type and add the following:
Use the `base` member function for this purpose:
```cpp
entt::reflect<derived_type>("derived").base<base_type>();
entt::meta<derived_type>().base<base_type>();
```
From now on, wherever a `base_type` is required, an instance of `derived_type`
@@ -128,7 +182,7 @@ It can be used to extend the reflected type and add the following:
Use the `conv` member function for this purpose:
```cpp
entt::reflect<double>().conv<int>();
entt::meta<double>().conv<int>();
```
That's all, everything users need to create meta types and enjoy the reflection
@@ -138,43 +192,39 @@ 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.
# Any as in any type
## Any to the rescue
The reflection system comes with its own meta any type. It may seem redundant
since C++17 introduced `std::any`, but it is not.<br/>
In fact, the _type_ returned by an `std::any` is a const reference to an
`std::type_info`, an implementation defined class that's not something everyone
wants to see in a software. Furthermore, the class `std::type_info` suffers from
some design flaws and there is even no way to _convert_ an `std::type_info` into
a meta type, thus linking the two worlds.
The reflection system offers a kind of _extended version_ of the `entt::any`
class (see the core module for more details).<br/>
The purpose is to add some feature on top of those already present, so as to
integrate it with the meta type system without having to duplicate the code.
A meta any object provides an API similar to that of its most famous counterpart
and serves the same purpose of being an opaque container for any type of
value.<br/>
It minimizes the allocations required, which are almost absent thanks to _SBO_
techniques. In fact, unless users deal with _fat types_ and create instances of
them though the reflection system, allocations are at zero.
A meta any object can be created by any other object or as an empty container
to initialize later:
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
objects either upon construction using `std::ref` and `std::cref` or from an
existing instance by means of the `as_ref` function. However, unlike `any`,
`meta_any` treats an empty instance and one initialized with `void` differently:
```cpp
// a meta any object that contains an int
entt::meta_any any{0};
// an empty meta any object
entt::meta_any empty{};
entt::meta_any other{std::in_place_type<void>};
```
It can be constructed or assigned by copy and move and it takes the burden of
destroying the contained object when required.<br/>
A meta any object has a `type` member function that returns the meta type of the
contained value, if any. The member functions `can_cast` and `can_convert` are
used to know if the underlying object has a given type as a base or if it can be
converted implicitly to it. Similarly, `cast` and `convert` do what they promise
and return the expected value.
While `any` treats both objects 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/>
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`.
# Enjoy the runtime
## Enjoy the runtime
Once the web of reflected types has been constructed, it's a matter of using it
at runtime where required.<br/>
@@ -182,30 +232,33 @@ All this has the great merit that, unlike the vast majority of the things
present in this library and closely linked to the compile-time, the reflection
system stands in fact as a non-intrusive tool for the runtime.
To search for a reflected type there are two options: by type or by name. In
both cases, the search can be done by means of the `resolve` function:
To search for a reflected type there are a few options:
```cpp
// search for a reflected type by type
// direct access to a reflected type
auto by_type = entt::resolve<my_type>();
// search for a reflected type by name
auto by_name = entt::resolve("reflected_type");
// lookup of a reflected type by identifier
auto by_id = entt::resolve_id("reflected_type"_hs);
// lookup of a reflected type by type id
auto by_type_id = entt::resolve_type(entt::type_hash<my_type>::value());
```
There exits also a third overload of the `resolve` function to use to iterate
all the reflected types at once:
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:
```cpp
resolve([](auto type) {
for(auto type: entt::resolve()) {
// ...
});
}
```
In all cases, the returned value is an instance of `meta_type`. This type of
objects offer an API to know the _runtime name_ of the type, to iterate all the
meta objects associated with them and even to build or destroy instances of the
underlying type.<br/>
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.
The meta objects that compose a meta type are accessed in the following ways:
@@ -219,56 +272,44 @@ The meta objects that compose a meta type are accessed in the following ways:
The returned type is `meta_ctor` and may be invalid if there is no constructor
that accepts the supplied arguments or at least some types from which they are
derived or to which they can be converted.<br/>
A meta constructor offers an API to know the number of arguments, the expected
meta types and to invoke it, therefore to construct a new instance of the
underlying type.
A meta constructor offers an API to know the number of its arguments and their
expected meta types. Furthermor, it's possible to invoke it and therefore to
construct new instances of the underlying type.
* _Meta destructor_. It's returned by a dedicated function:
* _Meta data_. They are accessed by _name_:
```cpp
auto dtor = entt::resolve<my_type>().dtor();
```
The returned type is `meta_dtor` and may be invalid if there is no custom
destructor set for the given meta type.<br/>
All what a meta destructor has to offer is a way to invoke it on a given
instance. Be aware that the result may not be what is expected.
* _Meta data_. They are accessed by name:
```cpp
auto data = entt::resolve<my_type>().data("member");
auto data = entt::resolve<my_type>().data("member"_hs);
```
The returned type is `meta_data` and may be invalid if there is no meta data
object associated with the given name.<br/>
A meta data object offers an API to query the underlying type (ie to know if
it's a const or a static one), to get the meta type of the variable and to set
or get the contained value.
object associated with the given identifier.<br/>
A meta data object offers an API to query the underlying type (for example, to
know if it's a const or a static one), to get the meta type of the variable
and to set or get the contained value.
* _Meta functions_. They are accessed by name:
* _Meta functions_. They are accessed by _name_:
```cpp
auto func = entt::resolve<my_type>().func("member");
auto func = entt::resolve<my_type>().func("member"_hs);
```
The returned type is `meta_func` and may be invalid if there is no meta
function object associated with the given name.<br/>
A meta function object offers an API to query the underlying type (ie 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 meta any object.
function object associated with the given identifier.<br/>
A meta function object offers an API to query the underlying type (for
example, to know if it's a const or a static function), to know the number of
arguments, the meta return type and the meta types of the parameters. In
addition, a meta function object can be 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:
* _Meta bases_. They are accessed through the _name_ of the base types:
```cpp
auto base = entt::resolve<derived_type>().base("base");
auto base = entt::resolve<derived_type>().base("base"_hs);
```
The returned type is `meta_base` and may be invalid if there is no meta base
object associated with the given name.<br/>
object associated with the given identifier.<br/>
Meta bases aren't meant to be used directly, even though they are freely
accessible. They expose only a few methods to use to know the meta type of the
base class and to convert a raw pointer between types.
@@ -283,47 +324,407 @@ The meta objects that compose a meta type are accessed in the following ways:
conversion function associated with the given type.<br/>
The meta conversion functions are as thin as the meta bases and with a very
similar interface. The sole difference is that they return a newly created
instance wrapped in a meta any object when they convert between different
instance wrapped in a `meta_any` object when they convert between different
types.
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:
```cpp
auto func = entt::resolve<my_type>().func("member");
if(func) {
if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
// ...
}
```
Furthermore, all meta objects with the exception of meta destructors can be
iterated through an overload that accepts a callback through which to return
them. As an example:
Furthermore, all them are also returned by specific overloads that provide the
caller with iterable objects. As an example:
```cpp
entt::resolve<my_type>().data([](auto data) {
for(auto data = entt::resolve<my_type>().data()) {
// ...
});
}
```
A meta type can also be used to `construct` or `destroy` actual instances of the
underlying type.<br/>
A meta type can be 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 returns a `meta_any` object that may or
may not be initialized, depending on whether a suitable constructor has been
found or not. On the other side, the `destroy` member function accepts instances
of `meta_any` as well as actual objects by reference and invokes the registered
destructor if any or a default one.<br/>
Be aware that the result of a call to `destroy` may not be what is expected.
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.
There is no object that wraps the destructor of a meta type nor a `destroy`
member function in its API. The reason is quickly explained: 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/>
Therefore, exposing destructors would be pointless and would add nothing to the
library itself.
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 official documentation to get the best out of this powerful tool.
read the inline documentation to get the best out of this powerful tool.
# Named constants and enums
## Container support
The meta module supports containers of all types out of the box.<br/>
Moreover, _containers_ doesn't necessarily mean those offered by the C++
standard library. In fact, user defined data structures can also work with the
meta system in many cases.
To make a container be recognized by the meta module, 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_
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
_associative containers_.
It's important to include the header file `container.hpp` to make these
specializations available to the compiler when needed.<br/>
The same file also contains many examples for the users that are interested in
making their own containers available to the meta system.
When a specialization of the `meta_sequence_container_traits` class exists, the
meta system treats the wrapped type as a sequence container. In a similar way,
a type is treated as an associative container if a specialization of the
`meta_associative_container_traits` class is found for it.<br/>
Proxy objects are returned by dedicated members of the `meta_any` class. The
following is a deliberately verbose example of how users can access a proxy
object for a sequence container:
```cpp
std::vector<int> vec{1, 2, 3};
entt::meta_any any{std::ref(vec)};
if(any.type().is_sequence_container()) {
if(auto view = any.as_sequence_container(); view) {
// ...
}
}
```
The method to use to get a proxy object for associative containers is
`as_associative_container` instead.<br/>
It 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/>
In all cases, users aren't expected to _reflect_ containers explicitly. It's
sufficient to assign a container for which a specialization of the traits
classes exists to a `meta_any` object to be able to get its proxy object.
The interface of the `meta_sequence_container` proxy object is the same for all
types of sequence containers, although the available features differ from case
to case. In particular:
* The `value_type` member function returns the meta type of the elements.
* The `size` member function returns the number of elements in the container as
an unsigned integer value:
```cpp
const auto size = view.size();
```
* The `resize` member function allows to resize the wrapped container and
returns true in case of succes:
```cpp
const bool ok = view.resize(3u);
```
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();
```
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:
```cpp
for(entt::meta_any element: view) {
// ...
}
```
In all cases, given an underlying container of type `C`, the returned element
contains an object of type `C::value_type` which therefore depends on the
actual container.<br/>
All meta iterators are input iterators and don't offer an indirection operator
on purpose.
* The `insert` member function can be used to add elements to the container. It
accepts a meta iterator and the element to insert:
```cpp
auto last = view.end();
// appends an integer to the container
view.insert(last, 42);
```
This function returns a meta iterator pointing to the inserted element and a
boolean value to indicate whether the operation was successful or not. 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.
* The `erase` member function can be used to remove elements from the container.
It accepts a meta iterator to the element to remove:
```cpp
auto first = view.begin();
// removes the first element from the container
view.erase(first);
```
This function returns a meta iterator following the last removed element and a
boolean value to indicate whether the operation was successful or not. Note
that 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:
```cpp
for(std::size_t pos{}, last = view.size(); pos < last; ++pos) {
entt::meta_any value = view[pos];
// ...
}
```
The function returns instances of `meta_any` that directly refer to the actual
elements. Modifying the returned object will then directly modify the element
inside the container.
Similarly, also the interface of the `meta_associative_container` proxy object
is the same for all types of associative containers. However, there are some
differences in behavior in the case of key-only containers. In particular:
* The `key_only` member function returns true if the wrapped container is a
key-only one.
* The `key_type` member function returns the meta type of the keys.
* The `mapped_type` member function returns an invalid meta type for key-only
containers and the meta type of the mapped values for all other types of
containers.
* The `value_type` member function returns the meta type of the elements.<br/>
For example, it returns the meta type of `int` for `std::set<int>` while it
returns the meta type of `std::pair<const int, char>` for
`std::map<int, char>`.
* The `size` member function returns the number of elements in the container as
an unsigned integer value:
```cpp
const auto size = view.size();
```
* The `clear` member function allows to clear the wrapped container and returns
true in case of success:
```cpp
const bool ok = view.clear();
```
* The `begin` and `end` member functions return opaque iterators that can be
used to iterate the container directly:
```cpp
for(std::pair<entt::meta_any, entt::meta_any> element: view) {
// ...
}
```
In all cases, given an underlying container of type `C`, the returned element
is a key-value pair where the key has type `C::key_type` and the value has
type `C::mapped_type`. Since key-only containers don't have a mapped type,
their _value_ is nothing more than an invalid `meta_any` object.<br/>
All meta iterators are input iterators and don't offer an indirection operator
on purpose.
While the accessed key is usually constant in the associative containers and
is therefore returned by copy, the value (if any) is wrapped by an instance of
`meta_any` that directly refers to the actual element. Modifying it will then
directly modify 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:
```cpp
auto last = view.end();
// appends an integer to the container
view.insert(last.handle(), 42, 'c');
```
This function returns a boolean value to indicate whether the operation was
successful or not. Note that 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:
```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.
* 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:
```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.
Container support is deliberately minimal but theoretically 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`, obtaining light _references_ to the pointed objects that are also
correctly associated with their meta types.<br/>
To make the meta system recognize a type as _pointer-like_, users can specialize
the `is_meta_pointer_like` class. `EnTT` already exports the specializations for
some common classes. In particular:
* All types of raw pointers.
* `std::unique_ptr` and `std::shared_ptr`.
It's important to include the header file `pointer.hpp` to make these
specializations available to the compiler when needed.<br/>
The same file also contains many examples for the users that are interested in
making their own containers available to the meta system.
When a type is recognized as a pointer-like one by the meta system, it's
possible to dereference the instances of `meta_any` that contain these objects.
The following is a deliberately verbose example to show how to use this feature:
```cpp
int value = 42;
// meta type equivalent to that of int *
entt::meta_any any{&value};
if(any.type().is_pointer_like()) {
// meta type equivalent to that of int
if(entt::meta_any ref = *any; ref) {
// ...
}
}
```
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.
In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However,
`EnTT` also supports classes that don't offer an `operator*`. In particular:
* It's possible to exploit a solution based on ADL lookup by offering a function
(also a template one) named `dereference_meta_pointer_like`:
```cpp
template<typename Type>
Type & dereference_meta_pointer_like(const custom_pointer_type<Type> &ptr) {
return ptr.deref();
}
```
* When not in control of the type's namespace, it's possible to inject into the
`entt` namespace a specialization of `adl_meta_pointer_like` class template to
bypass the adl lookup as a whole:
```cpp
template<typename Type>
struct entt::adl_meta_pointer_like<custom_pointer_type<Type>> {
static decltype(auto) dereference(const custom_pointer_type<Type> &ptr) {
return ptr.deref();
}
};
```
In all other cases, that is, when dereferencing a pointer works as expected and
regardless of the pointed type, no user intervention is required.
## Policies: the more, the less
Policies are a kind of compile-time directives that can be used when registering
reflection information.<br/>
Their purpose is to require slightly different behavior than the default in some
specific cases. For example, when reading a given data member, its value is
returned wrapped in a `meta_any` object which, by default, makes a copy of it.
For large objects or if the caller wants to access the original instance, this
behavior isn't desirable. Policies are there to offer a solution to this and
other problems.
There are a few alternatives available at the moment:
* The _as-is_ policy, associated with the type `entt::as_is_t`.<br/>
This is the default policy. In general, it should never be used explicitly,
since it's implicitly selected if no other policy is specified.<br/>
In this case, the return values of the functions as well as the properties
exposed as data members are always returned by copy in a dedicated wrapper and
therefore associated with their original meta types.
* The _as-void_ policy, associated with the type `entt::as_void_t`.<br/>
Its purpose is to discard the return value of a meta object, whatever it is,
thus making it appear as if its type were `void`.<br/>
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.
As an example of use:
```cpp
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
```
* 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.<br/>
These policies work with constructors (for example, when objects are taken
from an external container rather than created on demand), data members and
functions in general (as long as their return types are lvalue references).
As an example of use:
```cpp
entt::meta<my_type>().data<&my_type::data_member, entt::as_ref_t>("member"_hs);
```
Some uses are rather trivial, but it's useful to note that there are some less
obvious corner cases that can in turn be solved with the use of policies.
## Named constants and enums
A special mention should be made for constant values and enums. It wouldn't be
necessary, but it will help distracted readers.
@@ -342,48 +743,109 @@ members of the reflected types.
Exporting constant values or elements from an enum is as simple as ever:
```cpp
entt::reflect<my_enum>()
.data<my_enum::a_value>("a_value")
.data<my_enum::another_value>("another_value");
entt::meta<my_enum>()
.data<my_enum::a_value>("a_value"_hs)
.data<my_enum::another_value>("another_value"_hs);
entt::reflect<int>().data<2048>("max_int");
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:
```cpp
auto value = entt::resolve<my_enum>().data("a_value").get({}).cast<my_enum>();
auto max = entt::resolve<int>().data("max_int").get({}).cast<int>();
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
allocation because of the small object optimization performed by the `meta_any`
class.
# Properties and meta objects
## Properties and meta objects
Sometimes (ie when it comes to creating an editor) it might be useful to be able
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/>
To attach a property to a meta object, no matter what as long as it supports
properties, it is sufficient to provide an object at the time of construction
such that `std::get<0>` and `std::get<1>` are valid for it. In other terms, the
properties are nothing more than key/value pairs users can put in an
`std::pair`. As an example:
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:
```cpp
entt::reflect<my_type>("reflected", std::make_pair("tooltip"_hs, "message"));
entt::meta<my_type>().type("reflected_type"_hs).prop("tooltip"_hs, "message");
```
The meta objects that support properties offer then a couple of member functions
named `prop` to iterate them at once and to search a specific property by key:
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 as key/value pairs:
```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.
* Annotations:
```cpp
entt::meta<my_type>().type("reflected_type"_hs).prop(&property_generator);
```
An annotation is an invocable object that returns one or more properties. All
of them are treated individually.
It's possible to invoke the `prop` function several times if needed, one for
each property to associate with the last meta object created:
```cpp
// iterate all the properties of a meta type
entt::resolve<my_type>().prop([](auto prop) {
entt::meta<my_type>()
.type("reflected_type"_hs)
.prop(entt::hashed_string{"Name"}, "Reflected Type")
.data<&my_type::data_member>("member"_hs)
.prop(std::make_pair("tooltip"_hs, "Member"))
.prop(my_enum::a_value, 42);
```
Alternatively, the `props` function is available to associate several properties
at a time. However, in this case properties in the key/value form aren't
allowed, since they would be interpreted as two different properties rather than
a single one.
The meta objects for which properties are supported are currently the meta
types, meta constructors, meta data and meta functions. It's not possible to
attach properties to other types of meta objects and the factory returned as a
result of their construction won't allow such an operation.
These types offer a couple of member functions named `prop` to iterate all
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()) {
// ...
});
}
// search for a given property by name
auto prop = entt::resolve<my_type>().prop("tooltip"_hs);
@@ -391,24 +853,22 @@ 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.
the key and the value contained in the form of `meta_any` objects, respectively.
# Unregister types
## Unregister types
A type registered with the reflection system can also be unregistered. This
means unregistering all its data members, member functions, conversion functions
and so on. However, the base classes won't be unregistered, 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) won't
be unregistered.
To unregister a type, users can use the `unregister` function from the global
namespace:
be unregistered.<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:
```cpp
entt::unregister<my_type>();
entt::resolve<my_type>().reset();
```
This function returns a boolean value that is true if the type is actually
registered with the reflection system, false otherwise.<br/>
The type can be re-registered later with a completely different name and form.

338
docs/md/poly.md Normal file
View File

@@ -0,0 +1,338 @@
# Crash Course: poly
<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents
* [Introduction](#introduction)
* [Other libraries](#other-libraries)
* [Concept and implementation](#concept-and-implementation)
* [Deduced interface](#deduced-interface)
* [Defined interface](#defined-interface)
* [Fullfill a concept](#fullfill-a-concept)
* [Inheritance](#inheritance)
* [Static polymorphism in the wild](#static-polymorphism-in-the-wild)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
Static polymorphism is a very powerful tool in C++, albeit sometimes cumbersome
to obtain.<br/>
This module aims to make it simple and easy to use.
The library allows to define _concepts_ as interfaces to 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
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.
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/>
Likewise, the `poly` class template also benefits from the small buffer
optimization offered by the `entt::any` class and therefore minimizes the number
of allocations, avoiding them altogether where possible.
## Other libraries
There are some very interesting libraries regarding static polymorphism.<br/>
Among all, the two that I prefer are:
* [`dyno`](https://github.com/ldionne/dyno): runtime polymorphism done right.
* [`Poly`](https://github.com/facebook/folly/blob/master/folly/docs/Poly.md):
a class template that makes it easy to define a type-erasing polymorphic
object wrapper.
The former is admittedly an experimental library, with many interesting ideas.
I've some doubts about the usefulness of some feature in real world projects,
but perhaps my lack of experience comes into play here. In my opinion, its only
flaw is the API which I find slightly more cumbersome than other solutions.<br/>
The latter was undoubtedly a source of inspiration for this module, although I
opted for different choices in the implementation of both the final API and some
feature.
Either way, the authors are gurus of the C++ community, people I only have to
learn from.
# Concept and implementation
The first thing to do to create a _type-erasing polymorphic object wrapper_ (to
use the terminology introduced by Eric Niebler) is to define a _concept_ that
types will have to adhere to.<br/>
For this purpose, the library offers a single class that supports both deduced
and fully defined interfaces. Although having interfaces deduced automatically
is convenient and allows users to write less code in most cases, this 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/>
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:
```cpp
struct Drawable: entt::type_list<> {
template<typename Base>
struct type: Base {
void draw() { this->template invoke<0>(*this); }
};
// ...
};
```
It's recognizable by the fact that it inherits from an empty type list.<br/>
Functions can also be const, accept any number of paramters and return a type
other than `void`:
```cpp
struct Drawable: entt::type_list<> {
template<typename Base>
struct type: Base {
bool draw(int pt) const { return this->template invoke<0>(*this, pt); }
};
// ...
};
```
In this case, all parameters must be 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
external call:
```cpp
struct Drawable: entt::type_list<> {
template<typename Base>
struct type: Base {
bool draw() const { entt::poly_call<0>(*this); }
};
// ...
};
```
Once the _concept_ is defined, users must provide a generic implementation of it
in order to tell the system how any type can satisfy its requirements. This is
done via an alias template within the concept itself.<br/>
The index passed as a template parameter to either `invoke` or `poly_call`
refers to how this alias is defined.
## Defined interface
A fully defined concept is no different to one for which the interface is
deduced, with the only difference that the list of types is not empty this time:
```cpp
struct Drawable: entt::type_list<void()> {
template<typename Base>
struct type: Base {
void draw() { entt::poly_call<0>(*this); }
};
// ...
};
```
Again, parameters and return values other than `void` are allowed. Also, the
function type must be const when the method to bind to it is const:
```cpp
struct Drawable: entt::type_list<bool(int) const> {
template<typename Base>
struct type: Base {
bool draw(int pt) const { return entt::poly_call<0>(*this, pt); }
};
// ...
};
```
Why should a user fully define a concept if the function types are the same as
the deduced ones?<br>
Because, in fact, this is exactly 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:
* Either by a class that exposes a member function with the same name and the
same signature.
* Or through a lambda that makes use of existing member functions from the
interface itself.
In other words, it's not possible to make use of functions not belonging to the
interface, even if they are present in the types that fulfill the concept.<br/>
Similarly, it's not possible to deduce a function in the static virtual table
with a function type different from that of the associated member function in
the interface itself.
Explicitly defining a static virtual table suppresses the deduction step and
allows maximum flexibility when providing the implementation for a concept.
## Fullfill a concept
The `impl` alias template of a concept is used to define how it's fulfilled:
```cpp
struct Drawable: entt::type_list<> {
// ...
template<typename Type>
using impl = entt::value_list<&Type::draw>;
};
```
In this case, it's stated that the `draw` method of a generic type will be
enough to satisfy the requirements of the `Drawable` concept.<br/>
Both member functions and free functions are supported to fullfill concepts:
```cpp
template<typename Type>
void print(Type &self) { self.print(); }
struct Drawable: entt::type_list<void()> {
// ...
template<typename Type>
using impl = entt::value_list<&print<Type>>;
};
```
Likewise, as long as the parameter types and return type support conversions to
and from those of the function type referenced in the static virtual table, the
actual implementation may differ in its function type since it's erased
internally.<br/>
Moreover, the `self` parameter isn't strictly required by the system and can be
left out for free functions if not required.
Refer to the inline documentation for more details.
# Inheritance
_Concept inheritance_ is straightforward due to how poly looks like in `EnTT`.
Therefore, it's quite easy to build hierarchies of concepts if necessary.<br/>
The only constraint is that all concepts in a hierarchy must belong to the same
_family_, that is, they must be either all deduced or all defined.
For a deduced concept, inheritance is achieved in a few steps:
```cpp
struct DrawableAndErasable: entt::type_list<> {
template<typename Base>
struct type: typename Drawable::type<Base> {
static constexpr auto base = std::tuple_size_v<typename entt::poly_vtable<Drawable>::type>;
void erase() { entt::poly_call<base + 0>(*this); }
};
template<typename Type>
using impl = entt::value_list_cat_t<
typename Drawable::impl<Type>,
entt::value_list<&Type::erase>
>;
};
```
The static virtual table is empty and must remain so.<br/>
On the other hand, `type` no longer inherits from `Base` and instead forwards
its template parameter to the type exposed by the _base class_. Internally, the
size of the static virtual table of the base class is used as an offset for the
local indexes.<br/>
Finally, by means of the `value_list_cat_t` utility, the implementation consists
in appending the new functions to the previous list.
As for a defined concept instead, also the list of types must be extended, in a
similar way to what is shown for the implementation of the above concept.<br/>
To do this, it's useful to declare a function that allows to convert a _concept_
into its underlying `type_list` object:
```cpp
template<typename... Type>
entt::type_list<Type...> as_type_list(const entt::type_list<Type...> &);
```
The definition isn't strictly required, since the function will only be used
through a `decltype` as it follows:
```cpp
struct DrawableAndErasable: entt::type_list_cat_t<
decltype(as_type_list(std::declval<Drawable>())),
entt::type_list<void()>
> {
// ...
};
```
Similar to above, `type_list_cat_t` is used to concatenate the underlying static
virtual table with the new function types.<br/>
Everything else is the same as already shown instead.
# Static polymorphism in the wild
Once the _concept_ and implementation have been introduced, it will be possible
to use the `poly` class template to contain instances that meet the
requirements:
```cpp
using drawable = entt::poly<Drawable>;
struct circle {
void draw() { /* ... */ }
};
struct square {
void draw() { /* ... */ }
};
// ...
drawable d{circle{}};
d->draw();
d = square{};
d->draw();
```
The `poly` class template offers a wide range of constructors, from the default
one (which will return an uninitialized `poly` object) to the copy and move
constructor, as well as the ability to create objects in-place.<br/>
Among others, there is a constructor that allows users to wrap unmanaged objects
in a `poly` instance (either const or non-const ones):
```cpp
circle c;
drawable d{std::ref(c)};
```
Similarly, it's possible to create non-owning copies of `poly` from an existing
object:
```cpp
drawable other = as_ref(d);
```
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.
Note also how the underlying concept is accessed via a call to `operator->` and
not directly as `d.draw()`.<br/>
This allows users to decouple the API of the wrapper from that of the concept.
Therefore, where `d.data()` will invoke the `data` member function of the poly
object, `d->data()` will map directly to the functionality exposed by the
underlying concept.

View File

@@ -74,6 +74,10 @@ Here is a minimal example for the sake of curiosity:
struct my_process: entt::process<my_process, std::uint32_t> {
using delta_type = std::uint32_t;
my_process(delta_type delay)
: remaining{delay}
{}
void update(delta_type delta, void *) {
remaining -= std::min(remaining, delta);
@@ -85,7 +89,7 @@ struct my_process: entt::process<my_process, std::uint32_t> {
}
private:
delta_type remaining{1000u};
delta_type remaining;
};
```
@@ -158,7 +162,7 @@ To attach a process to a scheduler there are mainly two ways:
the `attach` member function:
```cpp
scheduler.attach<my_process>("foobar");
scheduler.attach<my_process>(1000u);
```
* Otherwise, in case of a lambda or a functor, it's enough to provide an
@@ -182,7 +186,7 @@ scheduler.attach([](auto delta, void *, auto succeed, auto fail) {
// ...
})
// appends a child in the form of a process class
.then<my_process>();
.then<my_process>(1000u);
```
To update a scheduler and therefore all its processes, the `update` member

59
docs/md/references.md Normal file
View File

@@ -0,0 +1,59 @@
# Similar projects
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 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.
* [Diana](https://github.com/discoloda/Diana): an ECS that uses sparse sets to
keep track of entities in systems.
* [Flecs](https://github.com/SanderMertens/flecs): a multithreaded archetype
ECS based on semi-contiguous arrays rather than chunks.
* [lent](https://github.com/nem0/lent): the Donald Trump of the ECS libraries.
* C++:
* [decs](https://github.com/vblanco20-1/decs): a chunk based archetype ECS.
* [ecst](https://github.com/SuperV1234/ecst): a multithreaded compile-time
ECS that uses sparse sets to keep track of entities in systems.
* [EntityX](https://github.com/alecthomas/entityx): a bitset based ECS that
uses a single large matrix of components indexed with entities.
* C#
* [Entitas](https://github.com/sschmid/Entitas-CSharp): the ECS framework for
C# and Unity, where _reactive systems_ were invented.
* [Svelto.ECS](https://github.com/sebas77/Svelto.ECS): a very interesting
platform agnostic and table based ECS framework.
* Go:
* [gecs](https://github.com/tutumagi/gecs): a sparse sets based ECS inspired
by `EnTT`.
* Javascript:
* [\@javelin/ecs](https://github.com/3mcd/javelin/tree/master/packages/ecs): an
archetype ECS in TypeScript.
* [ecsy](https://github.com/MozillaReality/ecsy): I haven't had the time to
investigate the underlying design of `ecsy` but it looks cool anyway.
* Rust:
* [Legion](https://github.com/TomGillen/legion): a chunk based archetype ECS.
* [Shipyard](https://github.com/leudz/shipyard): it borrows some ideas from
`EnTT` and offers a sparse sets based ECS with grouping functionalities.
* [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

@@ -42,7 +42,7 @@ 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 the dedicated base class as in the following example:
inherit directly from a dedicated base class as in the following example:
```cpp
struct my_loader final: entt::resource_loader<my_loader, my_resource> {
@@ -76,11 +76,11 @@ Finally, a cache is a specialization of a class template tailored to a specific
resource:
```cpp
using my_resource_cache = entt::resource_cache<my_resource>;
using my_cache = entt::resource_cache<my_resource>;
// ...
my_resource_cache cache{};
my_cache cache{};
```
The idea is to create different caches for different types of resources and to
@@ -105,21 +105,14 @@ cache.clear();
Besides these member functions, a cache contains what is needed to load, use and
discard resources of the given type.<br/>
Before to explore this part of the interface, it makes sense to mention how
resources are identified. The type of the identifiers to use is defined as:
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:
```cpp
entt::resource_cache<resource>::resource_type
```
Where `resource_type` is an alias for `entt::hashed_string::hash_type`.
Therefore, resource identifiers are created explicitly as in the following
example:
```cpp
constexpr auto identifier = entt::resource_cache<resource>::resource_type{"my/resource/identifier"_hs};
constexpr auto identifier = "my/resource/identifier"_hs;
// this is equivalent to the following
constexpr auto hs = entt::hashed_string{"my/resource/identifier"};
constexpr entt::id_type hs = entt::hashed_string{"my/resource/identifier"};
```
The class `hashed_string` is described in a dedicated section, so I won't go in
@@ -142,7 +135,7 @@ 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(auto handle = cache.load<my_loader>("another/identifier"_hs, 42); handle) {
if(entt::resource_handle handle = cache.load<my_loader>("another/identifier"_hs, 42); handle) {
// ...
}
```
@@ -187,24 +180,24 @@ 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 const reference on request:
resource as a (possibly const) reference on request:
* By means of the `get` member function:
```cpp
const auto &resource = handle.get();
auto &resource = handle.get();
```
* Using the proper cast operator:
```cpp
const auto &resource = handle;
auto &resource = handle;
```
* Through the dereference operator:
```cpp
const auto &resource = *handle;
auto &resource = *handle;
```
The resource can also be accessed directly using the arrow operator if required:

View File

@@ -7,6 +7,8 @@
* [Introduction](#introduction)
* [Delegate](#delegate)
* [Runtime arguments](#runtime-arguments)
* [Lambda support](#lambda-support)
* [Signals](#signals)
* [Event dispatcher](#event-dispatcher)
* [Event emitter](#event-emitter)
@@ -28,18 +30,19 @@ 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 potential of an `std::function` are not
required or where you are looking for something different, `EnTT` offers a full
set of classes to solve completely different problems.
In case that the flexibility and power of an `std::function` isn't required or
if the price to pay for them is too high,` EnTT` offers a complete set of
lightweight classes to solve the same and many other problems.
# Delegate
A delegate can be used as a general purpose invoker with no memory overhead for
free functions and members provided along with an instance on which to invoke
them.<br/>
It does not claim to be a drop-in replacement for an `std::function`, so do not
expect to use it whenever an `std::function` fits well. However, it can be used
to send opaque delegates around to be used to invoke functions as needed.
It doesn't claim to be a drop-in replacement for an `std::function`, so don't
expect to use it whenever an `std::function` fits well. That said, it's most
likely even a better fit than an `std::function` in a lot of cases, so expect to
use it quite a lot anyway.
The interface is trivial. It offers a default constructor to create empty
delegates:
@@ -50,7 +53,7 @@ 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 function one wants to assign to it.
member one wants to assign to it.
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,
@@ -62,7 +65,7 @@ As an example of use:
int f(int i) { return i; }
struct my_struct {
int f(const int &i) { return i }
int f(const int &i) const { return i; }
};
// bind a free function to the delegate
@@ -70,30 +73,47 @@ delegate.connect<&f>();
// bind a member function to the delegate
my_struct instance;
delegate.connect<&my_struct::f>(&instance);
delegate.connect<&my_struct::f>(instance);
```
The delegate class accepts also 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.<br/>
Functions having type equivalent to `void(T *, args...)` are accepted as well.
In this case, `T *` is considered a payload and the function will receive it
back every time it's invoked. In other terms, this works just fine with the
above definition:
value of the data member is at least convertible to the return type.
Free functions having type equivalent to `void(T &, args...)` are accepted as
well. The first argument `T &` is considered a payload and the function will
receive it back every time it's invoked. In other terms, this works just fine
with the above definition:
```cpp
void g(const char *c, int i) { /* ... */ }
void g(const char &c, int i) { /* ... */ }
const char c = 'c';
delegate.connect<&g>(&c);
delegate.connect<&g>(c);
delegate(42);
```
The function `g` will be invoked with a pointer to `c` and `42`. However, the
function type of the delegate is still `void(int)`, mainly because this is also
the signature of its function call operator.
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.
To create and initialize a delegate at once, there are also some specialized
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:
```cpp
void g() { /* ... */ }
delegate.connect<&g>();
delegate(42);
```
Where the function type of the delegate is `void(int)` as above. It goes without
saying that the extra arguments are silently discarded internally.<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.
To create and initialize a delegate at once, there are a few specialized
constructors. Because of the rules of the language, the listener is provided by
means of the `entt::connect_arg` variable template:
@@ -113,55 +133,138 @@ if(delegate) {
```
Finally, to invoke a delegate, the function call operator is the way to go as
usual:
already shown in the examples above:
```cpp
auto ret = delegate(42);
```
As shown above, listeners do not have to strictly follow the signature of the
In all cases, the 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.
Probably too much small and pretty poor of functionalities, but the delegate
class can help in a lot of cases and it has shown that it is worth keeping it
within the library.
As a side note, members of classes may or may not be associated with instances.
If they are not, the first argument of the function type must be that of the
class on which the members operate and an instance of this class must obviously
be passed when invoking the delegate:
```cpp
entt::delegate<void(my_struct &, int)> delegate;
delegate.connect<&my_struct::f>();
my_struct instance;
delegate(instance, 42);
```
In this case, it's not possible to deduce the function type since the first
argument doesn't necessarily have to be a reference (for example, it can be a
pointer, as well as a const reference).<br/>
Therefore, the function type must be declared explicitly for unbound members.
## Runtime arguments
The `delegate` class is meant to be used primarily with template arguments.
However, as a consequence of its design, it can also offer minimal support for
runtime arguments.<br/>
When used in this modality, some feature aren't supported though. In particular:
* Curried functions aren't accepted.
* Functions with an argument list that differs from that of the delegate aren't
supported.
* Return type and types of arguments **must** coincide with those of the
delegate and _being at least convertible_ isn't enough anymore.
Moreover, for a given function type `Ret(Args...)`, the signature of the
functions connected at runtime must necessarily be `Ret(const void *, Args...)`.
Runtime arguments can be passed both to the constructor of a delegate and to the
`connect` member function. An optional parameter is also accepted in both cases.
This argument is used to pass arbitrary user data back and forth as a
`const void *` upon invocation.<br/>
To connect a function to a delegate _in the hard way_:
```cpp
int func(const void *ptr, int i) { return *static_cast<const int *>(ptr) * i; }
const int value = 42;
// use the constructor ...
entt::delegate delegate{&func, &value};
// ... or the connect member function
delegate.connect(&func, &value);
```
The type of the delegate is deduced from the function if possible. In this case,
since the first argument is an implementation detail, the deduced function type
is `int(int)`.<br/>
Invoking a delegate built in this way follows the same rules as previously
explained.
## Lambda support
In general, the `delegate` class doesn't fully support lambda functions in all
their nuances. The reason is pretty simple: a `delegate` isn't a drop-in
replacement for an `std::function`. Instead, it tries to overcome the problems
with the latter.<br/>
That being said, non-capturing lambda functions are supported, even though some
feature aren't available in this case.
This is a logical consequence of the support for connecting functions at
runtime. Therefore, lambda functions undergo the same rules and
limitations.<br/>
In fact, since non-capturing lambda functions decay to pointers to functions,
they can be used with a `delegate` as if they were _normal functions_ with
optional payload:
```cpp
my_struct instance;
// use the constructor ...
entt::delegate delegate{+[](const void *ptr, int value) {
return static_cast<const my_struct *>(ptr)->f(value);
}, &instance};
// ... or the connect member function
delegate.connect([](const void *ptr, int value) {
return static_cast<const my_struct *>(ptr)->f(value);
}, &instance);
```
As above, the first parameter (`const void *`) isn't part of the function type
of the delegate and is used to dispatch arbitrary user data back and forth. In
other terms, the function type of the delegate above is `int(int)`.
# Signals
Signal handlers work with naked pointers, function pointers and pointers to
member functions. Listeners can be any kind of objects and users are in charge
of connecting and disconnecting them from a signal to avoid crashes due to
Signal handlers work with references to classes, function pointers and pointers
to members. Listeners can be any kind of objects and users are in charge of
connecting and disconnecting them from a signal to avoid crashes due to
different lifetimes. On the other side, performance shouldn't be affected that
much by the presence of such a signal handler.<br/>
Signals make use of delegates internally and therefore they undergo the same
rules and offer similar functionalities. It may be a good idea to consult the
documentation of the `delegate` class for further information.
A signal handler 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 its _sink_ class, that is a tool
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. The most important thing is that
it comes in two forms: with and without a collector. In case a signal is
associated with a collector, all the values returned by the listeners can be
literally _collected_ and used later by the caller. Otherwise it works just like
a plain signal that emits events from time to time.<br/>
**Note**: collectors are allowed only in case of function types whose the return
type isn't `void` for obvious reasons.
To create instances of signal handlers there exist mainly two ways:
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
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
function to which they refer:
```cpp
// no collector type
entt::sigh<void(int, char)> signal;
// explicit collector type
entt::sigh<void(int, char), my_collector<bool>> collector;
```
As expected, they offer all the basic functionalities required to know how many
listeners they contain (`size`) or if they contain at least a listener (`empty`)
and even to swap two signal handlers (`swap`).
Signals offer all the basic functionalities required to know how many listeners
they contain (`size`) or if they contain at least a listener (`empty`), as well
as a function to use to swap handlers (`swap`).
Besides them, there are member functions to use both to connect and disconnect
listeners in all their forms by means of a sink:
@@ -175,26 +278,45 @@ struct listener {
// ...
entt::sink sink{signal};
listener instance;
signal.sink().connect<&foo>();
signal.sink().connect<&listener::bar>(&instance);
sink.connect<&foo>();
sink.connect<&listener::bar>(instance);
// ...
// disconnects a free function
signal.sink().disconnect<&foo>();
sink.disconnect<&foo>();
// disconnect a member function of an instance
signal.sink().disconnect<&listener::bar>(&instance);
sink.disconnect<&listener::bar>(instance);
// discards all the listeners at once
signal.sink().disconnect();
// disconnect all member functions of an instance, if any
sink.disconnect(instance);
// discards all listeners at once
sink.disconnect();
```
As shown above, listeners do not have to strictly follow the signature of the
As shown above, the 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 result type, everything works just fine.
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.
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`
@@ -207,6 +329,34 @@ 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:
```cpp
int f() { return 0; }
int g() { return 1; }
// ...
entt::sigh<int()> signal;
entt::sink sink{signal};
sink.connect<&f>();
sink.connect<&g>();
std::vector<int> vec{};
signal.collect([&vec](int value) { vec.push_back(value); });
assert(vec[0] == 0);
assert(vec[1] == 1);
```
A collector must expose a function operator that accepts as an argument a type
to which the return type of the listeners can be converted. Moreover, it can
optionally return a boolean value that is true to stop collecting data, false
otherwise. This way one can avoid calling all the listeners in case it isn't
necessary.<br/>
Functors can also be used in place of a lambda. Since the collector is copied
when invoking the `collect` member function, `std::ref` is the way to go in this
case:
```cpp
struct my_collector {
std::vector<int> vec{};
@@ -217,27 +367,12 @@ struct my_collector {
}
};
int f() { return 0; }
int g() { return 1; }
// ...
entt::sigh<int(), my_collector<int>> signal;
signal.sink().connect<&f>();
signal.sink().connect<&g>();
my_collector collector = signal.collect();
assert(collector.vec[0] == 0);
assert(collector.vec[1] == 1);
my_collector collector;
signal.collect(std::ref(collector));
```
A collector must expose a function operator that accepts as an argument a type
to which the return type of the listeners can be converted. Moreover, it has to
return a boolean value that is false to stop collecting data, true otherwise.
This way one can avoid calling all the listeners in case it isn't necessary.
# Event dispatcher
The event dispatcher class is designed so as to be used in a loop. It allows
@@ -247,14 +382,14 @@ 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:
```cpp
// define a general purpose dispatcher that works with naked pointers
// 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
`const E &` can be converted to them for each type of event `E`, no matter what
the return value is.<br/>
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:
@@ -262,8 +397,7 @@ the `connect` member function of the sink in charge for the specific event:
struct an_event { int value; };
struct another_event {};
struct listener
{
struct listener {
void receive(const an_event &) { /* ... */ }
void method(const another_event &) { /* ... */ }
};
@@ -271,16 +405,16 @@ struct listener
// ...
listener listener;
dispatcher.sink<an_event>().connect<&listener::receive>(&listener);
dispatcher.sink<another_event>().connect<&listener::method>(&listener);
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
selectively remove listeners:
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::method>(&listener);
dispatcher.sink<an_event>().disconnect<&listener::receive>(listener);
dispatcher.sink<another_event>().disconnect(listener);
```
The `trigger` member function serves the purpose of sending an immediate event
@@ -313,7 +447,7 @@ the messages that are still pending are sent to the listeners at once:
```cpp
// emits all the events of the given type at once
dispatcher.update<my_event>();
dispatcher.update<an_event>();
// emits all the events queued so far at once
dispatcher.update();
@@ -343,9 +477,9 @@ 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 const 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/>
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/>
@@ -359,10 +493,10 @@ my_emitter emitter{};
```
Listeners must be movable and callable objects (free functions, lambdas,
functors, `std::function`s, whatever) whose function type is:
functors, `std::function`s, whatever) whose function type is compatible with:
```cpp
void(const Event &, my_emitter &)
void(Event &, my_emitter &)
```
Where `Event` is the type of event they want to listen.<br/>

107
docs/md/unreal.md Normal file
View File

@@ -0,0 +1,107 @@
# EnTT and Unreal Engine
<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents
* [Enable Cpp17](#enable-cpp17)
* [EnTT as a third party module](#entt-as-a-third-party-module)
* [Include EnTT](#include-entt)
<!--
@endcond TURN_OFF_DOXYGEN
-->
## Enable Cpp17
As of writing (Unreal Engine v4.25), the default C++ standard of Unreal Engine
is C++14.<br/>
On the other hand, note that `EnTT` requires C++17 to compile. To enable it, in
the main module of the project there should be a `<Game Name>.Build.cs` file,
the constructor of which must contain the following lines:
```cs
PCHUsage = PCHUsageMode.NoSharedPCHs;
PrivatePCHHeaderFile = "<PCH filename>.h";
CppStandard = CppStandardVersion.Cpp17;
```
Replace `<PCH filename>.h` with the name of the already existing PCH header
file, if any.<br/>
In case the project doesn't already contain a file of this type, it's possible
to create one with the following content:
```cpp
#pragma once
#include "CoreMinimal.h"
```
Remember to remove any old `PCHUsage = <...>` line that was previously there. At
this point, C++17 support should be in place.<br/>
Try to compile the project to ensure it works as expected before following
further steps.
Note that updating a *project* to C++17 doesn't necessarily mean that the IDE in
use will also start to recognize its syntax.<br/>
If the plan is to use C++17 in the project too, check the specific instructions
for the IDE in use.
## EnTT as a third party module
Once this point is reached, the `Source` directory should look like this:
```
Source
| MyGame.Target.cs
| MyGameEditor.Target.cs
|
+---MyGame
| | MyGame.Build.cs
| | MyGame.h (PCH Header file)
|
\---ThirdParty
\---EnTT
| EnTT.Build.cs
|
\---entt (GitHub repository content inside)
```
To make this happen, create the folder `ThirdParty` under `Source` if it doesn't
exist already. Then, add an `EnTT` folder under `ThirdParty`.<br/>
Within the latter, create a new file `EnTT.Build.cs` with the following content:
```cs
using System.IO;
using UnrealBuildTool;
public class EnTT: ModuleRules {
public EnTT(ReadOnlyTargetRules Target) : base(Target) {
Type = ModuleType.External;
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "entt", "src", "entt"));
}
}
```
The last line indicates that the actual files will be found in the directory
`EnTT/entt/src/entt`.<br/>
Download the repository for `EnTT` and place it next to `EnTT.Build.cs` or
update the path above accordingly.
Finally, open the `<Game Name>.Build.cs` file and add `EnTT` as a dependency at
the end of the list:
```cs
PublicDependencyModuleNames.AddRange(new[] {
"Core", "CoreUObject", "Engine", "InputCore", [...], "EnTT"
});
```
Note that some IDEs might require a restart to start recognizing the new module
for code-highlighting features and such.
## Include EnTT
In any source file of the project, add `#include "entt.hpp"` or any other path
to the file from `EnTT` to use it.<br/>
Try to create a registry as `entt::registry registry;` to make sure everything
compiles fine.

View File

@@ -41,14 +41,14 @@ echo "Sedding..."
# change the url in the formula file
# the slashes in the URL must be escaped
ESCAPED_URL="$(sed -e 's/[\/&]/\\&/g' <<< "$URL")"
ESCAPED_URL="$(echo "$URL" | sed -e 's/[\/&]/\\&/g')"
sed -i -e '/url/s/".*"/"'$ESCAPED_URL'"/' $FORMULA
# change the hash in the formula file
sed -i -e '/sha256/s/".*"/"'$HASH'"/' $FORMULA
# delete temporary file created by sed
rm "$FORMULA-e"
rm -rf "$FORMULA-e"
# update remote repo
echo "Gitting..."

View File

@@ -1,3 +0,0 @@
#!/bin/sh
scripts/update_homebrew.sh $1

File diff suppressed because it is too large Load Diff

View File

@@ -3,42 +3,58 @@
#ifndef ENTT_NOEXCEPT
#define ENTT_NOEXCEPT noexcept
#endif // ENTT_NOEXCEPT
#ifndef ENTT_HS_SUFFIX
#define ENTT_HS_SUFFIX _hs
#endif // ENTT_HS_SUFFIX
#ifndef ENTT_NO_ATOMIC
#include <atomic>
template<typename Type>
using maybe_atomic_t = std::atomic<Type>;
#else // ENTT_NO_ATOMIC
template<typename Type>
using maybe_atomic_t = Type;
#endif // ENTT_NO_ATOMIC
#ifndef ENTT_ID_TYPE
#include <cstdint>
#define ENTT_ID_TYPE std::uint32_t
#endif // ENTT_ID_TYPE
#ifndef ENTT_PAGE_SIZE
#define ENTT_PAGE_SIZE 32768
# define ENTT_NOEXCEPT noexcept
#endif
#ifndef ENTT_DISABLE_ASSERT
#include <cassert>
#define ENTT_ASSERT(condition) assert(condition)
#else // ENTT_DISABLE_ASSERT
#define ENTT_ASSERT(...) ((void)0)
#endif // ENTT_DISABLE_ASSERT
#ifndef ENTT_USE_ATOMIC
# define ENTT_MAYBE_ATOMIC(Type) Type
#else
# include <atomic>
# define ENTT_MAYBE_ATOMIC(Type) std::atomic<Type>
#endif
#endif // ENTT_CONFIG_CONFIG_H
#ifndef ENTT_ID_TYPE
# include <cstdint>
# define ENTT_ID_TYPE std::uint32_t
#endif
#ifndef ENTT_PAGE_SIZE
# define ENTT_PAGE_SIZE 4096
#endif
#ifdef ENTT_DISABLE_ASSERT
# undef ENTT_ASSERT
# define ENTT_ASSERT(...) (void(0))
#elif !defined ENTT_ASSERT
# include <cassert>
# define ENTT_ASSERT(condition) assert(condition)
#endif
#ifndef ENTT_NO_ETO
# include <type_traits>
# define ENTT_IS_EMPTY(Type) std::is_empty<Type>
#else
# include <type_traits>
# define ENTT_IS_EMPTY(Type) std::false_type
#endif
#ifndef ENTT_STANDARD_CPP
# if defined __clang__ || defined __GNUC__
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
# define ENTT_PRETTY_FUNCTION_PREFIX '='
# define ENTT_PRETTY_FUNCTION_SUFFIX ']'
# elif defined _MSC_VER
# define ENTT_PRETTY_FUNCTION __FUNCSIG__
# define ENTT_PRETTY_FUNCTION_PREFIX '<'
# define ENTT_PRETTY_FUNCTION_SUFFIX '>'
# endif
#endif
#endif

View File

@@ -2,10 +2,9 @@
#define ENTT_CONFIG_VERSION_H
#define ENTT_VERSION "3.0.0"
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 0
#define ENTT_VERSION_MINOR 6
#define ENTT_VERSION_PATCH 0
#endif // ENTT_CONFIG_VERSION_H
#endif

View File

@@ -2,9 +2,12 @@
#define ENTT_CORE_ALGORITHM_HPP
#include <functional>
#include <algorithm>
#include <vector>
#include <utility>
#include <iterator>
#include <algorithm>
#include <functional>
#include "utility.hpp"
namespace entt {
@@ -54,18 +57,81 @@ struct insertion_sort {
*/
template<typename It, typename Compare = std::less<>>
void operator()(It first, It last, Compare compare = Compare{}) const {
if(first != last) {
auto it = first + 1;
if(first < last) {
for(auto it = first + 1; it < last; ++it) {
auto value = std::move(*it);
auto pre = it;
while(it != last) {
auto pre = it++;
auto value = *pre;
while(pre-- != first && compare(value, *pre)) {
*(pre+1) = *pre;
for(; pre > first && compare(value, *(pre-1)); --pre) {
*pre = std::move(*(pre-1));
}
*(pre+1) = value;
*pre = std::move(value);
}
}
}
};
/**
* @brief Function object for performing LSD radix sort.
* @tparam Bit Number of bits processed per pass.
* @tparam N Maximum number of bits to sort.
*/
template<std::size_t Bit, std::size_t N>
struct radix_sort {
static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass");
/**
* @brief Sorts the elements in a range.
*
* Sorts the elements in a range using the given _getter_ to access the
* actual data to be sorted.
*
* This implementation is inspired by the online book
* [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort).
*
* @tparam It Type of random access iterator.
* @tparam Getter Type of _getter_ function object.
* @param first An iterator to the first element of the range to sort.
* @param last An iterator past the last element of the range to sort.
* @param getter A valid _getter_ function object.
*/
template<typename It, typename Getter = identity>
void operator()(It first, It last, Getter getter = Getter{}) const {
if(first < last) {
static constexpr auto mask = (1 << Bit) - 1;
static constexpr auto buckets = 1 << Bit;
static 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) {
std::size_t index[buckets]{};
std::size_t count[buckets]{};
for(auto it = from; it != to; ++it) {
++count[(getter(*it) >> start) & mask];
}
for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
index[pos + 1u] = index[pos] + count[pos];
}
for(auto it = from; it != to; ++it) {
out[index[(getter(*it) >> start) & mask]++] = std::move(*it);
}
};
for(std::size_t pass = 0; pass < (passes & ~1); pass += 2) {
part(first, last, aux.begin(), pass * Bit);
part(aux.begin(), aux.end(), first, (pass + 1) * Bit);
}
if constexpr(passes & 1) {
part(first, last, aux.begin(), (passes - 1) * Bit);
std::move(aux.begin(), aux.end(), first);
}
}
}
@@ -75,4 +141,4 @@ struct insertion_sort {
}
#endif // ENTT_CORE_ALGORITHM_HPP
#endif

370
src/entt/core/any.hpp Normal file
View File

@@ -0,0 +1,370 @@
#ifndef ENTT_CORE_ANY_HPP
#define ENTT_CORE_ANY_HPP
#include <functional>
#include <new>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "type_info.hpp"
#include "type_traits.hpp"
namespace entt {
/*! @brief A SBO friendly, type-safe container for single values of any type. */
class any {
enum class operation { COPY, MOVE, DTOR, COMP, ADDR, CADDR, REF, CREF, TYPE };
using storage_type = std::aligned_storage_t<sizeof(double[2]), alignof(double[2])>;
using vtable_type = const void *(const operation, const any &, const void *);
template<typename Type>
static constexpr auto in_situ = sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v<Type>;
template<typename Type>
[[nodiscard]] static bool compare(const void *lhs, const void *rhs) {
if constexpr(!std::is_function_v<Type> && is_equality_comparable_v<Type>) {
return *static_cast<const Type *>(lhs) == *static_cast<const Type *>(rhs);
} else {
return lhs == rhs;
}
}
static type_info & as_type_info(const void *data) {
return *const_cast<type_info *>(static_cast<const type_info *>(data));
}
static any & as_any(const void *data) {
return *const_cast<any *>(static_cast<const any *>(data));
}
template<typename Type>
static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const any &from, [[maybe_unused]] const void *to) {
if constexpr(!std::is_void_v<Type>) {
if constexpr(std::is_lvalue_reference_v<Type>) {
using base_type = std::remove_reference_t<Type>;
switch(op) {
case operation::REF:
case operation::CREF:
as_any(to).vtable = (op == operation::REF) ? basic_vtable<Type> : basic_vtable<const base_type &>;
[[fallthrough]];
case operation::COPY:
case operation::MOVE:
as_any(to).instance = from.instance;
[[fallthrough]];
case operation::DTOR:
break;
case operation::COMP:
return compare<std::remove_const_t<base_type>>(from.instance, to) ? to : nullptr;
case operation::ADDR:
return std::is_const_v<base_type> ? nullptr : from.instance;
case operation::CADDR:
return from.instance;
case operation::TYPE:
as_type_info(to) = type_id<std::remove_const_t<base_type>>();
break;
}
} else if constexpr(in_situ<Type>) {
#if __cpp_lib_launder >= 201606L
auto *instance = const_cast<Type *>(std::launder(reinterpret_cast<const Type *>(&from.storage)));
#else
auto *instance = const_cast<Type *>(reinterpret_cast<const Type *>(&from.storage));
#endif
switch(op) {
case operation::COPY:
new (&as_any(to).storage) Type{std::as_const(*instance)};
break;
case operation::MOVE:
new (&as_any(to).storage) Type{std::move(*instance)};
[[fallthrough]];
case operation::DTOR:
instance->~Type();
break;
case operation::COMP:
return compare<Type>(instance, to) ? to : nullptr;
case operation::ADDR:
case operation::CADDR:
return instance;
case operation::REF:
case operation::CREF:
as_any(to).vtable = (op == operation::REF) ? basic_vtable<Type &> : basic_vtable<const Type &>;
as_any(to).instance = instance;
break;
case operation::TYPE:
as_type_info(to) = type_id<Type>();
break;
}
} else {
switch(op) {
case operation::COPY:
as_any(to).instance = new Type{*static_cast<const Type *>(from.instance)};
break;
case operation::REF:
case operation::CREF:
as_any(to).vtable = (op == operation::REF) ? basic_vtable<Type &> : basic_vtable<const Type &>;
[[fallthrough]];
case operation::MOVE:
as_any(to).instance = from.instance;
break;
case operation::DTOR:
delete static_cast<const Type *>(from.instance);
break;
case operation::COMP:
return compare<Type>(from.instance, to) ? to : nullptr;
case operation::ADDR:
case operation::CADDR:
return from.instance;
case operation::TYPE:
as_type_info(to) = type_id<Type>();
break;
}
}
}
return nullptr;
}
public:
/*! @brief Default constructor. */
any() ENTT_NOEXCEPT
: any{std::in_place_type<void>}
{}
/**
* @brief Constructs an any by directly initializing the new object.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
explicit any(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
: vtable{&basic_vtable<Type>},
instance{}
{
if constexpr(!std::is_void_v<Type>) {
if constexpr(std::is_lvalue_reference_v<Type>) {
static_assert(sizeof...(Args) == 1u && (std::is_pointer_v<std::remove_reference_t<Args>> && ...));
ENTT_ASSERT(((args != nullptr) && ...));
instance = (args, ...);
} else if constexpr(in_situ<Type>) {
new (&storage) Type{std::forward<Args>(args)...};
} else {
instance = new Type{std::forward<Args>(args)...};
}
}
}
/**
* @brief Constructs an any that holds an unmanaged object.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
*/
template<typename Type>
any(std::reference_wrapper<Type> value) ENTT_NOEXCEPT
: any{std::in_place_type<Type &>, &value.get()}
{}
/**
* @brief Constructs an any from a given value.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
*/
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, any>>>
any(Type &&value)
: any{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
{}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
any(const any &other)
: any{}
{
vtable = other.vtable;
vtable(operation::COPY, other, this);
}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
any(any &&other) ENTT_NOEXCEPT
: any{}
{
vtable = std::exchange(other.vtable, &basic_vtable<void>);
vtable(operation::MOVE, other, this);
}
/*! @brief Frees the internal storage, whatever it means. */
~any() {
vtable(operation::DTOR, *this, nullptr);
}
/**
* @brief Assignment operator.
* @param other The instance to assign from.
* @return This any object.
*/
any & operator=(any other) {
swap(*this, other);
return *this;
}
/**
* @brief Returns the type of the contained object.
* @return The type of the contained object, if any.
*/
[[nodiscard]] type_info type() const ENTT_NOEXCEPT {
type_info info;
vtable(operation::TYPE, *this, &info);
return info;
}
/**
* @brief Returns an opaque pointer to the contained instance.
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] const void * data() const ENTT_NOEXCEPT {
return vtable(operation::CADDR, *this, nullptr);
}
/*! @copydoc data */
[[nodiscard]] void * data() ENTT_NOEXCEPT {
return const_cast<void *>(vtable(operation::ADDR, *this, nullptr));
}
/**
* @brief Replaces the contained object by creating a new instance directly.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
void emplace(Args &&... args) {
*this = any{std::in_place_type<Type>, std::forward<Args>(args)...};
}
/**
* @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 {
return !(vtable(operation::CADDR, *this, nullptr) == nullptr);
}
/**
* @brief Checks if two wrappers differ in their content.
* @param other Wrapper with which to compare.
* @return False if the two objects differ in their content, true otherwise.
*/
bool operator==(const any &other) const ENTT_NOEXCEPT {
return type() == other.type() && (vtable(operation::COMP, *this, other.data()) == other.data());
}
/**
* @brief Swaps two any objects.
* @param lhs A valid any object.
* @param rhs A valid any object.
*/
friend void swap(any &lhs, any &rhs) {
any tmp{};
lhs.vtable(operation::MOVE, lhs, &tmp);
rhs.vtable(operation::MOVE, rhs, &lhs);
lhs.vtable(operation::MOVE, tmp, &rhs);
std::swap(lhs.vtable, rhs.vtable);
}
/**
* @brief Aliasing constructor.
* @param other A reference to an object that isn't necessarily initialized.
* @return An any that shares a reference to an unmanaged object.
*/
[[nodiscard]] friend any as_ref(any &other) ENTT_NOEXCEPT {
any ref{};
other.vtable(operation::REF, other, &ref);
return ref;
}
/*! @copydoc as_ref */
[[nodiscard]] friend any as_ref(const any &other) ENTT_NOEXCEPT {
any ref{};
other.vtable(operation::CREF, other, &ref);
return ref;
}
private:
vtable_type *vtable;
union { const void *instance; storage_type storage; };
};
/**
* @brief Checks if two wrappers differ in their content.
* @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.
*/
[[nodiscard]] inline bool operator!=(const any &lhs, const any &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/**
* @brief Performs type-safe access to the contained object.
* @tparam Type Type to which conversion is required.
* @param data Target any object.
* @return The element converted to the requested type.
*/
template<typename Type>
Type any_cast(const any &data) ENTT_NOEXCEPT {
const auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
ENTT_ASSERT(instance);
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type>
Type any_cast(any &data) ENTT_NOEXCEPT {
// forces const on non-reference types to make them work also with wrappers for const references
auto * const instance = any_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>(&data);
ENTT_ASSERT(instance);
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type>
Type any_cast(any &&data) ENTT_NOEXCEPT {
// forces const on non-reference types to make them work also with wrappers for const references
auto * const instance = any_cast<std::conditional_t<std::is_reference_v<Type>, std::remove_reference_t<Type>, const Type>>(&data);
ENTT_ASSERT(instance);
return static_cast<Type>(std::move(*instance));
}
/*! @copydoc any_cast */
template<typename Type>
const Type * any_cast(const any *data) ENTT_NOEXCEPT {
return (data->type() == type_id<Type>() ? static_cast<const Type *>(data->data()) : nullptr);
}
/*! @copydoc any_cast */
template<typename Type>
Type * any_cast(any *data) ENTT_NOEXCEPT {
// last attempt to make wrappers for const references return their values
return (data->type() == type_id<Type>() ? static_cast<Type *>(static_cast<constness_as_t<any, Type> *>(data)->data()) : nullptr);
}
}
#endif

33
src/entt/core/attribute.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef ENTT_CORE_ATTRIBUTE_H
#define ENTT_CORE_ATTRIBUTE_H
#ifndef ENTT_EXPORT
# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER
# define ENTT_EXPORT __declspec(dllexport)
# define ENTT_IMPORT __declspec(dllimport)
# define ENTT_HIDDEN
# elif defined __GNUC__ && __GNUC__ >= 4
# define ENTT_EXPORT __attribute__((visibility("default")))
# define ENTT_IMPORT __attribute__((visibility("default")))
# define ENTT_HIDDEN __attribute__((visibility("hidden")))
# else /* Unsupported compiler */
# define ENTT_EXPORT
# define ENTT_IMPORT
# define ENTT_HIDDEN
# endif
#endif
#ifndef ENTT_API
# if defined ENTT_API_EXPORT
# define ENTT_API ENTT_EXPORT
# elif defined ENTT_API_IMPORT
# define ENTT_API ENTT_IMPORT
# else /* No API */
# define ENTT_API
# endif
#endif
#endif

View File

@@ -2,8 +2,8 @@
#define ENTT_CORE_FAMILY_HPP
#include <type_traits>
#include "../config/config.h"
#include "fwd.hpp"
namespace entt {
@@ -18,23 +18,20 @@ namespace entt {
*/
template<typename...>
class family {
inline static maybe_atomic_t<ENTT_ID_TYPE> identifier;
template<typename...>
inline static const auto inner = identifier++;
inline static ENTT_MAYBE_ATOMIC(id_type) identifier{};
public:
/*! @brief Unsigned integer type. */
using family_type = ENTT_ID_TYPE;
using family_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 in place of family_type here
inline static const family_type type = inner<std::decay_t<Type>...>;
// at the time I'm writing, clang crashes during compilation if auto is used instead of family_type
inline static const family_type type = identifier++;
};
}
#endif // ENTT_CORE_FAMILY_HPP
#endif

18
src/entt/core/fwd.hpp Normal file
View File

@@ -0,0 +1,18 @@
#ifndef ENTT_CORE_FWD_HPP
#define ENTT_CORE_FWD_HPP
#include "../config/config.h"
namespace entt {
/*! @brief Alias declaration for type identifiers. */
using id_type = ENTT_ID_TYPE;
}
#endif

View File

@@ -3,7 +3,9 @@
#include <cstddef>
#include <cstdint>
#include "../config/config.h"
#include "fwd.hpp"
namespace entt {
@@ -24,6 +26,7 @@ struct fnv1a_traits;
template<>
struct fnv1a_traits<std::uint32_t> {
using type = std::uint32_t;
static constexpr std::uint32_t offset = 2166136261;
static constexpr std::uint32_t prime = 16777619;
};
@@ -31,6 +34,7 @@ struct fnv1a_traits<std::uint32_t> {
template<>
struct fnv1a_traits<std::uint64_t> {
using type = std::uint64_t;
static constexpr std::uint64_t offset = 14695981039346656037ull;
static constexpr std::uint64_t prime = 1099511628211ull;
};
@@ -41,7 +45,7 @@ struct fnv1a_traits<std::uint64_t> {
/**
* Internal details not to be documented.
* @endcond TURN_OFF_DOXYGEN
* @endcond
*/
@@ -53,53 +57,35 @@ struct fnv1a_traits<std::uint64_t> {
* counterparts at runtime.<br/>
* Because of that, a hashed string can also be used in constant expressions if
* required.
*
* @tparam Char Character type.
*/
class hashed_string {
using traits_type = internal::fnv1a_traits<ENTT_ID_TYPE>;
template<typename Char>
class basic_hashed_string {
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 *curr) ENTT_NOEXCEPT: str{curr} {}
const Char *str;
};
// FowlerNollVo hash function v. 1a - the good
inline static constexpr ENTT_ID_TYPE helper(ENTT_ID_TYPE partial, const char *curr) ENTT_NOEXCEPT {
return curr[0] == 0 ? partial : helper((partial^curr[0])*traits_type::prime, curr+1);
[[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT {
auto value = traits_type::offset;
while(*curr != 0) {
value = (value ^ static_cast<traits_type::type>(*(curr++))) * traits_type::prime;
}
return value;
}
public:
/*! @brief Character type. */
using value_type = Char;
/*! @brief Unsigned integer type. */
using hash_type = ENTT_ID_TYPE;
/**
* @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 = hashed_string::to_value("my.png");
* @endcode
*
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifer.
* @return The numeric representation of the string.
*/
template<std::size_t N>
inline static constexpr hash_type to_value(const char (&str)[N]) ENTT_NOEXCEPT {
return helper(traits_type::offset, str);
}
/**
* @brief Returns directly the numeric representation of a string.
* @param wrapper Helps achieving the purpose by relying on overloading.
* @return The numeric representation of the string.
*/
inline static hash_type to_value(const_wrapper wrapper) ENTT_NOEXCEPT {
return helper(traits_type::offset, wrapper.str);
}
using hash_type = id_type;
/**
* @brief Returns directly the numeric representation of a string view.
@@ -107,50 +93,79 @@ public:
* @param size Length of the string to hash.
* @return The numeric representation of the string.
*/
inline static hash_type to_value(const char *str, std::size_t size) ENTT_NOEXCEPT {
ENTT_ID_TYPE partial{traits_type::offset};
[[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
id_type partial{traits_type::offset};
while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
return partial;
}
/*! @brief Constructs an empty hashed string. */
constexpr hashed_string() ENTT_NOEXCEPT
: str{nullptr}, hash{}
{}
/**
* @brief Constructs a hashed string from an array of const chars.
* @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}
* hashed_string hs{"my.png"};
* const auto value = basic_hashed_string<char>::to_value("my.png");
* @endcode
*
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifer.
* @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);
}
/**
* @brief Returns directly the numeric representation of a string.
* @param wrapper Helps achieving the purpose by relying on overloading.
* @return The numeric representation of the string.
*/
[[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT {
return helper(wrapper.str);
}
/*! @brief Constructs an empty hashed string. */
constexpr basic_hashed_string() ENTT_NOEXCEPT
: str{nullptr}, hash{}
{}
/**
* @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.
*/
template<std::size_t N>
constexpr hashed_string(const char (&curr)[N]) ENTT_NOEXCEPT
: str{curr}, hash{helper(traits_type::offset, curr)}
constexpr basic_hashed_string(const value_type (&curr)[N]) ENTT_NOEXCEPT
: str{curr}, hash{helper(curr)}
{}
/**
* @brief Explicit constructor on purpose to avoid constructing a hashed
* string directly from a `const char *`.
* string directly from a `const value_type *`.
* @param wrapper Helps achieving the purpose by relying on overloading.
*/
explicit constexpr hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
: str{wrapper.str}, hash{helper(traits_type::offset, wrapper.str)}
explicit constexpr basic_hashed_string(const_wrapper wrapper) ENTT_NOEXCEPT
: str{wrapper.str}, hash{helper(wrapper.str)}
{}
/**
* @brief Returns the human-readable representation of a hashed string.
* @return The string used to initialize the instance.
*/
constexpr const char * data() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT {
return str;
}
@@ -158,46 +173,71 @@ public:
* @brief Returns the numeric representation of a hashed string.
* @return The numeric representation of the instance.
*/
constexpr hash_type value() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr hash_type value() const ENTT_NOEXCEPT {
return hash;
}
/**
* @brief Returns the human-readable representation of a hashed string.
* @return The string used to initialize the instance.
*/
constexpr operator const char *() const ENTT_NOEXCEPT { return str; }
/*! @copydoc data */
[[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); }
/*! @copydoc value */
constexpr operator hash_type() const ENTT_NOEXCEPT { return hash; }
/**
* @brief Returns the numeric representation of a hashed string.
* @return The numeric representation of the instance.
*/
[[nodiscard]] constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); }
/**
* @brief Compares two hashed strings.
* @param other Hashed string with which to compare.
* @return True if the two hashed strings are identical, false otherwise.
*/
constexpr bool operator==(const hashed_string &other) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT {
return hash == other.hash;
}
private:
const char *str;
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.
* @tparam N Number of characters of the identifier.
* @param str Human-readable identifer.
*/
template<typename Char, std::size_t N>
basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT
-> basic_hashed_string<Char>;
/**
* @brief Compares two hashed strings.
* @tparam Char Character type.
* @param lhs A valid hashed string.
* @param rhs A valid hashed string.
* @return True if the two hashed strings are identical, false otherwise.
*/
constexpr bool operator!=(const hashed_string &lhs, const hashed_string &rhs) ENTT_NOEXCEPT {
template<typename Char>
[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
}
/*! @brief Aliases for common character types. */
using hashed_string = basic_hashed_string<char>;
/*! @brief Aliases for common character types. */
using hashed_wstring = basic_hashed_string<wchar_t>;
inline namespace literals {
/**
@@ -205,9 +245,25 @@ constexpr bool operator!=(const hashed_string &lhs, const hashed_string &rhs) EN
* @param str The literal without its suffix.
* @return A properly initialized hashed string.
*/
constexpr entt::hashed_string operator"" ENTT_HS_SUFFIX(const char *str, std::size_t) ENTT_NOEXCEPT {
[[nodiscard]] constexpr entt::hashed_string operator"" _hs(const char *str, std::size_t) ENTT_NOEXCEPT {
return entt::hashed_string{str};
}
#endif // ENTT_CORE_HASHED_STRING_HPP
/**
* @brief User defined literal for hashed wstrings.
* @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};
}
}
}
#endif

View File

@@ -2,10 +2,12 @@
#define ENTT_CORE_IDENT_HPP
#include <tuple>
#include <cstddef>
#include <utility>
#include <type_traits>
#include "../config/config.h"
#include "fwd.hpp"
#include "type_traits.hpp"
namespace entt {
@@ -40,25 +42,23 @@ namespace entt {
*/
template<typename... Types>
class identifier {
using tuple_type = std::tuple<std::decay_t<Types>...>;
template<typename Type, std::size_t... Indexes>
static constexpr ENTT_ID_TYPE get(std::index_sequence<Indexes...>) ENTT_NOEXCEPT {
static_assert(std::disjunction_v<std::is_same<Type, Types>...>);
return (0 + ... + (std::is_same_v<Type, std::tuple_element_t<Indexes, tuple_type>> ? ENTT_ID_TYPE(Indexes) : ENTT_ID_TYPE{}));
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{}));
}
public:
/*! @brief Unsigned integer type. */
using identifier_type = ENTT_ID_TYPE;
using identifier_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::make_index_sequence<sizeof...(Types)>{});
static constexpr identifier_type type = get<std::decay_t<Type>>(std::index_sequence_for<Types...>{});
};
}
#endif // ENTT_CORE_IDENT_HPP
#endif

View File

@@ -2,9 +2,8 @@
#define ENTT_CORE_MONOSTATE_HPP
#include <cassert>
#include "../config/config.h"
#include "hashed_string.hpp"
#include "fwd.hpp"
namespace entt {
@@ -21,7 +20,7 @@ namespace entt {
* both during an assignment and when they try to read back their data.
* Otherwise, they can incur in unexpected results.
*/
template<hashed_string::hash_type>
template<id_type>
struct monostate {
/**
* @brief Assigns a value of a specific type to a given key.
@@ -45,7 +44,7 @@ struct monostate {
private:
template<typename Type>
inline static maybe_atomic_t<Type> value{};
inline static ENTT_MAYBE_ATOMIC(Type) value{};
};
@@ -53,11 +52,11 @@ private:
* @brief Helper variable template.
* @tparam Value Value used to differentiate between different variables.
*/
template<hashed_string::hash_type Value>
template<id_type Value>
inline monostate<Value> monostate_v = {};
}
#endif // ENTT_CORE_MONOSTATE_HPP
#endif

251
src/entt/core/type_info.hpp Normal file
View File

@@ -0,0 +1,251 @@
#ifndef ENTT_CORE_TYPE_INFO_HPP
#define ENTT_CORE_TYPE_INFO_HPP
#include <string_view>
#include <type_traits>
#include "../config/config.h"
#include "../core/attribute.h"
#include "hashed_string.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
struct ENTT_API type_seq final {
[[nodiscard]] static id_type next() ENTT_NOEXCEPT {
static ENTT_MAYBE_ATOMIC(id_type) value{};
return value++;
}
};
template<typename Type>
[[nodiscard]] constexpr auto stripped_type_name() ENTT_NOEXCEPT {
#if defined ENTT_PRETTY_FUNCTION
std::string_view pretty_function{ENTT_PRETTY_FUNCTION};
auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX)+1);
auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first);
return value;
#else
return std::string_view{};
#endif
}
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
[[nodiscard]] static constexpr std::string_view type_name(int) ENTT_NOEXCEPT {
constexpr auto value = stripped_type_name<Type>();
return value;
}
template<typename Type>
[[nodiscard]] static std::string_view type_name(char) ENTT_NOEXCEPT {
static const auto value = stripped_type_name<Type>();
return value;
}
template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
[[nodiscard]] static constexpr id_type type_hash(int) ENTT_NOEXCEPT {
constexpr auto stripped = stripped_type_name<Type>();
constexpr auto value = hashed_string::value(stripped.data(), stripped.size());
return value;
}
template<typename Type>
[[nodiscard]] static id_type type_hash(char) ENTT_NOEXCEPT {
static const auto value = [](const auto stripped) {
return hashed_string::value(stripped.data(), stripped.size());
}(stripped_type_name<Type>());
return value;
}
}
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief Type sequential identifier.
* @tparam Type Type for which to generate a sequential identifier.
*/
template<typename Type, typename = void>
struct ENTT_API type_seq final {
/**
* @brief Returns the sequential identifier of a given type.
* @return The sequential identifier of a given type.
*/
[[nodiscard]] static id_type value() ENTT_NOEXCEPT {
static const id_type value = internal::type_seq::next();
return value;
}
};
/**
* @brief Type hash.
* @tparam Type Type for which to generate a hash value.
*/
template<typename Type, typename = void>
struct type_hash final {
/**
* @brief Returns the numeric representation of a given type.
* @return The numeric representation of the given type.
*/
#if defined ENTT_PRETTY_FUNCTION
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
return internal::type_hash<Type>(0);
#else
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
return type_seq<Type>::value();
#endif
}
};
/**
* @brief Type name.
* @tparam Type Type for which to generate a name.
*/
template<typename Type, typename = void>
struct type_name final {
/**
* @brief Returns the name of a given type.
* @return The name of the given type.
*/
[[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT {
return internal::type_name<Type>(0);
}
};
/*! @brief Implementation specific information about a type. */
class type_info final {
template<typename>
friend type_info type_id() ENTT_NOEXCEPT;
type_info(id_type seq_v, id_type hash_v, std::string_view name_v) ENTT_NOEXCEPT
: seq_value{seq_v},
hash_value{hash_v},
name_value{name_v}
{}
public:
/*! @brief Default constructor. */
type_info() ENTT_NOEXCEPT
: type_info({}, {}, {})
{}
/*! @brief Default copy constructor. */
type_info(const type_info &) ENTT_NOEXCEPT = default;
/*! @brief Default move constructor. */
type_info(type_info &&) ENTT_NOEXCEPT = default;
/**
* @brief Default copy assignment operator.
* @return This type info object.
*/
type_info & operator=(const type_info &) ENTT_NOEXCEPT = default;
/**
* @brief Default move assignment operator.
* @return This type info object.
*/
type_info & operator=(type_info &&) ENTT_NOEXCEPT = default;
/**
* @brief Checks if a type info object is properly initialized.
* @return True if the object is properly initialized, false otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return !name_value.empty();
}
/**
* @brief Type sequential identifier.
* @return Type sequential identifier.
*/
[[nodiscard]] id_type seq() const ENTT_NOEXCEPT {
return seq_value;
}
/**
* @brief Type hash.
* @return Type hash.
*/
[[nodiscard]] id_type hash() const ENTT_NOEXCEPT {
return hash_value;
}
/**
* @brief Type name.
* @return Type name.
*/
[[nodiscard]] std::string_view name() const ENTT_NOEXCEPT {
return name_value;
}
/**
* @brief Compares the contents of two type info objects.
* @param other Object with which to compare.
* @return False if the two contents differ, true otherwise.
*/
[[nodiscard]] bool operator==(const type_info &other) const ENTT_NOEXCEPT {
return hash_value == other.hash_value;
}
private:
id_type seq_value;
id_type hash_value;
std::string_view name_value;
};
/**
* @brief Compares the contents of two type info objects.
* @param lhs A type info object.
* @param rhs A type info object.
* @return True if the two contents differ, false otherwise.
*/
[[nodiscard]] inline bool operator!=(const type_info &lhs, const type_info &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/**
* @brief Returns the type info object for a given type.
* @tparam Type Type for which to generate a type info object.
* @return The type info object for the given type.
*/
template<typename Type>
type_info type_id() ENTT_NOEXCEPT {
return type_info{
type_seq<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()
};
}
}
#endif

View File

@@ -2,29 +2,197 @@
#define ENTT_CORE_TYPE_TRAITS_HPP
#include <cstddef>
#include <utility>
#include <type_traits>
#include "../core/hashed_string.hpp"
#include "../config/config.h"
#include "fwd.hpp"
namespace entt {
/**
* @brief Identity type trait.
*
* Useful to establish non-deduced contexts in template argument deduction
* (waiting for C++20) or to provide types through function arguments.
*
* @tparam Type A type.
*/
template<typename Type>
struct type_identity {
/*! @brief Identity type. */
using type = Type;
};
/**
* @brief Helper type.
* @tparam Type A type.
*/
template<typename Type>
using type_identity_t = typename type_identity<Type>::type;
/**
* @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains.
* @tparam Type The type of which to return the size.
* @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> {};
/*! @copydoc size_of */
template<typename Type>
struct size_of<Type, std::void_t<decltype(sizeof(Type))>>
: std::integral_constant<std::size_t, sizeof(Type)>
{};
/**
* @brief Helper variable template.
* @tparam Type The type of which to return the size.
*/
template<class Type>
inline constexpr auto size_of_v = size_of<Type>::value;
/**
* @brief Using declaration to be used to _repeat_ the same type a number of
* times equal to the size of a given parameter pack.
* @tparam Type A type to repeat.
*/
template<typename Type, typename>
using unpack_as_t = Type;
/**
* @brief Helper variable template to be used to _repeat_ the same value a
* number of times equal to the size of a given parameter pack.
* @tparam Value A value to repeat.
*/
template<auto Value, typename>
inline constexpr auto unpack_as_v = Value;
/**
* @brief Wraps a static constant.
* @tparam Value A static constant.
*/
template<auto Value>
using integral_constant = std::integral_constant<decltype(Value), Value>;
/**
* @brief Alias template to facilitate the creation of named values.
* @tparam Value A constant value at least convertible to `id_type`.
*/
template<id_type Value>
using tag = integral_constant<Value>;
/**
* @brief Utility class to disambiguate overloaded functions.
* @tparam N Number of choices available.
*/
template<std::size_t N>
struct choice_t
// Unfortunately, doxygen cannot parse such a construct.
/*! @cond TURN_OFF_DOXYGEN */
: choice_t<N-1>
/*! @endcond */
{};
/*! @copybrief choice_t */
template<>
struct choice_t<0> {};
/**
* @brief Variable template for the choice trick.
* @tparam N Number of choices available.
*/
template<std::size_t N>
inline constexpr choice_t<N> choice{};
/**
* @brief A class to use to push around lists of types, nothing more.
* @tparam Type Types provided by the given type list.
* @tparam Type Types provided by the type list.
*/
template<typename... Type>
struct type_list {
/*! @brief Unsigned integer type. */
/*! @brief Type list type. */
using type = type_list;
/*! @brief Compile-time number of elements in the type list. */
static constexpr auto size = sizeof...(Type);
};
/*! @brief Primary template isn't defined on purpose. */
template<std::size_t, typename>
struct type_list_element;
/**
* @brief Provides compile-time indexed access to the types of a type list.
* @tparam Index Index of the type to return.
* @tparam Type 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...>>
: 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 Other Other types provided by the type list.
*/
template<typename Type, typename... Other>
struct type_list_element<0u, type_list<Type, Other...>> {
/*! @brief Searched type. */
using type = Type;
};
/**
* @brief Helper type.
* @tparam Index Index of the type to return.
* @tparam List Type list to search into.
*/
template<std::size_t Index, typename List>
using type_list_element_t = typename type_list_element<Index, List>::type;
/**
* @brief Concatenates multiple type lists.
* @tparam Type Types provided by the first type list.
* @tparam Other Types provided by the second type list.
* @return A type list composed by the types of both the type lists.
*/
template<typename... Type, typename... Other>
constexpr type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) { return {}; }
/*! @brief Primary template isn't defined on purpose. */
template<typename...>
struct type_list_cat;
/*! @brief Concatenates multiple type lists. */
template<>
struct type_list_cat<> {
/*! @brief A type list composed by the types of all the type lists. */
using type = type_list<>;
};
/**
* @brief Concatenates multiple type lists.
* @tparam Type Types provided by the first type list.
@@ -94,135 +262,325 @@ template<typename Type>
using type_list_unique_t = typename type_list_unique<Type>::type;
/*! @brief Traits class used mainly to push things across boundaries. */
template<typename>
struct named_type_traits;
/**
* @brief Provides the member constant `value` to true if a type list contains a
* given type, false otherwise.
* @tparam List Type list.
* @tparam Type Type to look for.
*/
template<typename List, typename Type>
struct type_list_contains;
/**
* @brief Specialization used to get rid of constness.
* @tparam Type Named type.
* @copybrief type_list_contains
* @tparam Type Types provided by the type list.
* @tparam Other Type to look for.
*/
template<typename Type>
struct named_type_traits<const Type>
: named_type_traits<Type>
{};
/**
* @brief Helper type.
* @tparam Type Potentially named type.
*/
template<typename Type>
using named_type_traits_t = typename named_type_traits<Type>::type;
/**
* @brief Provides the member constant `value` to true if a given type has a
* name. In all other cases, `value` is false.
*/
template<typename, typename = std::void_t<>>
struct is_named_type: std::false_type {};
/**
* @brief Provides the member constant `value` to true if a given type has a
* name. In all other cases, `value` is false.
* @tparam Type Potentially named type.
*/
template<typename Type>
struct is_named_type<Type, std::void_t<named_type_traits_t<std::decay_t<Type>>>>: std::true_type {};
template<typename... Type, typename Other>
struct type_list_contains<type_list<Type...>, Other>: std::disjunction<std::is_same<Type, Other>...> {};
/**
* @brief Helper variable template.
*
* True if a given type has a name, false otherwise.
*
* @tparam Type Potentially named type.
* @tparam List Type list.
* @tparam Type Type to look for.
*/
template<class List, typename Type>
inline constexpr auto type_list_contains_v = type_list_contains<List, Type>::value;
/**
* @brief A class to use to push around lists of constant values, nothing more.
* @tparam Value Values provided by the value list.
*/
template<auto... Value>
struct value_list {
/*! @brief Value list type. */
using type = value_list;
/*! @brief Compile-time number of elements in the value list. */
static constexpr auto size = sizeof...(Value);
};
/*! @brief Primary template isn't defined on purpose. */
template<std::size_t, typename>
struct value_list_element;
/**
* @brief Provides compile-time indexed access to the values of a value list.
* @tparam Index Index of the value to return.
* @tparam Value First value provided by the value list.
* @tparam Other Other values provided by the value list.
*/
template<std::size_t Index, auto Value, auto... Other>
struct value_list_element<Index, value_list<Value, Other...>>
: value_list_element<Index - 1u, value_list<Other...>>
{};
/**
* @brief Provides compile-time indexed access to the types of a type list.
* @tparam Value First value provided by the value list.
* @tparam Other Other values provided by the value list.
*/
template<auto Value, auto... Other>
struct value_list_element<0u, value_list<Value, Other...>> {
/*! @brief Searched value. */
static constexpr auto value = Value;
};
/**
* @brief Helper type.
* @tparam Index Index of the value to return.
* @tparam List Value list to search into.
*/
template<std::size_t Index, typename List>
inline constexpr auto value_list_element_v = value_list_element<Index, List>::value;
/**
* @brief Concatenates multiple value lists.
* @tparam Value Values provided by the first value list.
* @tparam Other Values provided by the second value list.
* @return A value list composed by the values of both the value lists.
*/
template<auto... Value, auto... Other>
constexpr value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) { return {}; }
/*! @brief Primary template isn't defined on purpose. */
template<typename...>
struct value_list_cat;
/*! @brief Concatenates multiple value lists. */
template<>
struct value_list_cat<> {
/*! @brief A value list composed by the values of all the value lists. */
using type = value_list<>;
};
/**
* @brief Concatenates multiple value lists.
* @tparam Value Values provided by the first value list.
* @tparam Other Values provided by the second value list.
* @tparam List Other value lists, if any.
*/
template<auto... Value, auto... Other, typename... List>
struct value_list_cat<value_list<Value...>, value_list<Other...>, List...> {
/*! @brief A value list composed by the values of all the value lists. */
using type = typename value_list_cat<value_list<Value..., Other...>, List...>::type;
};
/**
* @brief Concatenates multiple value lists.
* @tparam Value Values provided by the value list.
*/
template<auto... Value>
struct value_list_cat<value_list<Value...>> {
/*! @brief A value list composed by the values of all the value lists. */
using type = value_list<Value...>;
};
/**
* @brief Helper type.
* @tparam List Value lists to concatenate.
*/
template<typename... List>
using value_list_cat_t = typename value_list_cat<List...>::type;
/**
* @brief Provides the member constant `value` to true if a given type is
* equality comparable, false otherwise.
* @tparam Type Potentially equality comparable type.
*/
template<typename Type, typename = void>
struct is_equality_comparable: std::false_type {};
/*! @copydoc is_equality_comparable */
template<typename Type>
struct is_equality_comparable<Type, std::void_t<decltype(std::declval<Type>() == std::declval<Type>())>>
: std::true_type
{};
/**
* @brief Helper variable template.
* @tparam Type Potentially equality comparable type.
*/
template<class Type>
constexpr auto is_named_type_v = is_named_type<Type>::value;
inline constexpr auto is_equality_comparable_v = is_equality_comparable<Type>::value;
/*! @brief Same as std::is_invocable, but with tuples. */
template<typename, typename>
struct is_applicable: std::false_type {};
/**
* @copybrief is_applicable
* @tparam Func A valid function type.
* @tparam Tuple Tuple-like type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Func, template<typename...> class Tuple, typename... Args>
struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
/**
* @copybrief is_applicable
* @tparam Func A valid function type.
* @tparam Tuple Tuple-like type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Func, template<typename...> class Tuple, typename... Args>
struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args...> {};
/**
* @brief Helper variable template.
* @tparam Func A valid function type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Func, typename Args>
inline constexpr auto is_applicable_v = is_applicable<Func, Args>::value;
/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */
template<typename, typename, typename>
struct is_applicable_r: std::false_type {};
/**
* @copybrief is_applicable_r
* @tparam Ret The type to which the return type of the function should be
* convertible.
* @tparam Func A valid function type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Ret, typename Func, typename... Args>
struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret, Func, Args...> {};
/**
* @brief Helper variable template.
* @tparam Ret The type to which the return type of the function should be
* convertible.
* @tparam Func A valid function type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Ret, typename Func, typename Args>
inline constexpr auto is_applicable_r_v = is_applicable_r<Ret, Func, Args>::value;
/**
* @brief Provides the member constant `value` to true if a given type is
* complete, false otherwise.
* @tparam Type Potential complete type.
*/
template<typename Type, typename = void>
struct is_complete: std::false_type {};
/*! @copydoc is_complete */
template<typename Type>
struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {};
/**
* @brief Helper variable template.
* @tparam Type Potential complete type.
*/
template<typename Type>
inline constexpr auto is_complete_v = is_complete<Type>::value;
/**
* @brief Provides the member constant `value` to true if a given type is empty
* and the empty type optimization is enabled, false otherwise.
* @tparam Type Potential empty type.
*/
template<typename Type, typename = void>
struct is_empty: ENTT_IS_EMPTY(Type) {};
/**
* @brief Helper variable template.
* @tparam Type Potential empty type.
*/
template<typename Type>
inline constexpr auto is_empty_v = is_empty<Type>::value;
/**
* @brief Transcribes the constness of a type to another type.
* @tparam To The type to which to transcribe the constness.
* @tparam From The type from which to transcribe the constness.
*/
template<typename To, typename From>
struct constness_as {
/*! @brief The type resulting from the transcription of the constness */
using type = std::remove_const_t<To>;
};
/*! @copydoc constness_as */
template<typename To, typename From>
struct constness_as<To, const From> {
/*! @brief The type resulting from the transcription of the constness */
using type = std::add_const_t<To>;
};
/**
* @brief Alias template to facilitate the transcription of the constness.
* @tparam To The type to which to transcribe the constness.
* @tparam From The type from which to transcribe the constness.
*/
template<typename To, typename From>
using constness_as_t = typename constness_as<To, From>::type;
/**
* @brief Extracts the class of a non-static member object or function.
* @tparam Member A pointer to a non-static member object or function.
*/
template<typename Member>
class member_class {
static_assert(std::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function");
template<typename Class, typename Ret, typename... Args>
static Class * clazz(Ret(Class:: *)(Args...));
template<typename Class, typename Ret, typename... Args>
static Class * clazz(Ret(Class:: *)(Args...) const);
template<typename Class, typename Type>
static Class * clazz(Type Class:: *);
public:
/*! @brief The class of the given non-static member object or function. */
using type = std::remove_pointer_t<decltype(clazz(std::declval<Member>()))>;
};
/**
* @brief Helper type.
* @tparam Member A pointer to a non-static member object or function.
*/
template<typename Member>
using member_class_t = typename member_class<Member>::type;
}
/**
* @brief Utility macro to deal with an issue of MSVC.
*
* See _msvc-doesnt-expand-va-args-correctly_ on SO for all the details.
*
* @param args Argument to expand.
*/
#define ENTT_EXPAND(args) args
/**
* @brief Makes an already existing type a named type.
* @param type Type to assign a name to.
*/
#define ENTT_NAMED_TYPE(type)\
template<>\
struct entt::named_type_traits<type>\
: std::integral_constant<typename entt::hashed_string::hash_type, entt::hashed_string::to_value(#type)>\
{\
static_assert(std::is_same_v<std::decay_t<type>, type>);\
};
/**
* @brief Defines a named type (to use for structs).
* @param clazz Name of the type to define.
* @param body Body of the type to define.
*/
#define ENTT_NAMED_STRUCT_ONLY(clazz, body)\
struct clazz body;\
ENTT_NAMED_TYPE(clazz)
/**
* @brief Defines a named type (to use for structs).
* @param ns Namespace where to define the named type.
* @param clazz Name of the type to define.
* @param body Body of the type to define.
*/
#define ENTT_NAMED_STRUCT_WITH_NAMESPACE(ns, clazz, body)\
namespace ns { struct clazz body; }\
ENTT_NAMED_TYPE(ns::clazz)
/*! @brief Utility function to simulate macro overloading. */
#define ENTT_NAMED_STRUCT_OVERLOAD(_1, _2, _3, FUNC, ...) FUNC
/*! @brief Defines a named type (to use for structs). */
#define ENTT_NAMED_STRUCT(...) ENTT_EXPAND(ENTT_NAMED_STRUCT_OVERLOAD(__VA_ARGS__, ENTT_NAMED_STRUCT_WITH_NAMESPACE, ENTT_NAMED_STRUCT_ONLY,)(__VA_ARGS__))
/**
* @brief Defines a named type (to use for classes).
* @param clazz Name of the type to define.
* @param body Body of the type to define.
*/
#define ENTT_NAMED_CLASS_ONLY(clazz, body)\
class clazz body;\
ENTT_NAMED_TYPE(clazz)
/**
* @brief Defines a named type (to use for classes).
* @param ns Namespace where to define the named type.
* @param clazz Name of the type to define.
* @param body Body of the type to define.
*/
#define ENTT_NAMED_CLASS_WITH_NAMESPACE(ns, clazz, body)\
namespace ns { class clazz body; }\
ENTT_NAMED_TYPE(ns::clazz)
/*! @brief Utility function to simulate macro overloading. */
#define ENTT_NAMED_CLASS_MACRO(_1, _2, _3, FUNC, ...) FUNC
/*! @brief Defines a named type (to use for classes). */
#define ENTT_NAMED_CLASS(...) ENTT_EXPAND(ENTT_NAMED_CLASS_MACRO(__VA_ARGS__, ENTT_NAMED_CLASS_WITH_NAMESPACE, ENTT_NAMED_CLASS_ONLY,)(__VA_ARGS__))
#endif // ENTT_CORE_TYPE_TRAITS_HPP
#endif

View File

@@ -2,31 +2,104 @@
#define ENTT_CORE_UTILITY_HPP
#include <utility>
#include "../config/config.h"
namespace entt {
/*! @brief Identity function object (waiting for C++20). */
struct identity {
/**
* @brief Returns its argument unchanged.
* @tparam Type Type of the argument.
* @param value The actual argument.
* @return The submitted value as-is.
*/
template<class Type>
[[nodiscard]] constexpr Type && operator()(Type &&value) const ENTT_NOEXCEPT {
return std::forward<Type>(value);
}
};
/**
* @brief Constant utility to disambiguate overloaded member functions.
* @tparam Type Function type of the desired overload.
* @tparam Class Type of class to which the member functions belong.
* @param member A valid pointer to a member function.
* @return Pointer to the member function.
* @brief Constant utility to disambiguate overloaded members of a class.
* @tparam Type Type of the desired overload.
* @tparam Class Type of class to which the member belongs.
* @param member A valid pointer to a member.
* @return Pointer to the member.
*/
template<typename Type, typename Class>
constexpr auto overload(Type Class:: *member) { return member; }
[[nodiscard]] constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; }
/**
* @brief Constant utility to disambiguate overloaded functions.
* @tparam Type Function type of the desired overload.
* @tparam Func Function type of the desired overload.
* @param func A valid pointer to a function.
* @return Pointer to the function.
*/
template<typename Type>
constexpr auto overload(Type *func) { return func; }
template<typename Func>
[[nodiscard]] constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; }
/**
* @brief Helper type for visitors.
* @tparam Func Types of function objects.
*/
template<class... Func>
struct overloaded: Func... {
using Func::operator()...;
};
/**
* @brief Deduction guide.
* @tparam Func Types of function objects.
*/
template<class... Func>
overloaded(Func...) -> overloaded<Func...>;
/**
* @brief Basic implementation of a y-combinator.
* @tparam Func Type of a potentially recursive function.
*/
template<class Func>
struct y_combinator {
/**
* @brief Constructs a y-combinator from a given function.
* @param recursive A potentially recursive function.
*/
y_combinator(Func recursive):
func{std::move(recursive)}
{}
/**
* @brief Invokes a y-combinator and therefore its underlying function.
* @tparam Args Types of arguments to use to invoke the underlying function.
* @param args Parameters to use to invoke the underlying function.
* @return Return value of the underlying function, if any.
*/
template <class... Args>
decltype(auto) operator()(Args &&... args) const {
return func(*this, std::forward<Args>(args)...);
}
/*! @copydoc operator()() */
template <class... Args>
decltype(auto) operator()(Args &&... args) {
return func(*this, std::forward<Args>(args)...);
}
private:
Func func;
};
}
#endif // ENTT_CORE_UTILITY_HPP
#endif

View File

@@ -1,180 +0,0 @@
#ifndef ENTT_ENTITY_ACTOR_HPP
#define ENTT_ENTITY_ACTOR_HPP
#include <cassert>
#include <utility>
#include <type_traits>
#include "../config/config.h"
#include "registry.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Dedicated to those who aren't confident with entity-component systems.
*
* Tiny wrapper around a registry, for all those users that aren't confident
* with entity-component systems and prefer to iterate objects directly.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
struct basic_actor {
/*! @brief Type of registry used internally. */
using registry_type = basic_registry<Entity>;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/**
* @brief Constructs an actor by using the given registry.
* @param ref An entity-component system properly initialized.
*/
basic_actor(registry_type &ref)
: reg{&ref}, entt{ref.create()}
{}
/*! @brief Default destructor. */
virtual ~basic_actor() {
reg->destroy(entt);
}
/**
* @brief Move constructor.
*
* After actor move construction, instances that have been moved from are
* placed in a valid but unspecified state. It's highly discouraged to
* continue using them.
*
* @param other The instance to move from.
*/
basic_actor(basic_actor &&other)
: reg{other.reg}, entt{other.entt}
{
other.entt = null;
}
/**
* @brief Move assignment operator.
*
* After actor move assignment, instances that have been moved from are
* placed in a valid but unspecified state. It's highly discouraged to
* continue using them.
*
* @param other The instance to move from.
* @return This actor.
*/
basic_actor & operator=(basic_actor &&other) {
if(this != &other) {
auto tmp{std::move(other)};
std::swap(reg, tmp.reg);
std::swap(entt, tmp.entt);
}
return *this;
}
/**
* @brief Assigns the given component to an actor.
*
* A new instance of the given component is created and initialized with the
* arguments provided (the component must have a proper constructor or be of
* aggregate type). Then the component is assigned to the actor.<br/>
* In case the actor already has a component of the given type, it's
* replaced with the new one.
*
* @tparam Component Type of the component to create.
* @tparam Args Types of arguments to use to construct the component.
* @param args Parameters to use to initialize the component.
* @return A reference to the newly created component.
*/
template<typename Component, typename... Args>
decltype(auto) assign(Args &&... args) {
return reg->template assign_or_replace<Component>(entt, std::forward<Args>(args)...);
}
/**
* @brief Removes the given component from an actor.
* @tparam Component Type of the component to remove.
*/
template<typename Component>
void remove() {
reg->template remove<Component>(entt);
}
/**
* @brief Checks if an actor has the given component.
* @tparam Component Type of the component for which to perform the check.
* @return True if the actor has the component, false otherwise.
*/
template<typename Component>
bool has() const ENTT_NOEXCEPT {
return reg->template has<Component>(entt);
}
/**
* @brief Returns references to the given components for an actor.
* @tparam Component Types of components to get.
* @return References to the components owned by the actor.
*/
template<typename... Component>
decltype(auto) get() const ENTT_NOEXCEPT {
return std::as_const(*reg).template get<Component...>(entt);
}
/*! @copydoc get */
template<typename... Component>
decltype(auto) get() ENTT_NOEXCEPT {
return reg->template get<Component...>(entt);
}
/**
* @brief Returns pointers to the given components for an actor.
* @tparam Component Types of components to get.
* @return Pointers to the components owned by the actor.
*/
template<typename... Component>
auto try_get() const ENTT_NOEXCEPT {
return std::as_const(*reg).template try_get<Component...>(entt);
}
/*! @copydoc try_get */
template<typename... Component>
auto try_get() ENTT_NOEXCEPT {
return reg->template try_get<Component...>(entt);
}
/**
* @brief Returns a reference to the underlying registry.
* @return A reference to the underlying registry.
*/
inline const registry_type & backend() const ENTT_NOEXCEPT {
return *reg;
}
/*! @copydoc backend */
inline registry_type & backend() ENTT_NOEXCEPT {
return const_cast<registry_type &>(std::as_const(*this).backend());
}
/**
* @brief Returns the entity associated with an actor.
* @return The entity associated with the actor.
*/
inline entity_type entity() const ENTT_NOEXCEPT {
return entt;
}
private:
registry_type *reg;
Entity entt;
};
}
#endif // ENTT_ENTITY_ACTOR_HPP

View File

@@ -2,6 +2,9 @@
#define ENTT_ENTITY_ENTITY_HPP
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include "../config/config.h"
@@ -14,34 +17,18 @@ namespace entt {
* Primary template isn't defined on purpose. All the specializations give a
* compile-time error unless the template parameter is an accepted entity type.
*/
template<typename>
template<typename, typename = void>
struct entt_traits;
/**
* @brief Entity traits for a 16 bits entity identifier.
*
* A 16 bits entity identifier guarantees:
*
* * 12 bits for the entity number (up to 4k entities).
* * 4 bit for the version (resets in [0-15]).
* @brief Entity traits for enumeration types.
* @tparam Type The type to check.
*/
template<>
struct entt_traits<std::uint16_t> {
/*! @brief Underlying entity type. */
using entity_type = std::uint16_t;
/*! @brief Underlying version type. */
using version_type = std::uint8_t;
/*! @brief Difference type. */
using difference_type = std::int32_t;
/*! @brief Mask to use to get the entity number out of an identifier. */
static constexpr std::uint16_t entity_mask = 0xFFF;
/*! @brief Mask to use to get the version out of an identifier. */
static constexpr std::uint16_t version_mask = 0xF;
/*! @brief Extent of the entity number within an identifier. */
static constexpr auto entity_shift = 12;
};
template<typename Type>
struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>>
: entt_traits<std::underlying_type_t<Type>>
{};
/**
@@ -62,11 +49,11 @@ struct entt_traits<std::uint32_t> {
using difference_type = std::int64_t;
/*! @brief Mask to use to get the entity number out of an identifier. */
static constexpr std::uint32_t entity_mask = 0xFFFFF;
static constexpr entity_type entity_mask = 0xFFFFF;
/*! @brief Mask to use to get the version out of an identifier. */
static constexpr std::uint32_t version_mask = 0xFFF;
static constexpr entity_type version_mask = 0xFFF;
/*! @brief Extent of the entity number within an identifier. */
static constexpr auto entity_shift = 20;
static constexpr std::size_t entity_shift = 20u;
};
@@ -88,82 +75,121 @@ struct entt_traits<std::uint64_t> {
using difference_type = std::int64_t;
/*! @brief Mask to use to get the entity number out of an identifier. */
static constexpr std::uint64_t entity_mask = 0xFFFFFFFF;
static constexpr entity_type entity_mask = 0xFFFFFFFF;
/*! @brief Mask to use to get the version out of an identifier. */
static constexpr std::uint64_t version_mask = 0xFFFFFFFF;
static constexpr entity_type version_mask = 0xFFFFFFFF;
/*! @brief Extent of the entity number within an identifier. */
static constexpr auto entity_shift = 32;
static constexpr std::size_t entity_shift = 32u;
};
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
* @brief Converts an entity type to its underlying type.
* @tparam Entity The value type.
* @param entity The value to convert.
* @return The integral representation of the given value.
*/
template<typename Entity>
[[nodiscard]] constexpr auto to_integral(const Entity entity) ENTT_NOEXCEPT {
return static_cast<typename entt_traits<Entity>::entity_type>(entity);
}
namespace internal {
struct null {
/*! @brief Null object for all entity identifiers. */
struct null_t {
/**
* @brief Converts the null object to identifiers of any type.
* @tparam Entity Type of entity identifier.
* @return The null representation for the given identifier.
*/
template<typename Entity>
constexpr operator Entity() const ENTT_NOEXCEPT {
using traits_type = entt_traits<Entity>;
return traits_type::entity_mask | (traits_type::version_mask << traits_type::entity_shift);
[[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT {
return Entity{entt_traits<Entity>::entity_mask};
}
constexpr bool operator==(null) const ENTT_NOEXCEPT {
/**
* @brief Compares two null objects.
* @return True in all cases.
*/
[[nodiscard]] constexpr bool operator==(const null_t &) const ENTT_NOEXCEPT {
return true;
}
constexpr bool operator!=(null) const ENTT_NOEXCEPT {
/**
* @brief Compares two null objects.
* @return False in all cases.
*/
[[nodiscard]] constexpr bool operator!=(const null_t &) const ENTT_NOEXCEPT {
return false;
}
/**
* @brief Compares a null object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
return entity == static_cast<Entity>(*this);
[[nodiscard]] constexpr bool operator==(const Entity &entity) const ENTT_NOEXCEPT {
return (to_integral(entity) & entt_traits<Entity>::entity_mask) == to_integral(static_cast<Entity>(*this));
}
/**
* @brief Compares a null object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT {
return entity != static_cast<Entity>(*this);
[[nodiscard]] constexpr bool operator!=(const Entity &entity) const ENTT_NOEXCEPT {
return !(entity == *this);
}
};
/**
* @brief Compares a null object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @param other A null object yet to be converted.
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
constexpr bool operator==(const Entity entity, null other) ENTT_NOEXCEPT {
return other == entity;
[[nodiscard]] constexpr bool operator==(const Entity &entity, const null_t &other) ENTT_NOEXCEPT {
return other.operator==(entity);
}
/**
* @brief Compares a null object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @param other A null object yet to be converted.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
constexpr bool operator!=(const Entity entity, null other) ENTT_NOEXCEPT {
return other != entity;
}
[[nodiscard]] constexpr bool operator!=(const Entity &entity, const null_t &other) ENTT_NOEXCEPT {
return !(other == entity);
}
/**
* Internal details not to be documented.
* @endcond TURN_OFF_DOXYGEN
* @endcond
*/
/**
* @brief Null entity.
* @brief Compile-time constant for null entities.
*
* There exist implicit conversions from this variable to entity identifiers of
* any allowed type. Similarly, there exist comparision operators between the
* null entity and any other entity identifier.
*/
constexpr auto null = internal::null{};
inline constexpr null_t null{};
}
#endif // ENTT_ENTITY_ENTITY_HPP
#endif

View File

@@ -2,88 +2,145 @@
#define ENTT_ENTITY_FWD_HPP
#include <cstdint>
#include "../config/config.h"
#include "../core/fwd.hpp"
namespace entt {
/*! @class basic_registry */
template <typename>
template<typename>
class basic_sparse_set;
template<typename, typename, typename>
class basic_storage;
template<typename>
class basic_registry;
/*! @class basic_view */
template<typename, typename...>
template<typename...>
class basic_view;
/*! @class basic_runtime_view */
template<typename>
class basic_runtime_view;
/*! @class basic_group */
template<typename...>
class basic_group;
/*! @class basic_actor */
template <typename>
struct basic_actor;
/*! @class basic_prototype */
template<typename>
class basic_prototype;
class basic_observer;
template<typename>
class basic_organizer;
template<typename, typename...>
struct basic_handle;
/*! @class basic_snapshot */
template<typename>
class basic_snapshot;
/*! @class basic_snapshot_loader */
template<typename>
class basic_snapshot_loader;
/*! @class basic_continuous_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 entity = std::uint32_t;
using sparse_set = basic_sparse_set<entity>;
/**
* @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 actor = basic_actor<entity>;
/*! @brief Alias declaration for the most common use case. */
using prototype = basic_prototype<entity>;
using observer = basic_observer<entity>;
/*! @brief Alias declaration for the most common use case. */
using organizer = basic_organizer<entity>;
/*! @brief Alias declaration for the most common use case. */
using handle = basic_handle<entity>;
/*! @brief Alias declaration for the most common use case. */
using const_handle = basic_handle<const entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using handle_view = basic_handle<entity, Args...>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Args Other template parameters.
*/
template<typename... Args>
using const_handle_view = basic_handle<const entity, Args...>;
/*! @brief Alias declaration for the most common use case. */
using snapshot = basic_snapshot<entity>;
/*! @brief Alias declaration for the most common use case. */
using snapshot_loader = basic_snapshot_loader<entity>;
/*! @brief Alias declaration for the most common use case. */
using continuous_loader = basic_continuous_loader<entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Component Types of components iterated by the view.
* @tparam Args Other template parameters.
*/
template<typename... Types>
using view = basic_view<entity, Types...>;
template<typename... Args>
using view = basic_view<entity, Args...>;
/*! @brief Alias declaration for the most common use case. */
using runtime_view = basic_runtime_view<entity>;
/**
* @brief Alias declaration for the most common use case.
* @tparam Types Types of components iterated by the group.
* @tparam Args Other template parameters.
*/
template<typename... Types>
using group = basic_group<entity, Types...>;
template<typename... Args>
using group = basic_group<entity, Args...>;
}
#endif // ENTT_ENTITY_FWD_HPP
#endif

File diff suppressed because it is too large Load Diff

341
src/entt/entity/handle.hpp Normal file
View File

@@ -0,0 +1,341 @@
#ifndef ENTT_ENTITY_HANDLE_HPP
#define ENTT_ENTITY_HANDLE_HPP
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "fwd.hpp"
#include "registry.hpp"
namespace entt {
/**
* @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.
*/
template<typename Entity, typename... Type>
struct basic_handle {
/*! @brief Underlying entity identifier. */
using entity_type = std::remove_const_t<Entity>;
/*! @brief Type of registry accepted by the handle. */
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
/*! @brief Constructs an invalid handle. */
basic_handle() ENTT_NOEXCEPT
: reg{}, entt{null}
{}
/**
* @brief Constructs a handle from a given registry and entity.
* @param ref An instance of the registry class.
* @param value An entity identifier.
*/
basic_handle(registry_type &ref, entity_type value) ENTT_NOEXCEPT
: reg{&ref}, entt{value}
{}
/**
* @brief Compares two handles.
* @tparam Args Template parameters of the handle with which to compare.
* @param other Handle with which to compare.
* @return True if both handles refer to the same registry and the same
* entity, false otherwise.
*/
template<typename... Args>
[[nodiscard]] bool operator==(const basic_handle<Args...> &other) const ENTT_NOEXCEPT {
return reg == other.registry() && entt == other.entity();
}
/**
* @brief Constructs a const handle from a non-const one.
* @tparam Other A valid entity type (see entt_traits for more details).
* @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>)
&& (sizeof...(Type) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Type)) && ... && (type_list_contains_v<type_list<Type...>, Args>))),
"Invalid conversion between different handles"
);
return reg ? basic_handle<Other, Args...>{*reg, entt} : basic_handle<Other, Args...>{};
}
/**
* @brief Converts a handle to its underlying entity.
* @return An entity identifier.
*/
[[nodiscard]] operator entity_type() const ENTT_NOEXCEPT {
return entity();
}
/**
* @brief Checks if a handle refers to non-null registry pointer and entity.
* @return True if the handle refers to non-null registry and entity, false otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return reg && reg->valid(entt);
}
/**
* @brief Checks if a handle refers to a valid entity or not.
* @return True if the handle refers to a valid entity, false otherwise.
*/
[[nodiscard]] bool valid() const {
return reg->valid(entt);
}
/**
* @brief Returns a pointer to the underlying registry, if any.
* @return A pointer to the underlying registry, if any.
*/
[[nodiscard]] registry_type * registry() const ENTT_NOEXCEPT {
return reg;
}
/**
* @brief Returns the entity associated with a handle.
* @return The entity associated with the handle.
*/
[[nodiscard]] entity_type entity() const ENTT_NOEXCEPT {
return entt;
}
/**
* @brief Destroys the entity associated with a handle.
* @sa basic_registry::destroy
*/
void destroy() {
reg->destroy(entt);
}
/**
* @brief Destroys the entity associated with a handle.
* @sa basic_registry::destroy
* @param version A desired version upon destruction.
*/
void destroy(const typename registry_type::version_type version) {
reg->destroy(entt, 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.
* @return A reference to the newly created component.
*/
template<typename Component, typename... Args>
decltype(auto) emplace(Args &&... args) const {
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
return reg->template emplace<Component>(entt, std::forward<Args>(args)...);
}
/**
* @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.
* @return A reference to the newly created component.
*/
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");
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.
* @return A reference to the patched component.
*/
template<typename Component, typename... Func>
decltype(auto) patch(Func &&... func) const {
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
return reg->template patch<Component>(entt, std::forward<Func>(func)...);
}
/**
* @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.
* @return A reference to the component being replaced.
*/
template<typename Component, typename... Args>
decltype(auto) replace(Args &&... args) const {
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "Invalid type");
return reg->template replace<Component>(entt, std::forward<Args>(args)...);
}
/**
* @brief Removes the given components from a handle.
* @sa basic_registry::remove
* @tparam Component Types of components to remove.
*/
template<typename... Component>
void remove() const {
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
reg->template remove<Component...>(entt);
}
/**
* @brief Removes the given components from a handle.
* @sa basic_registry::remove_if_exists
* @tparam Component Types of components to remove.
* @return The number of components actually removed.
*/
template<typename... Component>
decltype(auto) remove_if_exists() const {
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
return reg->template remove_if_exists<Component...>(entt);
}
/**
* @brief Removes all the components from a handle and makes it orphaned.
* @sa basic_registry::remove_all
*/
void remove_all() const {
static_assert(sizeof...(Type) == 0, "Invalid operation");
reg->remove_all(entt);
}
/**
* @brief Checks if a handle has all the given components.
* @sa basic_registry::has
* @tparam Component Components for which to perform the check.
* @return True if the handle has all the components, false otherwise.
*/
template<typename... Component>
[[nodiscard]] decltype(auto) has() const {
return reg->template has<Component...>(entt);
}
/**
* @brief Checks if a handle has at least one of the given components.
* @sa basic_registry::any
* @tparam Component Components for which to perform the check.
* @return True if the handle has at least one of the given components,
* false otherwise.
*/
template<typename... Component>
[[nodiscard]] decltype(auto) any() const {
return reg->template any<Component...>(entt);
}
/**
* @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");
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.
* @return Reference to the component owned by the handle.
*/
template<typename Component, typename... Args>
[[nodiscard]] decltype(auto) get_or_emplace(Args &&... args) const {
static_assert(((sizeof...(Type) == 0) || ... || std::is_same_v<Component, Type>), "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");
return reg->template try_get<Component...>(entt);
}
/**
* @brief Checks if a handle has components assigned.
* @return True if the handle has no components assigned, false otherwise.
*/
[[nodiscard]] bool orphan() const {
return reg->orphan(entt);
}
/**
* @brief Visits a handle and returns the types for its components.
* @sa basic_registry::visit
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void visit(Func &&func) const {
reg->visit(entt, std::forward<Func>(func));
}
private:
registry_type *reg;
entity_type entt;
};
/**
* @brief Compares two handles.
* @tparam Type A valid entity type (see entt_traits for more details).
* @tparam Other A valid entity type (see entt_traits for more details).
* @param lhs A valid handle.
* @param rhs A valid handle.
* @return False if both handles refer to the same registry and the same
* entity, true otherwise.
*/
template<typename Type, typename Other>
bool operator!=(const basic_handle<Type> &lhs, const basic_handle<Other> &rhs) ENTT_NOEXCEPT {
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>;
}
#endif

View File

@@ -4,9 +4,10 @@
#include <type_traits>
#include "../config/config.h"
#include "../core/hashed_string.hpp"
#include "../signal/sigh.hpp"
#include "../core/type_traits.hpp"
#include "../signal/delegate.hpp"
#include "registry.hpp"
#include "fwd.hpp"
namespace entt {
@@ -14,13 +15,14 @@ namespace entt {
/**
* @brief Converts a registry to a view.
* @tparam Const Constness of the accepted registry.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<bool Const, typename Entity>
template<typename Entity>
struct as_view {
/*! @brief Underlying entity identifier. */
using entity_type = std::remove_const_t<Entity>;
/*! @brief Type of registry to convert. */
using registry_type = std::conditional_t<Const, const entt::basic_registry<Entity>, entt::basic_registry<Entity>>;
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
/**
* @brief Constructs a converter for a given registry.
@@ -30,12 +32,13 @@ struct as_view {
/**
* @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.
* @return A newly created view.
*/
template<typename... Component>
inline operator entt::basic_view<Entity, Component...>() const {
return reg.template view<Component...>();
template<typename Exclude, typename... Component>
operator basic_view<entity_type, Exclude, Component...>() const {
return reg.template view<Component...>(Exclude{});
}
private:
@@ -52,23 +55,24 @@ private:
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_view(basic_registry<Entity> &) ENTT_NOEXCEPT -> as_view<false, Entity>;
as_view(basic_registry<Entity> &) ENTT_NOEXCEPT -> as_view<Entity>;
/*! @copydoc as_view */
template<typename Entity>
as_view(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_view<true, Entity>;
as_view(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_view<const Entity>;
/**
* @brief Converts a registry to a group.
* @tparam Const Constness of the accepted registry.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<bool Const, typename Entity>
template<typename Entity>
struct as_group {
/*! @brief Underlying entity identifier. */
using entity_type = std::remove_const_t<Entity>;
/*! @brief Type of registry to convert. */
using registry_type = std::conditional_t<Const, const entt::basic_registry<Entity>, entt::basic_registry<Entity>>;
using registry_type = constness_as_t<basic_registry<entity_type>, Entity>;
/**
* @brief Constructs a converter for a given registry.
@@ -78,17 +82,18 @@ struct as_group {
/**
* @brief Conversion function from a registry to a group.
*
* @note
* Unfortunately, only full owning groups are supported because of an issue
* with msvc that doesn't manage to correctly deduce types.
*
* @tparam Exclude Types of components used to filter the group.
* @tparam Get Types of components observed by the group.
* @tparam Owned Types of components owned by the group.
* @return A newly created group.
*/
template<typename... Owned>
inline operator entt::basic_group<Entity, get_t<>, Owned...>() const {
return reg.template group<Owned...>();
template<typename Exclude, typename Get, typename... Owned>
operator basic_group<entity_type, Exclude, Get, Owned...>() 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{});
}
}
private:
@@ -105,107 +110,46 @@ private:
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_group(basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<false, Entity>;
as_group(basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<Entity>;
/*! @copydoc as_group */
template<typename Entity>
as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<true, Entity>;
as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<const Entity>;
/**
* @brief Dependency function prototype.
*
* A _dependency function_ is a built-in listener to use to automatically assign
* components to an entity when a type has a dependency on some other types.
*
* This is a prototype function to use to create dependencies.<br/>
* It isn't intended for direct use, although nothing forbids using it freely.
*
* @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 Component Type of component that triggers the dependency handler.
* @tparam Dependency Types of components to assign to an entity if triggered.
* @param reg A valid reference to a registry.
* @param entt A valid entity identifier.
* @param reg A registry that contains the given entity and its components.
* @param entt Entity from which to get the component.
*/
template<typename Entity, typename Component, typename... Dependency>
void dependency(basic_registry<Entity> &reg, const Entity entt, const Component &) {
((reg.template has<Dependency>(entt) ? void() : (reg.template assign<Dependency>(entt), void())), ...);
template<auto Member, typename Entity = entity>
void invoke(basic_registry<Entity> &reg, const Entity 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;
func.template connect<Member>(reg.template get<member_class_t<decltype(Member)>>(entt));
func(reg, entt);
}
/**
* @brief Connects a dependency function to the given sink.
*
* A _dependency function_ is a built-in listener to use to automatically assign
* components to an entity when a type has a dependency on some other types.
*
* The following adds components `a_type` and `another_type` whenever `my_type`
* is assigned to an entity:
* @code{.cpp}
* entt::registry registry;
* entt::connect<a_type, another_type>(registry.construction<my_type>());
* @endcode
*
* @tparam Dependency Types of components to assign to an entity if triggered.
* @tparam Component Type of component that triggers the dependency handler.
* @brief Returns the entity associated with a given component.
* @tparam Entity A valid entity type (see entt_traits for more details).
* @param sink A sink object properly initialized.
* @tparam Component Type of component.
* @param reg A registry that contains the given entity and its components.
* @param component A valid component instance.
* @return The entity associated with the given component.
*/
template<typename... Dependency, typename Component, typename Entity>
inline void connect(sink<void(basic_registry<Entity> &, const Entity, Component &)> sink) {
sink.template connect<dependency<Entity, Component, Dependency...>>();
template<typename Entity, typename Component>
Entity to_entity(const basic_registry<Entity> &reg, const Component &component) {
return *(reg.template data<Component>() + (&component - reg.template raw<Component>()));
}
/**
* @brief Disconnects a dependency function from the given sink.
*
* A _dependency function_ is a built-in listener to use to automatically assign
* components to an entity when a type has a dependency on some other types.
*
* The following breaks the dependency between the component `my_type` and the
* components `a_type` and `another_type`:
* @code{.cpp}
* entt::registry registry;
* entt::disconnect<a_type, another_type>(registry.construction<my_type>());
* @endcode
*
* @tparam Dependency Types of components used to create the dependency.
* @tparam Component Type of component that triggers the dependency handler.
* @tparam Entity A valid entity type (see entt_traits for more details).
* @param sink A sink object properly initialized.
*/
template<typename... Dependency, typename Component, typename Entity>
inline void disconnect(sink<void(basic_registry<Entity> &, const Entity, Component &)> sink) {
sink.template disconnect<dependency<Entity, Component, Dependency...>>();
}
/**
* @brief Alias template to ease the assignment of tags to entities.
*
* If used in combination with hashed strings, it simplifies the assignment of
* tags to entities and the use of tags in general where a type would be
* required otherwise.<br/>
* As an example and where the user defined literal for hashed strings hasn't
* been changed:
* @code{.cpp}
* entt::registry registry;
* registry.assign<entt::tag<"enemy"_hs>>(entity);
* @endcode
*
* @note
* Tags are empty components and therefore candidates for the empty component
* optimization.
*
* @tparam Value The numeric representation of an instance of hashed string.
*/
template<typename hashed_string::hash_type Value>
using tag = std::integral_constant<typename hashed_string::hash_type, Value>;
}
#endif // ENTT_ENTITY_HELPER_HPP
#endif

View File

@@ -0,0 +1,446 @@
#ifndef ENTT_ENTITY_OBSERVER_HPP
#define ENTT_ENTITY_OBSERVER_HPP
#include <limits>
#include <cstddef>
#include <cstdint>
#include <utility>
#include <type_traits>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "../signal/delegate.hpp"
#include "registry.hpp"
#include "storage.hpp"
#include "utility.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/*! @brief Grouping matcher. */
template<typename...>
struct matcher {};
/**
* @brief Collector.
*
* Primary template isn't defined on purpose. All the specializations give a
* compile-time error, but for a few reasonable cases.
*/
template<typename...>
struct basic_collector;
/**
* @brief Collector.
*
* A collector contains a set of rules (literally, matchers) to use to track
* entities.<br/>
* Its main purpose is to generate a descriptor that allows an observer to know
* how to connect to a registry.
*/
template<>
struct basic_collector<> {
/**
* @brief Adds a grouping matcher to the collector.
* @tparam AllOf Types of components tracked by the matcher.
* @tparam NoneOf Types of components used to filter out entities.
* @return The updated collector.
*/
template<typename... AllOf, typename... NoneOf>
static constexpr auto group(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>>{};
}
/**
* @brief Adds an observing matcher to the collector.
* @tparam AnyOf Type of component for which changes should be detected.
* @return The updated collector.
*/
template<typename AnyOf>
static constexpr auto update() ENTT_NOEXCEPT {
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>>{};
}
};
/**
* @brief Collector.
* @copydetails basic_collector<>
* @tparam Reject Untracked types used to filter out entities.
* @tparam Require Untracked types required by the matcher.
* @tparam Rule Specific details of the current matcher.
* @tparam Other Other matchers.
*/
template<typename... Reject, typename... Require, typename... Rule, typename... Other>
struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule...>, Other...> {
/*! @brief Current matcher. */
using current_type = matcher<type_list<Reject...>, type_list<Require...>, Rule...>;
/**
* @brief Adds a grouping matcher to the collector.
* @tparam AllOf Types of components tracked by the matcher.
* @tparam NoneOf Types of components used to filter out entities.
* @return The updated collector.
*/
template<typename... AllOf, typename... NoneOf>
static constexpr auto group(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
return basic_collector<matcher<type_list<>, type_list<>, type_list<NoneOf...>, AllOf...>, current_type, Other...>{};
}
/**
* @brief Adds an observing matcher to the collector.
* @tparam AnyOf Type of component for which changes should be detected.
* @return The updated collector.
*/
template<typename AnyOf>
static constexpr auto update() ENTT_NOEXCEPT {
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>, current_type, Other...>{};
}
/**
* @brief Updates the filter of the last added matcher.
* @tparam AllOf Types of components required by the matcher.
* @tparam NoneOf Types of components used to filter out entities.
* @return The updated collector.
*/
template<typename... AllOf, typename... NoneOf>
static constexpr auto where(exclude_t<NoneOf...> = {}) ENTT_NOEXCEPT {
using extended_type = matcher<type_list<Reject..., NoneOf...>, type_list<Require..., AllOf...>, Rule...>;
return basic_collector<extended_type, Other...>{};
}
};
/*! @brief Variable template used to ease the definition of collectors. */
inline constexpr basic_collector<> collector{};
/**
* @brief Observer.
*
* An observer returns all the entities and only the entities that fit the
* requirements of at least one matcher. Moreover, it's guaranteed that the
* entity list is tightly packed in memory for fast iterations.<br/>
* In general, observers don't stay true to the order of any set of components.
*
* Observers work mainly with two types of matchers, provided through a
* collector:
*
* * Observing matcher: an observer will return at least all the living entities
* for which one or more of the given components have been updated and not yet
* destroyed.
* * Grouping matcher: an observer will return at least all the living entities
* that would have entered the given group if it existed and that would have
* not yet left it.
*
* If an entity respects the requirements of multiple matchers, it will be
* returned once and only once by the observer in any case.
*
* Matchers support also filtering by means of a _where_ clause that accepts
* both a list of types and an exclusion list.<br/>
* Whenever a matcher finds that an entity matches its requirements, the
* condition of the filter is verified before to register the entity itself.
* Moreover, a registered entity isn't returned by the observer if the condition
* set by the filter is broken in the meantime.
*
* @b Important
*
* Iterators aren't invalidated if:
*
* * New instances of the given components are created and assigned to entities.
* * The entity currently pointed is modified (as an example, if one of the
* given components is removed from the entity to which the iterator points).
* * The entity currently pointed is destroyed.
*
* In all the other cases, modifying the pools of the given components in any
* way invalidates all the iterators and using them results in undefined
* behavior.
*
* @warning
* Lifetime of an observer doesn't necessarily have to overcome that of the
* registry to which it is connected. However, the observer must be disconnected
* from the registry before being destroyed to avoid crashes due to dangling
* pointers.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
class basic_observer {
using payload_type = std::uint32_t;
template<typename>
struct matcher_handler;
template<typename... Reject, typename... Require, typename AnyOf>
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
template<std::size_t Index>
static void maybe_valid_if(basic_observer &obs, basic_registry<Entity> &reg, const Entity entt) {
if(reg.template has<Require...>(entt) && !reg.template any<Reject...>(entt)) {
if(!obs.view.contains(entt)) {
obs.view.emplace(entt);
}
obs.view.get(entt) |= (1 << Index);
}
}
template<std::size_t Index>
static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
if(obs.view.contains(entt) && !(obs.view.get(entt) &= (~(1 << Index)))) {
obs.view.remove(entt);
}
}
template<std::size_t Index>
static void connect(basic_observer &obs, basic_registry<Entity> &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);
}
};
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) {
if([&reg, entt]() {
if constexpr(sizeof...(Ignore) == 0) {
return reg.template has<AllOf..., Require...>(entt) && !reg.template any<NoneOf..., Reject...>(entt);
} else {
return reg.template has<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !reg.template any<NoneOf>(entt)) && ...) && !reg.template any<Reject...>(entt);
}
}())
{
if(!obs.view.contains(entt)) {
obs.view.emplace(entt);
}
obs.view.get(entt) |= (1 << Index);
}
}
template<std::size_t Index>
static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
if(obs.view.contains(entt) && !(obs.view.get(entt) &= (~(1 << Index)))) {
obs.view.remove(entt);
}
}
template<std::size_t Index>
static void connect(basic_observer &obs, basic_registry<Entity> &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), ...);
(reg.template on_destroy<NoneOf>().template connect<&maybe_valid_if<Index, NoneOf>>(obs), ...);
(reg.template on_destroy<AllOf>().template connect<&discard_if<Index>>(obs), ...);
(reg.template on_construct<NoneOf>().template connect<&discard_if<Index>>(obs), ...);
}
static void disconnect(basic_observer &obs, 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), ...);
}
};
template<typename... Matcher>
static void disconnect(basic_registry<Entity> &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");
(matcher_handler<Matcher>::template connect<Index>(*this, reg), ...);
release.template connect<&basic_observer::disconnect<Matcher...>>(reg);
}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Random access iterator type. */
using iterator = typename basic_sparse_set<Entity>::iterator;
/*! @brief Default constructor. */
basic_observer()
: release{},
view{}
{}
/*! @brief Default copy constructor, deleted on purpose. */
basic_observer(const basic_observer &) = delete;
/*! @brief Default move constructor, deleted on purpose. */
basic_observer(basic_observer &&) = delete;
/**
* @brief Creates an observer and connects it to a given registry.
* @tparam Matcher Types of matchers to use to initialize the observer.
* @param reg A valid reference to a registry.
*/
template<typename... Matcher>
basic_observer(basic_registry<entity_type> &reg, basic_collector<Matcher...>)
: basic_observer{}
{
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.
*/
basic_observer & operator=(const basic_observer &) = delete;
/**
* @brief Default move assignment operator, deleted on purpose.
* @return This observer.
*/
basic_observer & operator=(basic_observer &&) = delete;
/**
* @brief Connects an observer to a given registry.
* @tparam Matcher Types of matchers to use to initialize the observer.
* @param reg A valid reference to a registry.
*/
template<typename... Matcher>
void connect(basic_registry<entity_type> &reg, basic_collector<Matcher...>) {
disconnect();
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
view.clear();
}
/*! @brief Disconnects an observer from the registry it keeps track of. */
void disconnect() {
if(release) {
release(*this);
release.reset();
}
}
/**
* @brief Returns the number of elements in an observer.
* @return Number of elements.
*/
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return view.size();
}
/**
* @brief Checks whether an observer is empty.
* @return True if the observer is empty, false otherwise.
*/
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return view.empty();
}
/**
* @brief Direct access to the list of entities of the observer.
*
* The returned pointer is such that range `[data(), data() + size())` is
* always a valid range, even if the container is empty.
*
* @note
* Entities are in the reverse order as returned by the `begin`/`end`
* iterators.
*
* @return A pointer to the array of entities.
*/
[[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT {
return view.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()`.
*
* @return An iterator to the first entity of the observer.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return view.basic_sparse_set<entity_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 view.basic_sparse_set<entity_type>::end();
}
/*! @brief Clears the underlying container. */
void clear() ENTT_NOEXCEPT {
view.clear();
}
/**
* @brief Iterates entities and applies the given function object to them.
*
* The function object is invoked for each entity.<br/>
* The signature of the function must be equivalent to the following form:
*
* @code{.cpp}
* void(const entity_type);
* @endcode
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) const {
for(const auto entity: *this) {
func(entity);
}
}
/**
* @brief Iterates entities and applies the given function object to them,
* then clears the observer.
*
* @sa each
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) {
std::as_const(*this).each(std::move(func));
clear();
}
private:
delegate<void(basic_observer &)> release;
basic_storage<entity_type, payload_type> view;
};
}
#endif

View File

@@ -0,0 +1,509 @@
#ifndef ENTT_ENTITY_ORGANIZER_HPP
#define ENTT_ENTITY_ORGANIZER_HPP
#include <cstddef>
#include <algorithm>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "fwd.hpp"
#include "helper.hpp"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
template<typename>
struct is_view: std::false_type {};
template<typename Entity, typename... Exclude, typename... Component>
struct is_view<basic_view<Entity, exclude_t<Exclude...>, Component...>>: std::true_type {};
template<typename Type>
inline constexpr bool is_view_v = is_view<Type>::value;
template<typename Type, typename Override>
struct unpack_type {
using ro = std::conditional_t<
type_list_contains_v<Override, std::add_const_t<Type>> || (std::is_const_v<Type> && !type_list_contains_v<Override, std::remove_const_t<Type>>),
type_list<std::remove_const_t<Type>>,
type_list<>
>;
using rw = std::conditional_t<
type_list_contains_v<Override, std::remove_const_t<Type>> || (!std::is_const_v<Type> && !type_list_contains_v<Override, std::add_const_t<Type>>),
type_list<Type>,
type_list<>
>;
};
template<typename Entity, typename... Override>
struct unpack_type<basic_registry<Entity>, 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 Entity, typename... Exclude, typename... Component, typename... Override>
struct unpack_type<basic_view<Entity, exclude_t<Exclude...>, Component...>, type_list<Override...>> {
using ro = type_list_cat_t<type_list<Exclude...>, typename unpack_type<Component, type_list<Override...>>::ro...>;
using rw = type_list_cat_t<typename unpack_type<Component, type_list<Override...>>::rw...>;
};
template<typename Entity, typename... Exclude, typename... Component, typename... Override>
struct unpack_type<const basic_view<Entity, exclude_t<Exclude...>, Component...>, type_list<Override...>>
: unpack_type<basic_view<Entity, exclude_t<Exclude...>, Component...>, type_list<Override...>>
{};
template<typename, typename>
struct resource;
template<typename... Args, typename... Req>
struct resource<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...));
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...));
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...));
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();
}
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief Utility class for creating a static task graph.
*
* This class offers minimal support (but sufficient in many cases) for creating
* an execution graph from functions and their requirements on resources.<br/>
* Note that the resulting tasks aren't executed in any case. This isn't the
* goal of the tool. Instead, they are returned to the user in the form of a
* graph that allows for safe execution.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
class basic_organizer final {
using callback_type = void(const void *, entt::basic_registry<Entity> &);
using prepare_type = void(entt::basic_registry<Entity> &);
using dependency_type = std::size_t(const bool, type_info *, const std::size_t);
struct vertex_data final {
std::size_t ro_count{};
std::size_t rw_count{};
const char *name{};
const void *payload{};
callback_type *callback{};
dependency_type *dependency;
prepare_type *prepare{};
type_info info{};
};
template<typename Type>
[[nodiscard]] static decltype(auto) extract(basic_registry<Entity> &reg) {
if constexpr(std::is_same_v<Type, basic_registry<Entity>>) {
return reg;
} else if constexpr(internal::is_view_v<Type>) {
return as_view{reg};
} else {
return reg.template ctx_or_set<std::remove_reference_t<Type>>();
}
}
template<typename... Args>
[[nodiscard]] static auto to_args(basic_registry<Entity> &reg, type_list<Args...>) {
return std::tuple<decltype(extract<Args>(reg))...>(extract<Args>(reg)...);
}
template<typename... Type>
static std::size_t fill_dependencies(type_list<Type...>, [[maybe_unused]] type_info *buffer, [[maybe_unused]] const std::size_t count) {
if constexpr(sizeof...(Type) == 0u) {
return {};
} else {
type_info info[sizeof...(Type)]{type_id<Type>()...};
const auto length = std::min(count, sizeof...(Type));
std::copy_n(info, length, buffer);
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;
}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Raw task function type. */
using function_type = callback_type;
/*! @brief Vertex type of a task graph defined as an adjacency list. */
struct vertex {
/**
* @brief Constructs a vertex of the task graph.
* @param vtype True if the vertex is a top-level one, false otherwise.
* @param data The data associated with the vertex.
* @param edges The indices of the children in the adjacency list.
*/
vertex(const bool vtype, vertex_data data, std::vector<std::size_t> edges)
: is_top_level{vtype},
node{std::move(data)},
reachable{std::move(edges)}
{}
/**
* @brief Fills a buffer with the type info objects for the writable
* resources of a vertex.
* @param buffer A buffer pre-allocated by the user.
* @param length The length of the user-supplied buffer.
* @return The number of type info objects written to the buffer.
*/
size_type ro_dependency(type_info *buffer, const std::size_t length) const ENTT_NOEXCEPT {
return node.dependency(false, buffer, length);
}
/**
* @brief Fills a buffer with the type info objects for the read-only
* resources of a vertex.
* @param buffer A buffer pre-allocated by the user.
* @param length The length of the user-supplied buffer.
* @return The number of type info objects written to the buffer.
*/
size_type rw_dependency(type_info *buffer, const std::size_t length) const ENTT_NOEXCEPT {
return node.dependency(true, buffer, length);
}
/**
* @brief Returns the number of read-only resources of a vertex.
* @return The number of read-only resources of the vertex.
*/
size_type ro_count() const ENTT_NOEXCEPT {
return node.ro_count;
}
/**
* @brief Returns the number of writable resources of a vertex.
* @return The number of writable resources of the vertex.
*/
size_type rw_count() const ENTT_NOEXCEPT {
return node.rw_count;
}
/**
* @brief Checks if a vertex is also a top-level one.
* @return True if the vertex is a top-level one, false otherwise.
*/
bool top_level() const ENTT_NOEXCEPT {
return is_top_level;
}
/**
* @brief Returns a type info object associated with a vertex.
* @return A properly initialized type info object.
*/
type_info info() const ENTT_NOEXCEPT {
return node.info;
}
/**
* @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 {
return node.name;
}
/**
* @brief Returns the function associated with a vertex.
* @return The function associated with the vertex.
*/
function_type * callback() const ENTT_NOEXCEPT {
return node.callback;
}
/**
* @brief Returns the payload associated with a vertex, if any.
* @return The payload associated with the vertex, if any.
*/
const void * data() const ENTT_NOEXCEPT {
return node.payload;
}
/**
* @brief Returns the list of nodes reachable from a given vertex.
* @return The list of nodes reachable from the vertex.
*/
const std::vector<std::size_t> & children() const ENTT_NOEXCEPT {
return reachable;
}
/**
* @brief Prepares a registry and assures that all required resources
* are properly instantiated before using them.
* @param reg A valid registry.
*/
void prepare(basic_registry<entity_type> &reg) const {
node.prepare ? node.prepare(reg) : void();
}
private:
bool is_top_level;
vertex_data node;
std::vector<std::size_t> reachable;
};
/**
* @brief Adds a free function to the task list.
* @tparam Candidate Function to add to the task list.
* @tparam Req Additional requirements and/or override resource access mode.
* @param name Optional name to associate with the task.
*/
template<auto Candidate, typename... Req>
void emplace(const char *name = nullptr) {
using resource_type = decltype(internal::free_function_to_resource<Req...>(Candidate));
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, basic_registry<entity_type>>;
callback_type *callback = +[](const void *, basic_registry<entity_type> &reg) {
std::apply(Candidate, to_args(reg, typename resource_type::args{}));
};
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
vertices.push_back({
resource_type::ro::size,
resource_type::rw::size,
name,
nullptr,
callback,
+[](const bool rw, type_info *buffer, const std::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); },
+[](basic_registry<entity_type> &reg) { void(to_args(reg, typename resource_type::args{})); },
type_id<std::integral_constant<decltype(Candidate), Candidate>>()
});
}
/**
* @brief Adds a free function with payload or a member function with an
* instance to the task list.
* @tparam Candidate Function or member to add to the task list.
* @tparam Req Additional requirements and/or override resource access mode.
* @tparam Type Type of class or type of payload.
* @param value_or_instance A valid object that fits the purpose.
* @param name Optional name to associate with the task.
*/
template<auto Candidate, typename... Req, typename Type>
void emplace(Type &value_or_instance, const char *name = nullptr) {
using resource_type = decltype(internal::constrained_function_to_resource<Req...>(Candidate));
constexpr auto requires_registry = type_list_contains_v<typename resource_type::args, basic_registry<entity_type>>;
callback_type *callback = +[](const void *payload, basic_registry<entity_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{})));
};
track_dependencies(vertices.size(), requires_registry, typename resource_type::ro{}, typename resource_type::rw{});
vertices.push_back({
resource_type::ro::size,
resource_type::rw::size,
name,
&value_or_instance,
callback,
+[](const bool rw, type_info *buffer, const std::size_t length) {
return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length);
},
+[](basic_registry<entity_type> &reg) {
void(to_args(reg, typename resource_type::args{}));
},
type_id<std::integral_constant<decltype(Candidate), Candidate>>()
});
}
/**
* @brief Adds an user defined function with optional payload to the task
* list.
* @tparam Req Additional requirements and/or override resource access mode.
* @param func Function to add to the task list.
* @param payload User defined arbitrary data.
* @param name Optional name to associate with the task.
*/
template<typename... Req>
void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) {
using resource_type = internal::resource<type_list<>, type_list<Req...>>;
track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{});
vertices.push_back({
resource_type::ro::size,
resource_type::rw::size,
name,
payload,
func,
+[](const bool rw, type_info *buffer, const std::size_t length) {
return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length);
},
nullptr,
type_info{}
});
}
/**
* @brief Generates a task graph for the current content.
* @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());
for(std::size_t col{}, length = vertices.size(); col < length; ++col) {
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(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));
}
return adjacency_list;
}
/*! @brief Erases all elements from a container. */
void clear() {
dependencies.clear();
vertices.clear();
}
private:
std::unordered_map<entt::id_type, std::vector<std::pair<std::size_t, bool>>> dependencies;
std::vector<vertex_data> vertices;
};
}
#endif

View File

@@ -0,0 +1,83 @@
#ifndef ENTT_ENTITY_POLY_STORAGE_HPP
#define ENTT_ENTITY_POLY_STORAGE_HPP
#include <cstddef>
#include <tuple>
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../poly/poly.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Basic poly storage implementation.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
struct Storage: type_list<
type_info() const ENTT_NOEXCEPT,
void(basic_registry<Entity> &, const Entity *, const Entity *)
> {
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/**
* @brief Concept definition.
* @tparam Base Opaque base class from which to inherit.
*/
template<typename Base>
struct type: Base {
/**
* @brief Returns a type info for the contained objects.
* @return The type info for the contained objects.
*/
type_info value_type() const ENTT_NOEXCEPT {
return poly_call<0>(*this);
}
/**
* @brief Removes entities from a storage.
* @param owner The registry that issued the request.
* @param first An iterator to the first element of the range of
* entities.
* @param last An iterator past the last element of the range of
* entities.
*/
void remove(basic_registry<entity_type> &owner, const entity_type *first, const entity_type *last) {
poly_call<1>(*this, owner, first, last);
}
};
/**
* @brief Concept implementation.
* @tparam Type Type for which to generate an implementation.
*/
template<typename Type>
using impl = value_list<
&type_id<typename Type::value_type>,
&Type::template remove<const entity_type *>
>;
};
/**
* @brief Defines the poly storage type associate with a given entity type.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity, typename = void>
struct poly_storage_traits {
/*! @brief Poly storage type for the given entity type. */
using storage_type = poly<Storage<Entity>>;
};
}
#endif

View File

@@ -1,483 +0,0 @@
#ifndef ENTT_ENTITY_PROTOTYPE_HPP
#define ENTT_ENTITY_PROTOTYPE_HPP
#include <tuple>
#include <utility>
#include <cstddef>
#include <type_traits>
#include <unordered_map>
#include "../config/config.h"
#include "registry.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Prototype container for _concepts_.
*
* A prototype is used to define a _concept_ in terms of components.<br/>
* Prototypes act as templates for those specific types of an application which
* users would otherwise define through a series of component assignments to
* entities. In other words, prototypes can be used to assign components to
* entities of a registry at once.
*
* @note
* Components used along with prototypes must be copy constructible. Prototypes
* wrap component types with custom types, so they do not interfere with other
* users of the registry they were built with.
*
* @warning
* Prototypes directly use their underlying registries to store entities and
* components for their purposes. Users must ensure that the lifetime of a
* registry and its contents exceed that of the prototypes that use it.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
class basic_prototype {
using basic_fn_type = void(const basic_prototype &, basic_registry<Entity> &, const Entity);
using component_type = typename basic_registry<Entity>::component_type;
template<typename Component>
struct component_wrapper { Component component; };
struct component_handler {
basic_fn_type *assign_or_replace;
basic_fn_type *assign;
};
void release() {
if(reg->valid(entity)) {
reg->destroy(entity);
}
}
public:
/*! @brief Registry type. */
using registry_type = basic_registry<Entity>;
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/**
* @brief Constructs a prototype that is bound to a given registry.
* @param ref A valid reference to a registry.
*/
basic_prototype(registry_type &ref)
: reg{&ref},
entity{ref.create()}
{}
/**
* @brief Releases all its resources.
*/
~basic_prototype() {
release();
}
/**
* @brief Move constructor.
*
* After prototype move construction, instances that have been moved from
* are placed in a valid but unspecified state. It's highly discouraged to
* continue using them.
*
* @param other The instance to move from.
*/
basic_prototype(basic_prototype &&other)
: handlers{std::move(other.handlers)},
reg{other.reg},
entity{other.entity}
{
other.entity = null;
}
/**
* @brief Move assignment operator.
*
* After prototype move assignment, instances that have been moved from are
* placed in a valid but unspecified state. It's highly discouraged to
* continue using them.
*
* @param other The instance to move from.
* @return This prototype.
*/
basic_prototype & operator=(basic_prototype &&other) {
if(this != &other) {
auto tmp{std::move(other)};
handlers.swap(tmp.handlers);
std::swap(reg, tmp.reg);
std::swap(entity, tmp.entity);
}
return *this;
}
/**
* @brief Assigns to or replaces the given component of a prototype.
* @tparam Component Type of component to assign or replace.
* @tparam Args Types of arguments to use to construct the component.
* @param args Parameters to use to initialize the component.
* @return A reference to the newly created component.
*/
template<typename Component, typename... Args>
Component & set(Args &&... args) {
component_handler handler;
handler.assign_or_replace = [](const basic_prototype &proto, registry_type &other, const Entity dst) {
const auto &wrapper = proto.reg->template get<component_wrapper<Component>>(proto.entity);
other.template assign_or_replace<Component>(dst, wrapper.component);
};
handler.assign = [](const basic_prototype &proto, registry_type &other, const Entity dst) {
if(!other.template has<Component>(dst)) {
const auto &wrapper = proto.reg->template get<component_wrapper<Component>>(proto.entity);
other.template assign<Component>(dst, wrapper.component);
}
};
handlers[reg->template type<Component>()] = handler;
auto &wrapper = reg->template assign_or_replace<component_wrapper<Component>>(entity, Component{std::forward<Args>(args)...});
return wrapper.component;
}
/**
* @brief Removes the given component from a prototype.
* @tparam Component Type of component to remove.
*/
template<typename Component>
void unset() ENTT_NOEXCEPT {
reg->template reset<component_wrapper<Component>>(entity);
handlers.erase(reg->template type<Component>());
}
/**
* @brief Checks if a prototype owns all the given components.
* @tparam Component Components for which to perform the check.
* @return True if the prototype owns all the components, false otherwise.
*/
template<typename... Component>
bool has() const ENTT_NOEXCEPT {
return reg->template has<component_wrapper<Component>...>(entity);
}
/**
* @brief Returns references to the given components.
*
* @warning
* Attempting to get a component from a prototype that doesn't own it
* results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* prototype doesn't own an instance of the given component.
*
* @tparam Component Types of components to get.
* @return References to the components owned by the prototype.
*/
template<typename... Component>
decltype(auto) get() const ENTT_NOEXCEPT {
if constexpr(sizeof...(Component) == 1) {
return (std::as_const(*reg).template get<component_wrapper<Component...>>(entity).component);
} else {
return std::tuple<std::add_const_t<Component> &...>{get<Component>()...};
}
}
/*! @copydoc get */
template<typename... Component>
inline decltype(auto) get() ENTT_NOEXCEPT {
if constexpr(sizeof...(Component) == 1) {
return (const_cast<Component &>(std::as_const(*this).template get<Component>()), ...);
} else {
return std::tuple<Component &...>{get<Component>()...};
}
}
/**
* @brief Returns pointers to the given components.
* @tparam Component Types of components to get.
* @return Pointers to the components owned by the prototype.
*/
template<typename... Component>
auto try_get() const ENTT_NOEXCEPT {
if constexpr(sizeof...(Component) == 1) {
const auto *wrapper = reg->template try_get<component_wrapper<Component...>>(entity);
return wrapper ? &wrapper->component : nullptr;
} else {
return std::tuple<std::add_const_t<Component> *...>{try_get<Component>()...};
}
}
/*! @copydoc try_get */
template<typename... Component>
inline auto try_get() ENTT_NOEXCEPT {
if constexpr(sizeof...(Component) == 1) {
return (const_cast<Component *>(std::as_const(*this).template try_get<Component>()), ...);
} else {
return std::tuple<Component *...>{try_get<Component>()...};
}
}
/**
* @brief Creates a new entity using a given prototype.
*
* Utility shortcut, equivalent to the following snippet:
*
* @code{.cpp}
* const auto entity = registry.create();
* prototype(registry, entity);
* @endcode
*
* @note
* The registry may or may not be different from the one already used by
* the prototype. There is also an overload that directly uses the
* underlying registry.
*
* @param other A valid reference to a registry.
* @return A valid entity identifier.
*/
entity_type create(registry_type &other) const {
const auto entt = other.create();
assign(other, entt);
return entt;
}
/**
* @brief Creates a new entity using a given prototype.
*
* Utility shortcut, equivalent to the following snippet:
*
* @code{.cpp}
* const auto entity = registry.create();
* prototype(entity);
* @endcode
*
* @note
* This overload directly uses the underlying registry as a working space.
* Therefore, the components of the prototype and of the entity will share
* the same registry.
*
* @return A valid entity identifier.
*/
inline entity_type create() const {
return create(*reg);
}
/**
* @brief Assigns the components of a prototype to a given entity.
*
* Assigning a prototype to an entity won't overwrite existing components
* under any circumstances.<br/>
* In other words, only those components that the entity doesn't own yet are
* copied over. All the other components remain unchanged.
*
* @note
* The registry may or may not be different from the one already used by
* the prototype. There is also an overload that directly uses the
* underlying registry.
*
* @warning
* Attempting to use an invalid entity results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entity.
*
* @param other A valid reference to a registry.
* @param dst A valid entity identifier.
*/
void assign(registry_type &other, const entity_type dst) const {
for(auto &handler: handlers) {
handler.second.assign(*this, other, dst);
}
}
/**
* @brief Assigns the components of a prototype to a given entity.
*
* Assigning a prototype to an entity won't overwrite existing components
* under any circumstances.<br/>
* In other words, only those components that the entity doesn't own yet are
* copied over. All the other components remain unchanged.
*
* @note
* This overload directly uses the underlying registry as a working space.
* Therefore, the components of the prototype and of the entity will share
* the same registry.
*
* @warning
* Attempting to use an invalid entity results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entity.
*
* @param dst A valid entity identifier.
*/
inline void assign(const entity_type dst) const {
assign(*reg, dst);
}
/**
* @brief Assigns or replaces the components of a prototype for an entity.
*
* Existing components are overwritten, if any. All the other components
* will be copied over to the target entity.
*
* @note
* The registry may or may not be different from the one already used by
* the prototype. There is also an overload that directly uses the
* underlying registry.
*
* @warning
* Attempting to use an invalid entity results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entity.
*
* @param other A valid reference to a registry.
* @param dst A valid entity identifier.
*/
void assign_or_replace(registry_type &other, const entity_type dst) const {
for(auto &handler: handlers) {
handler.second.assign_or_replace(*this, other, dst);
}
}
/**
* @brief Assigns or replaces the components of a prototype for an entity.
*
* Existing components are overwritten, if any. All the other components
* will be copied over to the target entity.
*
* @note
* This overload directly uses the underlying registry as a working space.
* Therefore, the components of the prototype and of the entity will share
* the same registry.
*
* @warning
* Attempting to use an invalid entity results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entity.
*
* @param dst A valid entity identifier.
*/
inline void assign_or_replace(const entity_type dst) const {
assign_or_replace(*reg, dst);
}
/**
* @brief Assigns the components of a prototype to an entity.
*
* Assigning a prototype to an entity won't overwrite existing components
* under any circumstances.<br/>
* In other words, only the components that the entity doesn't own yet are
* copied over. All the other components remain unchanged.
*
* @note
* The registry may or may not be different from the one already used by
* the prototype. There is also an overload that directly uses the
* underlying registry.
*
* @warning
* Attempting to use an invalid entity results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entity.
*
* @param other A valid reference to a registry.
* @param dst A valid entity identifier.
*/
inline void operator()(registry_type &other, const entity_type dst) const ENTT_NOEXCEPT {
assign(other, dst);
}
/**
* @brief Assigns the components of a prototype to an entity.
*
* Assigning a prototype to an entity won't overwrite existing components
* under any circumstances.<br/>
* In other words, only the components that the entity doesn't own yet are
* copied over. All the other components remain unchanged.
*
* @note
* This overload directly uses the underlying registry as a working space.
* Therefore, the components of the prototype and of the entity will share
* the same registry.
*
* @warning
* Attempting to use an invalid entity results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode in case of
* invalid entity.
*
* @param dst A valid entity identifier.
*/
inline void operator()(const entity_type dst) const ENTT_NOEXCEPT {
assign(*reg, dst);
}
/**
* @brief Creates a new entity using a given prototype.
*
* Utility shortcut, equivalent to the following snippet:
*
* @code{.cpp}
* const auto entity = registry.create();
* prototype(registry, entity);
* @endcode
*
* @note
* The registry may or may not be different from the one already used by
* the prototype. There is also an overload that directly uses the
* underlying registry.
*
* @param other A valid reference to a registry.
* @return A valid entity identifier.
*/
inline entity_type operator()(registry_type &other) const ENTT_NOEXCEPT {
return create(other);
}
/**
* @brief Creates a new entity using a given prototype.
*
* Utility shortcut, equivalent to the following snippet:
*
* @code{.cpp}
* const auto entity = registry.create();
* prototype(entity);
* @endcode
*
* @note
* This overload directly uses the underlying registry as a working space.
* Therefore, the components of the prototype and of the entity will share
* the same registry.
*
* @return A valid entity identifier.
*/
inline entity_type operator()() const ENTT_NOEXCEPT {
return create(*reg);
}
/**
* @brief Returns a reference to the underlying registry.
* @return A reference to the underlying registry.
*/
inline const registry_type & backend() const ENTT_NOEXCEPT {
return *reg;
}
/*! @copydoc backend */
inline registry_type & backend() ENTT_NOEXCEPT {
return const_cast<registry_type &>(std::as_const(*this).backend());
}
private:
std::unordered_map<component_type, component_handler> handlers;
registry_type *reg;
entity_type entity;
};
}
#endif // ENTT_ENTITY_PROTOTYPE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,12 @@
#include <iterator>
#include <cassert>
#include <vector>
#include <utility>
#include <algorithm>
#include <type_traits>
#include "../config/config.h"
#include "sparse_set.hpp"
#include "entity.hpp"
#include "fwd.hpp"
@@ -35,6 +34,7 @@ namespace entt {
* * New instances of the given components are created and assigned to entities.
* * The entity currently pointed is modified (as an example, if one of the
* given components is removed from the entity to which the iterator points).
* * The entity currently pointed is destroyed.
*
* In all the other cases, modifying the pools of the given components in any
* way invalidates all the iterators and using them results in undefined
@@ -48,88 +48,110 @@ namespace entt {
* have a valid reference and won't be updated accordingly).
*
* @warning
* Lifetime of a view must overcome the one of the registry that generated it.
* 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).
*/
template<typename Entity>
class basic_runtime_view {
/*! @brief A registry is allowed to create views. */
friend class basic_registry<Entity>;
class basic_runtime_view final {
using underlying_iterator = typename basic_sparse_set<Entity>::iterator;
using underlying_iterator_type = typename sparse_set<Entity>::iterator_type;
using extent_type = typename sparse_set<Entity>::size_type;
using traits_type = entt_traits<Entity>;
class iterator {
class view_iterator final {
friend class basic_runtime_view<Entity>;
iterator(underlying_iterator_type first, underlying_iterator_type last, const sparse_set<Entity> * const *others, const sparse_set<Entity> * const *length, extent_type ext) ENTT_NOEXCEPT
: begin{first},
end{last},
from{others},
to{length},
extent{ext}
view_iterator(const std::vector<const basic_sparse_set<Entity> *> &cpools, const std::vector<const basic_sparse_set<Entity> *> &ignore, underlying_iterator curr) ENTT_NOEXCEPT
: pools{&cpools},
filter{&ignore},
it{curr}
{
if(begin != end && !valid()) {
if(it != (*pools)[0]->end() && !valid()) {
++(*this);
}
}
bool valid() const ENTT_NOEXCEPT {
const auto entt = *begin;
const auto sz = size_type(entt & traits_type::entity_mask);
return sz < extent && std::all_of(from, to, [entt](const auto *view) {
return view->has(entt);
});
[[nodiscard]] bool valid() const {
return std::all_of(pools->begin()++, pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
}
public:
using difference_type = typename underlying_iterator_type::difference_type;
using value_type = typename underlying_iterator_type::value_type;
using pointer = typename underlying_iterator_type::pointer;
using reference = typename underlying_iterator_type::reference;
using iterator_category = std::forward_iterator_tag;
using difference_type = typename underlying_iterator::difference_type;
using value_type = typename underlying_iterator::value_type;
using pointer = typename underlying_iterator::pointer;
using reference = typename underlying_iterator::reference;
using iterator_category = std::bidirectional_iterator_tag;
iterator() ENTT_NOEXCEPT = default;
view_iterator() ENTT_NOEXCEPT = default;
iterator & operator++() ENTT_NOEXCEPT {
return (++begin != end && !valid()) ? ++(*this) : *this;
view_iterator & operator++() {
while(++it != (*pools)[0]->end() && !valid());
return *this;
}
iterator operator++(int) ENTT_NOEXCEPT {
iterator orig = *this;
view_iterator operator++(int) {
view_iterator orig = *this;
return ++(*this), orig;
}
bool operator==(const iterator &other) const ENTT_NOEXCEPT {
return other.begin == begin;
view_iterator & operator--() ENTT_NOEXCEPT {
while(--it != (*pools)[0]->begin() && !valid());
return *this;
}
inline bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
view_iterator operator--(int) ENTT_NOEXCEPT {
view_iterator orig = *this;
return operator--(), orig;
}
[[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
pointer operator->() const ENTT_NOEXCEPT {
return begin.operator->();
[[nodiscard]] pointer operator->() const {
return it.operator->();
}
inline reference operator*() const ENTT_NOEXCEPT {
[[nodiscard]] reference operator*() const {
return *operator->();
}
private:
underlying_iterator_type begin;
underlying_iterator_type end;
const sparse_set<Entity> * const *from;
const sparse_set<Entity> * const *to;
extent_type extent;
const std::vector<const basic_sparse_set<Entity> *> *pools;
const std::vector<const basic_sparse_set<Entity> *> *filter;
underlying_iterator it;
};
basic_runtime_view(std::vector<const sparse_set<Entity> *> others) ENTT_NOEXCEPT
: pools{std::move(others)}
[[nodiscard]] bool valid() const {
return !pools.empty() && pools.front();
}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Bidirectional iterator type. */
using iterator = view_iterator;
/*! @brief Default constructor to use to create empty, invalid views. */
basic_runtime_view() ENTT_NOEXCEPT
: pools{},
filter{}
{}
/**
* @brief Constructs a runtime view from a set of storage classes.
* @param cpools The storage for the types to iterate.
* @param epools The storage for the types used to filter the view.
*/
basic_runtime_view(std::vector<const basic_sparse_set<Entity> *> cpools, std::vector<const basic_sparse_set<Entity> *> epools) ENTT_NOEXCEPT
: pools{std::move(cpools)},
filter{std::move(epools)}
{
const auto it = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
@@ -139,48 +161,14 @@ class basic_runtime_view {
std::rotate(pools.begin(), it, pools.end());
}
extent_type min() const ENTT_NOEXCEPT {
extent_type extent{};
if(valid()) {
const auto it = std::min_element(pools.cbegin(), pools.cend(), [](const auto *lhs, const auto *rhs) {
return lhs->extent() < rhs->extent();
});
extent = (*it)->extent();
}
return extent;
}
inline bool valid() const ENTT_NOEXCEPT {
return !pools.empty() && pools.front();
}
public:
/*! @brief Underlying entity identifier. */
using entity_type = typename sparse_set<Entity>::entity_type;
/*! @brief Unsigned integer type. */
using size_type = typename sparse_set<Entity>::size_type;
/*! @brief Input iterator type. */
using iterator_type = iterator;
/**
* @brief Estimates the number of entities that have the given components.
* @return Estimated number of entities that have the given components.
* @brief Estimates the number of entities iterated by the view.
* @return Estimated number of entities iterated by the view.
*/
size_type size() const ENTT_NOEXCEPT {
[[nodiscard]] size_type size_hint() const {
return valid() ? pools.front()->size() : size_type{};
}
/**
* @brief Checks if the view is definitely empty.
* @return True if the view is definitely empty, false otherwise.
*/
bool empty() const ENTT_NOEXCEPT {
return !valid() || pools.front()->empty();
}
/**
* @brief Returns an iterator to the first entity that has the given
* components.
@@ -189,22 +177,10 @@ public:
* components. If the view is empty, the returned iterator will be equal to
* `end()`.
*
* @note
* Input iterators stay true to the order imposed to the underlying data
* structures.
*
* @return An iterator to the first entity that has the given components.
*/
iterator_type begin() const ENTT_NOEXCEPT {
iterator_type it{};
if(valid()) {
const auto &pool = *pools.front();
const auto * const *data = pools.data();
it = { pool.begin(), pool.end(), data + 1, data + pools.size(), min() };
}
return it;
[[nodiscard]] iterator begin() const {
return valid() ? iterator{pools, filter, pools[0]->begin()} : iterator{};
}
/**
@@ -215,22 +191,11 @@ public:
* has the given components. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @note
* Input iterators stay true to the order imposed to the underlying data
* structures.
*
* @return An iterator to the entity following the last entity that has the
* given components.
*/
iterator_type end() const ENTT_NOEXCEPT {
iterator_type it{};
if(valid()) {
const auto &pool = *pools.front();
it = { pool.end(), pool.end(), nullptr, nullptr, min() };
}
return it;
[[nodiscard]] iterator end() const {
return valid() ? iterator{pools, filter, pools[0]->end()} : iterator{};
}
/**
@@ -238,10 +203,9 @@ public:
* @param entt A valid entity identifier.
* @return True if the view contains the given entity, false otherwise.
*/
bool contains(const entity_type entt) const ENTT_NOEXCEPT {
return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *view) {
return view->has(entt) && view->data()[view->get(entt)] == entt;
});
[[nodiscard]] bool contains(const entity_type entt) const {
return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
}
/**
@@ -261,15 +225,18 @@ public:
*/
template<typename Func>
void each(Func func) const {
std::for_each(begin(), end(), func);
for(const auto entity: *this) {
func(entity);
}
}
private:
std::vector<const sparse_set<Entity> *> pools;
std::vector<const basic_sparse_set<Entity> *> pools;
std::vector<const basic_sparse_set<Entity> *> filter;
};
}
#endif // ENTT_ENTITY_RUNTIME_VIEW_HPP
#endif

View File

@@ -4,13 +4,17 @@
#include <array>
#include <cstddef>
#include <utility>
#include <iterator>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "entity.hpp"
#include "fwd.hpp"
#include "registry.hpp"
namespace entt {
@@ -28,48 +32,47 @@ namespace entt {
*/
template<typename Entity>
class basic_snapshot {
/*! @brief A registry is allowed to create snapshots. */
friend class basic_registry<Entity>;
using follow_fn_type = Entity(const basic_registry<Entity> &, const Entity);
basic_snapshot(const basic_registry<Entity> *source, Entity init, follow_fn_type *fn) ENTT_NOEXCEPT
: reg{source},
seed{init},
follow{fn}
{}
using traits_type = entt_traits<Entity>;
template<typename Component, typename Archive, typename It>
void get(Archive &archive, std::size_t sz, It first, It last) const {
archive(static_cast<Entity>(sz));
const auto view = reg->template view<std::add_const_t<Component>>();
archive(typename traits_type::entity_type(sz));
while(first != last) {
const auto entt = *(first++);
if(reg->template has<Component>(entt)) {
if constexpr(std::is_empty_v<Component>) {
archive(entt);
} else {
archive(entt, reg->template get<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... Indexes>
void component(Archive &archive, It first, It last, std::index_sequence<Indexes...>) const {
std::array<std::size_t, sizeof...(Indexes)> size{};
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 has<Component>(entt) ? ++size[Indexes] : size[Indexes]), ...);
((reg->template has<Component>(entt) ? ++size[Index] : size[Index]), ...);
}
(get<Component>(archive, size[Indexes], first, last), ...);
(get<Component>(archive, size[Index], first, last), ...);
}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/**
* @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
: reg{&source}
{}
/*! @brief Default move constructor. */
basic_snapshot(basic_snapshot &&) = default;
@@ -77,10 +80,10 @@ public:
basic_snapshot & operator=(basic_snapshot &&) = default;
/**
* @brief Puts aside all the entities that are still in use.
* @brief Puts aside all the entities from the underlying registry.
*
* Entities are serialized along with their versions. Destroyed entities are
* not taken in consideration by this function.
* taken in consideration as well by this function.
*
* @tparam Archive Type of output archive.
* @param archive A valid reference to an output archive.
@@ -88,36 +91,16 @@ public:
*/
template<typename Archive>
const basic_snapshot & entities(Archive &archive) const {
archive(static_cast<Entity>(reg->alive()));
reg->each([&archive](const auto entt) { archive(entt); });
return *this;
}
const auto sz = reg->size();
/**
* @brief Puts aside destroyed entities.
*
* Entities are serialized along with their versions. Entities that are
* still in use are not taken in consideration by this function.
*
* @tparam Archive Type of output archive.
* @param archive A valid reference to an output archive.
* @return An object of this type to continue creating the snapshot.
*/
template<typename Archive>
const basic_snapshot & destroyed(Archive &archive) const {
auto size = reg->size() - reg->alive();
archive(static_cast<Entity>(size));
archive(typename traits_type::entity_type(sz));
if(size) {
auto curr = seed;
archive(curr);
for(--size; size; --size) {
curr = follow(*reg, curr);
archive(curr);
}
for(auto first = reg->data(), last = first + sz; first != last; ++first) {
archive(*first);
}
archive(reg->destroyed());
return *this;
}
@@ -134,25 +117,7 @@ public:
*/
template<typename... Component, typename Archive>
const basic_snapshot & component(Archive &archive) const {
if constexpr(sizeof...(Component) == 1) {
const auto sz = reg->template size<Component...>();
const auto *entities = reg->template data<Component...>();
archive(static_cast<Entity>(sz));
for(std::remove_const_t<decltype(sz)> i{}; i < sz; ++i) {
const auto entt = entities[i];
if constexpr(std::is_empty_v<Component...>) {
archive(entt);
} else {
archive(entt, reg->template get<Component...>(entt));
}
};
} else {
(component<Component>(archive), ...);
}
(component<Component>(archive, reg->template data<Component>(), reg->template data<Component>() + reg->template size<Component>()), ...);
return *this;
}
@@ -172,14 +137,12 @@ public:
*/
template<typename... Component, typename Archive, typename It>
const basic_snapshot & component(Archive &archive, It first, It last) const {
component<Component...>(archive, first, last, std::make_index_sequence<sizeof...(Component)>{});
component<Component...>(archive, first, last, std::index_sequence_for<Component...>{});
return *this;
}
private:
const basic_registry<Entity> *reg;
const Entity seed;
follow_fn_type *follow;
const basic_registry<entity_type> *reg;
};
@@ -195,54 +158,49 @@ private:
*/
template<typename Entity>
class basic_snapshot_loader {
/*! @brief A registry is allowed to create snapshot loaders. */
friend class basic_registry<Entity>;
using traits_type = entt_traits<Entity>;
using force_fn_type = void(basic_registry<Entity> &, const Entity, const bool);
basic_snapshot_loader(basic_registry<Entity> *source, force_fn_type *fn) ENTT_NOEXCEPT
: reg{source},
force{fn}
{
// to restore a snapshot as a whole requires a clean registry
ENTT_ASSERT(reg->empty());
}
template<typename Archive>
void assure(Archive &archive, bool destroyed) const {
Entity length{};
template<typename Type, typename Archive>
void assign(Archive &archive) const {
typename traits_type::entity_type length{};
archive(length);
while(length--) {
Entity entt{};
archive(entt);
force(*reg, entt, destroyed);
}
}
entity_type entt{};
template<typename Type, typename Archive, typename... Args>
void assign(Archive &archive, Args... args) const {
Entity length{};
archive(length);
while(length--) {
static constexpr auto destroyed = false;
Entity entt{};
if constexpr(std::is_empty_v<Type>) {
if constexpr(std::tuple_size_v<decltype(reg->template view<Type>().get({}))> == 0) {
while(length--) {
archive(entt);
force(*reg, entt, destroyed);
reg->template assign<Type>(args..., entt);
} else {
Type instance{};
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
ENTT_ASSERT(entity == entt);
reg->template emplace<Type>(entity);
}
} else {
Type instance{};
while(length--) {
archive(entt, instance);
force(*reg, entt, destroyed);
reg->template assign<Type>(args..., entt, std::as_const(instance));
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
ENTT_ASSERT(entity == entt);
reg->template emplace<Type>(entity, std::move(instance));
}
}
}
public:
/*! @brief Underlying entity identifier. */
using entity_type = Entity;
/**
* @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
: reg{&source}
{
// restoring a snapshot as a whole requires a clean registry
ENTT_ASSERT(reg->empty());
}
/*! @brief Default move constructor. */
basic_snapshot_loader(basic_snapshot_loader &&) = default;
@@ -261,25 +219,20 @@ public:
*/
template<typename Archive>
const basic_snapshot_loader & entities(Archive &archive) const {
static constexpr auto destroyed = false;
assure(archive, destroyed);
return *this;
}
typename traits_type::entity_type length{};
archive(length);
std::vector<entity_type> all(length);
for(decltype(length) pos{}; pos < length; ++pos) {
archive(all[pos]);
}
entity_type destroyed;
archive(destroyed);
reg->assign(all.cbegin(), all.cend(), destroyed);
/**
* @brief Restores entities that were destroyed during serialization.
*
* This function restores the entities that were destroyed during
* serialization and gives them the versions they originally had.
*
* @tparam Archive Type of input archive.
* @param archive A valid reference to an input archive.
* @return A valid loader to continue restoring data.
*/
template<typename Archive>
const basic_snapshot_loader & destroyed(Archive &archive) const {
static constexpr auto destroyed = true;
assure(archive, destroyed);
return *this;
}
@@ -321,8 +274,7 @@ public:
}
private:
basic_registry<Entity> *reg;
force_fn_type *force;
basic_registry<entity_type> *reg;
};
@@ -330,7 +282,7 @@ private:
* @brief Utility class for _continuous loading_.
*
* A _continuous loader_ is designed to load data from a source registry to a
* (possibly) non-empty destination. The loader can accomodate in a registry
* (possibly) non-empty destination. The loader can accommodate in a registry
* more than one snapshot in a sort of _continuous loading_ that updates the
* destination one step at a time.<br/>
* Identifiers that entities originally had are not transferred to the target.
@@ -347,9 +299,7 @@ class basic_continuous_loader {
using traits_type = entt_traits<Entity>;
void destroy(Entity entt) {
const auto it = remloc.find(entt);
if(it == remloc.cend()) {
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);
@@ -363,67 +313,93 @@ class basic_continuous_loader {
const auto local = reg->create();
remloc.emplace(entt, std::make_pair(local, true));
} else {
remloc[entt].first = reg->valid(remloc[entt].first) ? remloc[entt].first : reg->create();
if(!reg->valid(remloc[entt].first)) {
remloc[entt].first = reg->create();
}
// set the dirty flag
remloc[entt].second = true;
}
}
template<typename Other, typename Type, typename Member>
void update(Other &instance, Member Type:: *member) {
if constexpr(!std::is_same_v<Other, Type>) {
return;
} else if constexpr(std::is_same_v<Member, Entity>) {
instance.*member = map(instance.*member);
} else {
// maybe a container? let's try...
for(auto &entt: instance.*member) {
entt = map(entt);
template<typename Container>
auto update(int, Container &container)
-> decltype(typename Container::mapped_type{}, void()) {
// map like container
Container other;
for(auto &&pair: container) {
using first_type = std::remove_const_t<typename std::decay_t<decltype(pair)>::first_type>;
using second_type = typename std::decay_t<decltype(pair)>::second_type;
if constexpr(std::is_same_v<first_type, entity_type> && std::is_same_v<second_type, entity_type>) {
other.emplace(map(pair.first), map(pair.second));
} else if constexpr(std::is_same_v<first_type, entity_type>) {
other.emplace(map(pair.first), std::move(pair.second));
} else {
static_assert(std::is_same_v<second_type, entity_type>, "Neither the key nor the value are of entity type");
other.emplace(std::move(pair.first), map(pair.second));
}
}
std::swap(container, other);
}
template<typename Container>
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");
for(auto &&entt: container) {
entt = map(entt);
}
}
template<typename Archive>
void assure(Archive &archive, void(basic_continuous_loader:: *member)(Entity)) {
Entity length{};
archive(length);
while(length--) {
Entity entt{};
archive(entt);
(this->*member)(entt);
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>) {
return;
} else if constexpr(std::is_same_v<Member, entity_type>) {
instance.*member = map(instance.*member);
} else {
// maybe a container? let's try...
update(0, instance.*member);
}
}
template<typename Component>
void reset() {
void remove_if_exists() {
for(auto &&ref: remloc) {
const auto local = ref.second.first;
if(reg->valid(local)) {
reg->template reset<Component>(local);
reg->template remove_if_exists<Component>(local);
}
}
}
template<typename Other, typename Archive, typename... Type, typename... Member>
void assign(Archive &archive, [[maybe_unused]] Member Type:: *... member) {
Entity length{};
typename traits_type::entity_type length{};
archive(length);
while(length--) {
Entity entt{};
entity_type entt{};
if constexpr(std::is_empty_v<Other>) {
if constexpr(std::tuple_size_v<decltype(reg->template view<Other>().get({}))> == 0) {
while(length--) {
archive(entt);
restore(entt);
reg->template assign_or_replace<Other>(map(entt));
} else {
Other instance{};
reg->template emplace_or_replace<Other>(map(entt));
}
} else {
Other instance{};
while(length--) {
archive(entt, instance);
(update(instance, member), ...);
restore(entt);
reg->template assign_or_replace<Other>(map(entt), std::as_const(instance));
reg->template emplace_or_replace<Other>(map(entt), std::move(instance));
}
}
}
@@ -433,7 +409,7 @@ public:
using entity_type = Entity;
/**
* @brief Constructs a loader that is bound to a given registry.
* @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
@@ -458,23 +434,24 @@ public:
*/
template<typename Archive>
basic_continuous_loader & entities(Archive &archive) {
assure(archive, &basic_continuous_loader::restore);
return *this;
}
typename traits_type::entity_type length{};
entity_type entt{};
archive(length);
for(decltype(length) pos{}; pos < length; ++pos) {
archive(entt);
if(const auto entity = (to_integral(entt) & traits_type::entity_mask); entity == pos) {
restore(entt);
} else {
destroy(entt);
}
}
// discards the head of the list of destroyed entities
archive(entt);
/**
* @brief Restores entities that were destroyed during serialization.
*
* This function restores the entities that were destroyed during
* serialization and creates local counterparts for them if required.
*
* @tparam Archive Type of input archive.
* @param archive A valid reference to an input archive.
* @return A non-const reference to this loader.
*/
template<typename Archive>
basic_continuous_loader & destroyed(Archive &archive) {
assure(archive, &basic_continuous_loader::destroy);
return *this;
}
@@ -499,7 +476,7 @@ public:
*/
template<typename... Component, typename Archive, typename... Type, typename... Member>
basic_continuous_loader & component(Archive &archive, Member Type:: *... member) {
(reset<Component>(), ...);
(remove_if_exists<Component>(), ...);
(assign<Component>(archive, member...), ...);
return *this;
}
@@ -557,7 +534,7 @@ public:
* @param entt An entity identifier.
* @return True if `entity` is managed by the loader, false otherwise.
*/
bool has(entity_type entt) const ENTT_NOEXCEPT {
[[nodiscard]] bool contains(entity_type entt) const ENTT_NOEXCEPT {
return (remloc.find(entt) != remloc.cend());
}
@@ -566,7 +543,7 @@ public:
* @param entt An entity identifier.
* @return The local identifier if any, the null entity otherwise.
*/
entity_type map(entity_type entt) const ENTT_NOEXCEPT {
[[nodiscard]] entity_type map(entity_type entt) const ENTT_NOEXCEPT {
const auto it = remloc.find(entt);
entity_type other = null;
@@ -578,12 +555,12 @@ public:
}
private:
std::unordered_map<Entity, std::pair<Entity, bool>> remloc;
basic_registry<Entity> *reg;
std::unordered_map<entity_type, std::pair<entity_type, bool>> remloc;
basic_registry<entity_type> *reg;
};
}
#endif // ENTT_ENTITY_SNAPSHOT_HPP
#endif

View File

@@ -2,14 +2,16 @@
#define ENTT_ENTITY_SPARSE_SET_HPP
#include <algorithm>
#include <iterator>
#include <utility>
#include <vector>
#include <memory>
#include <cstddef>
#include <type_traits>
#include "../config/config.h"
#include "../core/algorithm.hpp"
#include "entity.hpp"
#include "fwd.hpp"
namespace entt {
@@ -31,32 +33,28 @@ namespace entt {
* purpose of the framework.
*
* @note
* There are no guarantees that entities are returned in the insertion order
* when iterate a sparse set. Do not make assumption on the order in any case.
*
* @note
* Internal data structures arrange elements to maximize performance. Because of
* that, there are no guarantees that elements have the expected order when
* iterate directly the internal packed array (see `data` and `size` member
* functions for that). Use `begin` and `end` instead.
* Internal data structures arrange elements to maximize performance. There are
* no guarantees that entities are returned in the insertion order when iterate
* a sparse set. Do not make assumption on the order in any case.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
class sparse_set {
class basic_sparse_set {
static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0), "ENTT_PAGE_SIZE must be a power of two");
static constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(Entity);
using traits_type = entt_traits<Entity>;
using page_type = std::unique_ptr<Entity[]>;
static_assert(ENTT_PAGE_SIZE && ((ENTT_PAGE_SIZE & (ENTT_PAGE_SIZE - 1)) == 0));
static constexpr auto entt_per_page = ENTT_PAGE_SIZE / sizeof(typename entt_traits<Entity>::entity_type);
class sparse_set_iterator final {
friend class basic_sparse_set<Entity>;
class iterator {
friend class sparse_set<Entity>;
using direct_type = const std::vector<Entity>;
using packed_type = std::vector<Entity>;
using index_type = typename traits_type::difference_type;
iterator(direct_type *ref, const index_type idx) ENTT_NOEXCEPT
: direct{ref}, index{idx}
sparse_set_iterator(const packed_type &ref, const index_type idx) ENTT_NOEXCEPT
: packed{&ref}, index{idx}
{}
public:
@@ -66,108 +64,118 @@ class sparse_set {
using reference = const value_type &;
using iterator_category = std::random_access_iterator_tag;
iterator() ENTT_NOEXCEPT = default;
sparse_set_iterator() ENTT_NOEXCEPT = default;
iterator & operator++() ENTT_NOEXCEPT {
sparse_set_iterator & operator++() ENTT_NOEXCEPT {
return --index, *this;
}
iterator operator++(int) ENTT_NOEXCEPT {
sparse_set_iterator operator++(int) ENTT_NOEXCEPT {
iterator orig = *this;
return ++(*this), orig;
}
iterator & operator--() ENTT_NOEXCEPT {
sparse_set_iterator & operator--() ENTT_NOEXCEPT {
return ++index, *this;
}
iterator operator--(int) ENTT_NOEXCEPT {
iterator orig = *this;
return --(*this), orig;
sparse_set_iterator operator--(int) ENTT_NOEXCEPT {
sparse_set_iterator orig = *this;
return operator--(), orig;
}
iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
sparse_set_iterator & operator+=(const difference_type value) ENTT_NOEXCEPT {
index -= value;
return *this;
}
iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
return iterator{direct, index-value};
sparse_set_iterator operator+(const difference_type value) const ENTT_NOEXCEPT {
sparse_set_iterator copy = *this;
return (copy += value);
}
inline iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
sparse_set_iterator & operator-=(const difference_type value) ENTT_NOEXCEPT {
return (*this += -value);
}
inline iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
sparse_set_iterator operator-(const difference_type value) const ENTT_NOEXCEPT {
return (*this + -value);
}
difference_type operator-(const iterator &other) const ENTT_NOEXCEPT {
difference_type operator-(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return other.index - index;
}
reference operator[](const difference_type value) const ENTT_NOEXCEPT {
const auto pos = size_type(index-value-1);
return (*direct)[pos];
[[nodiscard]] reference operator[](const difference_type value) const {
const auto pos = size_type(index-value-1u);
return (*packed)[pos];
}
bool operator==(const iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] bool operator==(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return other.index == index;
}
inline bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] bool operator!=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
bool operator<(const iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] bool operator<(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return index > other.index;
}
bool operator>(const iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] bool operator>(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return index < other.index;
}
inline bool operator<=(const iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] bool operator<=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return !(*this > other);
}
inline bool operator>=(const iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] bool operator>=(const sparse_set_iterator &other) const ENTT_NOEXCEPT {
return !(*this < other);
}
pointer operator->() const ENTT_NOEXCEPT {
const auto pos = size_type(index-1);
return &(*direct)[pos];
[[nodiscard]] pointer operator->() const {
const auto pos = size_type(index-1u);
return &(*packed)[pos];
}
inline reference operator*() const ENTT_NOEXCEPT {
[[nodiscard]] reference operator*() const {
return *operator->();
}
private:
direct_type *direct;
const packed_type *packed;
index_type index;
};
void assure(const std::size_t page) {
if(!(page < reverse.size())) {
reverse.resize(page+1);
[[nodiscard]] auto page(const Entity entt) const ENTT_NOEXCEPT {
return size_type{(to_integral(entt) & traits_type::entity_mask) / entt_per_page};
}
[[nodiscard]] auto offset(const Entity entt) const ENTT_NOEXCEPT {
return size_type{to_integral(entt) & (entt_per_page - 1)};
}
[[nodiscard]] page_type & assure(const std::size_t pos) {
if(!(pos < sparse.size())) {
sparse.resize(pos+1);
}
if(!reverse[page].first) {
reverse[page].first = std::make_unique<entity_type[]>(entt_per_page);
if(!sparse[pos]) {
sparse[pos].reset(new entity_type[entt_per_page]);
// null is safe in all cases for our purposes
std::fill_n(reverse[page].first.get(), entt_per_page, null);
for(auto *first = sparse[pos].get(), *last = first + entt_per_page; first != last; ++first) {
*first = null;
}
}
return sparse[pos];
}
auto index(const Entity entt) const ENTT_NOEXCEPT {
const auto identifier = entt & traits_type::entity_mask;
const auto page = size_type(identifier / entt_per_page);
const auto offset = size_type(identifier & (entt_per_page - 1));
return std::make_pair(page, offset);
}
virtual void swap_at(const std::size_t, const std::size_t) {}
virtual void swap_and_pop(const std::size_t) {}
virtual void clear_all() {}
public:
/*! @brief Underlying entity identifier. */
@@ -175,50 +183,21 @@ public:
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Random access iterator type. */
using iterator_type = iterator;
using iterator = sparse_set_iterator;
/*! @brief Reverse iterator type. */
using reverse_iterator = const entity_type *;
/*! @brief Default constructor. */
sparse_set() = default;
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
sparse_set(const sparse_set &other)
: reverse{},
direct{other.direct}
{
for(size_type i = {}, last = other.reverse.size(); i < last; ++i) {
if(other.reverse[i].first) {
assure(i);
std::copy_n(other.reverse[i].first.get(), entt_per_page, reverse[i].first.get());
reverse[i].second = other.reverse[i].second;
}
}
}
basic_sparse_set() = default;
/*! @brief Default move constructor. */
sparse_set(sparse_set &&) = default;
basic_sparse_set(basic_sparse_set &&) = default;
/*! @brief Default destructor. */
virtual ~sparse_set() ENTT_NOEXCEPT = default;
/**
* @brief Copy assignment operator.
* @param other The instance to copy from.
* @return This sparse set.
*/
sparse_set & operator=(const sparse_set &other) {
if(&other != this) {
auto tmp{other};
*this = std::move(tmp);
}
return *this;
}
virtual ~basic_sparse_set() = default;
/*! @brief Default move assignment operator. @return This sparse set. */
sparse_set & operator=(sparse_set &&) = default;
basic_sparse_set & operator=(basic_sparse_set &&) = default;
/**
* @brief Increases the capacity of a sparse set.
@@ -228,8 +207,8 @@ public:
*
* @param cap Desired capacity.
*/
virtual void reserve(const size_type cap) {
direct.reserve(cap);
void reserve(const size_type cap) {
packed.reserve(cap);
}
/**
@@ -237,24 +216,19 @@ public:
* allocated space for.
* @return Capacity of the sparse set.
*/
size_type capacity() const ENTT_NOEXCEPT {
return direct.capacity();
[[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
return packed.capacity();
}
/*! @brief Requests the removal of unused capacity. */
virtual void shrink_to_fit() {
while(!reverse.empty() && !reverse.back().second) {
reverse.pop_back();
void shrink_to_fit() {
// conservative approach
if(packed.empty()) {
sparse.clear();
}
for(auto &&data: reverse) {
if(!data.second) {
data.first.reset();
}
}
reverse.shrink_to_fit();
direct.shrink_to_fit();
sparse.shrink_to_fit();
packed.shrink_to_fit();
}
/**
@@ -267,8 +241,8 @@ public:
*
* @return Extent of the sparse set.
*/
size_type extent() const ENTT_NOEXCEPT {
return reverse.size() * entt_per_page;
[[nodiscard]] size_type extent() const ENTT_NOEXCEPT {
return sparse.size() * entt_per_page;
}
/**
@@ -281,35 +255,32 @@ public:
*
* @return Number of elements.
*/
size_type size() const ENTT_NOEXCEPT {
return direct.size();
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return packed.size();
}
/**
* @brief Checks whether a sparse set is empty.
* @return True if the sparse set is empty, false otherwise.
*/
bool empty() const ENTT_NOEXCEPT {
return direct.empty();
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return packed.empty();
}
/**
* @brief Direct access to the internal packed array.
*
* The returned pointer is such that range `[data(), data() + size()]` is
* The returned pointer is such that range `[data(), data() + size())` is
* always a valid range, even if the container is empty.
*
* @note
* There are no guarantees on the order, even though `respect` has been
* previously invoked. Internal data structures arrange elements to maximize
* performance. Accessing them directly gives a performance boost but less
* guarantees. Use `begin` and `end` if you want to iterate the sparse set
* in the expected order.
* Entities are in the reverse order as returned by the `begin`/`end`
* iterators.
*
* @return A pointer to the internal packed array.
*/
const entity_type * data() const ENTT_NOEXCEPT {
return direct.data();
[[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT {
return packed.data();
}
/**
@@ -319,14 +290,11 @@ public:
* array. If the sparse set is empty, the returned iterator will be equal to
* `end()`.
*
* @note
* Input iterators stay true to the order imposed by a call to `respect`.
*
* @return An iterator to the first entity of the internal packed array.
*/
iterator_type begin() const ENTT_NOEXCEPT {
const typename traits_type::difference_type pos = direct.size();
return iterator_type{&direct, pos};
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
const typename traits_type::difference_type pos = packed.size();
return iterator{packed, pos};
}
/**
@@ -336,14 +304,39 @@ public:
* the internal packed array. Attempting to dereference the returned
* iterator results in undefined behavior.
*
* @note
* Input iterators stay true to the order imposed by a call to `respect`.
*
* @return An iterator to the element following the last entity of the
* internal packed array.
*/
iterator_type end() const ENTT_NOEXCEPT {
return iterator_type{&direct, {}};
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return iterator{packed, {}};
}
/**
* @brief Returns a reverse iterator to the beginning.
*
* The returned iterator points to the first entity of the reversed internal
* packed array. If the sparse set is empty, the returned iterator will be
* equal to `rend()`.
*
* @return An iterator to the first entity of the reversed internal packed
* array.
*/
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return packed.data();
}
/**
* @brief Returns a reverse iterator to the end.
*
* The returned iterator points to the element following the last entity in
* the reversed internal packed array. Attempting to dereference the
* returned iterator results in undefined behavior.
*
* @return An iterator to the element following the last entity of the
* reversed internal packed array.
*/
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return rbegin() + packed.size();
}
/**
@@ -352,8 +345,8 @@ public:
* @return An iterator to the given entity if it's found, past the end
* iterator otherwise.
*/
iterator_type find(const entity_type entt) const ENTT_NOEXCEPT {
return has(entt) ? --(end() - get(entt)) : end();
[[nodiscard]] iterator find(const entity_type entt) const {
return contains(entt) ? --(end() - index(entt)) : end();
}
/**
@@ -361,10 +354,10 @@ public:
* @param entt A valid entity identifier.
* @return True if the sparse set contains the entity, false otherwise.
*/
bool has(const entity_type entt) const ENTT_NOEXCEPT {
auto [page, offset] = index(entt);
// testing against null permits to avoid accessing the direct vector
return (page < reverse.size() && reverse[page].second && reverse[page].first[offset] != null);
[[nodiscard]] bool contains(const entity_type entt) const {
const auto curr = page(entt);
// testing against null permits to avoid accessing the packed array
return (curr < sparse.size() && sparse[curr] && sparse[curr][offset(entt)] != null);
}
/**
@@ -372,17 +365,14 @@ public:
*
* @warning
* Attempting to get the position of an entity that doesn't belong to the
* sparse set results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* sparse set doesn't contain the given entity.
* sparse set results in undefined behavior.
*
* @param entt A valid entity identifier.
* @return The position of the entity in the sparse set.
*/
size_type get(const entity_type entt) const ENTT_NOEXCEPT {
ENTT_ASSERT(has(entt));
auto [page, offset] = index(entt);
return size_type(reverse[page].first[offset]);
[[nodiscard]] size_type index(const entity_type entt) const {
ENTT_ASSERT(contains(entt));
return size_type{to_integral(sparse[page(entt)][offset(entt)])};
}
/**
@@ -390,19 +380,14 @@ public:
*
* @warning
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* sparse set already contains the given entity.
* results in undefined behavior.
*
* @param entt A valid entity identifier.
*/
void construct(const entity_type entt) {
ENTT_ASSERT(!has(entt));
auto [page, offset] = index(entt);
assure(page);
reverse[page].first[offset] = entity_type(direct.size());
reverse[page].second++;
direct.push_back(entt);
void emplace(const entity_type entt) {
ENTT_ASSERT(!contains(entt));
assure(page(entt))[offset(entt)] = entity_type{static_cast<typename traits_type::entity_type>(packed.size())};
packed.push_back(entt);
}
/**
@@ -410,25 +395,21 @@ public:
*
* @warning
* Attempting to assign an entity that already belongs to the sparse set
* results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* sparse set already contains the given entity.
* results in undefined behavior.
*
* @tparam It Type of forward iterator.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
template<typename It>
void batch(It first, It last) {
std::for_each(first, last, [next = entity_type(direct.size()), this](const auto entt) mutable {
ENTT_ASSERT(!has(entt));
auto [page, offset] = index(entt);
assure(page);
reverse[page].first[offset] = next++;
reverse[page].second++;
});
void insert(It first, It last) {
auto next = static_cast<typename traits_type::entity_type>(packed.size());
packed.insert(packed.end(), first, last);
direct.insert(direct.end(), first, last);
for(; first != last; ++first) {
ENTT_ASSERT(!contains(*first));
assure(page(*first))[offset(*first)] = entity_type{next++};
}
}
/**
@@ -436,45 +417,128 @@ public:
*
* @warning
* Attempting to remove an entity that doesn't belong to the sparse set
* results in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* sparse set doesn't contain the given entity.
* results in undefined behavior.
*
* @param entt A valid entity identifier.
*/
virtual void destroy(const entity_type entt) {
ENTT_ASSERT(has(entt));
auto [from_page, from_offset] = index(entt);
auto [to_page, to_offset] = index(direct.back());
direct[size_type(reverse[from_page].first[from_offset])] = direct.back();
reverse[to_page].first[to_offset] = reverse[from_page].first[from_offset];
reverse[from_page].first[from_offset] = null;
reverse[from_page].second--;
direct.pop_back();
void remove(const entity_type entt) {
ENTT_ASSERT(contains(entt));
auto &ref = sparse[page(entt)][offset(entt)];
const auto pos = size_type{to_integral(ref)};
const auto other = packed.back();
sparse[page(other)][offset(other)] = ref;
packed[pos] = other;
ref = null;
packed.pop_back();
swap_and_pop(pos);
}
/**
* @brief Swaps the position of two entities in the internal packed array.
* @brief Removes multiple entities from a pool.
* @tparam It Type of input iterator.
* @param first An iterator to the first element of the range of entities.
* @param last An iterator past the last element of the range of entities.
*/
template<typename It>
void remove(It first, It last) {
if(std::distance(first, last) == std::distance(packed.begin(), packed.end())) {
// no validity check, let it be misused
clear();
} else {
for(; first != last; ++first) {
remove(*first);
}
}
}
/**
* @brief Swaps two entities in the internal packed array.
*
* For what it's worth, this function affects both the internal sparse array
* and the internal packed array. Users should not care of that anyway.
*
* @warning
* Attempting to swap entities that don't belong to the sparse set results
* in undefined behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* sparse set doesn't contain the given entities.
* in undefined behavior.
*
* @param lhs A valid position within the sparse set.
* @param rhs A valid position within the sparse set.
* @param lhs A valid entity identifier.
* @param rhs A valid entity identifier.
*/
void swap(const size_type lhs, const size_type rhs) ENTT_NOEXCEPT {
ENTT_ASSERT(lhs < direct.size());
ENTT_ASSERT(rhs < direct.size());
auto [src_page, src_offset] = index(direct[lhs]);
auto [dst_page, dst_offset] = index(direct[rhs]);
std::swap(reverse[src_page].first[src_offset], reverse[dst_page].first[dst_offset]);
std::swap(direct[lhs], direct[rhs]);
void swap(const entity_type lhs, const entity_type rhs) {
const auto from = index(lhs);
const auto to = index(rhs);
std::swap(sparse[page(lhs)][offset(lhs)], sparse[page(rhs)][offset(rhs)]);
std::swap(packed[from], packed[to]);
swap_at(from, to);
}
/**
* @brief Sort the first count elements according to the given comparison
* function.
*
* The comparison function object must return `true` if the first element
* is _less_ than the second one, `false` otherwise. The signature of the
* comparison function should be equivalent to the following:
*
* @code{.cpp}
* bool(const Entity, const Entity);
* @endcode
*
* Moreover, the comparison function object shall induce a
* _strict weak ordering_ on the values.
*
* The sort function object must offer a member function template
* `operator()` that accepts three arguments:
*
* * An iterator to the first element of the range to sort.
* * An iterator past the last element of the range to sort.
* * A comparison function to use to compare the elements.
*
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param count Number of elements to sort.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort_n(const size_type count, Compare compare, Sort algo = Sort{}, Args &&... args) {
ENTT_ASSERT(!(count > size()));
algo(packed.rend() - count, packed.rend(), std::move(compare), std::forward<Args>(args)...);
for(size_type pos{}; pos < count; ++pos) {
auto curr = pos;
auto next = index(packed[curr]);
while(curr != next) {
swap_at(next, index(packed[next]));
sparse[page(packed[curr])][offset(packed[curr])] = entity_type{static_cast<typename traits_type::entity_type>(curr)};
curr = next;
next = index(packed[curr]);
}
}
}
/**
* @brief Sort all elements according to the given comparison function.
*
* @sa sort_n
*
* @tparam Compare Type of comparison function object.
* @tparam Sort Type of sort function object.
* @tparam Args Types of arguments to forward to the sort function object.
* @param compare A valid comparison function object.
* @param algo A valid sort function object.
* @param args Arguments to forward to the sort function object, if any.
*/
template<typename Compare, typename Sort = std_sort, typename... Args>
void sort(Compare compare, Sort algo = Sort{}, Args &&... args) {
sort_n(size(), std::move(compare), std::move(algo), std::forward<Args>(args)...);
}
/**
@@ -482,7 +546,7 @@ public:
*
* Entities that are part of both the sparse sets are ordered internally
* according to the order they have in `other`. All the other entities goes
* to the end of the list and there are no guarantess on their order.<br/>
* to the end of the list and there are no guarantees on their order.<br/>
* In other terms, this function can be used to impose the same order on two
* sets by using one of them as a master and the other one as a slave.
*
@@ -490,22 +554,18 @@ public:
* the expected order after a call to `respect`. See `begin` and `end` for
* more details.
*
* @note
* Attempting to iterate elements using the raw pointer returned by `data`
* gives no guarantees on the order, even though `respect` has been invoked.
*
* @param other The sparse sets that imposes the order of the entities.
*/
virtual void respect(const sparse_set &other) ENTT_NOEXCEPT {
void respect(const basic_sparse_set &other) {
const auto to = other.end();
auto from = other.begin();
size_type pos = direct.size() - 1;
size_type pos = packed.size() - 1;
while(pos && from != to) {
if(has(*from)) {
if(*from != direct[pos]) {
swap(pos, get(*from));
if(contains(*from)) {
if(*from != packed[pos]) {
swap(packed[pos], *from);
}
--pos;
@@ -515,21 +575,20 @@ public:
}
}
/**
* @brief Resets a sparse set.
*/
virtual void reset() {
reverse.clear();
direct.clear();
/*! @brief Clears a sparse set. */
void clear() ENTT_NOEXCEPT {
sparse.clear();
packed.clear();
clear_all();
}
private:
std::vector<std::pair<std::unique_ptr<entity_type[]>, size_type>> reverse;
std::vector<entity_type> direct;
std::vector<page_type> sparse;
std::vector<entity_type> packed;
};
}
#endif // ENTT_ENTITY_SPARSE_SET_HPP
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
#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{};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,435 @@
#ifndef ENTT_ENTITY_VIEW_PACK_HPP
#define ENTT_ENTITY_VIEW_PACK_HPP
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../core/type_traits.hpp"
#include "fwd.hpp"
#include "utility.hpp"
namespace entt {
/**
* @brief View pack.
*
* The view pack allows users to combine multiple views into a single iterable
* object, while also giving them full control over which view should lead the
* iteration.<br/>
* This class returns all and only the entities present in all views. Its
* intended primary use is for custom storage and views, but it can also be very
* convenient in everyday use.
*
* @tparam Head Type of the leading view of the pack.
* @tparam Tail Types of all other views of the pack.
*/
template<typename Head, typename... Tail>
class view_pack {
template<typename It>
class view_pack_iterator final {
friend class view_pack<Head, Tail...>;
view_pack_iterator(It from, It to, const std::tuple<Tail...> &other) ENTT_NOEXCEPT
: it{from},
last{to},
tail{other}
{
if(it != last && !valid()) {
++(*this);
}
}
[[nodiscard]] bool valid() const {
return std::apply([entity = *it](auto &&... curr) { return (curr.contains(entity) && ...); }, tail);
}
public:
using difference_type = typename std::iterator_traits<It>::difference_type;
using value_type = typename std::iterator_traits<It>::value_type;
using pointer = typename std::iterator_traits<It>::pointer;
using reference = typename std::iterator_traits<It>::reference;
using iterator_category = std::input_iterator_tag;
view_pack_iterator & operator++() ENTT_NOEXCEPT {
while(++it != last && !valid());
return *this;
}
view_pack_iterator operator++(int) ENTT_NOEXCEPT {
view_pack_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] reference operator*() const {
return *it;
}
[[nodiscard]] bool operator==(const view_pack_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const view_pack_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
private:
It it;
const It last;
const std::tuple<Tail...> tail;
};
class iterable_view_pack final {
friend class view_pack<Head, Tail...>;
using iterable_view = decltype(std::declval<Head>().each());
template<typename It>
class iterable_view_pack_iterator final {
friend class iterable_view_pack;
iterable_view_pack_iterator(It from, It to, const std::tuple<Tail...> &other) ENTT_NOEXCEPT
: it{from},
last{to},
tail{other}
{
if(it != last && !valid()) {
++(*this);
}
}
[[nodiscard]] bool valid() const {
return std::apply([entity = std::get<0>(*it)](auto &&... curr) { return (curr.contains(entity) && ...); }, tail);
}
public:
using difference_type = typename std::iterator_traits<It>::difference_type;
using value_type = decltype(std::tuple_cat(*std::declval<It>(), std::declval<Tail>().get({})...));
using pointer = void;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
iterable_view_pack_iterator & operator++() ENTT_NOEXCEPT {
while(++it != last && !valid());
return *this;
}
iterable_view_pack_iterator operator++(int) ENTT_NOEXCEPT {
iterable_view_pack_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] reference operator*() const {
return std::apply([value = *it](auto &&... curr) { return std::tuple_cat(value, curr.get(std::get<0>(value))...); }, tail);
}
[[nodiscard]] bool operator==(const iterable_view_pack_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const iterable_view_pack_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
private:
It it;
const It last;
const std::tuple<Tail...> tail;
};
iterable_view_pack(const Head &first, const std::tuple<Tail...> &last)
: iterable{first.each()},
tail{last}
{}
public:
using iterator = iterable_view_pack_iterator<typename iterable_view::iterator>;
using reverse_iterator = iterable_view_pack_iterator<typename iterable_view::reverse_iterator>;
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return { iterable.begin(), iterable.end(), tail };
}
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return { iterable.end(), iterable.end(), tail };
}
[[nodiscard]] reverse_iterator rbegin() const ENTT_NOEXCEPT {
return { iterable.rbegin(), iterable.rend(), tail };
}
[[nodiscard]] reverse_iterator rend() const ENTT_NOEXCEPT {
return { iterable.rend(), iterable.rend(), tail };
}
private:
iterable_view iterable;
std::tuple<Tail...> tail;
};
public:
/*! @brief Underlying entity identifier. */
using entity_type = std::common_type_t<typename Head::entity_type, typename Tail::entity_type...>;
/*! @brief Underlying entity identifier. */
using size_type = std::common_type_t<typename Head::size_type, typename Tail::size_type...>;
/*! @brief Input iterator type. */
using iterator = view_pack_iterator<typename Head::iterator>;
/*! @brief Reversed iterator type. */
using reverse_iterator = view_pack_iterator<typename Head::reverse_iterator>;
/**
* @brief Constructs a pack from a bunch of views.
* @param first A reference to the leading view for the pack.
* @param last References to the other views to use to construct the pack.
*/
view_pack(const Head &first, const Tail &... last)
: head{first},
tail{last...}
{}
/**
* @brief Returns an iterator to the first entity of the pack.
*
* The returned iterator points to the first entity of the pack. If the pack
* is empty, the returned iterator will be equal to `end()`.
*
* @return An iterator to the first entity of the pack.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return { head.begin(), head.end(), tail };
}
/**
* @brief Returns an iterator that is past the last entity of the pack.
*
* The returned iterator points to the entity following the last entity of
* the pack. Attempting to dereference the returned iterator results in
* undefined behavior.
*
* @return An iterator to the entity following the last entity of the pack.
*/
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return { head.end(), head.end(), tail };
}
/**
* @brief Returns an iterator to the first entity of the pack.
*
* The returned iterator points to the first entity of the reversed pack. If
* the pack is empty, the returned iterator will be equal to `rend()`.
*
* @return An iterator to the first entity of the pack.
*/
[[nodiscard]] reverse_iterator rbegin() const {
return { head.rbegin(), head.rend(), tail };
}
/**
* @brief Returns an iterator that is past the last entity of the reversed
* pack.
*
* The returned iterator points to the entity following the last entity of
* the reversed pack. Attempting to dereference the returned iterator
* results in undefined behavior.
*
* @return An iterator to the entity following the last entity of the
* reversed pack.
*/
[[nodiscard]] reverse_iterator rend() const {
return { head.rend(), head.rend(), tail };
}
/**
* @brief Returns the first entity of the pack, if any.
* @return The first entity of the pack if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type front() const {
const auto it = begin();
return it != end() ? *it : null;
}
/**
* @brief Returns the last entity of the pack, if any.
* @return The last entity of the pack if one exists, the null entity
* otherwise.
*/
[[nodiscard]] entity_type back() const {
const auto it = rbegin();
return it != rend() ? *it : null;
}
/**
* @brief Finds an entity.
* @param entt A valid entity identifier.
* @return An iterator to the given entity if it's found, past the end
* iterator otherwise.
*/
[[nodiscard]] iterator find(const entity_type entt) const {
iterator it{head.find(entt), head.end(), tail};
return (it != end() && *it == entt) ? it : end();
}
/**
* @brief Checks if a pack contains an entity.
* @param entt A valid entity identifier.
* @return True if the pack contains the given entity, false otherwise.
*/
[[nodiscard]] bool contains(const entity_type entt) const {
return head.contains(entt) && std::apply([entt](auto &&... curr) { return (curr.contains(entt) && ...); }, tail);
}
/**
* @brief Returns the components assigned to the given entity.
*
* Prefer this function instead of `registry::get` during iterations. It has
* far better performance than its counterpart.
*
* @warning
* Attempting to use an invalid component type results in a compilation
* error. Attempting to use an entity that doesn't belong to the pack
* results in undefined behavior.
*
* @tparam Comp Types of components to get.
* @param entt A valid entity identifier.
* @return The components assigned to the entity.
*/
template<typename... Comp>
[[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const {
ENTT_ASSERT(contains(entt));
auto component = std::apply([this, entt](auto &&... curr) { return std::tuple_cat(head.get(entt), curr.get(entt)...); }, tail);
if constexpr(sizeof...(Comp) == 0) {
return component;
} else if constexpr(sizeof...(Comp) == 1) {
return (std::get<Comp &>(component), ...);
} else {
return std::forward_as_tuple(std::get<Comp &>(component)...);
}
}
/**
* @brief Iterates entities and components and applies the given function
* object to them.
*
* The function object is invoked for each entity. It is provided with the
* entity itself and a set of references to non-empty components. The
* _constness_ of the components is as requested.<br/>
* The signature of the function must be equivalent to one of the following
* forms:
*
* @code{.cpp}
* void(const entity_type, Type &...);
* void(Type &...);
* @endcode
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void each(Func func) const {
for(auto &&value: head.each()) {
if(std::apply([&value](auto &&... curr) { return (curr.contains(std::get<0>(value)) && ...); }, tail)) {
auto args = std::apply([&value](auto &&... curr) { return std::tuple_cat(value, curr.get(std::get<0>(value))...); }, tail);
if constexpr(is_applicable_v<Func, decltype(args)>) {
std::apply(func, args);
} else {
std::apply([&func](const auto, auto &&... component) { func(std::forward<decltype(component)>(component)...); }, args);
}
}
}
}
/**
* @brief Returns an iterable object to use to _visit_ the pack.
*
* The iterable object returns tuples that contain the current entity and a
* set of references to its non-empty components. The _constness_ of the
* components is as requested.
*
* @note
* Empty types aren't explicitly instantiated and therefore they are never
* returned during iterations.
*
* @return An iterable object to use to _visit_ the pack.
*/
[[nodiscard]] iterable_view_pack each() const ENTT_NOEXCEPT {
return { head, tail };
}
/**
* @brief Returns a copy of the views stored by the pack.
* @return A copy of the views stored by the pack.
*/
std::tuple<Head, Tail...> pack() const ENTT_NOEXCEPT {
return std::apply([this](auto &&... curr) { return std::make_tuple(head, curr...); }, tail);
}
/**
* @brief Appends a view to a pack.
* @tparam Args View template arguments.
* @param other A reference to a view to append to the pack.
* @return The extended pack.
*/
template<typename... Args>
[[nodiscard]] auto operator|(const basic_view<Args...> &other) const {
return std::make_from_tuple<view_pack<Head, Tail..., basic_view<Args...>>>(std::tuple_cat(std::make_tuple(head), tail, std::make_tuple(other)));
}
/**
* @brief Appends a pack and therefore all its views to another pack.
* @tparam Pack Types of views of the pack to append.
* @param other A reference to the pack to append.
* @return The extended pack.
*/
template<typename... Pack>
[[nodiscard]] auto operator|(const view_pack<Pack...> &other) const {
return std::make_from_tuple<view_pack<Head, Tail..., Pack...>>(std::tuple_cat(std::make_tuple(head), tail, other.pack()));
}
private:
Head head;
std::tuple<Tail...> tail;
};
/**
* @brief Combines two views in a pack.
* @tparam Args Template arguments of the first view.
* @tparam Other Template arguments of the second view.
* @param lhs A reference to the first view with which to create the pack.
* @param rhs A reference to the second view with which to create the pack.
* @return A pack that combines the two views in a single iterable object.
*/
template<typename... Args, typename... Other>
[[nodiscard]] auto operator|(const basic_view<Args...> &lhs, const basic_view<Other...> &rhs) {
return view_pack{lhs, rhs};
}
/**
* @brief Combines a view with a pack.
* @tparam Args View template arguments.
* @tparam Pack Types of views of the pack.
* @param view A reference to the view to combine with the pack.
* @param pack A reference to the pack to combine with the view.
* @return The extended pack.
*/
template<typename... Args, typename... Pack>
[[nodiscard]] auto operator|(const basic_view<Args...> &view, const view_pack<Pack...> &pack) {
return view_pack{view} | pack;
}
}
#endif

View File

@@ -1,24 +1,43 @@
#include "config/version.h"
#include "core/algorithm.hpp"
#include "core/any.hpp"
#include "core/attribute.h"
#include "core/family.hpp"
#include "core/hashed_string.hpp"
#include "core/ident.hpp"
#include "core/monostate.hpp"
#include "core/type_info.hpp"
#include "core/type_traits.hpp"
#include "core/utility.hpp"
#include "entity/actor.hpp"
#include "entity/entity.hpp"
#include "entity/group.hpp"
#include "entity/handle.hpp"
#include "entity/helper.hpp"
#include "entity/prototype.hpp"
#include "entity/observer.hpp"
#include "entity/organizer.hpp"
#include "entity/poly_storage.hpp"
#include "entity/registry.hpp"
#include "entity/runtime_view.hpp"
#include "entity/snapshot.hpp"
#include "entity/sparse_set.hpp"
#include "entity/storage.hpp"
#include "entity/utility.hpp"
#include "entity/view.hpp"
#include "entity/view_pack.hpp"
#include "locator/locator.hpp"
#include "meta/adl_pointer.hpp"
#include "meta/container.hpp"
#include "meta/ctx.hpp"
#include "meta/factory.hpp"
#include "meta/internal.hpp"
#include "meta/meta.hpp"
#include "meta/pointer.hpp"
#include "meta/policy.hpp"
#include "meta/range.hpp"
#include "meta/resolve.hpp"
#include "meta/type_traits.hpp"
#include "platform/android-ndk-r17.hpp"
#include "poly/poly.hpp"
#include "process/process.hpp"
#include "process/scheduler.hpp"
#include "resource/cache.hpp"

View File

@@ -1,3 +1,4 @@
#include "core/fwd.hpp"
#include "entity/fwd.hpp"
#include "resource/fwd.hpp"
#include "signal/fwd.hpp"

View File

@@ -35,7 +35,7 @@ struct service_locator {
* @brief Tests if a valid service implementation is set.
* @return True if the service is set, false otherwise.
*/
inline static bool empty() ENTT_NOEXCEPT {
[[nodiscard]] static bool empty() ENTT_NOEXCEPT {
return !static_cast<bool>(service);
}
@@ -49,7 +49,7 @@ struct service_locator {
*
* @return A reference to the service implementation currently set, if any.
*/
inline static std::weak_ptr<Service> get() ENTT_NOEXCEPT {
[[nodiscard]] static std::weak_ptr<Service> get() ENTT_NOEXCEPT {
return service;
}
@@ -67,7 +67,7 @@ struct service_locator {
*
* @return A reference to the service implementation currently set, if any.
*/
inline static Service & ref() ENTT_NOEXCEPT {
[[nodiscard]] static Service & ref() ENTT_NOEXCEPT {
return *service;
}
@@ -78,7 +78,7 @@ struct service_locator {
* @param args Parameters to use to construct the service.
*/
template<typename Impl = Service, typename... Args>
inline static void set(Args &&... args) {
static void set(Args &&... args) {
service = std::make_shared<Impl>(std::forward<Args>(args)...);
}
@@ -86,7 +86,7 @@ struct service_locator {
* @brief Sets or replaces a service.
* @param ptr Service to use to replace the current one.
*/
inline static void set(std::shared_ptr<Service> ptr) {
static void set(std::shared_ptr<Service> ptr) {
ENTT_ASSERT(static_cast<bool>(ptr));
service = std::move(ptr);
}
@@ -96,7 +96,7 @@ struct service_locator {
*
* The service is no longer valid after a reset.
*/
inline static void reset() {
static void reset() {
service.reset();
}
@@ -108,4 +108,4 @@ private:
}
#endif // ENTT_LOCATOR_LOCATOR_HPP
#endif

View File

@@ -0,0 +1,40 @@
#ifndef ENTT_META_ADL_POINTER_HPP
#define ENTT_META_ADL_POINTER_HPP
namespace entt {
/**
* @brief ADL based lookup function for dereferencing meta pointer-like types.
* @tparam Type Element type.
* @param value A pointer-like object.
* @return The value returned from the dereferenced pointer.
*/
template<typename Type>
decltype(auto) dereference_meta_pointer_like(const Type &value) {
return *value;
}
/**
* @brief Fake ADL based lookup function for meta pointer-like types.
* @tparam Type Element type.
*/
template<typename Type>
struct adl_meta_pointer_like {
/**
* @brief Uses the default ADL based lookup method to resolve the call.
* @param value A pointer-like object.
* @return The value returned from the dereferenced pointer.
*/
static decltype(auto) dereference(const Type &value) {
return dereference_meta_pointer_like(value);
}
};
}
#endif

421
src/entt/meta/container.hpp Normal file
View File

@@ -0,0 +1,421 @@
#ifndef ENTT_META_CONTAINER_HPP
#define ENTT_META_CONTAINER_HPP
#include <array>
#include <map>
#include <set>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "type_traits.hpp"
namespace entt {
/**
* @brief Container traits.
* @tparam Container Type of the underlying container.
* @tparam Trait Traits associated with the underlying container.
*/
template<typename Container, template<typename> class... Trait>
struct meta_container_traits: public Trait<Container>... {};
/**
* @brief Basic STL-compatible container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_container {
/*! @brief Iterator type of the container. */
using iterator = typename Container::iterator;
/*! @brief Iterator type of the container. */
using const_iterator = typename Container::const_iterator;
/*! @brief Unsigned integer type. */
using size_type = typename Container::size_type;
/*! @brief Value type of the container. */
using value_type = typename Container::value_type;
/**
* @brief Returns the size of the given container.
* @param cont The container for which to return the size.
* @return The size of the given container.
*/
[[nodiscard]] static size_type size(const Container &cont) ENTT_NOEXCEPT {
return cont.size();
}
/**
* @brief Returns an iterator to the first element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator to the first element of the given container.
*/
[[nodiscard]] static iterator begin(Container &cont) {
return cont.begin();
}
/**
* @brief Returns an iterator to the first element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator to the first element of the given container.
*/
[[nodiscard]] static const_iterator cbegin(const Container &cont) {
return cont.begin();
}
/**
* @brief Returns an iterator past the last element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator past the last element of the given container.
*/
[[nodiscard]] static iterator end(Container &cont) {
return cont.end();
}
/**
* @brief Returns an iterator past the last element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator past the last element of the given container.
*/
[[nodiscard]] static const_iterator cend(const Container &cont) {
return cont.end();
}
};
/**
* @brief Basic STL-compatible associative container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_associative_container {
/*! @brief Key type of the sequence container. */
using key_type = typename Container::key_type;
/**
* @brief Returns an iterator to the element with key equivalent to the
* given one, if any.
* @param cont The container in which to search for the element.
* @param key The key of the element to search.
* @return An iterator to the element with the given key, if any.
*/
[[nodiscard]] static typename Container::iterator find(Container &cont, const key_type &key) {
return cont.find(key);
}
/*! @copydoc find */
[[nodiscard]] static typename Container::const_iterator cfind(const Container &cont, const key_type &key) {
return cont.find(key);
}
};
/**
* @brief Basic STL-compatible dynamic container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_dynamic_container {
/**
* @brief Clears the content of the given container.
* @param cont The container for which to clear the content.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear([[maybe_unused]] Container &cont) {
return cont.clear(), true;
}
};
/**
* @brief Basic STL-compatible dynamic associative container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_dynamic_associative_container {
/**
* @brief Removes the specified element from the given container.
* @param cont The container from which to remove the element.
* @param key The element to remove.
* @return A bool denoting whether the removal took place.
*/
[[nodiscard]] static bool erase([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
const auto sz = cont.size();
return cont.erase(key) != sz;
}
};
/**
* @brief Basic STL-compatible sequence container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_sequence_container {
/**
* @brief Returns a reference to the element at the specified location of
* the given container (no bounds checking is performed).
* @param cont The container from which to get the element.
* @param pos The position of the element to return.
* @return A reference to the requested element.
*/
[[nodiscard]] static typename Container::value_type & get(Container &cont, typename Container::size_type pos) {
return cont[pos];
}
/*! @copydoc get */
[[nodiscard]] static const typename Container::value_type & cget(const Container &cont, typename Container::size_type pos) {
return cont[pos];
}
};
/**
* @brief STL-compatible dynamic associative key-only container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct dynamic_associative_key_only_container {
/**
* @brief Inserts an element into the given container.
* @param cont The container in which to insert the element.
* @param key The element to insert.
* @return A bool denoting whether the insertion took place.
*/
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
return cont.insert(key).second;
}
};
/**
* @brief STL-compatible dynamic key-value associative container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct dynamic_associative_key_value_container {
/**
* @brief Inserts an element (a key/value pair) into the given container.
* @param cont The container in which to insert the element.
* @param key The key of the element to insert.
* @param value The value of the element to insert.
* @return A bool denoting whether the insertion took place.
*/
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key, [[maybe_unused]] const typename Container::mapped_type &value) {
return cont.insert(std::make_pair(key, value)).second;
}
};
/**
* @brief STL-compatible dynamic sequence container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct dynamic_sequence_container {
/**
* @brief Resizes the given container to contain the given number of
* elements.
* @param cont The container to resize.
* @param sz The new size of the container.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool resize([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::size_type sz) {
return cont.resize(sz), true;
}
/**
* @brief Inserts an element at the specified location of the given
* container.
* @param cont The container into which to insert the element.
* @param it Iterator before which the element will be inserted.
* @param value Element value to insert.
* @return A pair consisting of an iterator to the inserted element (in case
* of success) and a bool denoting whether the insertion took place.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> insert([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it, [[maybe_unused]] const typename Container::value_type &value) {
return { cont.insert(it, value), true };
}
/**
* @brief Removes the element at the specified location from the given
* container.
* @param cont The container from which to remove the element.
* @param it Iterator to the element to remove.
* @return A pair consisting of an iterator following the last removed
* element (in case of success) and a bool denoting whether the insertion
* took place.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> erase([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it) {
return { cont.erase(it), true };
}
};
/**
* @brief STL-compatible fixed sequence container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct fixed_sequence_container {
/**
* @brief Does nothing.
* @return False to indicate failure in all cases.
*/
[[nodiscard]] static bool resize(const Container &, typename Container::size_type) {
return false;
}
/**
* @brief Does nothing.
* @return False to indicate failure in all cases.
*/
[[nodiscard]] static bool clear(const Container &) {
return false;
}
/**
* @brief Does nothing.
* @return A pair consisting of an invalid iterator and a false value to
* indicate failure in all cases.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> insert(const Container &, typename Container::const_iterator, const typename Container::value_type &) {
return { {}, false };
}
/**
* @brief Does nothing.
* @return A pair consisting of an invalid iterator and a false value to
* indicate failure in all cases.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> erase(const Container &, typename Container::const_iterator) {
return { {}, false };
}
};
/**
* @brief Meta sequence container traits for `std::vector`s of any type.
* @tparam Type The type of elements.
* @tparam Args Other arguments.
*/
template<typename Type, typename... Args>
struct meta_sequence_container_traits<std::vector<Type, Args...>>
: meta_container_traits<
std::vector<Type, Args...>,
basic_container,
basic_dynamic_container,
basic_sequence_container,
dynamic_sequence_container
>
{};
/**
* @brief Meta sequence container traits for `std::array`s of any type.
* @tparam Type The type of elements.
* @tparam N The number of elements.
*/
template<typename Type, auto N>
struct meta_sequence_container_traits<std::array<Type, N>>
: meta_container_traits<
std::array<Type, N>,
basic_container,
basic_sequence_container,
fixed_sequence_container
>
{};
/**
* @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.
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::map<Key, Value, Args...>>
: meta_container_traits<
std::map<Key, Value, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_value_container
>
{
/*! @brief Mapped type of the sequence container. */
using mapped_type = typename std::map<Key, Value, Args...>::mapped_type;
};
/**
* @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.
*/
template<typename Key, typename Value, typename... Args>
struct meta_associative_container_traits<std::unordered_map<Key, Value, Args...>>
: meta_container_traits<
std::unordered_map<Key, Value, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_value_container
>
{
/*! @brief Mapped type of the sequence container. */
using mapped_type = typename std::unordered_map<Key, Value, Args...>::mapped_type;
};
/**
* @brief Meta associative container traits for `std::set`s of any type.
* @tparam Key The type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::set<Key, Args...>>
: meta_container_traits<
std::set<Key, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_only_container
>
{};
/**
* @brief Meta associative container traits for `std::unordered_set`s of any
* type.
* @tparam Key The type of elements.
* @tparam Args Other arguments.
*/
template<typename Key, typename... Args>
struct meta_associative_container_traits<std::unordered_set<Key, Args...>>
: meta_container_traits<
std::unordered_set<Key, Args...>,
basic_container,
basic_associative_container,
basic_dynamic_container,
basic_dynamic_associative_container,
dynamic_associative_key_only_container
>
{};
}
#endif

68
src/entt/meta/ctx.hpp Normal file
View File

@@ -0,0 +1,68 @@
#ifndef ENTT_META_CTX_HPP
#define ENTT_META_CTX_HPP
#include "../core/attribute.h"
#include "../config/config.h"
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
struct meta_type_node;
struct ENTT_API meta_context {
// we could use the lines below but VS2017 returns with an ICE if combined with ENTT_API despite the code being valid C++
// inline static meta_type_node *local = nullptr;
// inline static meta_type_node **global = &local;
[[nodiscard]] static meta_type_node * & local() ENTT_NOEXCEPT {
static meta_type_node *chain = nullptr;
return chain;
}
[[nodiscard]] static meta_type_node ** & global() ENTT_NOEXCEPT {
static meta_type_node **chain = &local();
return chain;
}
};
}
/**
* Internal details not to be documented.
* @endcond
*/
/*! @brief Opaque container for a meta context. */
struct meta_ctx {
/**
* @brief Binds the meta system to a given context.
* @param other A valid context to which to bind.
*/
static void bind(meta_ctx other) ENTT_NOEXCEPT {
internal::meta_context::global() = other.ctx;
}
private:
internal::meta_type_node **ctx{&internal::meta_context::local()};
};
}
#endif

File diff suppressed because it is too large Load Diff

279
src/entt/meta/internal.hpp Normal file
View File

@@ -0,0 +1,279 @@
#ifndef ENTT_META_INTERNAL_HPP
#define ENTT_META_INTERNAL_HPP
#include <cstddef>
#include <functional>
#include <iterator>
#include <type_traits>
#include <utility>
#include "../core/attribute.h"
#include "../config/config.h"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "type_traits.hpp"
namespace entt {
class meta_any;
struct meta_handle;
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
struct meta_type_node;
struct meta_prop_node {
meta_prop_node * next;
meta_any(* const key)();
meta_any(* const value)();
};
struct meta_base_node {
meta_type_node * const parent;
meta_base_node * next;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
const void *(* const cast)(const void *) ENTT_NOEXCEPT;
};
struct meta_conv_node {
meta_type_node * const parent;
meta_conv_node * next;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
meta_any(* const conv)(const void *);
};
struct meta_ctor_node {
using size_type = std::size_t;
meta_type_node * const parent;
meta_ctor_node * next;
meta_prop_node * prop;
const size_type size;
meta_type_node *(* const arg)(size_type) ENTT_NOEXCEPT;
meta_any(* const invoke)(meta_any * const);
};
struct meta_data_node {
id_type id;
meta_type_node * const parent;
meta_data_node * next;
meta_prop_node * prop;
const bool is_static;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
bool(* const set)(meta_handle, meta_any);
meta_any(* const get)(meta_handle);
};
struct meta_func_node {
using size_type = std::size_t;
id_type id;
meta_type_node * const parent;
meta_func_node * next;
meta_prop_node * prop;
const size_type size;
const bool is_const;
const bool is_static;
meta_type_node *(* const ret)() ENTT_NOEXCEPT;
meta_type_node *(* const arg)(size_type) ENTT_NOEXCEPT;
meta_any(* const invoke)(meta_handle, meta_any *);
};
struct meta_type_node {
using size_type = std::size_t;
const type_info info;
id_type id;
meta_type_node * next;
meta_prop_node * prop;
const size_type size_of;
const bool is_void;
const bool is_integral;
const bool is_floating_point;
const bool is_array;
const bool is_enum;
const bool is_union;
const bool is_class;
const bool is_pointer;
const bool is_function_pointer;
const bool is_member_object_pointer;
const bool is_member_function_pointer;
const bool is_pointer_like;
const bool is_sequence_container;
const bool is_associative_container;
const size_type rank;
size_type(* const extent)(size_type);
meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT;
meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT;
meta_base_node *base{nullptr};
meta_conv_node *conv{nullptr};
meta_ctor_node *ctor{nullptr};
meta_data_node *data{nullptr};
meta_func_node *func{nullptr};
void(* dtor)(void *){nullptr};
};
template<typename Node>
class meta_range {
struct range_iterator {
using difference_type = std::ptrdiff_t;
using value_type = Node;
using pointer = value_type *;
using reference = value_type &;
using iterator_category = std::forward_iterator_tag;
range_iterator() ENTT_NOEXCEPT = default;
range_iterator(Node *head) ENTT_NOEXCEPT
: node{head}
{}
range_iterator & operator++() ENTT_NOEXCEPT {
return node = node->next, *this;
}
range_iterator operator++(int) ENTT_NOEXCEPT {
range_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
return other.node == node;
}
[[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
[[nodiscard]] pointer operator->() const ENTT_NOEXCEPT {
return node;
}
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
return *operator->();
}
private:
Node *node{nullptr};
};
public:
using iterator = range_iterator;
meta_range() ENTT_NOEXCEPT = default;
meta_range(Node *head)
: node{head}
{}
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return iterator{node};
}
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return iterator{};
}
private:
Node *node{nullptr};
};
template<auto Member, typename Op>
auto find_if(const Op &op, const meta_type_node *node)
-> std::decay_t<decltype(node->*Member)> {
for(auto &&curr: meta_range{node->*Member}) {
if(op(&curr)) {
return &curr;
}
}
for(auto &&curr: meta_range{node->base}) {
if(auto *ret = find_if<Member>(op, curr.type()); ret) {
return ret;
}
}
return nullptr;
}
template<typename Type>
class ENTT_API meta_node {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Invalid type");
template<std::size_t... Index>
[[nodiscard]] static auto extent(meta_type_node::size_type dim, std::index_sequence<Index...>) {
meta_type_node::size_type ext{};
((ext = (dim == Index ? std::extent_v<Type, Index> : ext)), ...);
return ext;
}
public:
[[nodiscard]] static meta_type_node * resolve() ENTT_NOEXCEPT {
static meta_type_node node{
type_id<Type>(),
{},
nullptr,
nullptr,
size_of_v<Type>,
std::is_void_v<Type>,
std::is_integral_v<Type>,
std::is_floating_point_v<Type>,
std::is_array_v<Type>,
std::is_enum_v<Type>,
std::is_union_v<Type>,
std::is_class_v<Type>,
std::is_pointer_v<Type>,
std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
std::is_member_object_pointer_v<Type>,
std::is_member_function_pointer_v<Type>,
is_meta_pointer_like_v<Type>,
has_meta_sequence_container_traits_v<Type>,
has_meta_associative_container_traits_v<Type>,
std::rank_v<Type>,
[](meta_type_node::size_type dim) {
return extent(dim, std::make_index_sequence<std::rank_v<Type>>{});
},
&meta_node<std::remove_cv_t<std::remove_pointer_t<Type>>>::resolve,
&meta_node<std::remove_cv_t<std::remove_extent_t<Type>>>::resolve
};
return &node;
}
};
template<typename... Type>
struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>...> {};
}
/**
* Internal details not to be documented.
* @endcond
*/
}
#endif

File diff suppressed because it is too large Load Diff

49
src/entt/meta/pointer.hpp Normal file
View File

@@ -0,0 +1,49 @@
#ifndef ENTT_META_POINTER_HPP
#define ENTT_META_POINTER_HPP
#include <memory>
#include <type_traits>
#include "type_traits.hpp"
namespace entt {
/**
* @brief Makes plain pointers pointer-like types for the meta system.
* @tparam Type Element type.
*/
template<typename Type>
struct is_meta_pointer_like<Type *>
: std::true_type
{};
/**
* @brief Makes `std::shared_ptr`s of any type pointer-like types for the meta
* system.
* @tparam Type Element type.
*/
template<typename Type>
struct is_meta_pointer_like<std::shared_ptr<Type>>
: std::true_type
{};
/**
* @brief Makes `std::unique_ptr`s of any type pointer-like types for the meta
* system.
* @tparam Type Element type.
* @tparam Args Other arguments.
*/
template<typename Type, typename... Args>
struct is_meta_pointer_like<std::unique_ptr<Type, Args...>>
: std::true_type
{};
}
#endif

27
src/entt/meta/policy.hpp Normal file
View File

@@ -0,0 +1,27 @@
#ifndef ENTT_META_POLICY_HPP
#define ENTT_META_POLICY_HPP
namespace entt {
/*! @brief Empty class type used to request the _as ref_ policy. */
struct as_ref_t {};
/*! @brief Empty class type used to request the _as cref_ policy. */
struct as_cref_t {};
/*! @brief Empty class type used to request the _as-is_ policy. */
struct as_is_t {};
/*! @brief Empty class type used to request the _as void_ policy. */
struct as_void_t {};
}
#endif

100
src/entt/meta/range.hpp Normal file
View File

@@ -0,0 +1,100 @@
#ifndef ENTT_META_RANGE_HPP
#define ENTT_META_RANGE_HPP
#include <cstddef>
#include <iterator>
#include "internal.hpp"
namespace entt {
/**
* @brief Iterable range to use to iterate all types of meta objects.
* @tparam Type Type of meta objects iterated.
*/
template<typename Type>
class meta_range {
struct range_iterator {
using difference_type = std::ptrdiff_t;
using value_type = Type;
using pointer = void;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
using node_type = typename Type::node_type;
range_iterator() ENTT_NOEXCEPT = default;
range_iterator(node_type *head) ENTT_NOEXCEPT
: it{head}
{}
range_iterator & operator++() ENTT_NOEXCEPT {
return ++it, *this;
}
range_iterator operator++(int) ENTT_NOEXCEPT {
range_iterator orig = *this;
return it++, orig;
}
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
return it.operator->();
}
[[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
private:
typename internal::meta_range<node_type>::iterator it{};
};
public:
/*! @brief Node type. */
using node_type = typename Type::node_type;
/*! @brief Input iterator type. */
using iterator = range_iterator;
/*! @brief Default constructor. */
meta_range() ENTT_NOEXCEPT = default;
/**
* @brief Constructs a meta range from a given node.
* @param head The underlying node with which to construct the range.
*/
meta_range(node_type *head)
: node{head}
{}
/**
* @brief Returns an iterator to the beginning.
* @return An iterator to the first meta object of the range.
*/
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return iterator{node};
}
/**
* @brief Returns an iterator to the end.
* @return An iterator to the element following the last meta object of the
* range.
*/
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return iterator{};
}
private:
node_type *node{nullptr};
};
}
#endif

61
src/entt/meta/resolve.hpp Normal file
View File

@@ -0,0 +1,61 @@
#ifndef ENTT_META_RESOLVE_HPP
#define ENTT_META_RESOLVE_HPP
#include <algorithm>
#include "../core/type_info.hpp"
#include "ctx.hpp"
#include "meta.hpp"
#include "range.hpp"
namespace entt {
/**
* @brief Returns the meta type associated with a given type.
* @tparam Type Type to use to search for a meta type.
* @return The meta type associated with the given type, if any.
*/
template<typename Type>
[[nodiscard]] meta_type resolve() ENTT_NOEXCEPT {
return internal::meta_info<Type>::resolve();
}
/**
* @brief Returns a range to use to visit all meta types.
* @return An iterable range to use to visit all meta types.
*/
[[nodiscard]] inline meta_range<meta_type> resolve() {
return *internal::meta_context::global();
}
/**
* @brief Returns the meta type associated with a given identifier, if any.
* @param id Unique identifier.
* @return The meta type associated with the given identifier, if any.
*/
[[nodiscard]] inline meta_type resolve(const id_type id) ENTT_NOEXCEPT {
internal::meta_range range{*internal::meta_context::global()};
return std::find_if(range.begin(), range.end(), [id](const auto &curr) { return curr.id == id; }).operator->();
}
/**
* @brief Returns the meta type associated with a given type info object, if
* any.
* @param info The type info object of the requested type.
* @return The meta type associated with the given type info object, if any.
*/
[[nodiscard]] inline meta_type resolve(const type_info info) ENTT_NOEXCEPT {
internal::meta_range range{*internal::meta_context::global()};
return std::find_if(range.begin(), range.end(), [info](const auto &curr) { return curr.info == info; }).operator->();
}
}
#endif

View File

@@ -0,0 +1,128 @@
#ifndef ENTT_META_TYPE_TRAITS_HPP
#define ENTT_META_TYPE_TRAITS_HPP
#include <type_traits>
namespace entt {
/**
* @brief Traits class template to be specialized to enable support for meta
* sequence containers.
*/
template<typename>
struct meta_sequence_container_traits;
/**
* @brief Traits class template to be specialized to enable support for meta
* associative containers.
*/
template<typename>
struct meta_associative_container_traits;
/**
* @brief Provides the member constant `value` to true if support for meta
* sequence containers is enabled for the given type, false otherwise.
* @tparam Type Potentially sequence container type.
*/
template<typename Type, typename = void>
struct has_meta_sequence_container_traits: std::false_type {};
/*! @copydoc has_meta_sequence_container_traits */
template<typename Type>
struct has_meta_sequence_container_traits<Type, std::void_t<typename meta_sequence_container_traits<Type>::value_type>>
: std::true_type
{};
/**
* @brief Helper variable template.
* @tparam Type Potentially sequence container type.
*/
template<typename Type>
inline constexpr auto has_meta_sequence_container_traits_v = has_meta_sequence_container_traits<Type>::value;
/**
* @brief Provides the member constant `value` to true if support for meta
* associative containers is enabled for the given type, false otherwise.
* @tparam Type Potentially associative container type.
*/
template<typename, typename = void>
struct has_meta_associative_container_traits: std::false_type {};
/*! @copydoc has_meta_associative_container_traits */
template<typename Type>
struct has_meta_associative_container_traits<Type, std::void_t<typename meta_associative_container_traits<Type>::key_type>>
: std::true_type
{};
/**
* @brief Helper variable template.
* @tparam Type Potentially associative container type.
*/
template<typename Type>
inline constexpr auto has_meta_associative_container_traits_v = has_meta_associative_container_traits<Type>::value;
/**
* @brief Provides the member constant `value` to true if a meta associative
* container claims to wrap a key-only type, false otherwise.
* @tparam Type Potentially key-only meta associative container type.
*/
template<typename, typename = void>
struct is_key_only_meta_associative_container: std::true_type {};
/*! @copydoc is_key_only_meta_associative_container */
template<typename Type>
struct is_key_only_meta_associative_container<Type, std::void_t<typename meta_associative_container_traits<Type>::mapped_type>>
: std::false_type
{};
/**
* @brief Helper variable template.
* @tparam Type Potentially key-only meta associative container type.
*/
template<typename Type>
inline constexpr auto is_key_only_meta_associative_container_v = is_key_only_meta_associative_container<Type>::value;
/**
* @brief Provides the member constant `value` to true if a given type is a
* pointer-like type from the point of view of the meta system, false otherwise.
* @tparam Type Potentially pointer-like type.
*/
template<typename>
struct is_meta_pointer_like: std::false_type {};
/**
* @brief Partial specialization to ensure that const pointer-like types are
* also accepted.
* @tparam Type Potentially pointer-like type.
*/
template<typename Type>
struct is_meta_pointer_like<const Type>: is_meta_pointer_like<Type> {};
/**
* @brief Helper variable template.
* @tparam Type Potentially pointer-like type.
*/
template<typename Type>
inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like<Type>::value;
}
#endif

View File

@@ -0,0 +1,86 @@
#ifndef ENTT_PLATFORM_ANDROID_NDK_R17_HPP
#define ENTT_PLATFORM_ANDROID_NDK_R17_HPP
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
#ifdef __ANDROID__
#include <android/ndk-version.h>
#if __NDK_MAJOR__ == 17
#include <functional>
#include <type_traits>
#include <utility>
namespace std {
namespace internal {
template<typename Func, typename... Args>
constexpr auto is_invocable(int) -> decltype(std::invoke(std::declval<Func>(), std::declval<Args>()...), std::true_type{});
template<typename, typename...>
constexpr std::false_type is_invocable(...);
template<typename Ret, typename Func, typename... Args>
constexpr auto is_invocable_r(int)
-> std::enable_if_t<decltype(std::is_convertible_v<decltype(std::invoke(std::declval<Func>(), std::declval<Args>()...)), Ret>, std::true_type>;
template<typename, typename, typename...>
constexpr std::false_type is_invocable_r(...);
}
template<typename Func, typename... Args>
struct is_invocable: decltype(internal::is_invocable<Func, Args...>(0)) {};
template<typename Func, typename... Argsv>
inline constexpr bool is_invocable_v = std::is_invocable<Func, Args...>::value;
template<typename Ret, typename Func, typename... Args>
struct is_invocable_r: decltype(internal::is_invocable_r<Ret, Func, Args...>(0)) {};
template<typename Ret, typename Func, typename... Args>
inline constexpr bool is_invocable_r_v = std::is_invocable_r<Ret, Func, Args...>::value;
template<typename Func, typename...Args>
struct invoke_result {
using type = decltype(std::invoke(std::declval<Func>(), std::declval<Args>()...));
};
template<typename Func, typename... Args>
using invoke_result_t = typename std::invoke_result<Func, Args...>::type;
}
#endif
#endif
/**
* Internal details not to be documented.
* @endcond
*/
#endif

344
src/entt/poly/poly.hpp Normal file
View File

@@ -0,0 +1,344 @@
#ifndef ENTT_POLY_POLY_HPP
#define ENTT_POLY_POLY_HPP
#include <cstddef>
#include <functional>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/any.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
namespace entt {
/*! @brief Inspector class used to infer the type of the virtual table. */
struct poly_inspector {
/**
* @brief Generic conversion operator (definition only).
* @tparam Type Type to which conversion is requested.
*/
template <class Type>
operator Type &&() const;
/**
* @brief Dummy invocation function (definition only).
* @tparam Member Index of the function to invoke.
* @tparam Args Types of arguments to pass to the function.
* @param args The arguments to pass to the function.
* @return A poly inspector convertible to any type.
*/
template<auto Member, typename... Args>
poly_inspector invoke(Args &&... args) const;
/*! @copydoc invoke */
template<auto Member, typename... Args>
poly_inspector invoke(Args &&... args);
};
/**
* @brief Static virtual table factory.
* @tparam Concept Concept descriptor.
*/
template<typename Concept>
class poly_vtable {
using inspector = typename Concept::template type<poly_inspector>;
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(*)(inspector &, Args...)) -> Ret(*)(any &, Args...);
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(*)(const inspector &, Args...)) -> Ret(*)(const any &, Args...);
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(*)(Args...)) -> Ret(*)(const any &, Args...);
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(inspector:: *)(Args...)) -> Ret(*)(any &, Args...);
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(inspector:: *)(Args...) const) -> Ret(*)(const any &, Args...);
template<auto... Candidate>
static auto make_vtable(value_list<Candidate...>)
-> std::tuple<decltype(vtable_entry(Candidate))...>;
template<typename... Func>
[[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) {
if constexpr(sizeof...(Func) == 0) {
return decltype(make_vtable(typename Concept::template impl<inspector>{})){};
} else if constexpr((std::is_function_v<Func> && ...)) {
return decltype(std::make_tuple(vtable_entry(std::declval<Func inspector:: *>())...)){};
}
}
template<typename Type, auto Candidate, typename Ret, typename Any, typename... Args>
static void fill_vtable_entry(Ret(* &entry)(Any &, Args...)) {
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
entry = +[](Any &, Args... args) -> Ret {
return std::invoke(Candidate, std::forward<Args>(args)...);
};
} else {
entry = +[](Any &any, Args... args) -> Ret {
return static_cast<Ret>(std::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(any), std::forward<Args>(args)...));
};
}
}
template<typename Type, auto... Index>
[[nodiscard]] static auto fill_vtable(std::index_sequence<Index...>) {
type impl{};
(fill_vtable_entry<Type, value_list_element_v<Index, typename Concept::template impl<Type>>>(std::get<Index>(impl)), ...);
return impl;
}
public:
/*! @brief Virtual table type. */
using type = decltype(make_vtable(Concept{}));
/**
* @brief Returns a static virtual table for a specific concept and type.
* @tparam Type The type for which to generate the virtual table.
* @return A static virtual table for the given concept and type.
*/
template<typename Type>
[[nodiscard]] static const auto * instance() {
static_assert(std::is_same_v<Type, std::decay_t<Type>>, "Type differs from its decayed form");
static const auto vtable = fill_vtable<Type>(std::make_index_sequence<Concept::template impl<Type>::size>{});
return &vtable;
}
};
/**
* @brief Poly base class used to inject functionalities into concepts.
* @tparam Poly The outermost poly class.
*/
template<typename Poly>
struct poly_base {
/**
* @brief Invokes a function from the static virtual table.
* @tparam Member Index of the function to invoke.
* @tparam Args Types of arguments to pass to the function.
* @param self A reference to the poly object that made the call.
* @param args The arguments to pass to the function.
* @return The return value of the invoked function, if any.
*/
template<auto Member, typename... Args>
[[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&... args) const {
const auto &poly = static_cast<const Poly &>(self);
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
}
/*! @copydoc invoke */
template<auto Member, typename... Args>
[[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&... args) {
auto &poly = static_cast<Poly &>(self);
return std::get<Member>(*poly.vtable)(poly.storage, std::forward<Args>(args)...);
}
};
/**
* @brief Shortcut for calling `poly_base<Type>::invoke`.
* @tparam Member Index of the function to invoke.
* @tparam Poly A fully defined poly object.
* @tparam Args Types of arguments to pass to the function.
* @param self A reference to the poly object that made the call.
* @param args The arguments to pass to the function.
* @return The return value of the invoked function, if any.
*/
template<auto Member, typename Poly, typename... Args>
decltype(auto) poly_call(Poly &&self, Args &&... args) {
return std::forward<Poly>(self).template invoke<Member>(self, std::forward<Args>(args)...);
}
/**
* @brief Static polymorphism made simple and within everyone's reach.
*
* Static polymorphism is a very powerful tool in C++, albeit sometimes
* cumbersome to obtain.<br/>
* This class aims to make it simple and easy to use.
*
* @note
* Both deduced and defined static virtual tables are supported.<br/>
* Moreover, the `poly` class template also works with unmanaged objects.
*
* @tparam Concept Concept descriptor.
*/
template<typename Concept>
class poly: private Concept::template type<poly_base<poly<Concept>>> {
/*! @brief A poly base is allowed to snoop into a poly object. */
friend struct poly_base<poly<Concept>>;
using vtable_type = typename poly_vtable<Concept>::type;
public:
/*! @brief Concept type. */
using concept_type = typename Concept::template type<poly_base<poly<Concept>>>;
/*! @brief Default constructor. */
poly() ENTT_NOEXCEPT
: storage{},
vtable{}
{}
/**
* @brief Constructs a poly by directly initializing the new object.
* @tparam Type Type of object to use to initialize the poly.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
explicit poly(std::in_place_type_t<Type>, Args &&... args)
: storage{std::in_place_type<Type>, std::forward<Args>(args)...},
vtable{poly_vtable<Concept>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>()}
{}
/**
* @brief Constructs a poly that holds an unmanaged object.
* @tparam Type Type of object to use to initialize the poly.
* @param value An instance of an object to use to initialize the poly.
*/
template<typename Type>
poly(std::reference_wrapper<Type> value)
: poly{std::in_place_type<Type &>, &value.get()}
{}
/**
* @brief Constructs a poly from a given value.
* @tparam Type Type of object to use to initialize the poly.
* @param value An instance of an object to use to initialize the poly.
*/
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, poly>>>
poly(Type &&value) ENTT_NOEXCEPT
: poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
{}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
poly(const poly &other) = default;
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
poly(poly &&other) ENTT_NOEXCEPT
: poly{}
{
swap(*this, other);
}
/**
* @brief Assignment operator.
* @param other The instance to assign from.
* @return This poly object.
*/
poly & operator=(poly other) {
swap(other, *this);
return *this;
}
/**
* @brief Returns the type of the contained object.
* @return The type of the contained object, if any.
*/
[[nodiscard]] type_info type() const ENTT_NOEXCEPT {
return storage.type();
}
/**
* @brief Returns an opaque pointer to the contained instance.
* @return An opaque pointer the contained instance, if any.
*/
[[nodiscard]] const void * data() const ENTT_NOEXCEPT {
return storage.data();
}
/*! @copydoc data */
[[nodiscard]] void * data() ENTT_NOEXCEPT {
return storage.data();
}
/**
* @brief Replaces the contained object by creating a new instance directly.
* @tparam Type Type of object to use to initialize the poly.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
void emplace(Args &&... args) {
storage.emplace<Type>(std::forward<Args>(args)...);
vtable = poly_vtable<Concept>::template instance<Type>();
}
/**
* @brief Returns false if a poly is empty, true otherwise.
* @return False if the poly is empty, true otherwise.
*/
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return !(vtable == nullptr);
}
/**
* @brief Returns a pointer to the underlying concept.
* @return A pointer to the underlying concept.
*/
[[nodiscard]] concept_type * operator->() ENTT_NOEXCEPT {
return this;
}
/*! @copydoc operator-> */
[[nodiscard]] const concept_type * operator->() const ENTT_NOEXCEPT {
return this;
}
/**
* @brief Swaps two poly objects.
* @param lhs A valid poly object.
* @param rhs A valid poly object.
*/
friend void swap(poly &lhs, poly &rhs) {
using std::swap;
swap(lhs.storage, rhs.storage);
swap(lhs.vtable, rhs.vtable);
}
/**
* @brief Aliasing constructor.
* @param other A reference to an object that isn't necessarily initialized.
* @return A poly that shares a reference to an unmanaged object.
*/
[[nodiscard]] friend poly as_ref(poly &other) ENTT_NOEXCEPT {
poly ref;
ref.storage = as_ref(other.storage);
ref.vtable = other.vtable;
return ref;
}
/*! @copydoc as_ref */
[[nodiscard]] friend poly as_ref(const poly &other) ENTT_NOEXCEPT {
poly ref;
ref.storage = as_ref(other.storage);
ref.vtable = other.vtable;
return ref;
}
private:
any storage;
const vtable_type *vtable;
};
}
#endif

View File

@@ -81,41 +81,37 @@ class process {
FINISHED
};
template<state value>
using state_value_t = std::integral_constant<state, value>;
template<typename Target = Derived>
auto tick(int, state_value_t<state::UNINITIALIZED>)
-> decltype(std::declval<Target>().init()) {
auto next(std::integral_constant<state, state::UNINITIALIZED>)
-> decltype(std::declval<Target>().init(), void()) {
static_cast<Target *>(this)->init();
}
template<typename Target = Derived>
auto tick(int, state_value_t<state::RUNNING>, Delta delta, void *data)
-> decltype(std::declval<Target>().update(delta, data)) {
auto next(std::integral_constant<state, state::RUNNING>, Delta delta, void *data)
-> decltype(std::declval<Target>().update(delta, data), void()) {
static_cast<Target *>(this)->update(delta, data);
}
template<typename Target = Derived>
auto tick(int, state_value_t<state::SUCCEEDED>)
-> decltype(std::declval<Target>().succeeded()) {
auto next(std::integral_constant<state, state::SUCCEEDED>)
-> decltype(std::declval<Target>().succeeded(), void()) {
static_cast<Target *>(this)->succeeded();
}
template<typename Target = Derived>
auto tick(int, state_value_t<state::FAILED>)
-> decltype(std::declval<Target>().failed()) {
auto next(std::integral_constant<state, state::FAILED>)
-> decltype(std::declval<Target>().failed(), void()) {
static_cast<Target *>(this)->failed();
}
template<typename Target = Derived>
auto tick(int, state_value_t<state::ABORTED>)
-> decltype(std::declval<Target>().aborted()) {
auto next(std::integral_constant<state, state::ABORTED>)
-> decltype(std::declval<Target>().aborted(), void()) {
static_cast<Target *>(this)->aborted();
}
template<state value, typename... Args>
void tick(char, state_value_t<value>, Args &&...) const ENTT_NOEXCEPT {}
void next(...) const ENTT_NOEXCEPT {}
protected:
/**
@@ -171,8 +167,8 @@ public:
using delta_type = Delta;
/*! @brief Default destructor. */
virtual ~process() ENTT_NOEXCEPT {
static_assert(std::is_base_of_v<process, Derived>);
virtual ~process() {
static_assert(std::is_base_of_v<process, Derived>, "Incorrect use of the class template");
}
/**
@@ -183,12 +179,12 @@ public:
*
* @param immediately Requests an immediate operation.
*/
void abort(const bool immediately = false) ENTT_NOEXCEPT {
void abort(const bool immediately = false) {
if(alive()) {
current = state::ABORTED;
if(immediately) {
tick(0);
tick({});
}
}
}
@@ -197,7 +193,7 @@ public:
* @brief Returns true if a process is either running or paused.
* @return True if the process is still alive, false otherwise.
*/
bool alive() const ENTT_NOEXCEPT {
[[nodiscard]] bool alive() const ENTT_NOEXCEPT {
return current == state::RUNNING || current == state::PAUSED;
}
@@ -205,7 +201,7 @@ public:
* @brief Returns true if a process is already terminated.
* @return True if the process is terminated, false otherwise.
*/
bool dead() const ENTT_NOEXCEPT {
[[nodiscard]] bool dead() const ENTT_NOEXCEPT {
return current == state::FINISHED;
}
@@ -213,7 +209,7 @@ public:
* @brief Returns true if a process is currently paused.
* @return True if the process is paused, false otherwise.
*/
bool paused() const ENTT_NOEXCEPT {
[[nodiscard]] bool paused() const ENTT_NOEXCEPT {
return current == state::PAUSED;
}
@@ -221,7 +217,7 @@ public:
* @brief Returns true if a process terminated with errors.
* @return True if the process terminated with errors, false otherwise.
*/
bool rejected() const ENTT_NOEXCEPT {
[[nodiscard]] bool rejected() const ENTT_NOEXCEPT {
return stopped;
}
@@ -233,11 +229,11 @@ public:
void tick(const Delta delta, void *data = nullptr) {
switch (current) {
case state::UNINITIALIZED:
tick(0, state_value_t<state::UNINITIALIZED>{});
next(std::integral_constant<state, state::UNINITIALIZED>{});
current = state::RUNNING;
break;
case state::RUNNING:
tick(0, state_value_t<state::RUNNING>{}, delta, data);
next(std::integral_constant<state, state::RUNNING>{}, delta, data);
break;
default:
// suppress warnings
@@ -247,16 +243,16 @@ public:
// if it's dead, it must be notified and removed immediately
switch(current) {
case state::SUCCEEDED:
tick(0, state_value_t<state::SUCCEEDED>{});
next(std::integral_constant<state, state::SUCCEEDED>{});
current = state::FINISHED;
break;
case state::FAILED:
tick(0, state_value_t<state::FAILED>{});
next(std::integral_constant<state, state::FAILED>{});
current = state::FINISHED;
stopped = true;
break;
case state::ABORTED:
tick(0, state_value_t<state::ABORTED>{});
next(std::integral_constant<state, state::ABORTED>{});
current = state::FINISHED;
stopped = true;
break;
@@ -337,4 +333,4 @@ struct process_adaptor: process<process_adaptor<Func, Delta>, Delta>, private Fu
}
#endif // ENTT_PROCESS_PROCESS_HPP
#endif

View File

@@ -63,7 +63,7 @@ class scheduler {
template<typename Proc, typename... Args>
continuation then(Args &&... args) {
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>);
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
auto proc = typename process_handler::instance_type{new Proc{std::forward<Args>(args)...}, &scheduler::deleter<Proc>};
handler->next.reset(new process_handler{std::move(proc), &scheduler::update<Proc>, &scheduler::abort<Proc>, nullptr});
handler = handler->next.get();
@@ -80,7 +80,7 @@ class scheduler {
};
template<typename Proc>
static bool update(process_handler &handler, const Delta delta, void *data) {
[[nodiscard]] static bool update(process_handler &handler, const Delta delta, void *data) {
auto *process = static_cast<Proc *>(handler.instance.get());
process->tick(delta, data);
@@ -111,10 +111,10 @@ class scheduler {
public:
/*! @brief Unsigned integer type. */
using size_type = typename std::vector<process_handler>::size_type;
using size_type = std::size_t;
/*! @brief Default constructor. */
scheduler() ENTT_NOEXCEPT = default;
scheduler() = default;
/*! @brief Default move constructor. */
scheduler(scheduler &&) = default;
@@ -126,7 +126,7 @@ public:
* @brief Number of processes currently scheduled.
* @return Number of processes currently scheduled.
*/
size_type size() const ENTT_NOEXCEPT {
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return handlers.size();
}
@@ -134,7 +134,7 @@ public:
* @brief Returns true if at least a process is currently scheduled.
* @return True if there are scheduled processes, false otherwise.
*/
bool empty() const ENTT_NOEXCEPT {
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return handlers.empty();
}
@@ -175,7 +175,7 @@ public:
*/
template<typename Proc, typename... Args>
auto attach(Args &&... args) {
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>);
static_assert(std::is_base_of_v<process<Proc, Delta>, Proc>, "Invalid process type");
auto proc = typename process_handler::instance_type{new Proc{std::forward<Args>(args)...}, &scheduler::deleter<Proc>};
process_handler handler{std::move(proc), &scheduler::update<Proc>, &scheduler::abort<Proc>, nullptr};
// forces the process to exit the uninitialized state
@@ -281,9 +281,9 @@ public:
decltype(handlers) exec;
exec.swap(handlers);
std::for_each(exec.begin(), exec.end(), [immediately](auto &handler) {
for(auto &&handler: exec) {
handler.abort(handler, immediately);
});
}
std::move(handlers.begin(), handlers.end(), std::back_inserter(exec));
handlers.swap(exec);
@@ -297,4 +297,4 @@ private:
}
#endif // ENTT_PROCESS_SCHEDULER_HPP
#endif

View File

@@ -3,11 +3,11 @@
#include <memory>
#include <utility>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include "../config/config.h"
#include "../core/hashed_string.hpp"
#include "../core/fwd.hpp"
#include "handle.hpp"
#include "loader.hpp"
#include "fwd.hpp"
@@ -27,14 +27,11 @@ namespace entt {
* @tparam Resource Type of resources managed by a cache.
*/
template<typename Resource>
class resource_cache {
using container_type = std::unordered_map<hashed_string::hash_type, std::shared_ptr<Resource>>;
public:
struct resource_cache {
/*! @brief Unsigned integer type. */
using size_type = typename container_type::size_type;
using size_type = std::size_t;
/*! @brief Type of resources managed by a cache. */
using resource_type = typename hashed_string::hash_type;
using resource_type = Resource;
/*! @brief Default constructor. */
resource_cache() = default;
@@ -49,7 +46,7 @@ public:
* @brief Number of resources managed by a cache.
* @return Number of resources currently stored.
*/
size_type size() const ENTT_NOEXCEPT {
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return resources.size();
}
@@ -57,7 +54,7 @@ public:
* @brief Returns true if a cache contains no resources, false otherwise.
* @return True if the cache contains no resources, false otherwise.
*/
bool empty() const ENTT_NOEXCEPT {
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return resources.empty();
}
@@ -94,20 +91,20 @@ public:
* @return A handle for the given resource.
*/
template<typename Loader, typename... Args>
resource_handle<Resource> load(const resource_type id, Args &&... args) {
static_assert(std::is_base_of_v<resource_loader<Loader, Resource>, Loader>);
resource_handle<Resource> handle{};
resource_handle<Resource> load(const id_type id, Args &&... args) {
static_assert(std::is_base_of_v<resource_loader<Loader, Resource>, Loader>, "Invalid loader type");
resource_handle<Resource> resource{};
if(auto it = resources.find(id); it == resources.cend()) {
if(auto resource = Loader{}.get(std::forward<Args>(args)...); resource) {
resources[id] = resource;
handle = std::move(resource);
if(auto instance = Loader{}.get(std::forward<Args>(args)...); instance) {
resources[id] = instance;
resource = std::move(instance);
}
} else {
handle = it->second;
resource = it->second;
}
return handle;
return resource;
}
/**
@@ -134,7 +131,7 @@ public:
* @return A handle for the given resource.
*/
template<typename Loader, typename... Args>
resource_handle<Resource> reload(const resource_type id, Args &&... args) {
resource_handle<Resource> reload(const id_type id, Args &&... args) {
return (discard(id), load<Loader>(id, std::forward<Args>(args)...));
}
@@ -151,7 +148,7 @@ public:
* @return A handle for the given resource.
*/
template<typename Loader, typename... Args>
resource_handle<Resource> temp(Args &&... args) const {
[[nodiscard]] resource_handle<Resource> temp(Args &&... args) const {
return { Loader{}.get(std::forward<Args>(args)...) };
}
@@ -168,7 +165,7 @@ public:
* @param id Unique resource identifier.
* @return A handle for the given resource.
*/
resource_handle<Resource> handle(const resource_type id) const {
[[nodiscard]] resource_handle<Resource> handle(const id_type id) const {
auto it = resources.find(id);
return { it == resources.end() ? nullptr : it->second };
}
@@ -178,7 +175,7 @@ public:
* @param id Unique resource identifier.
* @return True if the cache contains the resource, false otherwise.
*/
bool contains(const resource_type id) const ENTT_NOEXCEPT {
[[nodiscard]] bool contains(const id_type id) const {
return (resources.find(id) != resources.cend());
}
@@ -190,18 +187,53 @@ public:
*
* @param id Unique resource identifier.
*/
void discard(const resource_type id) ENTT_NOEXCEPT {
void discard(const id_type id) {
if(auto it = resources.find(id); it != resources.end()) {
resources.erase(it);
}
}
/**
* @brief Iterates all resources.
*
* The function object is invoked for each element. It is provided with
* either the resource identifier, the resource handle or both of them.<br/>
* The signature of the function must be equivalent to one of the following
* forms:
*
* @code{.cpp}
* void(const entt::id_type);
* void(entt::resource_handle<Resource>);
* void(const entt::id_type, entt::resource_handle<Resource>);
* @endcode
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template <typename Func>
void each(Func func) const {
auto begin = resources.begin();
auto end = resources.end();
while(begin != end) {
auto curr = begin++;
if constexpr(std::is_invocable_v<Func, id_type>) {
func(curr->first);
} else if constexpr(std::is_invocable_v<Func, resource_handle<Resource>>) {
func(resource_handle{ curr->second });
} else {
func(curr->first, resource_handle{ curr->second });
}
}
}
private:
container_type resources;
std::unordered_map<id_type, std::shared_ptr<Resource>> resources;
};
}
#endif // ENTT_RESOURCE_CACHE_HPP
#endif

View File

@@ -2,21 +2,17 @@
#define ENTT_RESOURCE_FWD_HPP
#include "../config/config.h"
namespace entt {
/*! @class resource_cache */
template<typename>
class resource_cache;
struct resource_cache;
/*! @class resource_handle */
template<typename>
class resource_handle;
/*! @class resource_loader */
template<typename, typename>
class resource_loader;
@@ -24,4 +20,4 @@ class resource_loader;
}
#endif // ENTT_RESOURCE_FWD_HPP
#endif

View File

@@ -26,7 +26,7 @@ namespace entt {
template<typename Resource>
class resource_handle {
/*! @brief Resource handles are friends of their caches. */
friend class resource_cache<Resource>;
friend struct resource_cache<Resource>;
resource_handle(std::shared_ptr<Resource> res) ENTT_NOEXCEPT
: resource{std::move(res)}
@@ -40,60 +40,66 @@ public:
* @brief Gets a reference to the managed resource.
*
* @warning
* The behavior is undefined if the handle doesn't contain a resource.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* handle is empty.
* The behavior is undefined if the handle doesn't contain a resource.
*
* @return A reference to the managed resource.
*/
const Resource & get() const ENTT_NOEXCEPT {
[[nodiscard]] const Resource & get() const ENTT_NOEXCEPT {
ENTT_ASSERT(static_cast<bool>(resource));
return *resource;
}
/**
* @brief Casts a handle and gets a reference to the managed resource.
*
* @warning
* The behavior is undefined if the handle doesn't contain a resource.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* handle is empty.
*/
inline operator const Resource &() const ENTT_NOEXCEPT { return get(); }
/*! @copydoc get */
[[nodiscard]] Resource & get() ENTT_NOEXCEPT {
return const_cast<Resource &>(std::as_const(*this).get());
}
/*! @copydoc get */
[[nodiscard]] operator const Resource & () const ENTT_NOEXCEPT {
return get();
}
/*! @copydoc get */
[[nodiscard]] operator Resource & () ENTT_NOEXCEPT {
return get();
}
/*! @copydoc get */
[[nodiscard]] const Resource & operator *() const ENTT_NOEXCEPT {
return get();
}
/*! @copydoc get */
[[nodiscard]] Resource & operator *() ENTT_NOEXCEPT {
return get();
}
/**
* @brief Dereferences a handle to obtain the managed resource.
* @brief Gets a pointer to the managed resource.
*
* @warning
* The behavior is undefined if the handle doesn't contain a resource.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* handle is empty.
*
* @return A reference to the managed resource.
*/
inline const Resource & operator *() const ENTT_NOEXCEPT { return get(); }
/**
* @brief Gets a pointer to the managed resource from a handle.
*
* @warning
* The behavior is undefined if the handle doesn't contain a resource.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* handle is empty.
* The behavior is undefined if the handle doesn't contain a resource.
*
* @return A pointer to the managed resource or `nullptr` if the handle
* contains no resource at all.
*/
inline const Resource * operator->() const ENTT_NOEXCEPT {
[[nodiscard]] const Resource * operator->() const ENTT_NOEXCEPT {
ENTT_ASSERT(static_cast<bool>(resource));
return resource.get();
}
/*! @copydoc operator-> */
[[nodiscard]] Resource * operator->() ENTT_NOEXCEPT {
return const_cast<Resource *>(std::as_const(*this).operator->());
}
/**
* @brief Returns true if a handle contains a resource, false otherwise.
* @return True if the handle contains a resource, false otherwise.
*/
explicit operator bool() const { return static_cast<bool>(resource); }
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return static_cast<bool>(resource);
}
private:
std::shared_ptr<Resource> resource;
@@ -103,4 +109,4 @@ private:
}
#endif // ENTT_RESOURCE_HANDLE_HPP
#endif

View File

@@ -44,7 +44,7 @@ namespace entt {
template<typename Loader, typename Resource>
class resource_loader {
/*! @brief Resource loaders are friends of their caches. */
friend class resource_cache<Resource>;
friend struct resource_cache<Resource>;
/**
* @brief Loads the resource and returns it.
@@ -53,7 +53,7 @@ class resource_loader {
* @return The resource just loaded or an empty pointer in case of errors.
*/
template<typename... Args>
std::shared_ptr<Resource> get(Args &&... args) const {
[[nodiscard]] std::shared_ptr<Resource> get(Args &&... args) const {
return static_cast<const Loader *>(this)->load(std::forward<Args>(args)...);
}
};
@@ -62,4 +62,4 @@ class resource_loader {
}
#endif // ENTT_RESOURCE_LOADER_HPP
#endif

View File

@@ -2,10 +2,12 @@
#define ENTT_SIGNAL_DELEGATE_HPP
#include <cstring>
#include <algorithm>
#include <tuple>
#include <cstddef>
#include <utility>
#include <functional>
#include <type_traits>
#include "../core/type_traits.hpp"
#include "../config/config.h"
@@ -22,19 +24,33 @@ namespace internal {
template<typename Ret, typename... Args>
auto to_function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
auto function_pointer(Ret(*)(Args...)) -> Ret(*)(Args...);
template<typename Ret, typename... Args, typename Type>
auto to_function_pointer(Ret(*)(Type *, Args...), Type *) -> Ret(*)(Args...);
template<typename Ret, typename Type, typename... Args, typename Other>
auto function_pointer(Ret(*)(Type, Args...), Other &&) -> Ret(*)(Args...);
template<typename Class, typename Ret, typename... Args>
auto to_function_pointer(Ret(Class:: *)(Args...), Class *) -> Ret(*)(Args...);
template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...), Other &&...) -> Ret(*)(Args...);
template<typename Class, typename Ret, typename... Args>
auto to_function_pointer(Ret(Class:: *)(Args...) const, Class *) -> Ret(*)(Args...);
template<typename Class, typename Ret, typename... Args, typename... Other>
auto function_pointer(Ret(Class:: *)(Args...) const, Other &&...) -> Ret(*)(Args...);
template<typename Class, typename Type, typename... Other>
auto function_pointer(Type Class:: *, Other &&...) -> Type(*)();
template<typename... Type>
using function_pointer_t = decltype(internal::function_pointer(std::declval<Type>()...));
template<typename... Class, typename Ret, typename... Args>
[[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) {
return std::index_sequence_for<Class..., Args...>{};
}
}
@@ -42,7 +58,7 @@ auto to_function_pointer(Ret(Class:: *)(Args...) const, Class *) -> Ret(*)(Args.
/**
* Internal details not to be documented.
* @endcond TURN_OFF_DOXYGEN
* @endcond
*/
@@ -53,7 +69,7 @@ struct connect_arg_t {};
/*! @brief Constant of type connect_arg_t used to disambiguate calls. */
template<auto Func>
constexpr connect_arg_t<Func> connect_arg{};
inline constexpr connect_arg_t<Func> connect_arg{};
/**
@@ -72,20 +88,47 @@ class delegate;
* Unmanaged delegate for function pointers and members. Users of this class are
* in charge of disconnecting instances before deleting them.
*
* A delegate can be used as general purpose invoker with no memory overhead for
* free functions (with or without payload) and members provided along with an
* instance on which to invoke them.
* A delegate can be used as a general purpose invoker without memory overhead
* for free functions possibly with payloads and bound or unbound members.
*
* @tparam Ret Return type of a function type.
* @tparam Args Types of arguments of a function type.
*/
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
using proto_fn_type = Ret(const void *, Args...);
template<auto Candidate, std::size_t... Index>
[[nodiscard]] auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
return [](const void *, Args... args) -> Ret {
[[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
return static_cast<Ret>(std::invoke(Candidate, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
};
}
template<auto Candidate, typename Type, std::size_t... Index>
[[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
return [](const void *payload, Args... args) -> Ret {
[[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
return static_cast<Ret>(std::invoke(Candidate, *curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
};
}
template<auto Candidate, typename Type, std::size_t... Index>
[[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
return [](const void *payload, Args... args) -> Ret {
[[maybe_unused]] const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
return static_cast<Ret>(std::invoke(Candidate, curr, std::forward<type_list_element_t<Index, type_list<Args...>>>(std::get<Index>(arguments))...));
};
}
public:
/*! @brief Function type of the contained target. */
using function_type = Ret(const void *, Args...);
/*! @brief Function type of the delegate. */
using function_type = Ret(Args...);
using type = Ret(Args...);
/*! @brief Return type of the delegate. */
using result_type = Ret;
/*! @brief Default constructor. */
delegate() ENTT_NOEXCEPT
@@ -93,77 +136,125 @@ public:
{}
/**
* @brief Constructs a delegate and connects a free function to it.
* @tparam Function A valid free function pointer.
* @brief Constructs a delegate and connects a free function or an unbound
* member.
* @tparam Candidate Function or member to connect to the delegate.
*/
template<auto Function>
delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
: delegate{}
{
connect<Function>();
template<auto Candidate>
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT {
connect<Candidate>();
}
/**
* @brief Constructs a delegate and connects a member for a given instance
* or a free function with payload.
* @tparam Candidate Member or free function to connect to the delegate.
* @brief Constructs a delegate and connects a free function with payload or
* a bound member.
* @tparam Candidate Function or member to connect to the delegate.
* @tparam Type Type of class or type of payload.
* @param value_or_instance A valid pointer that fits the purpose.
* @param value_or_instance A valid object that fits the purpose.
*/
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type *value_or_instance) ENTT_NOEXCEPT
: delegate{}
{
connect<Candidate>(value_or_instance);
delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT {
connect<Candidate>(std::forward<Type>(value_or_instance));
}
/**
* @brief Connects a free function to a delegate.
* @tparam Function A valid free function pointer.
* @brief Constructs a delegate and connects an user defined function with
* optional payload.
* @param function Function to connect to the delegate.
* @param payload User defined arbitrary data.
*/
template<auto Function>
delegate(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
connect(function, payload);
}
/**
* @brief Connects a free function or an unbound member to a delegate.
* @tparam Candidate Function or member to connect to the delegate.
*/
template<auto Candidate>
void connect() ENTT_NOEXCEPT {
static_assert(std::is_invocable_r_v<Ret, decltype(Function), Args...>);
data = nullptr;
fn = [](const void *, Args... args) -> Ret {
// this allows void(...) to eat return values and avoid errors
return Ret(std::invoke(Function, args...));
};
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Args...>) {
fn = [](const void *, Args... args) -> Ret {
return Ret(std::invoke(Candidate, std::forward<Args>(args)...));
};
} else if constexpr(std::is_member_pointer_v<decltype(Candidate)>) {
fn = wrap<Candidate>(internal::index_sequence_for<type_list_element_t<0, type_list<Args...>>>(internal::function_pointer_t<decltype(Candidate)>{}));
} else {
fn = wrap<Candidate>(internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate)>{}));
}
}
/**
* @brief Connects a member function for a given instance or a free function
* with payload to a delegate.
* @brief Connects a free function with payload or a bound member to a
* delegate.
*
* The delegate isn't responsible for the connected object or the payload.
* Users must always guarantee that the lifetime of the instance overcomes
* the one of the delegate.<br/>
* the one of the delegate.<br/>
* When used to connect a free function with payload, its signature must be
* such that the instance is the first argument before the ones used to
* define the delegate itself.
*
* @tparam Candidate Member or free function to connect to the delegate.
* @tparam Candidate Function or member to connect to the delegate.
* @tparam Type Type of class or type of payload.
* @param value_or_instance A valid reference that fits the purpose.
*/
template<auto Candidate, typename Type>
void connect(Type &value_or_instance) ENTT_NOEXCEPT {
data = &value_or_instance;
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type &, Args...>) {
fn = [](const void *payload, Args... args) -> Ret {
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
};
} else {
fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
}
}
/**
* @brief Connects a free function with payload or a bound member to a
* delegate.
*
* @sa connect(Type &)
*
* @tparam Candidate Function or member to connect to the delegate.
* @tparam Type Type of class or type of payload.
* @param value_or_instance A valid pointer that fits the purpose.
*/
template<auto Candidate, typename Type>
void connect(Type *value_or_instance) ENTT_NOEXCEPT {
static_assert(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>);
data = value_or_instance;
fn = [](const void *payload, Args... args) -> Ret {
Type *curr = nullptr;
if constexpr(std::is_invocable_r_v<Ret, decltype(Candidate), Type *, Args...>) {
fn = [](const void *payload, Args... args) -> Ret {
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
};
} else {
fn = wrap<Candidate>(value_or_instance, internal::index_sequence_for(internal::function_pointer_t<decltype(Candidate), Type>{}));
}
}
if constexpr(std::is_const_v<Type>) {
curr = static_cast<Type *>(payload);
} else {
curr = static_cast<Type *>(const_cast<void *>(payload));
}
// this allows void(...) to eat return values and avoid errors
return Ret(std::invoke(Candidate, curr, args...));
};
/**
* @brief Connects an user defined function with optional payload to a
* delegate.
*
* The delegate isn't responsible for the connected object or the payload.
* Users must always guarantee that the lifetime of an instance overcomes
* the one of the delegate.<br/>
* The payload is returned as the first argument to the target function in
* all cases.
*
* @param function Function to connect to the delegate.
* @param payload User defined arbitrary data.
*/
void connect(function_type *function, const void *payload = nullptr) ENTT_NOEXCEPT {
fn = function;
data = payload;
}
/**
@@ -177,10 +268,10 @@ public:
}
/**
* @brief Returns the instance linked to a delegate, if any.
* @return An opaque pointer to the instance linked to the delegate, if any.
* @brief Returns the instance or the payload linked to a delegate, if any.
* @return An opaque pointer to the underlying data.
*/
const void * instance() const ENTT_NOEXCEPT {
[[nodiscard]] const void * instance() const ENTT_NOEXCEPT {
return data;
}
@@ -191,92 +282,84 @@ public:
*
* @warning
* Attempting to trigger an invalid delegate results in undefined
* behavior.<br/>
* An assertion will abort the execution at runtime in debug mode if the
* delegate has not yet been set.
* behavior.
*
* @param args Arguments to use to invoke the underlying function.
* @return The value returned by the underlying function.
*/
Ret operator()(Args... args) const {
ENTT_ASSERT(fn);
return fn(data, args...);
return fn(data, std::forward<Args>(args)...);
}
/**
* @brief Checks whether a delegate actually stores a listener.
* @return False if the delegate is empty, true otherwise.
*/
explicit operator bool() const ENTT_NOEXCEPT {
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
// no need to test also data
return fn;
return !(fn == nullptr);
}
/**
* @brief Checks if the connected functions differ.
*
* Instances connected to delegates are ignored by this operator. Use the
* `instance` member function instead.
*
* @brief Compares the contents of two delegates.
* @param other Delegate with which to compare.
* @return False if the connected functions differ, true otherwise.
* @return False if the two contents differ, true otherwise.
*/
bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
return fn == other.fn;
[[nodiscard]] bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
return fn == other.fn && data == other.data;
}
private:
proto_fn_type *fn;
function_type *fn;
const void *data;
};
/**
* @brief Checks if the connected functions differ.
*
* Instances connected to delegates are ignored by this operator. Use the
* `instance` member function instead.
*
* @brief Compares the contents of two delegates.
* @tparam Ret Return type of a function type.
* @tparam Args Types of arguments of a function type.
* @param lhs A valid delegate object.
* @param rhs A valid delegate object.
* @return True if the connected functions differ, false otherwise.
* @return True if the two contents differ, false otherwise.
*/
template<typename Ret, typename... Args>
bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)> &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/**
* @brief Deduction guide.
*
* It allows to deduce the function type of the delegate directly from a
* function provided to the constructor.
*
* @tparam Function A valid free function pointer.
* @tparam Candidate Function or member to connect to the delegate.
*/
template<auto Function>
delegate(connect_arg_t<Function>) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<decltype(internal::to_function_pointer(Function))>>;
template<auto Candidate>
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
/**
* @brief Deduction guide.
*
* It allows to deduce the function type of the delegate directly from a member
* or a free function with payload provided to the constructor.
*
* @tparam Candidate Member or free function to connect to the delegate.
* @tparam Candidate Function or member to connect to the delegate.
* @tparam Type Type of class or type of payload.
*/
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type *) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<decltype(internal::to_function_pointer(Candidate, std::declval<Type *>()))>>;
delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate), Type>>>;
/**
* @brief Deduction guide.
* @tparam Ret Return type of a function type.
* @tparam Args Types of arguments of a function type.
*/
template<typename Ret, typename... Args>
delegate(Ret(*)(const void *, Args...), const void * = nullptr) ENTT_NOEXCEPT
-> delegate<Ret(Args...)>;
}
#endif // ENTT_SIGNAL_DELEGATE_HPP
#endif

View File

@@ -2,13 +2,14 @@
#define ENTT_SIGNAL_DISPATCHER_HPP
#include <vector>
#include <cstddef>
#include <memory>
#include <utility>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/family.hpp"
#include "../core/type_traits.hpp"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "sigh.hpp"
@@ -22,117 +23,92 @@ namespace entt {
* events to be published all together once per tick.<br/>
* Listeners are provided in the form of member functions. For each event of
* type `Event`, listeners are such that they can be invoked with an argument of
* type `const Event &`, no matter what the return type is.
* type `Event &`, no matter what the return type is.
*
* The type of the instances is `Class *` (a naked pointer). It means that users
* must guarantee that the lifetimes of the instances overcome the one of the
* dispatcher itself to avoid crashes.
* The dispatcher creates instances of the `sigh` class internally. Refer to the
* documentation of the latter for more details.
*/
class dispatcher {
using event_family = family<struct internal_dispatcher_event_family>;
template<typename Class, typename Event>
using instance_type = typename sigh<void(const Event &)>::template instance_type<Class>;
struct base_wrapper {
virtual ~base_wrapper() = default;
struct basic_pool {
virtual ~basic_pool() = default;
virtual void publish() = 0;
virtual void disconnect(void *) = 0;
virtual void clear() ENTT_NOEXCEPT = 0;
};
template<typename Event>
struct signal_wrapper: base_wrapper {
using signal_type = sigh<void(const Event &)>;
struct pool_handler final: basic_pool {
static_assert(std::is_same_v<Event, std::decay_t<Event>>, "Invalid event type");
using signal_type = sigh<void(Event &)>;
using sink_type = typename signal_type::sink_type;
void publish() override {
for(const auto &event: events[current]) {
signal.publish(event);
const auto length = events.size();
for(std::size_t pos{}; pos < length; ++pos) {
signal.publish(events[pos]);
}
events[current++].clear();
current %= std::extent<decltype(events)>::value;
events.erase(events.cbegin(), events.cbegin()+length);
}
inline sink_type sink() ENTT_NOEXCEPT {
return signal.sink();
void disconnect(void *instance) override {
sink().disconnect(instance);
}
void clear() ENTT_NOEXCEPT override {
events.clear();
}
[[nodiscard]] sink_type sink() ENTT_NOEXCEPT {
return entt::sink{signal};
}
template<typename... Args>
inline void trigger(Args &&... args) {
signal.publish({ std::forward<Args>(args)... });
void trigger(Args &&... args) {
Event instance{std::forward<Args>(args)...};
signal.publish(instance);
}
template<typename... Args>
inline void enqueue(Args &&... args) {
events[current].emplace_back(std::forward<Args>(args)...);
void enqueue(Args &&... args) {
if constexpr(std::is_aggregate_v<Event>) {
events.push_back(Event{std::forward<Args>(args)...});
} else {
events.emplace_back(std::forward<Args>(args)...);
}
}
private:
signal_type signal{};
std::vector<Event> events[2];
int current{};
};
struct wrapper_data {
std::unique_ptr<base_wrapper> wrapper;
ENTT_ID_TYPE runtime_type;
std::vector<Event> events;
};
template<typename Event>
static auto type() ENTT_NOEXCEPT {
if constexpr(is_named_type_v<Event>) {
return named_type_traits<Event>::value;
} else {
return event_family::type<Event>;
}
}
[[nodiscard]] pool_handler<Event> & assure() {
const auto index = type_seq<Event>::value();
template<typename Event>
signal_wrapper<Event> & assure() {
const auto wtype = type<Event>();
wrapper_data *wdata = nullptr;
if constexpr(is_named_type_v<Event>) {
const auto it = std::find_if(wrappers.begin(), wrappers.end(), [wtype](const auto &candidate) {
return candidate.wrapper && candidate.runtime_type == wtype;
});
wdata = (it == wrappers.cend() ? &wrappers.emplace_back() : &(*it));
} else {
if(!(wtype < wrappers.size())) {
wrappers.resize(wtype+1);
}
wdata = &wrappers[wtype];
if(wdata->wrapper && wdata->runtime_type != wtype) {
wrappers.emplace_back();
std::swap(wrappers[wtype], wrappers.back());
wdata = &wrappers[wtype];
}
if(!(index < pools.size())) {
pools.resize(std::size_t(index)+1u);
}
if(!wdata->wrapper) {
wdata->wrapper = std::make_unique<signal_wrapper<Event>>();
wdata->runtime_type = wtype;
if(!pools[index]) {
pools[index].reset(new pool_handler<Event>{});
}
return static_cast<signal_wrapper<Event> &>(*wdata->wrapper);
return static_cast<pool_handler<Event> &>(*pools[index]);
}
public:
/*! @brief Type of sink for the given event. */
template<typename Event>
using sink_type = typename signal_wrapper<Event>::sink_type;
/**
* @brief Returns a sink object for the given event.
*
* A sink is an opaque object used to connect listeners to events.
*
* The function type for a listener is:
* The function type for a listener is _compatible_ with:
* @code{.cpp}
* void(const Event &);
* void(Event &);
* @endcode
*
* The order of invocation of the listeners isn't guaranteed.
@@ -143,7 +119,7 @@ public:
* @return A temporary sink object.
*/
template<typename Event>
inline sink_type<Event> sink() ENTT_NOEXCEPT {
[[nodiscard]] auto sink() {
return assure<Event>().sink();
}
@@ -158,7 +134,7 @@ public:
* @param args Arguments to use to construct the event.
*/
template<typename Event, typename... Args>
inline void trigger(Args &&... args) {
void trigger(Args &&... args) {
assure<Event>().trigger(std::forward<Args>(args)...);
}
@@ -172,7 +148,7 @@ public:
* @param event An instance of the given type of event.
*/
template<typename Event>
inline void trigger(Event &&event) {
void trigger(Event &&event) {
assure<std::decay_t<Event>>().trigger(std::forward<Event>(event));
}
@@ -187,7 +163,7 @@ public:
* @param args Arguments to use to construct the event.
*/
template<typename Event, typename... Args>
inline void enqueue(Args &&... args) {
void enqueue(Args &&... args) {
assure<Event>().enqueue(std::forward<Args>(args)...);
}
@@ -201,10 +177,57 @@ public:
* @param event An instance of the given type of event.
*/
template<typename Event>
inline void enqueue(Event &&event) {
void enqueue(Event &&event) {
assure<std::decay_t<Event>>().enqueue(std::forward<Event>(event));
}
/**
* @brief Utility function to disconnect everything related to a given value
* or instance from a dispatcher.
* @tparam Type Type of class or type of payload.
* @param value_or_instance A valid object that fits the purpose.
*/
template<typename Type>
void disconnect(Type &value_or_instance) {
disconnect(&value_or_instance);
}
/**
* @brief Utility function to disconnect everything related to a given value
* or instance from a dispatcher.
* @tparam Type Type of class or type of payload.
* @param value_or_instance A valid object that fits the purpose.
*/
template<typename Type>
void disconnect(Type *value_or_instance) {
for(auto &&cpool: pools) {
if(cpool) {
cpool->disconnect(value_or_instance);
}
}
}
/**
* @brief Discards all the events queued so far.
*
* If no types are provided, the dispatcher will clear all the existing
* pools.
*
* @tparam Event Type of events to discard.
*/
template<typename... Event>
void clear() {
if constexpr(sizeof...(Event) == 0) {
for(auto &&cpool: pools) {
if(cpool) {
cpool->clear();
}
}
} else {
(assure<Event>().clear(), ...);
}
}
/**
* @brief Delivers all the pending events of the given type.
*
@@ -215,7 +238,7 @@ public:
* @tparam Event Type of events to send.
*/
template<typename Event>
inline void update() {
void update() {
assure<Event>().publish();
}
@@ -226,22 +249,20 @@ public:
* delivered to the registered listeners. It's responsibility of the users
* to reduce at a minimum the time spent in the bodies of the listeners.
*/
inline void update() const {
for(auto pos = wrappers.size(); pos; --pos) {
auto &wdata = wrappers[pos-1];
if(wdata.wrapper) {
wdata.wrapper->publish();
void update() const {
for(auto pos = pools.size(); pos; --pos) {
if(auto &&cpool = pools[pos-1]; cpool) {
cpool->publish();
}
}
}
private:
std::vector<wrapper_data> wrappers;
std::vector<std::unique_ptr<basic_pool>> pools;
};
}
#endif // ENTT_SIGNAL_DISPATCHER_HPP
#endif

View File

@@ -2,16 +2,17 @@
#define ENTT_SIGNAL_EMITTER_HPP
#include <type_traits>
#include <functional>
#include <algorithm>
#include <utility>
#include <memory>
#include <vector>
#include <functional>
#include <iterator>
#include <list>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/family.hpp"
#include "../core/type_traits.hpp"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
namespace entt {
@@ -29,33 +30,33 @@ namespace entt {
* }
* @endcode
*
* Handlers for the type of events are created internally on the fly. It's not
* Pools for the type of events are created internally on the fly. It's not
* required to specify in advance the full list of accepted types.<br/>
* Moreover, whenever an event is published, an emitter provides the listeners
* with a reference to itself along with a const 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.
* 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.
*
* @tparam Derived Actual type of emitter that extends the class template.
*/
template<typename Derived>
class emitter {
using handler_family = family<struct internal_emitter_handler_family>;
struct base_handler {
virtual ~base_handler() = default;
struct basic_pool {
virtual ~basic_pool() = default;
virtual bool empty() const ENTT_NOEXCEPT = 0;
virtual void clear() ENTT_NOEXCEPT = 0;
};
template<typename Event>
struct event_handler: base_handler {
using listener_type = std::function<void(const Event &, Derived &)>;
struct pool_handler final: basic_pool {
static_assert(std::is_same_v<Event, std::decay_t<Event>>, "Invalid event type");
using listener_type = std::function<void(Event &, Derived &)>;
using element_type = std::pair<bool, listener_type>;
using container_type = std::list<element_type>;
using connection_type = typename container_type::iterator;
bool empty() const ENTT_NOEXCEPT override {
[[nodiscard]] bool empty() const ENTT_NOEXCEPT override {
auto pred = [](auto &&element) { return element.first; };
return std::all_of(once_list.cbegin(), once_list.cend(), pred) &&
@@ -64,24 +65,28 @@ class emitter {
void clear() ENTT_NOEXCEPT override {
if(publishing) {
auto func = [](auto &&element) { element.first = true; };
std::for_each(once_list.begin(), once_list.end(), func);
std::for_each(on_list.begin(), on_list.end(), func);
for(auto &&element: once_list) {
element.first = true;
}
for(auto &&element: on_list) {
element.first = true;
}
} else {
once_list.clear();
on_list.clear();
}
}
inline connection_type once(listener_type listener) {
connection_type once(listener_type listener) {
return once_list.emplace(once_list.cend(), false, std::move(listener));
}
inline connection_type on(listener_type listener) {
connection_type on(listener_type listener) {
return on_list.emplace(on_list.cend(), false, std::move(listener));
}
void erase(connection_type conn) ENTT_NOEXCEPT {
void erase(connection_type conn) {
conn->first = true;
if(!publishing) {
@@ -91,18 +96,19 @@ class emitter {
}
}
void publish(const Event &event, Derived &ref) {
void publish(Event &event, Derived &ref) {
container_type swap_list;
once_list.swap(swap_list);
auto func = [&event, &ref](auto &&element) {
return element.first ? void() : element.second(event, ref);
};
publishing = true;
std::for_each(on_list.rbegin(), on_list.rend(), func);
std::for_each(swap_list.rbegin(), swap_list.rend(), func);
for(auto &&element: on_list) {
element.first ? void() : element.second(event, ref);
}
for(auto &&element: swap_list) {
element.first ? void() : element.second(event, ref);
}
publishing = false;
@@ -115,57 +121,31 @@ class emitter {
container_type on_list{};
};
struct handler_data {
std::unique_ptr<base_handler> handler;
ENTT_ID_TYPE runtime_type;
};
template<typename Event>
static auto type() ENTT_NOEXCEPT {
if constexpr(is_named_type_v<Event>) {
return named_type_traits<Event>::value;
} else {
return handler_family::type<Event>;
[[nodiscard]] pool_handler<Event> * assure() {
const auto index = type_seq<Event>::value();
if(!(index < pools.size())) {
pools.resize(std::size_t(index)+1u);
}
if(!pools[index]) {
pools[index].reset(new pool_handler<Event>{});
}
return static_cast<pool_handler<Event> *>(pools[index].get());
}
template<typename Event>
event_handler<Event> * assure() const ENTT_NOEXCEPT {
const auto htype = type<Event>();
handler_data *hdata = nullptr;
if constexpr(is_named_type_v<Event>) {
const auto it = std::find_if(handlers.begin(), handlers.end(), [htype](const auto &candidate) {
return candidate.handler && candidate.runtime_type == htype;
});
hdata = (it == handlers.cend() ? &handlers.emplace_back() : &(*it));
} else {
if(!(htype < handlers.size())) {
handlers.resize(htype+1);
}
hdata = &handlers[htype];
if(hdata->handler && hdata->runtime_type != htype) {
handlers.emplace_back();
std::swap(handlers[htype], handlers.back());
hdata = &handlers[htype];
}
}
if(!hdata->handler) {
hdata->handler = std::make_unique<event_handler<Event>>();
hdata->runtime_type = htype;
}
return static_cast<event_handler<Event> *>(hdata->handler.get());
[[nodiscard]] const pool_handler<Event> * assure() const {
const auto index = type_seq<Event>::value();
return (!(index < pools.size()) || !pools[index]) ? nullptr : static_cast<const pool_handler<Event> *>(pools[index].get());
}
public:
/** @brief Type of listeners accepted for the given event. */
template<typename Event>
using listener = typename event_handler<Event>::listener_type;
using listener = typename pool_handler<Event>::listener_type;
/**
* @brief Generic connection type for events.
@@ -177,28 +157,28 @@ public:
* @tparam Event Type of event for which the connection is created.
*/
template<typename Event>
struct connection: private event_handler<Event>::connection_type {
struct connection: private pool_handler<Event>::connection_type {
/** @brief Event emitters are friend classes of connections. */
friend class emitter;
/*! @brief Default constructor. */
connection() ENTT_NOEXCEPT = default;
connection() = default;
/**
* @brief Creates a connection that wraps its underlying instance.
* @param conn A connection object to wrap.
*/
connection(typename event_handler<Event>::connection_type conn)
: event_handler<Event>::connection_type{std::move(conn)}
connection(typename pool_handler<Event>::connection_type conn)
: pool_handler<Event>::connection_type{std::move(conn)}
{}
};
/*! @brief Default constructor. */
emitter() ENTT_NOEXCEPT = default;
emitter() = default;
/*! @brief Default destructor. */
virtual ~emitter() ENTT_NOEXCEPT {
static_assert(std::is_base_of_v<emitter<Derived>, Derived>);
virtual ~emitter() {
static_assert(std::is_base_of_v<emitter<Derived>, Derived>, "Incorrect use of the class template");
}
/*! @brief Default move constructor. */
@@ -220,7 +200,8 @@ public:
*/
template<typename Event, typename... Args>
void publish(Args &&... args) {
assure<Event>()->publish({ std::forward<Args>(args)... }, *static_cast<Derived *>(this));
Event instance{std::forward<Args>(args)...};
assure<Event>()->publish(instance, *static_cast<Derived *>(this));
}
/**
@@ -232,7 +213,7 @@ public:
* to be used later to disconnect the listener if required.
*
* The listener is as a callable object that can be moved and the type of
* which is `void(const Event &, Derived &)`.
* which is _compatible_ with `void(Event &, Derived &)`.
*
* @note
* Whenever an event is emitted, the emitter provides the listener with a
@@ -257,7 +238,7 @@ public:
* to be used later to disconnect the listener if required.
*
* The listener is as a callable object that can be moved and the type of
* which is `void(const Event &, Derived &)`.
* which is _compatible_ with `void(Event &, Derived &)`.
*
* @note
* Whenever an event is emitted, the emitter provides the listener with a
@@ -283,7 +264,7 @@ public:
* @param conn A valid connection.
*/
template<typename Event>
void erase(connection<Event> conn) ENTT_NOEXCEPT {
void erase(connection<Event> conn) {
assure<Event>()->erase(std::move(conn));
}
@@ -296,7 +277,7 @@ public:
* @tparam Event Type of event to reset.
*/
template<typename Event>
void clear() ENTT_NOEXCEPT {
void clear() {
assure<Event>()->clear();
}
@@ -307,9 +288,11 @@ public:
* results in undefined behavior.
*/
void clear() ENTT_NOEXCEPT {
std::for_each(handlers.begin(), handlers.end(), [](auto &&hdata) {
return hdata.handler ? hdata.handler->clear() : void();
});
for(auto &&cpool: pools) {
if(cpool) {
cpool->clear();
}
}
}
/**
@@ -318,26 +301,27 @@ public:
* @return True if there are no listeners registered, false otherwise.
*/
template<typename Event>
bool empty() const ENTT_NOEXCEPT {
return assure<Event>()->empty();
[[nodiscard]] bool empty() const {
const auto *cpool = assure<Event>();
return !cpool || cpool->empty();
}
/**
* @brief Checks if there are listeners registered with the event emitter.
* @return True if there are no listeners registered, false otherwise.
*/
bool empty() const ENTT_NOEXCEPT {
return std::all_of(handlers.cbegin(), handlers.cend(), [](auto &&hdata) {
return !hdata.handler || hdata.handler->empty();
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return std::all_of(pools.cbegin(), pools.cend(), [](auto &&cpool) {
return !cpool || cpool->empty();
});
}
private:
mutable std::vector<handler_data> handlers{};
std::vector<std::unique_ptr<basic_pool>> pools{};
};
}
#endif // ENTT_SIGNAL_EMITTER_HPP
#endif

View File

@@ -2,26 +2,35 @@
#define ENTT_SIGNAL_FWD_HPP
#include "../config/config.h"
namespace entt {
/*! @class delegate */
template<typename>
class delegate;
/*! @class sink */
class dispatcher;
template<typename>
class emitter;
class connection;
struct scoped_connection;
template<typename>
class sink;
/*! @class sigh */
template<typename, typename>
struct sigh;
template<typename>
class sigh;
}
#endif // ENTT_SIGNAL_FWD_HPP
#endif

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