Compare commits

..

1080 Commits

Author SHA1 Message Date
Michele Caini
dd6863f71d update single include file 2021-07-28 09:58:14 +02:00
Michele Caini
dc7c976518 Ready to cut v3.8.1 2021-07-28 09:56:40 +02:00
Michele Caini
3408556eea sparse_set: fix an issue with assuring pages properly on emplace (close #746) 2021-07-27 18:53:30 +02:00
Michele Caini
f94b9773da build system: test id type std::uint64_t on the CI, all platforms 2021-07-26 23:37:55 +02:00
Michele Caini
e0b3786d97 test: make tests for entity traits work when id_type is std::uint64_t 2021-07-26 23:37:50 +02:00
Michele Caini
4047cb01a8 test: make tests for hashed string work when id_type is std::uint64_t 2021-07-26 23:37:46 +02:00
Michele Caini
8cfd08b137 sparse set: make vs2017 work (more or less) fine when id_type is std::uint64_t 2021-07-26 23:37:42 +02:00
Michele Caini
311011672c entity: avoid UBs when id type is std::uint64_t (close #745) 2021-07-26 23:37:39 +02:00
Hussein Taher
6df19c833d snapshot: fix warning for discarding a nodiscard (#728) 2021-07-26 23:37:36 +02:00
Michele Caini
78d9e71888 test: get rid of inconsistent line (close #741) 2021-07-26 23:37:32 +02:00
Michele Caini
94131648dd type_traits: try to also please gcc :) 2021-07-26 23:37:12 +02:00
Michele Caini
151f180199 core: make is_equality_comparable[_v] work with iterators (close #739) 2021-07-26 23:37:02 +02:00
Michele Caini
bb8bfaf262 meta_any: avoid risky fallthrough in the vtable (close #736) 2021-07-26 23:36:51 +02:00
Michele Caini
2d5a3f24aa doc: updated documentation 2021-07-21 00:07:02 +02:00
Michele Caini
1639429edd registry: minor changes 2021-07-01 15:32:30 +02:00
Michele Caini
f81abf4883 add cpp.hint to .gitignore 2021-07-01 12:32:18 +02:00
Michele Caini
dcddb7d50e registry: allow non-const types in const overloads of registry context variable getters (close #720) 2021-06-30 09:35:36 +02:00
Michele Caini
42a763031c storage: minor changes 2021-06-30 08:55:21 +02:00
Michele Caini
0964ca5918 storage: turn to assure_at_least based on position to avoid errors at call site 2021-06-29 16:36:00 +02:00
Michele Caini
4e870b83cd test: suppress warnings due to suggested braces 2021-06-29 15:17:58 +02:00
Michele Caini
0b19c9be0b storage: add override specifier 2021-06-29 15:10:41 +02:00
Michele Caini
ac655902a0 storage:
* internal review for memory management
* added support for nosy destructors to ::in_place_pop
* optimized ::emplace/::insert
2021-06-29 15:05:03 +02:00
Michele Caini
e4fb293b55 sparse_set: added ::emplace_back 2021-06-29 12:37:39 +02:00
Michele Caini
d3df64ef4b sparse_set: emplace returns the slot used for insertion 2021-06-28 18:51:28 +02:00
Michele Caini
93e3d14f34 sparse_set: added ::slot to return the next slot available for insertion 2021-06-28 18:46:02 +02:00
Michele Caini
bc687d412d test: suppress some warnings due to [[nodiscard]] 2021-06-28 18:02:43 +02:00
Michele Caini
71e85b44b0 sparse_set: make ::policy [[nodiscard]] 2021-06-28 18:00:40 +02:00
Michele Caini
d4b59aff97 sparse_set: tombstone/null debug check in ::contains 2021-06-28 16:51:24 +02:00
Michele Caini
e3c21e1f3d sparse_set/storage (close #707):
* improved perf on erase/remove (and therefore also registry::destroy)
* allow to inhibit a pop from derived classes
* removed about_to_pop (virtual) function
2021-06-28 15:53:59 +02:00
Michele Caini
e012250e0a type_traits: minor changes 2021-06-28 11:43:27 +02:00
Michele Caini
c6bf82664c doc: added a note about optimized range-destroy 2021-06-28 11:20:40 +02:00
Michele Caini
c61e98009f registry/benchmark: rollback optimized remove/erase (benchmarks have shown that they are not worth it) 2021-06-28 10:19:27 +02:00
Michele Caini
44bccaaad6 basic_registry:
* added fast path to destroy
* added fast path to remove
* added fast path to erase
* minor changes
2021-06-28 09:24:12 +02:00
Michele Caini
aebca14dea view: added member type iterator_type to internal class view_iterator 2021-06-28 09:10:52 +02:00
Michele Caini
4576f27f6e sparse_set: minor changes 2021-06-28 09:10:12 +02:00
Michele Caini
0c213fca40 type_traits:
* added entt::is_iterator[_v]
* added entt::is_iterator_type[_v]
2021-06-28 09:09:55 +02:00
Michele Caini
891f596191 view: minor changes 2021-06-25 17:26:22 +02:00
Michele Caini
eb2b724902 benchmark: tombstone policy runs 2021-06-24 14:04:35 +02:00
Michele Caini
1f8c896181 registry:
* deprecated ::destroyed (use ::released instead)
* added ::release overloads (aka force-destroy)
2021-06-24 10:51:03 +02:00
Michele Caini
12b39e1fbe doc: added missing tokens 2021-06-23 16:35:00 +02:00
Michele Caini
206d31f27a registry: const ::view/::group also support non-const types (close #715) 2021-06-23 15:37:46 +02:00
Michele Caini
6709331182 resource_handle: conversion functions (close #706) 2021-06-22 18:54:27 +02:00
Michele Caini
9460e04ea5 entt_traits: review/cleanup 2021-06-22 15:39:15 +02:00
Michele Caini
462bfea733 entt_traits: review to reduce the risk of ambiguous calls 2021-06-22 13:03:32 +02:00
Michele Caini
a2d61dfaeb runtime_view: suppress warning for shadow parameter 2021-06-22 09:58:19 +02:00
Michele Caini
538425e35c doc: in-place delete and pointer stability 2021-06-22 09:53:56 +02:00
Michele Caini
2e86c1f1a2 component: add basic_component_traits aside component_traits 2021-06-22 09:52:43 +02:00
Michele Caini
8aa4d46ce0 runtime_view: support for storage policy (tombstones) 2021-06-21 15:18:13 +02:00
Michele Caini
cdf67a1421 sparse_set: public ::policy method for opaque runtime detection 2021-06-21 14:44:09 +02:00
Michele Caini
93d905d93d updated TODO 2021-06-21 13:04:46 +02:00
Michele Caini
2c35203647 view:
* split view iterator from multi-type view
* stable/packed storage policy support
2021-06-21 13:04:37 +02:00
Michele Caini
216871fe56 runtime_view: minor changes 2021-06-21 12:59:44 +02:00
Michele Caini
03511f39b1 registry:
* prevent groups from being used with tombstones
* support to compact one, several or all pools
2021-06-21 12:59:26 +02:00
Michele Caini
5ad0832b22 group: minor changes 2021-06-21 12:57:35 +02:00
Michele Caini
d49e7ba4b2 sparse_set/storage:
* added component traits (component.hpp)
* support for in-place delete (tombstones)
2021-06-21 12:56:33 +02:00
Michele Caini
a621b36389 type_traits: removed internal is_empty[_v] 2021-06-21 12:44:50 +02:00
Michele Caini
d093df02ac test: minor changes 2021-06-21 12:39:18 +02:00
Michele Caini
2e1529e78d entity:
* Updated doc
* No const-ref for basic types
2021-06-21 12:32:30 +02:00
Michele Caini
90be1db402 entity:
* extended entt_traits<T>::to_type support
* added null_t::operator|
* added tombstone_t::operator|
2021-06-04 11:01:26 +02:00
Michele Caini
29265e4181 doc: updated doxy.in file 2021-06-03 10:44:13 +02:00
Michele Caini
2689a7ef13 registry: minor changes 2021-06-03 09:06:38 +02:00
Michele Caini
88b58cf23d doc: added a note about tombstones 2021-06-03 09:06:36 +02:00
Michele Caini
e2e433480b entity/registry:
* added entt_traits<T>::reserved()
* added tombstone_t type and tombstone constant
* create-with-hint also accepts null entities (discarded)
* registry skips over tombstone versions and rejects them
2021-06-03 09:06:34 +02:00
Michele Caini
b8bc3e4e94 test: exception safety for sparse set and storage 2021-06-03 08:44:48 +02:00
Michele Caini
c28f52b816 sparse_set/storage: exception safety (kind of) 2021-06-03 08:44:43 +02:00
Michele Caini
ca34309f75 config: removed ENTT_NOEXCEPT, added ENTT_NOEXCEPTION 2021-06-03 08:44:30 +02:00
Michele Caini
ea614a0f3f entity: review of entt_traits<T>::to_type 2021-05-28 08:59:50 +02:00
Michele Caini
3e7dc7af29 entity:
* review of entt_traits design
* added static constexpr member function entt_traits::to_integral
* added static constexpr member function entt_traits::to_entity
* added static constexpr member function entt_traits::to_version
* added static constexpr member function entt_traits::to_type
* custom class identifiers must expose member type entity_field
* it's no longer required to specialize entt_traits (breaking change)
2021-05-28 08:59:50 +02:00
Michele Caini
0b3e3fd19a doc: updated links (close #709) and TODO file 2021-05-28 08:58:36 +02:00
Michele Caini
d3372dc05c organizer: wrap std::min to trick windows.h (close #710) 2021-05-28 08:54:41 +02:00
Michele Caini
7d141cb183 storage: fix move ctor/op 2021-05-27 16:16:45 +02:00
Michele Caini
755699c31b config:
* removed entt::page_size
* renamed ENTT_PAGE_SIZE to ENTT_SPARSE_PAGE
* added ENTT_PACKED_PAGE (page size for component arrays)
2021-05-25 10:07:20 +02:00
Michele Caini
acf3d4cd74 sparse_set/storage: suppress a couple of warnings 2021-05-25 10:06:55 +02:00
Michele Caini
92414c91b5 sparse_set/storage: review memory management for fancy allocators and the like 2021-05-24 11:53:45 +02:00
Michele Caini
ff67f402bb sparse_set/storage:
* better performance on insertion
* exception guarantee for nothrow default constructible entity types
2021-05-24 10:36:33 +02:00
Michele Caini
f048a3f1d8 sparse_set: minor changes 2021-05-24 10:27:30 +02:00
Michele Caini
9d39cb51cf storage/registry: review range ::insert (breaking change) 2021-05-24 10:27:30 +02:00
Michele Caini
7624a9d34c sparse_set/storage:
* exception safety guarantee (sort of)
* ::insert optimization for non random access iterators
2021-05-24 10:27:30 +02:00
Michele Caini
0fe73fb6ed storage: free memory in move assignment operator (with tests) 2021-05-24 10:27:10 +02:00
Michele Caini
ae11652493 sparse_set: free memory in move assignment operator (with tests) 2021-05-24 09:52:09 +02:00
Michele Caini
0ab46870ae updated TODO list 2021-05-21 09:00:18 +02:00
Michele Caini
a5381374b8 updated workflow 2021-05-20 11:00:42 +02:00
Michele Caini
7fae655651 updated TODO file 2021-05-19 10:49:23 +02:00
Michele Caini
3d9959c8e5 sparse_set/storage: small review and optimizations 2021-05-19 09:29:37 +02:00
Michele Caini
bc86576aa8 storage: improved performance when emplacing 2021-05-17 12:34:42 +02:00
Michele Caini
7c2bce8baf core: added entt::page_size 2021-05-17 12:07:48 +02:00
Michele Caini
b062bbf58d storage/view/group: reintroduce (opaque) ::raw functions as it ought to be 2021-05-17 11:59:51 +02:00
Michele Caini
8e5a048913 storage: updated pointer type for storage iterator 2021-05-17 10:10:54 +02:00
Michele Caini
ff642ffff7 sparse_set: updated pointer type for sparse set iterator 2021-05-17 10:09:50 +02:00
Michele Caini
656c12cebd view/group: opaque pointer type for ::data 2021-05-17 00:00:06 +02:00
Michele Caini
48f3fcf3bd doc: updated links (close #704) 2021-05-16 22:33:04 +02:00
Michele Caini
d797af695b registry: much faster range ::create 2021-05-16 00:26:57 +02:00
Michele Caini
75e0161c5f view :minor changes 2021-05-15 23:01:50 +02:00
Michele Caini
c0662816f1 updated TODO file 2021-05-14 18:24:09 +02:00
Michele Caini
415a31ce23 storage: forward allocator to base class 2021-05-14 15:12:29 +02:00
Michele Caini
6e603e2e51 sparse_set: suppress conversion warning 2021-05-14 15:12:26 +02:00
Michele Caini
9af318a767 test: minor changes 2021-05-14 15:12:23 +02:00
Michele Caini
30827120f6 registry: cleanup 2021-05-14 15:12:20 +02:00
Michele Caini
6194e12616 entity:
* allocator support for sparse set and storage
* pointer stability when assigning components
* removed ::raw functions (registry, view, group)
* to_entity returns null for invalid components
2021-05-14 15:12:16 +02:00
Michele Caini
59a27fb652 registry: deprecated ::reserve_pools 2021-05-13 11:01:46 +02:00
Michele Caini
f8ec57c2f6 *: cleanup 2021-05-11 10:50:38 +02:00
Michele Caini
844ef5e232 meta: avoid warning for unused variable 2021-05-10 09:49:44 +02:00
Michele Caini
5bf3f7b77e meta: suppress warning for extra ; 2021-05-08 17:19:06 +02:00
Michele Caini
00c0afd093 meta: avoid using y_combinator to clean up types (close #700) 2021-05-08 17:13:52 +02:00
Michele Caini
5228739c87 meta: make it work also with VS2017 2021-05-08 17:13:52 +02:00
Michele Caini
0f6d1268c7 meta: further reduced number of instantiations/size of symbols 2021-05-08 17:13:52 +02:00
Michele Caini
b2a4515d2b any: minor changes 2021-05-08 17:13:51 +02:00
Michele Caini
3576c80d33 meta_any: drastically reduce the number of instantiations/size of vtable 2021-05-08 17:13:51 +02:00
Michele Caini
77afd2d36c any: ::owner function (useful to also review meta_any) 2021-05-08 17:13:51 +02:00
Michele Caini
e6ddd5d9c2 any: drastically reduced the number of instantiations/size of vtable 2021-05-08 17:13:51 +02:00
Michele Caini
b9bf1a234e config: added ENTT_LAUNDER 2021-05-08 17:13:51 +02:00
Michele Caini
0ce9122449 any: reduce vtable size, simplify ref/cref creation 2021-05-08 17:13:51 +02:00
Michele Caini
dc41657872 any: empty vtable for void type 2021-05-08 17:13:51 +02:00
Michele Caini
64d9380031 *: updated messages for deprecated functions 2021-05-08 17:13:51 +02:00
Michele Caini
eca7484e30 doc: updated doc for any/meta_any 2021-05-08 17:13:51 +02:00
Michele Caini
2b5c393a13 meta: forward_as_meta 2021-05-08 17:13:51 +02:00
Michele Caini
0817d416a3 meta: make_meta_any -> make_meta 2021-05-08 17:13:51 +02:00
Michele Caini
ccff753305 any: forward_as_any 2021-05-08 17:13:51 +02:00
Michele Caini
11481a430a meta: minor changes 2021-05-08 17:13:51 +02:00
Michele Caini
e252b22735 test: code coverage 2021-05-08 17:13:51 +02:00
Michele Caini
a32ca8eb1d doc: updated doc for any/meta_any/poly 2021-05-08 17:13:50 +02:00
Michele Caini
1979a2279f poly: removed std::reference_wrapper support (incomplete, breaking change) 2021-05-08 17:13:50 +02:00
Michele Caini
1434f942dd *: make it work with VS2017 2021-05-08 17:13:50 +02:00
Michele Caini
955d325f07 meta_any: deprecated std::reference_wrapper support 2021-05-08 17:13:50 +02:00
Michele Caini
3fac3fe2d7 any: deprecate std::reference_wrapper support 2021-05-08 17:13:50 +02:00
Michele Caini
6ff217e74e meta: removed any reference to std::reference_wrapper/std::ref/std::cref 2021-05-08 17:13:50 +02:00
Michele Caini
cd667fe34b meta: make_meta_any 2021-05-08 17:13:50 +02:00
Michele Caini
3d6202ecfd any: make_any 2021-05-08 17:13:50 +02:00
Michele Caini
c40f0ef2bb type traits: is_equality_comparable support for nlohmann json like types (where T::value_type is T) - close #701 2021-05-08 10:43:27 +02:00
Michele Caini
c4b169edd1 registry: make ::remove and ::erase work also with iterators returned by views 2021-05-07 11:16:32 +02:00
Michele Caini
c6bba98828 registry: ::destroy review 2021-05-06 16:34:36 +02:00
Michele Caini
e5d4f1bb58 entity: deprecate handle::remove_all and registry::remove_all 2021-05-06 16:33:43 +02:00
Michele Caini
cf522d60ca doc: updated doc for handle 2021-05-06 10:31:43 +02:00
Michele Caini
daf72a7c61 entity: registry ::remove/::erase entity/range and safe/unsafe versions (close #486) 2021-05-04 11:36:02 +02:00
Michele Caini
f116ad0594 test: use iterators in the poly storage example 2021-05-03 22:29:39 +02:00
Michele Caini
e59d40834d any: reduce vtable options 2021-04-29 11:17:15 +02:00
Michele Caini
d06328af7f any: small review 2021-04-29 10:24:18 +02:00
Michele Caini
baa9d7d836 any: avoid invalid state from assignment operator for non-copyable types 2021-04-29 10:05:01 +02:00
Michele Caini
b030df55ee registry: clean up 2021-04-22 08:55:20 +02:00
Michele Caini
64eb8a2d0d sparse_set: ::remove returns number of actually removed elements 2021-04-22 08:42:35 +02:00
Michele Caini
7d7c36e0c7 registry: clean up ::remove_all 2021-04-21 16:50:33 +02:00
Michele Caini
9ad5768050 registry: clean up ::clear 2021-04-21 16:46:39 +02:00
Michele Caini
1cafbcff38 sparse_set: remove (and range-remove) if exists 2021-04-21 16:39:51 +02:00
Michele Caini
4bbf93fd0c sparse_set: remove -> erase 2021-04-21 15:46:02 +02:00
Michele Caini
120918bc37 any: refine the aggregate support to make any closer to its standard counterpart 2021-04-21 13:45:51 +02:00
Michele Caini
253448cffb sparse_set: suppress warnings for unused variables 2021-04-20 12:38:06 +02:00
Michele Caini
26f19fb90e storage: cleanup 2021-04-20 12:37:50 +02:00
Michele Caini
e8f982e909 view/group: raw() isn't bound to pointer types 2021-04-19 16:05:08 +02:00
Michele Caini
0fa433187e storage: valid state on component removal (allows component destructors to access pools) 2021-04-19 15:34:41 +02:00
Michele Caini
b0069299ea meta_any: avoid dereferencing C-style arrays 2021-04-15 11:45:10 +02:00
Michele Caini
375d5d3e9b doc: cleanup 2021-04-14 15:44:33 +02:00
Michele Caini
2d9398ae1a entity: handle review 2021-04-14 15:44:27 +02:00
Michele Caini
fc69e91636 test: refined custom id example 2021-04-14 15:44:17 +02:00
Michele Caini
5c56cbd672 process: dead -> finished 2021-04-13 09:02:29 +02:00
Michele Caini
a42255158d config: added error messages to ENTT_ASSERT 2021-04-13 09:02:29 +02:00
Michele Caini
f3d10a97df now working on v3.8.0 2021-04-13 09:02:26 +02:00
Michele Caini
5d15a3d69f updated single include file 2021-04-13 08:46:28 +02:00
Michele Caini
94292872dc ready to cut v3.7.1 (general quality of life improvements, no bug fixes, no new feature) 2021-04-12 23:37:53 +02:00
Michele Caini
5c8a1e7d10 type traits: removed is_std_hashable[_v] 2021-04-12 23:37:46 +02:00
Michele Caini
e98d8426bb meta: treat T(*)[N] as non-pointer-like types 2021-04-12 15:59:35 +02:00
Michele Caini
77f80cecf9 test: re-enable tests left commented by mistake 2021-04-12 15:59:31 +02:00
Michele Caini
bce26a1499 meta: remove dependency on std::array 2021-04-12 15:59:28 +02:00
Michele Caini
453f1c6edc test: std::strcmp ... 🤦‍♂️ 2021-04-12 15:59:20 +02:00
Michele Caini
9f8a36f2c9 any/meta: cleanup/better traits usage 2021-04-12 15:58:59 +02:00
Michele Caini
e6a5945463 meta_any: suppress a warning from clang 2021-04-12 15:56:01 +02:00
Michele Caini
60393fbc5f meta_any: decays Type on storage construction to handle correctly const T[N] types (close #687) 2021-04-12 15:55:59 +02:00
Michele Caini
b9a925dbd4 test: avoid regressions with any and deduced const T[N] types 2021-04-12 15:55:57 +02:00
Michele Caini
5dbdb1bcb5 any: internal support for both aggreagates and non-aggregates (qol enhancement :) 2021-04-12 15:55:55 +02:00
Michele Caini
d55cefc086 meta_any: no redundant copies, better perf 2021-04-12 15:55:53 +02:00
Michele Caini
5380e6d98b any: no redundant copies, better perf 2021-04-12 15:55:49 +02:00
Michele Caini
45cc24e0b8 any: favor aggregate initialization upon construction 2021-04-12 15:55:45 +02:00
Michele Caini
76bf1791eb test: cleanup 2021-04-12 13:02:23 +02:00
Michele Caini
7e9a4c4b16 view: initialize all data members on construction 2021-04-12 12:52:22 +02:00
Michele Caini
75cd5f169f *: review deduction guides 2021-04-12 12:48:36 +02:00
Michele Caini
10636c82a2 view/group: review extended iterable mode (close #686) 2021-04-07 10:33:52 +02:00
Michele Caini
04a6729963 build_system: minor changes 2021-04-06 16:49:11 +02:00
Michele Caini
b5617398ad doc: fixed typo 2021-04-06 16:47:20 +02:00
Michele Caini
da14641ccb meta: reduce instantiations due to meta_prop 2021-04-06 16:47:14 +02:00
Michele Caini
3997bd2396 meta: minor changes 2021-04-06 16:47:03 +02:00
Michele Caini
c876350e05 updated single include file 2021-04-02 12:04:31 +02:00
Michele Caini
1e07b981f0 build_system: manually install missing compilers 2021-04-01 14:42:10 +02:00
Michele Caini
756e909f5e *: (static) assert messages 2021-03-31 15:10:15 +02:00
Michele Caini
2404392daf meta_any: vtable review for empty/void types 2021-03-30 15:55:48 +02:00
Michele Caini
bf6576f5af any: use std::addressof to get the address of an object reliably 2021-03-30 15:27:49 +02:00
Michele Caini
158c2ab76e delegate: removed redundant calls to delegate constructors 2021-03-30 11:52:16 +02:00
Michele Caini
56fa50385e build system: minor changes 2021-03-29 23:32:35 +02:00
Michele Caini
eb05ab5fab test: code coverage 2021-03-29 23:30:13 +02:00
Michele Caini
7f87b637d5 workflow: use lcov to process codecoverage 2021-03-29 23:12:34 +02:00
Michele Caini
4b213adc75 test: cleanup 2021-03-29 19:03:10 +02:00
Michele Caini
7e7d5bbf17 registry: suppress a wrong warning from gcc 7.5 2021-03-29 19:00:09 +02:00
Michele Caini
e18c0a0c19 test: verify that dtor isn't invoked for a meta_any that wraps a reference 2021-03-29 17:01:05 +02:00
Michele Caini
02b6ffc771 build system: add ubsan to the CI 2021-03-29 12:19:52 +02:00
Michele Caini
340d66c24c build system: split build and sanitizer runs 2021-03-29 12:07:49 +02:00
Michele Caini
2cbf9d3620 build system: added poly.md to fake docs all target 2021-03-29 12:03:36 +02:00
Michele Caini
11e6793544 build system: cleanup 2021-03-29 12:00:42 +02:00
Michele Caini
d07e0336a2 test: fix ub in the tests 2021-03-29 10:28:58 +02:00
Michele Caini
7dbfb3d9ae test: code coverage (and try to please new gcov) 2021-03-29 08:23:30 +02:00
Michele Caini
02ef5db6e3 test: cleanup 2021-03-28 00:02:51 +01:00
Michele Caini
bb43bb5508 test: code coverage 2021-03-27 23:59:13 +01:00
Michele Caini
a771f083a7 process: added rejected state 2021-03-27 23:19:15 +01:00
Michele Caini
67f8bce1dd test: code coverage 2021-03-27 23:03:24 +01:00
Michele Caini
3b6dd23598 scheduler: small review for perf improvements 2021-03-27 22:48:54 +01:00
Michele Caini
66bbeae7da test: code coverage 2021-03-27 22:47:15 +01:00
Michele Caini
059334a861 test: code coverage 2021-03-27 18:14:36 +01:00
Michele Caini
f874c8309f registry: make vs2017 happy again 2021-03-26 15:35:11 +01:00
Michele Caini
27be812cc3 registry: small review of const correctness for components 2021-03-26 15:11:37 +01:00
Michele Caini
2adc2e97e1 registry: a "better" get 2021-03-26 14:49:42 +01:00
Michele Caini
dc4279a2d0 any/poly: review align parameter and default values (close #676) 2021-03-26 13:05:52 +01:00
Michele Caini
85bff4525a registry: non-const try_get doesn't create pools anymore 2021-03-26 09:38:58 +01:00
Michele Caini
bd648c0745 registry: avoid embedding asserts with return expressions 2021-03-25 11:13:50 +01:00
Michele Caini
d5e7005edd doc: minor changes to make doxygen happy 2021-03-25 09:46:06 +01:00
Michele Caini
8913c7ea18 poly: make vs2017 happy again 2021-03-24 13:53:02 +01:00
Michele Caini
0e2afe4f98 resource: remove the requirement to use shared_ptr (close #679) 2021-03-24 12:03:43 +01:00
Michele Caini
a936f7cdbe doc: added a note about configurable alignment requirements for any and poly 2021-03-24 12:03:43 +01:00
Michele Caini
44fa466618 poly: support for alignment requirements 2021-03-24 12:03:43 +01:00
Michele Caini
b05d84e8e3 test: minor changes 2021-03-24 12:03:43 +01:00
Michele Caini
7787c1ddd7 poly: redefine poly to basic_poly, introduce poly alias declaration 2021-03-24 12:03:43 +01:00
Michele Caini
52bfddd2e7 any: support for sbo storage alignment (close #676) 2021-03-24 12:03:43 +01:00
Michele Caini
f59adcdc37 test: no sbo overaligned any 2021-03-24 12:03:43 +01:00
Michele Caini
e996d3398f any: take in consideration alignment requirements for in_situ test (see #676) 2021-03-24 12:03:43 +01:00
Michele Caini
d73892d25a build system: more on pkg-config + updated README file 2021-03-18 13:48:38 +01:00
Alexandru-Sergiu Marton
1ebf614d79 build system: add pkg-config support (#674) 2021-03-18 13:48:38 +01:00
Michele Caini
f9c995f03f storage: cleanup 2021-03-18 13:47:53 +01:00
Michele Caini
2dcdd561f0 registry: minor changes 2021-03-17 16:10:00 +01:00
Michele Caini
90f97aa8d7 doc: updated try-it link (close #678) 2021-03-17 15:10:10 +01:00
Michele Caini
5a4b067cee view:
* removed view_pack and its tests
* added the possibility of combining different views
* updated documentation
2021-03-17 14:57:51 +01:00
Michele Caini
cabcc761c6 view: uniform design (prepare for chaining) 2021-03-16 17:14:20 +01:00
Michele Caini
a40ac1c46c registry: minor changes 2021-03-16 13:38:29 +01:00
Michele Caini
85ddfc4d21 test: clean up 2021-03-16 13:13:55 +01:00
Michele Caini
037a35df1d storage: removed storage category 2021-03-15 18:47:17 +01:00
Michele Caini
64c753023e doc: minor changes 2021-03-15 17:52:50 +01:00
Michele Caini
9d72ffb9fe test: minor changes 2021-03-12 13:52:46 +01:00
Michele Caini
4162d4fbc6 type_info: a more reliable operator bool 2021-03-12 09:33:42 +01:00
Michele Caini
a4d16bffd3 any: minor changes 2021-03-12 08:42:41 +01:00
Michele Caini
bcaf1489c0 meta: extended template info support 2021-03-11 12:17:48 +01:00
Michele Caini
a85712e8aa meta:
* removed has_meta_sequence_container[_v]
* removed has_meta_associative_container[_v]
2021-03-11 10:40:13 +01:00
Michele Caini
0f95d02cdc any: minor changes 2021-03-10 08:55:02 +01:00
Michele Caini
c151d55237 dispatcher: help std::is_copy_constructible to solve its problems with std::vector :) 2021-03-10 08:51:06 +01:00
Michele Caini
785cd6bc11 storage (close #675):
* stable sigh_storage_mixin::swap_and_pop
* added tests to avoid regressions
2021-03-09 16:09:19 +01:00
Michele Caini
8ec7e3cc97 test: suppress warnings for unused variables 2021-03-09 12:25:32 +01:00
Michele Caini
e376493970 test: removed unnecessary static functions 2021-03-09 12:17:00 +01:00
Michele Caini
08e2322d79 test: meta corner cases and re-registration 2021-03-09 12:11:25 +01:00
Michele Caini
2832767daa meta: updated doc 2021-03-09 12:10:55 +01:00
Michele Caini
62e12ee0aa meta: no need to check the instance in the dtor wrapper 2021-03-09 10:34:06 +01:00
Michele Caini
80e73c1089 meta:
* props no longer depend on the value type
* more tests for meta_prop
2021-03-09 10:26:21 +01:00
Michele Caini
4f93995bd7 test: suppress warnings + increase code coverage 2021-03-09 10:24:28 +01:00
Michele Caini
03c7dac92f meta: internal review to fully support re-registration 2021-03-09 09:50:48 +01:00
Michele Caini
d0b93f565a meta: prop key is returned by const reference rather than by copy 2021-03-08 15:22:25 +01:00
Michele Caini
1512fbae55 meta: safer factory, no-op re-registration 2021-03-08 14:52:46 +01:00
Michele Caini
4d91afdf9f meta: allow range-reset 2021-03-08 14:44:08 +01:00
Michele Caini
c239c3fea3 factory: avoid re-registration of data and type if already registered 2021-03-08 09:29:54 +01:00
Michele Caini
a0b431e8c4 doc: context aliased properties 2021-03-08 09:01:13 +01:00
Michele Caini
005e03aeb3 registry:
* context const correctness
* added support for aliased variables to context
* code coverage to avoid regressions
2021-03-06 22:51:01 +01:00
Michele Caini
6002d373e2 meta: factory ignores already existing unnamed meta objects 2021-03-05 11:32:32 +01:00
Michele Caini
a53066424b meta: cleanup/minor changes 2021-03-04 10:22:36 +01:00
Michele Caini
38ab02ff88 doc: minor changes 2021-03-03 16:49:20 +01:00
Michele Caini
fee0b29a0b registry: added missing template keyword (thanks msvc for accepting it anyway) 2021-03-03 14:24:38 +01:00
Michele Caini
2553695029 meta: minor changes 2021-03-03 12:26:59 +01:00
Michele Caini
301939983f registry: minor changes 2021-03-03 12:26:11 +01:00
Michele Caini
cd9ae1fbad poly: ::emplace support for reference types 2021-03-03 12:25:34 +01:00
Michele Caini
54e9bc86cc doc: updated links 2021-03-02 12:05:49 +01:00
Michele Caini
a1dd4c28c3 view: clean up 2021-03-02 11:21:40 +01:00
Michele Caini
6d3857f337 registry: clean up 2021-03-01 23:55:57 +01:00
Michele Caini
c4be3e731a poly: fwd.hpp 2021-02-28 23:29:36 +01:00
Michele Caini
ea4407b847 doc: fixed typo 2021-02-28 23:24:32 +01:00
Michele Caini
a62a83044f poly: make it work also with non-default Len 2021-02-27 17:34:09 +01:00
Michele Caini
e7e7b06744 doc: updated links 2021-02-26 14:36:20 +01:00
Michele Caini
2222e31885 config: ENTT_PAGE_SIZE sets the number of elements of a page, not the size in bytes 2021-02-25 00:18:04 +01:00
Michele Caini
c3f7f83c55 registry/view (close #660):
* const registry::view is no longer thread safe
* views are always valid when created from a registry, either const or not
* added a note to the doc about const registry and multithreading
2021-02-23 17:01:38 +01:00
Michele Caini
86e18f68c4 sparse_set: added unchecked operator[](pos) 2021-02-23 15:01:05 +01:00
Michele Caini
cc7d9e03d9 doc: updated list of similar projects 2021-02-23 14:39:37 +01:00
Michele Caini
c8639ae434 meta: minor changes 2021-02-23 12:00:59 +01:00
Michele Caini
85cf32516e view: minor changes 2021-02-22 16:52:54 +01:00
Michele Caini
bc85817b07 doc: updated doc for type_seq and the like 2021-02-22 16:39:42 +01:00
Michele Caini
1016394be5 *: minor changes 2021-02-22 16:35:36 +01:00
Michele Caini
de35cbf4af type_info: add conversion operators to underlying types (close #664) 2021-02-22 14:48:35 +01:00
Michele Caini
bb1acee36a entity:
* sparse_set: added optional user data to ::remove and ::clear
* sparse_set: remove the payload, it was really meh
* storage: review sigh_storage_mixin, simplified storage_adapter_mixin
* registry: pass itself twhen adding/patchin/removing components

test: updated tests for sparse set and poly storage
examples: added a test to avoid regressions on storage_adapter_mixin
2021-02-22 14:32:29 +01:00
Michele Caini
c6a2ed78c3 poly: add missing template keyword 2021-02-22 09:45:55 +01:00
Michele Caini
7729958082 doc: updated links 2021-02-21 16:39:29 +01:00
Michele Caini
ccdaec86b3 poly: added configurable sbo size (0 -> forced dyn) 2021-02-20 00:12:43 +01:00
Michele Caini
42afeef993 any: updated tests (sbo vs zeroed sbo size) 2021-02-19 23:46:44 +01:00
Michele Caini
3d06911886 test: code coverage (codecov is odd sometimes) 2021-02-19 16:26:55 +01:00
Michele Caini
98f929e41e any: try to get around an issue with clang only 2021-02-19 16:23:33 +01:00
Michele Caini
94d4e0231e *: suppress a few warnings + fix a call that msvc accepted by mistake 2021-02-19 16:11:19 +01:00
Michele Caini
e60cdb2e3b config: update ENTT_PAGE_SIZE 2021-02-19 15:50:09 +01:00
Michele Caini
550c021097 any: make VS happy :) 2021-02-19 14:56:39 +01:00
Michele Caini
1aec7f71b8 any: doc + test for configurable sbo 2021-02-19 14:45:26 +01:00
Michele Caini
07565927f2 any:
* added configurable sbo size (0 -> forced dyn)
* reverted changes for forced dyn vtable
2021-02-19 12:51:30 +01:00
Michele Caini
fda78ede1b any: prepare for in-place forced dynamic construction 2021-02-19 11:48:25 +01:00
Michele Caini
1249a4f8d3 any/meta_any/poly: as_ref is a member function, no longer an in-class friend function exported in the global namespace 2021-02-19 11:19:32 +01:00
Michele Caini
4e631f1536 meta_handle: deleted copy constructor (close #661) 2021-02-18 23:49:39 +01:00
Michele Caini
1757dbc225 registry: get around an issue of gcc 2021-02-16 17:12:02 +01:00
Michele Caini
8149e204d2 *: refine code that msvc accepts by mistake (🤦‍♂️) 2021-02-16 15:55:45 +01:00
Michele Caini
412f2ef63e doc: updated/reviewed 2021-02-16 15:08:34 +01:00
Michele Caini
ea33673daa registry: faster, better ::clear 2021-02-16 14:53:33 +01:00
Michele Caini
169b816613 entity:
* sparse_set: stable virtual remove
* basic_storage: fake get for empty types,
* sigh_storage_mixin: use swap_and_pop, drop ::remove, ignore emptiness
* poly_storage: ::remove is no longer part of its interface by default
2021-02-16 14:46:42 +01:00
Michele Caini
48edf077fc sigh_storage_mixin:
* Owner as template parameter (to make it reusable in other contexts)
* Use storage payload for retrieving the owner from the storage
2021-02-16 10:44:03 +01:00
Michele Caini
91db153710 registry: rebind pools from move constructor/assignment operator 2021-02-15 18:11:02 +01:00
Michele Caini
ea1f010b1a sparse_set/storage: swap_at and swap_and_pop are protected and non-final 2021-02-15 15:57:17 +01:00
Michele Caini
935a852745 storage:
* Removed storage_adapter_mixin (intermediate step towards the owner-as-payload model)
* The class sigh_storage_mixin expects a plain storage as a base class (intermediate step towards the owner-as-payload model)
* Further reduced the number of instantiations
* All storage classes must expose a ::patch function
2021-02-15 15:56:27 +01:00
Michele Caini
0eb6d7de3c sparse_set: added opaque payload (mainly meant to attach owners for augmented storage mixins) 2021-02-15 15:15:41 +01:00
Michele Caini
3118cd4fa5 sparse_set: added ::at to get the entity at a given position, if any 2021-02-15 14:56:18 +01:00
Michele Caini
18832fcb37 core: make type_id [[nodiscard]] (see #658) 2021-02-14 11:04:12 +01:00
Michele Caini
612554f6af registry: minor changes 2021-02-12 18:18:39 +01:00
Michele Caini
1c794591b9 sparse_set: review sort_n 2021-02-12 15:47:52 +01:00
Michele Caini
a8d95b284d meta: general renaming, size -> arity when it returns the arity of a function 2021-02-12 11:05:07 +01:00
Michele Caini
772c2dba2f type traits: add is_std_hashable[_v] (see #629) 2021-02-11 11:57:55 +01:00
Kartik Saranathan
9d1a210c97 core: PS4 build fix for entt::any (#657)
PS4 headers doesn't define __cpp_lib_launder which fails to compile with -Werror
2021-02-11 10:16:28 +01:00
Michele Caini
b04b966db1 meta:
* updated meta_any::operator== to make it consistent across boundaries
* constness review for meta_type_node
2021-02-10 15:57:20 +01:00
Michele Caini
e2c61d90e9 meta: use meta_node internally to generate template_info 2021-02-09 18:27:40 +01:00
Michele Caini
d50655c4f7 test: suppress a couple of shadow warnings 2021-02-09 18:20:42 +01:00
Michele Caini
5e4c63736b meta: added minimal class template support to meta_type 2021-02-09 17:18:24 +01:00
Michele Caini
b90b71c8c0 meta: support for proxy pointers 2021-02-09 10:57:50 +01:00
Michele Caini
722033e906 meta: split node.hpp and meta.hpp 2021-02-09 09:59:51 +01:00
Michele Caini
b6ec91fcd0 doc: updated links, removed broken one 2021-02-09 08:17:49 +01:00
Michele Caini
e94c0d003a any/registry:
* copying an entt::any always returns a copy of the contained object
* registry::storage returns references (eventually const) to the poly storage
2021-02-08 11:46:22 +01:00
Michele Caini
5c46ccb37e meta:
* avoid copies from meta_type::invoke (small perf improvement)
* meta_handle::operator* no longer available
* added meta_handle::operator bool
2021-02-08 11:33:53 +01:00
Michele Caini
fd989feea3 any: review copy, prepare for #652 2021-02-06 23:22:32 +01:00
Michele Caini
1b53e83dde any: minor changes 2021-02-06 18:35:08 +01:00
Michele Caini
3ebe827b51 doc: minor changes 2021-02-05 11:10:04 +01:00
Michele Caini
b8266e1169 registry: minor changes 2021-02-04 16:12:06 +01:00
Michele Caini
4efbe24607 test: minor changes (code coverage) 2021-02-04 12:14:35 +01:00
Michele Caini
e96ac1f6ff handle: rename ::has/::any to ::all_of/any_of 2021-02-04 12:03:38 +01:00
Michele Caini
14915368c7 test: avoid some ASSERT_DEATH that don't trigger in release mode 2021-02-04 11:50:52 +01:00
Michele Caini
0ff5c18743 registry: rename ::any to ::any_of 2021-02-04 09:45:11 +01:00
Michele Caini
240814cc85 registry: rename ::has to ::all_of 2021-02-04 09:36:28 +01:00
Michele Caini
1912350cc6 registry: use entt::any to store context variables 2021-02-04 09:21:27 +01:00
Michele Caini
146faa6008 doc: updated links 2021-02-04 08:20:03 +01:00
Michele Caini
e5fa67850b sparse_set/registry: avoids UB with sparse_set::clear and component-less registry::clear 2021-02-03 16:18:25 +01:00
Michele Caini
1377b51341 doc: minor changes 2021-02-03 13:07:39 +01:00
Ευάριστος
db67fb3539 build system: delete @bazel_tools//src/conditions:windows_msys. (#649)
This condition is no longer available from Bazel 4.0.0.
2021-02-03 10:08:38 +01:00
Michele Caini
6d216406f3 registry: minor changes 2021-02-03 10:04:16 +01:00
Michele Caini
ab225eaec1 registry: updated precondition of ::assign 2021-02-02 23:37:09 +01:00
Michele Caini
4d6d9e567d registry: minor changes 2021-02-02 13:53:51 +01:00
Michele Caini
0fcf0142ba sparse_set: prepare for detached pools 2021-02-02 12:59:07 +01:00
Michele Caini
ab907e4fef updated README 2021-02-01 10:04:54 +01:00
Michele Caini
1c1c3eb271 meta: added support to self pointer in meta_any 2021-01-29 22:13:31 +01:00
Michele Caini
a03a569534 meta: support for std::vector<bool> and the like 2021-01-29 18:58:18 +01:00
Michele Caini
309fb0fa83 test: updated storage poly example (close #644) 2021-01-29 11:10:01 +01:00
Michele Caini
14c1431848 doc: fixed typo (close #646) 2021-01-29 10:06:22 +01:00
Michele Caini
c3dc32415b meta: make meta utility public and freely available to users 2021-01-28 12:19:02 +01:00
Michele Caini
44d6246278 doc: fixed typo 2021-01-28 12:18:33 +01:00
Michele Caini
5bbd7e03f9 meta: prepare to make internal utilities public 2021-01-27 16:47:01 +01:00
Michele Caini
f5f463b411 any: relaxed checks/constraints 2021-01-26 16:45:02 +01:00
Michele Caini
6eaefbe25c doc: update doc of the runtime reflection system (close #641) 2021-01-26 08:41:41 +01:00
Michele Caini
4b5c2c85a5 doc: updated inline doc (close #640) 2021-01-26 08:36:56 +01:00
Michele Caini
0f951cd322 test: suppress a warning due to an unused variable 2021-01-25 15:22:46 +01:00
Michele Caini
cf0da32fd0 meta: iterators of meta associative containers return keys by const reference rather than by copy 2021-01-25 15:12:59 +01:00
Michele Caini
5a3085c42b registry: removed data<T> and raw<T> (use view<T>::data/::raw instead) 2021-01-25 12:29:22 +01:00
Michele Caini
42cc480bf5 doc: updated links and TODO file 2021-01-23 18:39:08 +01:00
Michele Caini
2822eda858 poly: added ::reset 2021-01-23 18:22:15 +01:00
Michele Caini
6c804b5ca2 meta: added meta_any::reset 2021-01-23 18:19:11 +01:00
Michele Caini
5149d1395e any: minor changes 2021-01-23 18:18:54 +01:00
Michele Caini
f75a2dab8d any (meta/poly): make T& in place construction work with references rather than pointers 2021-01-23 18:09:41 +01:00
Michele Caini
a045c88c61 any: added ::reset 2021-01-23 18:04:03 +01:00
Michele Caini
a5fdf917df test: minor changes (code coverage) 2021-01-22 20:13:15 +01:00
Michele Caini
80a0e47f1a core: more tests for hashed_string (code coverage) 2021-01-22 15:39:03 +01:00
Michele Caini
a304313ad4 any: more tests for the support to not copyable types (code coverage) 2021-01-22 15:28:24 +01:00
Michele Caini
05b1d5a4da meta: more tests for entt::resolve (code coverage) 2021-01-22 15:22:36 +01:00
Michele Caini
edeef3541c meta: tests (code coverage) for meta_ctor (implicitly generated default constructor) 2021-01-22 15:20:03 +01:00
Michele Caini
cd929d8e65 meta: review + tests (code coverage) for implicitly generated default constructors 2021-01-22 15:17:58 +01:00
Michele Caini
b005971427 doc: removed broken badge 2021-01-22 15:17:19 +01:00
Michele Caini
c35614fb63 meta: more tests for meta pointers (code coverage) 2021-01-22 15:08:45 +01:00
Michele Caini
18e16b09f2 any: more tests (code coverage) 2021-01-22 14:57:50 +01:00
Michele Caini
b18b76c1f0 meta: as_ref_t adapts to const objects/const-ref return types 2021-01-22 11:41:17 +01:00
Michele Caini
c9f65267ba meta: factory getter, better is_invocable_v test 2021-01-22 09:17:37 +01:00
Michele Caini
cce52c673b view: use get_as_tuple internally 2021-01-22 09:17:00 +01:00
Michele Caini
fdde216f0e doc: minor changes 2021-01-21 10:32:25 +01:00
Michele Caini
d1901a97d1 doc: minor changes 2021-01-21 09:59:43 +01:00
Michele Caini
eb2077b95b meta: suppress warnings 2021-01-20 19:51:59 +01:00
Michele Caini
fad3bdeed4 meta: ::reset doesn't remove the implicitly generated default constructors 2021-01-20 15:29:35 +01:00
Michele Caini
e1a537e547 doc: minor changes 2021-01-20 15:20:51 +01:00
Michele Caini
ba098e1199 any: use actual constructors to be more like std::any 2021-01-15 17:24:10 +01:00
Michele Caini
0ec755fccf meta: iterable base types as instances of meta_type 2021-01-15 14:34:27 +01:00
Michele Caini
997dd433b3 doc: type list and value list 2021-01-15 11:04:06 +01:00
Michele Caini
4aea1567db type_traits: make is_equality_comparable work with all major compilers 2021-01-15 10:37:14 +01:00
Michele Caini
446c8df3b4 type_traits: added type_list_diff[_t] 2021-01-15 08:36:22 +01:00
Michele Caini
f4bd868d6a type_traits: is_equality_comparable, support for standard containers 2021-01-14 12:56:31 +01:00
Michele Caini
8490264af3 doc: updated list for similar projects 2021-01-13 15:21:01 +01:00
Michele Caini
505cfdd193 any: detect C-style arrays and use delete[] when needed 2021-01-13 13:30:10 +01:00
Michele Caini
39ecd1545c meta: support for dereferencing pointers to functions 2021-01-13 13:14:21 +01:00
Michele Caini
9b80c0028d meta:
* implicitly generated default constructor (overridable)
* pointer-like to void support (no dereference)
2021-01-13 11:53:15 +01:00
Michele Caini
35276b55af any: support for non-copyable types 2021-01-12 16:24:18 +01:00
Michele Caini
eb63dd6227 meta: merged internal.hpp with meta.hpp 2021-01-11 15:08:44 +01:00
Michele Caini
9f24b3c584 meta: minor changes 2021-01-11 14:58:50 +01:00
Michele Caini
53e951d96d meta: removed internal::meta_range 2021-01-11 12:31:55 +01:00
Michele Caini
17dd386937 meta_any: minor changes 2021-01-11 11:53:06 +01:00
Michele Caini
3eb00382e7 meta: removed meta_base, meta_base_node is used internally when needed 2021-01-11 10:46:51 +01:00
Michele Caini
98b5f7a26a meta: removed meta_conv, meta_conv_node is used internally when needed 2021-01-11 10:34:30 +01:00
Michele Caini
fb70ec1cb0 doc: minor changes 2021-01-11 09:46:47 +01:00
Michele Caini
47ada87ba2 now working on version 3.7.0 2021-01-09 17:15:42 +01:00
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
194 changed files with 68012 additions and 22235 deletions

16
.github/FUNDING.yml vendored
View File

@@ -1,12 +1,12 @@
# These are supported funding model platforms
github: skypjack
patreon: skypjack
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
patreon:
open_collective:
ko_fi:
tidelift:
community_bridge:
liberapay:
issuehunt:
otechie:
custom: https://www.paypal.me/skypjack

View File

@@ -9,24 +9,48 @@ jobs:
strategy:
matrix:
compiler: [g++, clang++]
compiler:
- pkg: g++-7
exe: g++-7
- pkg: g++-8
exe: g++-8
- pkg: g++-9
exe: g++-9
- pkg: g++
exe: g++
- pkg: clang-8
exe: clang++-8
- pkg: clang-9
exe: clang++-9
- pkg: clang-10
exe: clang++-10
- pkg: clang
exe: clang++
id_type: [uint32, uint64]
include:
- id_type: uint64
id_type_option: -DENTT_BUILD_UINT64=ON
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install compiler
run: |
sudo apt-get update
sudo apt-get install ${{ matrix.compiler.pkg }} -y
- name: Compile tests
working-directory: build
env:
CXX: ${{ matrix.compiler }}
CXX: ${{ matrix.compiler.exe }}
run: |
cmake -DBUILD_TESTING=ON -DBUILD_LIB=ON ..
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.id_type_option }} ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 5 -C Debug -j4
run: ctest --timeout 10 -C Debug -j4
windows:
timeout-minutes: 10
@@ -34,13 +58,20 @@ jobs:
strategy:
matrix:
os: [windows-latest, windows-2016]
toolset: [clang-cl, default]
toolset: [clang-cl, default, v141]
id_type: [uint32, uint64]
include:
- toolset: clang-cl
toolset_option: -T"ClangCl"
- toolset: v141
toolset_option: -T"v141"
- id_type: uint64
id_type_option: -DENTT_BUILD_UINT64=ON
exclude:
- os: windows-2016
toolset: clang-cl
- os: windows-2016
toolset: v141
runs-on: ${{ matrix.os }}
@@ -49,16 +80,24 @@ jobs:
- name: Compile tests
working-directory: build
run: |
cmake -DBUILD_TESTING=ON -DBUILD_LIB=ON ${{ matrix.toolset_option }} ..
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.id_type_option }} ${{ 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
run: ctest --timeout 10 -C Debug -j4
macos:
timeout-minutes: 10
strategy:
matrix:
id_type: [uint32, uint64]
include:
- id_type: uint64
id_type_option: -DENTT_BUILD_UINT64=ON
runs-on: macOS-latest
steps:
@@ -66,10 +105,10 @@ jobs:
- name: Compile tests
working-directory: build
run: |
cmake -DBUILD_TESTING=ON -DBUILD_LIB=ON ..
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.id_type_option }} ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 5 -C Debug -j4
run: ctest --timeout 10 -C Debug -j4

View File

@@ -9,25 +9,30 @@ jobs:
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 -DBUILD_TESTING=ON -DBUILD_LIB=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 test/
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
env:
CXXFLAGS: "--coverage -fno-inline"
CXX: g++
run: |
cmake -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 10 -C Debug -j4
- name: Collect data
working-directory: build
run: |
sudo apt install lcov
lcov -c -d . -o coverage.info
lcov -l coverage.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: build/coverage.info
name: EnTT
fail_ci_if_error: true

View File

@@ -20,8 +20,7 @@ jobs:
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
run: git clone https://$GITHUB_ACTOR:$PERSONAL_ACCESS_TOKEN@github.com/$GITHUB_ACTOR/$GH_REPO.git
- name: Prepare formula
working-directory: build
run: |
@@ -37,4 +36,4 @@ jobs:
git config --local user.name "$GITHUB_ACTOR"
git add $FORMULA
git commit -m "Update to ${{ github.ref }}"
git push --dry-run origin master
git push origin master

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

@@ -0,0 +1,33 @@
name: sanitizer
on: [push, pull_request]
jobs:
linux:
timeout-minutes: 10
strategy:
matrix:
compiler: [clang++]
id_type: [uint32, uint64]
include:
- id_type: uint64
id_type_option: -DENTT_BUILD_UINT64=ON
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Compile tests
working-directory: build
env:
CXX: ${{ matrix.compiler }}
run: |
cmake -DENTT_USE_SANITIZER=ON -DENTT_BUILD_TESTING=ON -DENTT_BUILD_LIB=ON -DENTT_BUILD_EXAMPLE=ON ${{ matrix.id_type_option }} ..
make -j4
- name: Run tests
working-directory: build
env:
CTEST_OUTPUT_ON_FAILURE: 1
run: ctest --timeout 10 -C Debug -j4

3
.gitignore vendored
View File

@@ -5,6 +5,9 @@ conan/test_package/build
*.user
.idea
.vscode
.vs
CMakeSettings.json
cpp.hint
# Bazel
/bazel-*

View File

@@ -4,17 +4,21 @@ skypjack
# Contributors
alexames
BenediktConze
bjadamson
ceeac
ColinH
corystegel
Croydon
cugone
dbacchet
dBagrat
djarek
DonKult
drglove
eliasdaler
erez-o
eugeneko
gale83
ghost
@@ -22,13 +26,16 @@ grdowns
Green-Sky
Innokentiy-Alaytsev
Kerndog73
Koward
Lawrencemm
markand
mhammerc
Milerius
morbo84
m-waka
netpoetica
NixAJ
Oortonaut
Paolo-Oliverio
pgruenbacher
prowolf

View File

@@ -9,7 +9,6 @@ cc_library(
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

@@ -37,19 +37,19 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif()
message("*")
message("* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})")
message("* Copyright (c) 2017-2020 Michele Caini <michele.caini@gmail.com>")
message("*")
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 "*")
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(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if availbale." ON)
option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags" OFF)
#
# Compiler stuff
#
if(NOT WIN32 AND USE_LIBCPP)
if(NOT WIN32 AND ENTT_USE_LIBCPP)
include(CheckCXXSourceCompiles)
include(CMakePushCheckState)
@@ -60,10 +60,10 @@ if(NOT WIN32 AND USE_LIBCPP)
check_cxx_source_compiles("
#include<type_traits>
int main() { return std::is_same_v<int, char>; }
" HAS_LIBCPP)
" 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()
@@ -85,36 +85,44 @@ target_include_directories(
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
if(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>)
if(ENTT_USE_SANITIZER)
target_compile_options(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
target_link_libraries(EnTT INTERFACE $<$<CONFIG:Debug>:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>)
endif()
if(HAS_LIBCPP)
if(ENTT_HAS_LIBCPP)
target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++)
endif()
target_compile_features(EnTT INTERFACE cxx_std_17)
#
# Install pkg-config file
#
set(EnTT_PKGCONFIG ${CMAKE_CURRENT_BINARY_DIR}/entt.pc)
configure_file(
${EnTT_SOURCE_DIR}/cmake/in/entt.pc.in
${EnTT_PKGCONFIG}
@ONLY
)
install(
FILES ${EnTT_PKGCONFIG}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
#
# Install EnTT
#
include(CMakePackageConfigHelpers)
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(CUSTOM_INSTALL_CONFIGDIR cmake)
else()
set(CUSTOM_INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/entt)
endif()
install(TARGETS EnTT EXPORT EnTTTargets)
configure_package_config_file(
${EnTT_SOURCE_DIR}/cmake/in/EnTTConfig.cmake.in
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(
@@ -123,10 +131,22 @@ write_basic_package_version_file(
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 ${CUSTOM_INSTALL_CONFIGDIR}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake
NAMESPACE EnTT::
)
@@ -134,23 +154,28 @@ install(
FILES
${PROJECT_BINARY_DIR}/EnTTConfig.cmake
${PROJECT_BINARY_DIR}/EnTTConfigVersion.cmake
DESTINATION ${CUSTOM_INSTALL_CONFIGDIR}
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)
option(FIND_GTEST_PACKAGE "Enable finding gtest package." OFF)
option(BUILD_BENCHMARK "Build benchmark." OFF)
option(BUILD_LIB "Build lib 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)
option(ENTT_BUILD_UINT64 "Build using 64b entity identifiers" OFF)
include(CTest)
enable_testing()
add_subdirectory(test)
endif()
@@ -159,9 +184,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)
@@ -179,6 +204,7 @@ add_custom_target(
.github/workflows/build.yml
.github/workflows/coverage.yml
.github/workflows/deploy.yml
.github/workflows/sanitizer.yml
.github/FUNDING.yml
AUTHORS
CONTRIBUTING.md

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2017-2020 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

305
README.md
View File

@@ -1,23 +1,22 @@
![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)](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/v8txVr)
[![Try online](https://img.shields.io/badge/try-online-brightgreen)](https://godbolt.org/z/zxW73f)
[![Documentation](https://img.shields.io/badge/docs-docsforge-blue)](http://entt.docsforge.com/)
[![Gitter chat](https://badges.gitter.im/skypjack/entt.png)](https://gitter.im/skypjack/entt)
[![Discord channel](https://img.shields.io/discord/707607951396962417?logo=discord)](https://discord.gg/5BjPWBd)
[![Donate](https://img.shields.io/badge/donate-paypal-blue.svg)](https://www.paypal.me/skypjack)
[![Patreon](https://img.shields.io/badge/become-patron-red.svg)](https://www.patreon.com/bePatron?c=1772573)
`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 and the
[**ArcGIS Runtime SDKs**](https://developers.arcgis.com/arcgis-runtime/) by
Esri.<br/>
in [**Minecraft**](https://minecraft.net/en-us/attribution/) by Mojang, the
[**ArcGIS Runtime SDKs**](https://developers.arcgis.com/arcgis-runtime/) by Esri
and the amazing [**Ragdoll**](https://ragdolldynamics.com/).<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:
@@ -25,22 +24,21 @@ 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) and the
[discord server](https://discord.gg/5BjPWBd), meet other users like you. The
more we are, the better for everyone.<br/>
Don't forget to check the
[FAQs](https://github.com/skypjack/entt/wiki/Frequently-Asked-Questions) and the
[wiki](https://github.com/skypjack/entt/wiki) too. Your answers may already be
there.
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.
Do you want to support `EnTT`? Consider becoming a
[**sponsor**](https://github.com/users/skypjack/sponsorship).
Many thanks to [these people](https://skypjack.github.io/sponsorship/) and
**special** thanks to:
If you use `EnTT` and you want to say thanks or support the project, please
**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.
[![mojang](https://user-images.githubusercontent.com/1812216/106253145-67ca1980-6217-11eb-9c0b-d93561b37098.png)](https://mojang.com)
[![imgly](https://user-images.githubusercontent.com/1812216/106253726-271ed000-6218-11eb-98e0-c9c681925770.png)](https://img.ly/)
# Table of Contents
@@ -48,16 +46,16 @@ and still support me today.
* [Code Example](#code-example)
* [Motivation](#motivation)
* [Performance](#performance)
* [Build Instructions](#build-instructions)
* [Integration](#integration)
* [Requirements](#requirements)
* [Library](#library)
* [Documentation](#documentation)
* [Tests](#tests)
* [Packaging Tools](#packaging-tools)
* [CMake](#cmake)
* [Packaging Tools](#packaging-tools)
* [pkg-config](#pkg-config)
* [Documentation](#documentation)
* [Tests](#tests)
* [EnTT in Action](#entt-in-action)
* [Contributors](#contributors)
* [License](#license)
* [Support](#support)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@@ -85,10 +83,11 @@ Here is a brief, yet incomplete list of what it offers today:
* Views and groups to iterate entities and components and allow different access
patterns, from **perfect SoA** to fully random.
* A lot of **facilities** built on top of the entity-component system to help
the users and avoid reinventing the wheel (dependencies, snapshot, actor
class, support for **reactive systems** and so on).
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**.
* **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
@@ -100,16 +99,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` 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;
@@ -122,45 +120,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);
// ...
}
```
@@ -189,8 +178,8 @@ reasons.
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 `BUILD_BENCHMARK` option of `CMake` to `ON`, then evaluate yourself whether
you're satisfied with the results or not.
the `ENTT_BUILD_BENCHMARK` option of `CMake` to `ON`, then evaluate yourself
whether you're satisfied with the results or not.
Honestly I got tired of updating the README file whenever there is an
improvement.<br/>
@@ -210,26 +199,7 @@ new features, mainly for fun.<br/>
If you want to contribute and/or have suggestions, feel free to make a PR or
open an issue to discuss your idea.
# Build Instructions
## Requirements
To be able to use `EnTT`, users must provide a full-featured compiler that
supports at least C++17.<br/>
The requirements below are mandatory to compile the tests and to extract the
documentation:
* `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`.
## Library
# Integration
`EnTT` is a header-only library. This means that including the `entt.hpp` header
is enough to include the library as a whole and use it. For those who are
@@ -250,48 +220,33 @@ Use the line below to include only the entity-component system instead:
Then pass the proper `-I` argument to the compiler to add the `src` directory to
the include paths.
## Documentation
## Requirements
The documentation is based on [doxygen](http://www.doxygen.nl/).
To build it:
To be able to use `EnTT`, users must provide a full-featured compiler that
supports at least C++17.<br/>
The requirements below are mandatory to compile the tests and to extract the
documentation:
$ cd build
$ cmake .. -DBUILD_DOCS=ON
$ make
* `CMake` version 3.7 or later.
* `Doxygen` version 1.8 or later.
The API reference will be created in HTML format within the directory
`build/docs/html`. To navigate it with your favorite browser:
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.
$ cd build
$ your_favorite_browser docs/html/index.html
## CMake
<!--
@cond TURN_OFF_DOXYGEN
-->
It's also available [online](https://skypjack.github.io/entt/) for the latest
version, that is the last stable tag.<br/>
Moreover, there exists a [wiki](https://github.com/skypjack/entt/wiki) dedicated
to the project where users can find all related documentation pages.
<!--
@endcond TURN_OFF_DOXYGEN
-->
To use `EnTT` from a `CMake` project, just link an existing target to the
`EnTT::EnTT` alias.<br/>
The library offers everything you need for locating (as in `find_package`),
embedding (as in `add_subdirectory`), fetching (as in `FetchContent`) or using
it in many of the ways that you can think of and that involve `CMake`.<br/>
Covering all possible cases would require a treaty and not a simple README file,
but I'm confident that anyone reading this section also knows what it's about
and can use `EnTT` from a `CMake` project without problems.
## Tests
To compile and run the tests, `EnTT` requires *googletest*.<br/>
`cmake` will download and compile the library before compiling anything else.
In order to build the tests, set the CMake option `BUILD_TESTING` to `ON`.
To build the most basic set of tests:
* `$ cd build`
* `$ cmake -DBUILD_TESTING=ON ..`
* `$ make`
* `$ make test`
Note that benchmarks are not part of this set.
# Packaging Tools
## Packaging Tools
`EnTT` is available for some of the most known packaging tools. In particular:
@@ -324,7 +279,84 @@ Note that benchmarks are not part of this set.
brew install skypjack/entt/entt
```
Consider this list a work in progress and help me to make it longer.
* [`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 if you like.
## pkg-config
`EnTT` also supports `pkg-config` (for some definition of _supports_ at least).
A suitable file called `entt.pc` is generated and installed in a proper
directory when running `CMake`.<br/>
This should also make it easier to use with tools such as `Meson` or similar.
# Documentation
The documentation is based on [doxygen](http://www.doxygen.nl/). To build it:
$ cd build
$ cmake .. -DENTT_BUILD_DOCS=ON
$ make
The API reference will be created in HTML format within the directory
`build/docs/html`. To navigate it with your favorite browser:
$ cd build
$ your_favorite_browser docs/html/index.html
<!--
@cond TURN_OFF_DOXYGEN
-->
The same version is also available [online](https://skypjack.github.io/entt/)
for the latest release, that is the last stable tag. If you are looking for
something more pleasing to the eye, consider reading the nice-looking version
available on [docsforge](https://entt.docsforge.com/): same documentation, much
more pleasant to read.<br/>
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
-->
# Tests
To compile and run the tests, `EnTT` requires *googletest*.<br/>
`cmake` will download and compile the library before compiling anything else.
In order to build the tests, set the `CMake` option `ENTT_BUILD_TESTING` to
`ON`.
To build the most basic set of tests:
* `$ cd build`
* `$ cmake -DENTT_BUILD_TESTING=ON ..`
* `$ make`
* `$ make test`
Note that benchmarks are not part of this set.
<!--
@cond TURN_OFF_DOXYGEN
@@ -346,18 +378,14 @@ open an issue or a PR and I'll be glad to add them to the list.
# Contributors
`EnTT` was written initially as a faster alternative to other well known and
open source entity-component systems. Nowadays this library is moving its first
steps. Much more will come in the future and hopefully I'm going to work on it
for a long time.<br/>
Requests for features, PR, suggestions ad feedback are highly appreciated.
Requests for features, PRs, suggestions ad feedback are highly appreciated.
If you find you can help me and want to contribute to the project with your
experience or you do want to get part of the project for some other reasons,
feel free to contact me directly (you can find the mail in the
If you find you can help and want to contribute to the project with your
experience or you do want to get part of the project for some other reason, feel
free to contact me directly (you can find the mail in the
[profile](https://github.com/skypjack)).<br/>
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.
assure that I'll do my best to take them all as soon as possible.
If you decide to participate, please see the guidelines for
[contributing](CONTRIBUTING.md) before to create issues or pull
@@ -371,25 +399,12 @@ know who has participated so far.
# License
Code and documentation Copyright (c) 2017-2020 Michele Caini.<br/>
Logo Copyright (c) 2018-2020 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/).
<!--
@cond TURN_OFF_DOXYGEN
-->
# Support
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
-->

55
TODO
View File

@@ -1,33 +1,36 @@
* long term feature: shared_ptr less locator and resource cache
* custom allocators and EnTT allocator-aware in general (long term feature, I don't actually need it at the moment) - see #22
* debugging tools (#60): the issue online already contains interesting tips on this, look at it
* work stealing job system (see #100) + mt scheduler based on const awareness for types
* meta: sort of meta view based on meta stuff to iterate entities, void * and meta info objects (remove runtime views, welcome reflection)
* add opaque input iterators to views and groups that return tuples <entity, T &...> (proxy), multi-pass guaranteed
* allow to replace std:: with custom implementations
* custom (decoupled) pools ==> N-buffering, shared components, multi-model, hibitsets, and so on
* add examples (and credits) from @alanjfs :)
* static reflection, hint: template<> meta_type_t<Type>: meta_descriptor<name, func..., props..., etc...> (see #342)
* observer: user defined filters (eg .replace<T, &function> or .group<T, U, &func>)
* can we write a bool conv func for entt::entity that silently compares it to null?
* reset... reset everywhere...
* is it possible to make 0 the entity null?
* document undocumented parts (entt::overload and a few others)
* any-of rule for views/groups (eg entity has A and any of B/C/D)
- get -> all, exclude -> none
* review prepare after clone and the others have been removed
* unlock deploy.yml
* custom pools example (multi instance, tables, enable/disable, and so on...)
Next:
* review pool<T>::remove, ::assign
* replace observer class with observer functions
* workflow to update the single include file automatically
* workflow to update the doc automatically
WIP:
* remove view/storage dispatcher, add support to relax policy constraints on user request (eg view.use<T>())
* improve perf for sparse_set/storage::insert/emplace/destroy/remove/...
* custom allocators all over
* WIP:
- deprecate snapshot, loader, ...
- provide documentation to describe alternatives
* WIP: snapshot rework/deprecation
- remove snapshot/loader from registry, make them external (faster) tools
- deprecate snapshot classes, update documentation to describe alternatives
WIP:
* make value_type available from meta container types, otherwise we have to default construct a container to get it
* make it possible to register externally managed pools with the registry (allow for system centric mode)
* registry: switch to the udata/mixin model and get rid of poly storage, use pointer to sparse set only for pools, discard pool_data type.
* it's now possible to have 0 as null entity/version, so we can finally switch to it
* make pools available (registry/view/group), review operator| for views
* page size: add per-pool size, allow for 0 sizes (old fully packed array)
* compressed pair to exploit ebo in sparse set and the others
* isolate view iterator, unwrap iterators in registry ::remove/::erase/::destroy to use the faster solution for non-view iterators
* remove view each<T>(F), each<T>(), make view::use return a view and remove the mutable data member
* resource, forward the id to the loader from the cache and if constexpr the call to load, update doc and describe customization points
* make it possible to create views of the type `view<T, T>`, add get by index and such, allow to register custom pools by name with the registry
* add user data to type_info
* any_vector for context variables
* make const registry::view thread safe, switch to a view<T...>{registry} model (long term goal)
* weak reference wrapper example with custom storage
* headless (sparse set only) view
* write documentation for custom storages and views!!
* make runtime views use opaque storage and therefore return also elements.
* add exclude-only views to combine with packs
* entity-aware observer, add observer functions aside observer class
* deprecate non-owning groups in favor of owning views and view packs, introduce lazy owning views
* snapshot: support for range-based archives
* add example: 64 bit ids with 32 bits reserved for users' purposes

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@")

8
cmake/in/entt.pc.in Normal file
View File

@@ -0,0 +1,8 @@
prefix=@CMAKE_INSTALL_PREFIX@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
Name: EnTT
Description: Gaming meets modern C++
Url: https://github.com/skypjack/entt
Version: @ENTT_VERSION@
Cflags: -I${includedir}

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

@@ -16,6 +16,7 @@ add_custom_target(
VERBATIM
SOURCES
dox/extra.dox
md/config.md
md/core.md
md/entity.md
md/faq.md
@@ -23,9 +24,12 @@ add_custom_target(
md/links.md
md/locator.md
md/meta.md
md/poly.md
md/process.md
md/reference.md
md/resource.md
md/signal.md
md/unreal.md
doxy.in
)

View File

@@ -1,4 +1,4 @@
# Doxyfile 1.8.16
# Doxyfile 1.9.1
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@@ -217,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.
@@ -253,12 +261,6 @@ TAB_SIZE = 4
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
@@ -299,19 +301,22 @@ OPTIMIZE_OUTPUT_SLICE = NO
# 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,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
# 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), VHDL, tcl. 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.
# 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.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen.
# the files are not read by doxygen. When specifying no_extension you should add
# * to the FILE_PATTERNS.
#
# Note see also the list of default file extension mappings.
EXTENSION_MAPPING =
@@ -445,6 +450,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
#---------------------------------------------------------------------------
@@ -508,6 +526,13 @@ EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
# If this flag is set to YES, the name of an unnamed parameter in a declaration
# will be determined by the corresponding definition. By default unnamed
# parameters remain unnamed in the output.
# The default value is: YES.
RESOLVE_UNNAMED_PARAMS = YES
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
@@ -525,8 +550,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
@@ -545,11 +570,18 @@ HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
# names in lower-case letters. If set to YES, upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# (including Cygwin) ands Mac users are advised to set this option to NO.
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
# able to match the capabilities of the underlying filesystem. In case the
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# The default value is: system dependent.
CASE_SENSE_NAMES = YES
@@ -788,7 +820,10 @@ WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered.
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# The default value is: NO.
WARN_AS_ERROR = NO
@@ -826,8 +861,8 @@ INPUT = @DOXY_SOURCE_DIRECTORY@ \
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
# possible encodings.
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
@@ -840,11 +875,15 @@ INPUT_ENCODING = UTF-8
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
# *.m, *.markdown, *.md, *.mm, *.dox (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 \
@@ -1062,16 +1101,22 @@ USE_HTAGS = NO
VERBATIM_HEADERS = YES
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
# cost of reduced performance. This can be particularly helpful with template
# rich C++ code for which doxygen's built-in parser lacks the necessary type
# information.
# clang parser (see:
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# performance. This can be particularly helpful with template rich C++ code for
# which doxygen's built-in parser lacks the necessary type information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
CLANG_ASSISTED_PARSING = NO
# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
# YES then doxygen will add the directory of each input to the include path.
# The default value is: YES.
CLANG_ADD_INC_PATHS = YES
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
@@ -1081,10 +1126,13 @@ CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS =
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the 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.
# 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.
@@ -1101,13 +1149,6 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = YES
# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
# which the alphabetical index list will be split.
# Minimum value: 1, maximum value: 20, default value: 5.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
@@ -1246,9 +1287,9 @@ 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
# 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,
# 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.
@@ -1278,10 +1319,11 @@ HTML_INDEX_NUM_ENTRIES = 100
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see: https://developer.apple.com/xcode/), introduced with OSX
# 10.5 (Leopard). To create a documentation set, doxygen will generate a
# Makefile in the HTML output directory. Running make will produce the docset in
# that directory and running make install will install the docset in
# environment (see:
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
# create a documentation set, doxygen will generate a Makefile in the HTML
# output directory. Running make will produce the docset in that directory and
# running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information.
@@ -1323,8 +1365,8 @@ DOCSET_PUBLISHER_NAME = Publisher
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
# (see:
# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
@@ -1354,7 +1396,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.
@@ -1399,7 +1441,8 @@ QCH_FILE =
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1407,8 +1450,8 @@ QHP_NAMESPACE = org.doxygen.Project
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
# folders).
# Folders (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
@@ -1416,16 +1459,16 @@ QHP_VIRTUAL_FOLDER = doc
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
# filters).
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
@@ -1437,9 +1480,9 @@ QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
# The QHG_LOCATION tag can be used to specify the location of Qt's
# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
# generated .qhp file.
# The QHG_LOCATION tag can be used to specify the location (absolute path
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
# run qhelpgenerator on the generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
@@ -1516,6 +1559,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
@@ -1536,8 +1590,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
# https://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
@@ -1549,7 +1609,7 @@ USE_MATHJAX = NO
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see:
# http://docs.mathjax.org/en/latest/output.html) for more details.
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
# Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS.
@@ -1565,7 +1625,7 @@ MATHJAX_FORMAT = HTML-CSS
# 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 https://www.mathjax.org before deployment.
# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
# 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 = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/
@@ -1579,7 +1639,8 @@ MATHJAX_EXTENSIONS =
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
# (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
@@ -1607,7 +1668,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
@@ -1626,7 +1687,8 @@ SERVER_BASED_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/).
# Xapian (see:
# https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
@@ -1639,8 +1701,9 @@ EXTERNAL_SEARCH = NO
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see: https://xapian.org/). See the section "External Indexing and
# Searching" for details.
# Xapian (see:
# https://xapian.org/). See the section "External Indexing and Searching" for
# details.
# This tag requires that the tag SEARCHENGINE is set to YES.
SEARCHENGINE_URL =
@@ -1804,9 +1867,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.
@@ -2100,7 +2165,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
@@ -2317,10 +2382,32 @@ UML_LOOK = NO
# but if the number exceeds 15, the total amount of fields shown is limited to
# 10.
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
# This tag requires that the tag UML_LOOK is set to YES.
UML_LIMIT_NUM_FIELDS = 10
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
# tag is set to YES, doxygen will add type and arguments for attributes and
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
# will not generate fields with class member information in the UML graphs. The
# class diagrams will look similar to the default class diagrams but using UML
# notation for the relationships.
# Possible values are: NO, YES and NONE.
# The default value is: NO.
# This tag requires that the tag UML_LOOK is set to YES.
DOT_UML_DETAILS = NO
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_WRAP_THRESHOLD = 17
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
# instances.
@@ -2512,9 +2599,11 @@ DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
# files that are used to generate the various graphs.
#
# Note: This setting is not only used for dot files but also for msc and
# plantuml temporary files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES

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

@@ -0,0 +1,111 @@
# Crash Course: configuration
<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents
* [Introduction](#introduction)
* [Definitions](#definitions)
* [ENTT_NOEXCEPTION](#entt_noexcept)
* [ENTT_USE_ATOMIC](#entt_use_atomic)
* [ENTT_ID_TYPE](#entt_id_type)
* [ENTT_SPARSE_PAGE](#entt_sparse_page)
* [ENTT_PACKED_PAGE](#entt_packed_page)
* [ENTT_ASSERT](#entt_assert)
* [ENTT_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_NOEXCEPTION
This parameter can be used to switch off exception handling in `EnTT`.<br/>
To do this, simply define the variable without assigning any value to it. This
is roughly equivalent to setting the compiler flag `-ff-noexceptions`.
## 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_SPARSE_PAGE
It's known that the ECS module of `EnTT` is based on _sparse sets_. What is less
known perhaps is that the sparse arrays are paged to reduce memory usage.<br/>
Default size of pages (that is, the number of elements they contain) is 4096 but
users can adjust it if appropriate. In all case, the chosen value **must** be a
power of 2.
## ENTT_PACKED_PAGE
Similar to sparse arrays, packed arrays of components are paginated as well. In
However, int this case the aim isn't to reduce memory usage but to have pointer
stability upon component creation.<br/>
Default size of pages (that is, the number of elements they contain) is 1024 but
users can adjust it if appropriate. In all case, the chosen value **must** be a
power of 2.
## ENTT_ASSERT
For performance reasons, `EnTT` doesn't use exceptions or any other control
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,17 +6,28 @@
# 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)
* [Type info](#type-info)
* [Almost unique identifiers](#almost-unique-identifiers)
* [Traits](#traits)
* [Member class type](#member-class-type)
* [Tags](#tags)
* [Any as in any type](#any-as-in-any-type)
* [Small buffer optimization](#small-buffer-optimization)
* [Alignment requirement](#alignment-requirement)
* [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)
* [Type list and value list](#type-list-and-value-list)
* [Utilities](#utilities)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@@ -28,19 +39,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>;
@@ -58,14 +70,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 {};
@@ -77,35 +89,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
@@ -114,7 +121,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.
@@ -133,9 +141,31 @@ 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`.
@@ -147,7 +177,7 @@ In this case, the user defined literal to use to create hashed strings on the
fly is `_hws`:
```cpp
constexpr auto str = "text"_hws;
constexpr auto str = L"text"_hws;
```
Note that the hash type of the `hashed_wstring` is the same of its counterpart.
@@ -188,66 +218,299 @@ const bool b = entt::monostate<"mykey"_hs>{};
const int i = entt::monostate<entt::hashed_string{"mykey"}>{};
```
# Type info
# Any as in any type
The `type_info` class template is meant to provide some basic information about
types of all kinds.<br/>
Currently, the only information available is the numeric identifier associated
with a given 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
auto id = entt::type_info<my_type>::id();
// 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};
```
In general, the `id` function is also `constexpr` but this isn't guaranteed for
all compilers and platforms (although it's valid with the most well-known and
popular compilers).<br/>
This function **can** use non-standard features of the language for its own
purposes. This allows it to provide compile-time identifiers that remain stable
between different runs. However, it's possible to force the use of standard
features only by defining the macro `ENTT_STANDARD_CPP`. In this case, there is
no guarantee that the identifiers are stable across executions though. Moreover,
identifiers are generated at runtime and are no longer a compile-time thing.
An external type system can also be used if needed. In fact, `type_info` can be
specialized by type and is also _sfinae-friendly_ in order to allow more refined
specializations such as:
Alternatively, the `make_any` function serves the same purpose but requires to
always be explicit about the type:
```cpp
template<typename Type>
struct entt::type_info<Type, std::void_d<decltype(Type::custom_id())>> {
static constexpr ENTT_ID_TYPE id() ENTT_NOEXCEPT {
return Type::custom_id();
}
};
entt::any any = entt::make_any<int>(42);
```
Note that this class template and its specializations are widely used within
`EnTT`. It also plays a very important role in making `EnTT` work transparently
across boundaries.<br/>
Please refer to the dedicated section for more details.
In both cases, the `any` class takes the burden of destroying the contained
element when required, regardless of the storage strategy used for the specific
object.<br/>
Furthermore, an instance of `any` is not tied to an actual type. Therefore, the
wrapper will be reconfigured by assigning it an object of a different type than
the one contained, so as to be able to handle the new instance.<br/>
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:
## Almost unique identifiers
```cpp
if(any == empty) { /* ... */ }
```
Since the default non-standard, compile-time implementation makes use of hashed
strings, it may happen that two types are assigned the same numeric
identifier.<br/>
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;
entt::any any{std::in_place_type<int &>(value)};
entt::any cany = entt::make_any<const int &>(value);
entt::any fwd = entt::forward_as_any(value);
any.emplace<const int &>(value);
```
In other words, whenever `any` is explicitly told to construct an _alias_, it
acts as a pointer to the original instance rather than making a copy of it or
moving it internally. The contained object is never destroyed and users must
ensure that its lifetime exceeds that of the container.<br/>
Similarly, it's possible to create non-owning copies of `any` from an existing
object:
```cpp
// aliasing constructor
entt::any ref = other.as_ref();
```
In this case, it doesn't matter if the original container actually holds an
object or 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.
## Small buffer optimization
The `any` class uses a technique called _small buffer optimization_ to reduce
the number of allocations where possible.<br/>
The default reserved size for an instance of `any` is `sizeof(double[2])`.
However, this is also configurable if needed. In fact, `any` is defined as an
alias for `basic_any<Len>`, where `Len` is the size above.<br/>
Users can easily set a custom size or define their own aliases:
```cpp
using my_any = entt::basic_any<sizeof(double[4])>;
```
This feature, in addition to allowing the choice of a size that best suits the
needs of an application, also offers the possibility of forcing dynamic creation
of objects during construction.<br/>
In other terms, if the size is 0, `any` avoids the use of any optimization and
always dynamically allocates objects (except for aliasing cases).
Note that the size of the internal storage as well as the alignment requirements
are directly part of the type and therefore contribute to define different types
that won't be able to interoperate with each other.
## Alignment requirement
The alignment requirement is optional and by default the most stringent (the
largest) for any object whose size is at most equal to the one provided.<br/>
The `basic_any` class template inspects the alignment requirements in each case,
even when not provided and may decide not to use the small buffer optimization
in order to meet them.
The alignment requirement is provided as an optional second parameter following
the desired size for the internal storage:
```cpp
using my_any = entt::basic_any<sizeof(double[4]), alignof(double[4])>;
```
Note that the alignment requirements as well as the size of the internal storage
are directly part of the type and therefore contribute to define different types
that won't be able to interoperate with each other.
# 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.<br/>
Since the default model is based on the name of the classes, if the types belong
to the same namespace then their identifiers _could_ be identical (they won't
necessarily be the same though).
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. Note that
runtime identifiers don't suffer from the sam problem. However, this solution
* 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_info` class for one of the
* 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.
@@ -260,12 +523,58 @@ 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.
# Traits
## Type traits
This section contains a handful of utilities and traits not present in the
standard template library but which can be useful in everyday life.
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.
## Member class type
### 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
@@ -277,20 +586,131 @@ template<typename Member>
using clazz = entt::member_class_t<Member>;
```
## Tags
### Integral constant
Since in `EnTT` the type identified by `ENTT_ID_TYPE` is very important and
widely used, there is a more user-friendly shortcut for the creation of integral
constants based on it.<br/>
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.assign<entt::tag<"enemy"_hs>>(entity);
registry.emplace<entt::tag<"enemy"_hs>>(entity);
```
However, this isn't the only permitted use. Literally any value convertible to
`ENTT_ID_TYPE` is a good candidate, such as the named constants of an unscoped
enum.
`id_type` is a good candidate, such as the named constants of an unscoped enum.
### Type list and value list
There is no respectable library where the much desired _type list_ can be
missing.<br/>
`EnTT` is no exception and provides (making extensive use of it internally) the
`type_list` type, in addition to its `value_list` counterpart dedicated to
non-type template parameters.
Here is a (possibly incomplete) list of the functionalities that come with a
type list:
* `type_list_element[_t]` to get the N-th element of a type list.
* `type_list_cast[_t]` and a handy `operator+` to concatenate type lists.
* `type_list_unique[_t]` to remove duplicate types from a type list.
* `type_list_contains[_v]` to know if a type list contains a given type.
* `type_list_diff[_t]` to remove types from type lists.
I'm also pretty sure that more and more utilities will be added over time as
needs become apparent.<br/>
Many of these functionalities also exist in their version dedicated to value
lists. We therefore have `value_list_element[_v]` as well as
`value_list_cat[_t]`and so on.
# 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

@@ -13,6 +13,7 @@
* [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
-->
@@ -76,49 +77,30 @@ not different techniques depending on how the data are laid out.
I tried to describe some of the techniques that fit well with the model of
`EnTT`. [Here](https://skypjack.github.io/2019-06-25-ecs-baf-part-4/) is the
first post of a series that tries to explore the problem. More will probably
come in future.
Long story short, you can always define a tree where the nodes expose implicit
lists of children by means of the following type:
```cpp
struct relationship {
std::size_t children{};
entt::entity first{entt::null};
entt::entity prev{entt::null};
entt::entity next{entt::null};
entt::entity parent{entt::null};
// ... other data members ...
};
```
The sort functionalities of `EnTT`, the groups and all the other features of the
library can help then to get the best in terms of data locality and therefore
performance from this component.
come in future.<br/>
In addition, `EnTT` also offers the possibility to create stable storage types
and therefore have pointer stability for one, all or some components. This is by
far the most convenient solution when it comes to creating hierarchies and
whatnot. See the documentation for the ECS part of the library and in particular
what concerns the `component_traits` class for further details.
## Custom entity identifiers: yay or nay?
Custom entity identifiers are definitely a good idea in two cases at least:
* If `std::uint32_t` isn't large enough as an underlying type.
* If `std::uint32_t` isn't large enough for your purposes, since this is the
underlying type of `entt::entity`.
* If you want to avoid conflicts when using multiple registries.
These identifiers are nothing more than enum classes with some salt.<br/>
To simplify the creation of new identifiers, `EnTT` provides the macro
`ENTT_OPAQUE_TYPE` that accepts two arguments:
* The name you want to give to the new identifier (watch out for namespaces).
* The underlying type to use (either `std::uint16_t`, `std::uint32_t`
or `std::uint64_t`).
In fact, this is the definition of `entt::entity`:
Identifiers can be defined through enum classes and class types that define an
`entity_type` member of type `std::uint32_t` or `std::uint64_t`.<br/>
In fact, this is a definition equivalent to that of `entt::entity`:
```cpp
ENTT_OPAQUE_TYPE(entity, std::uint32_t)
enum class entity: std::uint32_t {};
```
The use of this macro is highly recommended, so as not to run into problems if
the requirements for the identifiers should change in the future.
There is no limit to the number of identifiers that can be defined.
## Warning C4307: integral constant overflow
@@ -132,7 +114,7 @@ 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}\
#define HS(str) __pragma(warning(suppress:4307)) entt::hashed_string{str}
#else
#define HS(str) entt::hashed_string{str}
#endif
@@ -198,3 +180,24 @@ struct type {
```
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,46 +5,70 @@
-->
# Table of Contents
* [Introduction](#introduction)
* [The EnTT way](#the-entt-way)
* [Meta context](#meta-context)
* [Memory management](#memory-management)
* [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 was mainly due to a custom utility used to assign unique, sequential
identifiers to different types.<br/>
Fortunately, nowadays using `EnTT` across boundaries is straightforward. In
fact, everything just works transparently in almost all cases. There are only a
few exceptions, easy to deal with anyway.
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.
# The EnTT way
## The EnTT way
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_info` class template is how identifiers are generated and thus made
available to the rest of the library.
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.
In general, this class doesn't arouse much interest. The only exception is in
case of conflicts between identifiers (definitely uncommon though) or where the
default solution proposed by `EnTT` isn't suitable for the user's purposes.<br/>
The section dedicated to this core class contains all the details to get around
the problem in a concise and elegant way. Please refer to the specific
documentation.
In general, these classes don't arouse much interest. The only exceptions are:
# Meta context
* 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 to a static context to which the visible components are
attached and different contexts don't relate to each other, they must be
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
@@ -67,7 +91,7 @@ attached the new visible meta types, no matter where they are created.<br/>
A context can also be reset and then associated again locally as:
```cpp
entt::meta_ctx::bind{entt::meta_ctx{});
entt::meta_ctx::bind(entt::meta_ctx{});
```
This is allowed because local and global contexts are separated. Therefore, it's
@@ -78,7 +102,7 @@ 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.
# Memory Management
## Memory Management
There is another subtle problem due to memory management that can lead to
headaches.<br/>

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,10 +17,21 @@ 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.
* [Land of the Rair](https://github.com/LandOfTheRair/core2): the new backend
of [a retro-style MUD](https://rair.land/) for the new age.
* [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
@@ -32,8 +43,8 @@ I hope this list can grow much more in the future:
* [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](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
@@ -52,22 +63,41 @@ I hope this list can grow much more in the future:
football game.
* [DungeonSlayer](https://github.com/alohaeee/DungeonSlayer): 2D game made
from scratch in C++.
* [3DGame](https://github.com/kwarkGorny/3DGame): 2.5D top-down space shooter.
* [Pulcher](https://github.com/AODQ/pulcher): 2D cross-platform game inspired
by Quake.
* [Destroid](https://github.com/tyrannicaltoucan/destroid): _one-bazillionth_
arcade game about shooting dirty rocks in space, inspired by Asteroids.
* [Wanderer](https://github.com/albin-johansson/wanderer): a 2D exploration
based indie game.
* [Spelunky® Classic remake](https://github.com/dbeef/spelunky-psp): A truly
multiplatform experience with a rewrite from scratch.
* 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.
* [NovusCore](https://github.com/novuscore/NovusCore): a modern take on World
of Warcraft emulation.
* [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
@@ -76,13 +106,41 @@ I hope this list can grow much more in the future:
developed for educational purposes.
* [Lumos](https://github.com/jmorton06/Lumos): game engine written in C++
using OpenGL and Vulkan.
* [Chrysalis](https://github.com/ivanhawkes/Chrysalis): action RPG SDK for
CRYENGINE games.
* [Silvanus](https://github.com/hobbyistmaker/silvanus): Silvanus Fusion 360
Box Generator.
* [Lina Engine](https://github.com/inanevin/LinaEngine): an open-source,
modular, tiny and fast C++ game engine, aimed to develop 3D desktop games.
* [Spike](https://github.com/FahimFuad/Spike): a powerful game engine which
can run on a toaster.
* [Helena Framework](https://github.com/NIKEA-SOFT/HelenaFramework): a modern
framework in C++17 for backend development.
* [Unity/EnTT](https://github.com/TongTungGiang/unity-entt): tech demo of a
native simulation layer using `EnTT` and `Unity` as a rendering engine.
* 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
@@ -94,27 +152,46 @@ I hope this list can grow much more in the future:
* [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 about the process followed and the results of the integration
of `EnTT` into `Chrysalis`.
a blog entry (and its
[follow-up](https://www.tauradius.com/post/chrysalis-update-2020-08-02/))
about the integration of `EnTT` into `Chrysalis`, an action RPG SDK for
CRYENGINE games.
* [Creating Minecraft in One Week with C++ and Vulkan](https://vazgriz.com/189/creating-minecraft-in-one-week-with-c-and-vulkan/):
a crack at recreating Minecraft in one week using a custom C++ engine and
Vulkan ([code included](https://github.com/vazgriz/VoxelGame)).
* [Ability Creator](https://www.erichildebrand.net/blog/ability-creator-project-retrospect):
project retrospect by [Eric Hildebrand](https://www.erichildebrand.net/).
* [EnTT Entity Component System Gaming Library](https://gamefromscratch.com/entt-entity-component-system-gaming-library/):
`EnTT` on GameFromScratch.com.
* 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).
* [Sequentity](https://github.com/alanjfs/sequentity): A MIDI-like
sequencer/tracker for C++ and `ImGui` (with `Magnum` and `EnTT`).
* [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/).

View File

@@ -8,8 +8,12 @@
* [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)
* [Any to the rescue](#any-to-the-rescue)
* [Enjoy the runtime](#enjoy-the-runtime)
* [Container support](#container-support)
* [Pointer-like types](#pointer-like-types)
* [Template information](#template-information)
* [Implicitly generated default constructor](#implicitly-generated-default-constructor)
* [Policies: the more, the less](#policies-the-more-the-less)
* [Named constants and enums](#named-constants-and-enums)
* [Properties and meta objects](#properties-and-meta-objects)
@@ -20,15 +24,15 @@
# Introduction
Reflection (or rather, its lack) is a trending topic in the C++ world and, in
the specific case of `EnTT`, a tool that can unlock a lot of other features. I
Reflection (or rather, its lack) is a trending topic in the C++ world and a tool
that can unlock a lot of interesting feature in the specific case of `EnTT`. I
looked for a third-party library that met my needs on the subject, but I always
came across some details that I didn't like: macros, being intrusive, too many
allocations. In one word: unsatisfactory.<br/>
allocations, and so on.<br/>
I finally decided to write a built-in, non-intrusive and macro-free runtime
reflection system for `EnTT`. Maybe I didn't do better than others or maybe yes,
time will tell me, but at least I can model this tool around the library to
which it belongs and not vice versa.
which it belongs and not the opposite.
# Names and identifiers
@@ -40,9 +44,9 @@ 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.
However, the examples in the following sections are all based on the
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
identifier is required, it's likely that an user defined literal is used as
follows:
```cpp
@@ -78,18 +82,21 @@ type. In order to make the type _visible_, users can assign it an identifier:
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
```
When working with named types, it isn't even necessary to specify the
identifier. In fact, it isn't allowed and it will trigger a compilation
error.<br/>
Identifiers are important because users can retrieve meta types at runtime by
searching for them by _name_ other than by type. 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 allow searching the type by _name_. In this case, it's sufficient not
to invoke `type` and the type will not be searchable _by name_.
Or use the default one, that is, the built-in identifier for the given 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:
```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 return the factory itself or a
decorated version of it. This object can be used to add the following:
* _Constructors_. Actual constructors can be assigned to a reflected type by
specifying their list of arguments. Free functions (namely, factories) can be
@@ -116,8 +123,8 @@ a decorated version of it. This object can be used to add the following:
* _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
@@ -127,18 +134,24 @@ a decorated version of it. This object can be used to add the following:
.data<&global_variable>("global"_hs);
```
This function requires as an argument the identifier to give to the meta data
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 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/>
Data members can also be defined by means of a setter and getter pair. Setters
and getters can be either free functions, class members or a mix of them, as
long as they respect the required signatures. This approach is also convenient
to create a read-only variable from a non-const data member:
```cpp
entt::meta<my_type>().data<nullptr, &my_type::data_member>("member"_hs);
```
Refer to the inline documentation for all the details.
* _Member functions_. Both real member functions of the underlying type and free
functions can be attached to a meta type. From 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
@@ -148,9 +161,11 @@ a decorated version of it. This object can be used to add the following:
.func<&free_function>("free"_hs);
```
This function requires as an argument the identifier to give to the meta
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_.
searching for them by _name_.<br/>
Overloading of meta functions is supported. Overloaded functions are resolved
at runtime by the reflection system according to the types of the arguments.
* _Base classes_. A base class is such that the underlying type is actually
derived from it. In this case, the reflection system tracks the relationship
@@ -181,100 +196,67 @@ 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.
The class `meta_any` offers 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 through the reflection system, allocations are at zero.
Creating instances of `meta_any`, whether empty or from existing objects, is
trivial:
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 with `forward_as_meta` or using the `std::in_place_type<T &>`
disambiguation tag, as well as from an existing object by means of the `as_ref`
member function. However, unlike `any`, `meta_any` treats an empty instance and
one initialized with `void` differently:
```cpp
// a container for an int
entt::meta_any any{0};
// an empty container
entt::meta_any empty{};
entt::meta_any other{std::in_place_type<void>};
```
The `meta_any` class takes also the burden of destroying the contained object
when required.<br/>
Furthermore, an instance of `meta_any` is not tied to a specific 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.
A particularly interesting feature of this class is that it can also be used as
an opaque container for unmanaged objects:
```cpp
int value;
entt::meta_any any{std::ref(value)};
```
In other words, whenever `meta_any` intercepts a `reference_wrapper`, it acts as
a reference to the original instance rather than making a copy of it. The
contained object is never destroyed and users must ensure that its lifetime
exceeds that of the container.<br/>
Similarly, to create a copy that works as a light reference for the managed
object, it's possible to dereference a given `meta_any`:
```cpp
entt::meta_any ref = *any;
```
It doesn't matter if the starting container actually holds an object or acts 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/>
It means that, starting from the example above, both `ref` and` any` will point
to the same object, whether it's initially contained in `any` or already an
unmanaged one. This is particularly useful for passing instances of `meta_any`
belonging to the external context by reference to a function or a constructor
rather than making copies of them.
The `meta_any` class has also a `type` member function that returns the meta
type of the contained value, if any. The member functions `try_cast`, `cast` and
`convert` are then used to know if the underlying object has a given type as a
base or if it can be converted implicitly to it.
While `any` considers both as empty, `meta_any` treats objects initialized with
`void` as if they were _valid_ ones. This allows to differentiate between failed
function calls and function calls that are successful but return nothing.<br/>
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
Once the web of reflected types has been constructed, it's a matter of using it
at runtime where required.<br/>
All this has the great merit that, 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.
All this has the great merit that the reflection system stands in fact as a
non-intrusive tool for the runtime, unlike the vast majority of the things
offered by this library and closely linked to the compile-time.
To search for a reflected type there are 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"_hs);
// look up a reflected type by identifier
auto by_id = entt::resolve("reflected_type"_hs);
// look up a reflected type by type info
auto by_type_id = entt::resolve(entt::type_id<my_type>());
```
There 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 kind of
@@ -330,24 +312,8 @@ The meta objects that compose a meta type are accessed in the following ways:
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 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.
* _Meta conversion functions_. They are accessed by type:
```cpp
auto conv = entt::resolve<double>().conv<int>();
```
The returned type is `meta_conv` and may be invalid if there is no meta
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
types.
The returned type is `meta_type` and may be invalid if there is no meta base
object associated with the given identifier.
All the objects thus obtained as well as the meta types can be explicitly
converted to a boolean value to check if they are valid:
@@ -358,13 +324,13 @@ if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
}
```
Furthermore, all meta objects 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 ranges of top-level elements. As an example:
```cpp
entt::resolve<my_type>().data([](auto data) {
for(auto data = entt::resolve<my_type>().data()) {
// ...
});
}
```
A meta type can be used to `construct` actual instances of the underlying
@@ -375,12 +341,12 @@ 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.
member function in its API. Destructors are invoked implicitly by `meta_any`
behind the scenes and users have not to deal with them explicitly. Furthermore,
they have no name, cannot be searched and wouldn't have member functions to
expose anyway.<br/>
Similarly, conversion functions aren't directly accessible. They are used
internally by `meta_any` and the meta objects when needed.
Meta types and meta objects in general contain much more than what is said: a
plethora of functions in addition to those listed whose purposes and uses go
@@ -388,9 +354,403 @@ unfortunately beyond the scope of this document.<br/>
I invite anyone interested in the subject to look at the code, experiment and
read the inline documentation to get the best out of this powerful tool.
## Container support
The runtime reflection system also supports containers of all types.<br/>
Moreover, _containers_ doesn't necessarily mean those offered by the C++
standard library. In fact, user defined data structures can also work with the
meta system in many cases.
To make a container be recognized as such by the meta system, users are required
to provide specializations for either the `meta_sequence_container_traits` class
or the `meta_associative_container_traits` class, according 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 = entt::forward_as_meta(vec);
if(any.type().is_sequence_container()) {
if(auto view = any.as_sequence_container(); view) {
// ...
}
}
```
The method to use to get a proxy object for associative containers is
`as_associative_container` instead.<br/>
It 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 minimal but likely sufficient to satisfy all needs.
## Pointer-like types
As with containers, it's also possible to communicate to the meta system which
types to consider _pointers_. This will allow to dereference instances of
`meta_any`, thus obtaining light _references_ to the pointed objects that are
also correctly associated with their meta types.<br/>
To make the meta system recognize a type as _pointer-like_, users can specialize
the `is_meta_pointer_like` class. `EnTT` already exports the specializations for
some common classes. In particular:
* All types of raw pointers.
* `std::unique_ptr` and `std::shared_ptr`.
It's important to include the header file `pointer.hpp` to make these
specializations available to the compiler when needed.<br/>
The same file also contains many examples for the users that are interested in
making their own pointer-like types available to the meta system.
When a type is recognized as a pointer-like one by the meta system, it's
possible to dereference the instances of `meta_any` that contain these objects.
The following is a deliberately verbose example to show how to use this feature:
```cpp
int value = 42;
// meta type equivalent to that of int *
entt::meta_any any{&value};
if(any.type().is_pointer_like()) {
// meta type equivalent to that of int
if(entt::meta_any ref = *any; ref) {
// ...
}
}
```
Of course, it's not necessary to perform a double check. Instead, it's enough to
query the meta type or verify that the returned object is valid. For example,
invalid instances are returned when the wrapped object isn't a pointer-like
type.<br/>
Note that dereferencing a pointer-like object returns an instance of `meta_any`
which refers to the pointed object and allows users to modify it directly
(unless the returned element is const, of course).
In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However,
`EnTT` also supports classes that don't offer an `operator*`. In particular:
* It's possible to exploit a solution based on ADL lookup by offering a function
(also a template one) named `dereference_meta_pointer_like`:
```cpp
template<typename Type>
Type & dereference_meta_pointer_like(const custom_pointer_type<Type> &ptr) {
return ptr.deref();
}
```
* When not in control of the type's namespace, it's possible to inject into the
`entt` namespace a specialization of the `adl_meta_pointer_like` class
template to bypass the adl lookup as a whole:
```cpp
template<typename Type>
struct entt::adl_meta_pointer_like<custom_pointer_type<Type>> {
static decltype(auto) dereference(const custom_pointer_type<Type> &ptr) {
return ptr.deref();
}
};
```
In all other cases, that is, when dereferencing a pointer works as expected and
regardless of the pointed type, no user intervention is required.
## Template information
Meta types also provide a minimal set of information about the nature of the
original type in case it's a class template.<br/>
By default, this works out of the box and requires no user action. However, it's
important to include the header file `template.hpp` to make these information
available to the compiler when needed.
Meta template information are easily found:
```cpp
// this method returns true if the type is recognized as a class template specialization
if(auto type = entt::resolve<std::shared_ptr<my_type>>(); type.is_template_specialization()) {
// meta type of the class template conveniently wrapped by entt::meta_class_template_tag
auto class_type = type.template_type();
// number of template arguments
std::size_t arity = type.template_arity();
// meta type of the i-th argument
auto arg_type = type.template_arg(0u);
}
```
Typically, when template information for a type are required, what the library
provides is sufficient. However, there are some cases where a user may want more
details or a different set of information.<br/>
Consider the case of a class template that is meant to wrap function types:
```cpp
template<typename>
struct function_type;
template<typename Ret, typename... Args>
struct function_type<Ret(Args...)> {};
```
In this case, rather than the function type, the user might want the return type
and unpacked arguments as if they were different template parameters for the
original class template.<br/>
To achieve this, users must enter the library internals and provide their own
specialization for the class template `entt::meta_template_traits`, such as:
```cpp
template<typename Ret, typename... Args>
struct entt::meta_template_traits<function_type<Ret(Args...)>> {
using class_type = meta_class_template_tag<function_type>;
using args_type = type_list<Ret, Args...>;
};
```
The reflection system doesn't verify the accuracy of the information nor infer a
correspondence between real types and meta types.<br/>
Therefore, the specialization will be used as is and the information it contains
will be associated with the appropriate type when required.
## Implicitly generated default constructor
In many cases, it's useful to be able to create objects of default constructible
types through the reflection system, while not having to explicitly register the
meta type or the default constructor.<br/>
For example, in the case of primitive types like `int` or `char`, but not just
them.
For this reason and only for default constructible types, default constructors
are automatically defined and associated with their meta types, whether they are
explicitly or implicitly generated.<br/>
Therefore, it won't be necessary to do this in order to construct an integer
from its meta type:
```cpp
entt::meta<int>().ctor<>();
```
Instead, just do this:
```cpp
entt::resolve<int>().construct();
```
Where the meta type can be for example the one returned from a meta container,
useful for building keys without knowing or having to register the actual types.
In all cases, when users register custom defaul constructors, they are preferred
both during searches and when the `construct` member function is invoked.<br/>
However, the implicitly generated default constructor will always be returned,
either if one is not explicitly specified or if all constructors are iterated
for some reason (in this case, it will always be the last element).
## Policies: the more, the less
Policies are a kind of compile-time directives that can be used when recording
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
@@ -410,32 +770,30 @@ There are a few alternatives available at the moment:
* The _as-void_ policy, associated with the type `entt::as_void_t`.<br/>
Its purpose is to discard the return value of a meta object, whatever it is,
thus making it appear as if its type were `void`.<br/>
thus making it appear as if its type were `void`:
```cpp
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
```
If the use with functions is obvious, it must be said that it's also possible
to use this policy with constructors and data members. In the first case, the
constructor will be invoked but the returned wrapper will actually be empty.
In the second case, instead, the property will not be accessible for reading.
As an example of use:
* 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:
```cpp
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
```
* The _as-alias_ policy, associated with the type `entt::as_alias_t`.<br/>
It allows to build wrappers that act as aliases for the objects that generated
them. Modifying the object contained in the wrapper for which the _aliasing_
was requested will make it possible to directly modify the instance used to
initialize the wrapper itself.<br/>
This policy works 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_alias_t>("member"_hs);
entt::meta<my_type>().data<&my_type::data_member, entt::as_ref_t>("member"_hs);
```
These policies work with constructors (for example, when objects are taken
from an external container rather than created on demand), data members and
functions in general.<br/>
If on the one hand `as_cref_t` always forces the return type to be const,
`as_ref_t` _adapts_ to the constness of the passed object and to that of the
return type if any.
Some uses are rather trivial, but it's useful to note that there are some less
obvious corner cases that can in turn be solved with the use of policies.
@@ -460,8 +818,8 @@ Exporting constant values or elements from an enum is as simple as ever:
```cpp
entt::meta<my_enum>()
.data<my_enum::a_value>("a_value"_hs)
.data<my_enum::another_value>("another_value"_hs);
.data<my_enum::a_value>("a_value"_hs)
.data<my_enum::another_value>("another_value"_hs);
entt::meta<int>().data<2048>("max_int"_hs);
```
@@ -518,8 +876,7 @@ Multiple formats are supported when it comes to defining a property:
* 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));
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.
@@ -538,11 +895,11 @@ each property to associate with the last meta object created:
```cpp
entt::meta<my_type>()
.type("reflected_type"_hs)
.prop(entt::hashed_string{"Name"}, "Reflected Type")
.data<&my_type::data_member>("member"_hs)
.prop(std::make_pair("tooltip"_hs, "Member"))
.prop(my_enum::a_value, 42);
.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
@@ -560,9 +917,9 @@ properties at once or to search a specific property by key:
```cpp
// iterate all properties of a meta type
entt::resolve<my_type>().prop([](auto prop) {
for(auto prop: entt::resolve<my_type>().prop()) {
// ...
});
}
// search for a given property by name
auto prop = entt::resolve<my_type>().prop("tooltip"_hs);
@@ -576,16 +933,16 @@ the key and the value contained in the form of `meta_any` objects, respectively.
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
and so on. However, base classes aren't unregistered as well, since they don't
necessarily depend on it. Similarly, implicitly generated types (as an example,
the meta types implicitly generated for function parameters when needed) won't
be unregistered.<br/>
the meta types implicitly generated for function parameters when needed) aren't
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::meta<my_type>().reset();
entt::resolve<my_type>().reset();
```
The type can be re-registered later with a completely different name and form.

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

@@ -0,0 +1,359 @@
# 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)
* [Storage size and alignment requirement](#storage-size-and-alignment-requirement)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
Static polymorphism is a very powerful tool in C++, albeit sometimes cumbersome
to obtain.<br/>
This module aims to make it simple and easy to use.
The library allows to define _concepts_ as interfaces to 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::template type<Base> {
static constexpr auto base = std::tuple_size_v<typename entt::poly_vtable<Drawable>::type>;
void erase() { entt::poly_call<base + 0>(*this); }
};
template<typename Type>
using impl = entt::value_list_cat_t<
typename Drawable::impl<Type>,
entt::value_list<&Type::erase>
>;
};
```
The static virtual table is empty and must remain so.<br/>
On the other hand, `type` no longer inherits from `Base` 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 instance{circle{}};
instance->draw();
instance = square{};
instance->draw();
```
The `poly` class template offers a wide range of constructors, from the default
one (which will return an uninitialized `poly` object) to the copy and move
constructors, as well as the ability to create objects in-place.<br/>
Among others, there is also a constructor that allows users to wrap unmanaged
objects in a `poly` instance (either const or non-const ones):
```cpp
circle shape;
drawable instance{std::in_place_type<circle &>, shape};
```
Similarly, it's possible to create non-owning copies of `poly` from an existing
object:
```cpp
drawable other = instance.as_ref();
```
In both cases, although the interface of the `poly` object doesn't change, it
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 `instance.draw()`.<br/>
This allows users to decouple the API of the wrapper from that of the concept.
Therefore, where `instance.data()` will invoke the `data` member function of the
poly object, `instance->data()` will map directly to the functionality exposed
by the underlying concept.
# Storage size and alignment requirement
Under the hood, the `poly` class template makes use of `entt::any`. Therefore,
it can take advantage of the possibility of defining at compile-time the size of
the storage suitable for the small buffer optimization as well as the alignment
requirements:
```cpp
entt::basic_poly<Drawable, sizeof(double[4]), alignof(double[4])>
```
The default size is `sizeof(double[2])`, which seems like a good compromise
between a buffer that is too large and one unable to hold anything larger than
an integer. The alignment requirement is optional instead and by default such
that it's the most stringent (the largest) for any object whose size is at most
equal to the one provided.<br/>
It's worth noting that providing a size of 0 (which is an accepted value in all
respects) will force the system to dynamically allocate the contained objects in
all cases.

View File

@@ -28,9 +28,9 @@ A typical process must inherit from the `process` class template that stays true
to the CRTP idiom. Moreover, derived classes must specify what's the intended
type for elapsed times.
A process should expose publicly the following member functions whether
required (note that it isn't required to define a function unless the derived
class wants to _override_ the default behavior):
A process should expose publicly the following member functions whether needed
(note that it isn't required to define a function unless the derived class wants
to _override_ the default behavior):
* `void update(Delta, void *);`

63
docs/md/reference.md Normal file
View File

@@ -0,0 +1,63 @@
# 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.
* [Polypropylene](https://github.com/pmbittner/Polypropylene): a hybrid
solution between an ECS and dynamic mixins.
* C#
* [Entitas](https://github.com/sschmid/Entitas-CSharp): the ECS framework for
C# and Unity, where _reactive systems_ were invented.
* [LeoECS](https://github.com/Leopotam/ecs): simple lightweight C# Entity
Component System framework.
* [Svelto.ECS](https://github.com/sebas77/Svelto.ECS): a very interesting
platform agnostic and table based ECS framework.
* Go:
* [gecs](https://github.com/tutumagi/gecs): a sparse sets based ECS inspired
by `EnTT`.
* Javascript:
* [\@javelin/ecs](https://github.com/3mcd/javelin/tree/master/packages/ecs): an
archetype ECS in TypeScript.
* [ecsy](https://github.com/MozillaReality/ecsy): I haven't had the time to
investigate the underlying design of `ecsy` but it looks cool anyway.
* 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

@@ -23,7 +23,7 @@ loading, and so on.
`EnTT` doesn't pretend to offer a _one-fits-all_ solution for the different
cases. Instead, it offers a minimal and perhaps trivial cache that can be useful
most of the time during prototyping and sometimes even in a production
environment.<br/>
environments.<br/>
For those interested in the subject, the plan is to improve it considerably over
time in terms of performance, memory usage and functionalities. Hoping to make
it, of course, one step at a time.
@@ -42,10 +42,10 @@ 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::loader<my_loader, my_resource> {
struct my_loader final: entt::resource_loader<my_loader, my_resource> {
// ...
};
```
@@ -57,7 +57,7 @@ resource.<br/>
As an example:
```cpp
struct my_loader: entt::loader<my_loader, my_resource> {
struct my_loader: entt::resource_loader<my_loader, my_resource> {
std::shared_ptr<my_resource> load(int value) const {
// ...
return std::shared_ptr<my_resource>(new my_resource{ value });
@@ -76,7 +76,7 @@ Finally, a cache is a specialization of a class template tailored to a specific
resource:
```cpp
using my_cache = entt::cache<my_resource>;
using my_cache = entt::resource_cache<my_resource>;
// ...
@@ -105,20 +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::cache<resource>::id_type
```
Where `id_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::cache<resource>::id_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
@@ -132,7 +126,7 @@ identifier and the parameters used to construct the resource as arguments:
// uses the identifier declared above
cache.load<my_loader>(identifier, 0);
// uses a const char * directly as an identifier
// uses a hashed string directly
cache.load<my_loader>("another/identifier"_hs, 42);
```
@@ -141,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) {
// ...
}
```
@@ -186,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)
@@ -63,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
@@ -142,12 +144,12 @@ delegate. As long as a listener can be invoked with the given arguments to yield
a result that is convertible to the given result type, everything works just
fine.
As a side note, note that members of a class 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:
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>();
@@ -160,6 +162,79 @@ 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 references to classes, function pointers and pointers
@@ -312,9 +387,9 @@ 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:
@@ -372,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();
@@ -402,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/>
@@ -418,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.

File diff suppressed because it is too large Load Diff

View File

@@ -2,18 +2,24 @@
#define ENTT_CONFIG_CONFIG_H
#ifndef ENTT_NOEXCEPT
#if defined(__cpp_exceptions) && !defined(ENTT_NOEXCEPTION)
# define ENTT_NOEXCEPT noexcept
# define ENTT_THROW throw
# define ENTT_TRY try
# define ENTT_CATCH catch(...)
#else
# define ENTT_NOEXCEPT
# define ENTT_THROW
# define ENTT_TRY if(true)
# define ENTT_CATCH if(false)
#endif
#ifndef ENTT_HS_SUFFIX
# define ENTT_HS_SUFFIX _hs
#endif
#ifndef ENTT_HWS_SUFFIX
# define ENTT_HWS_SUFFIX _hws
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606L
# include <new>
# define ENTT_LAUNDER(expr) std::launder(expr)
#else
# define ENTT_LAUNDER(expr) expr
#endif
@@ -31,35 +37,47 @@
#endif
#ifndef ENTT_PAGE_SIZE
# define ENTT_PAGE_SIZE 32768
#endif
#ifndef ENTT_ASSERT
# include <cassert>
# define ENTT_ASSERT(condition) assert(condition)
#endif
#ifndef ENTT_DISABLE_ETO
# include <type_traits>
# define ENTT_ENABLE_ETO(Type) (std::is_default_constructible_v<Type> && std::is_empty_v<Type>)
#ifdef ENTT_SPARSE_PAGE
static_assert(ENTT_SPARSE_PAGE && ((ENTT_SPARSE_PAGE & (ENTT_SPARSE_PAGE - 1)) == 0), "ENTT_SPARSE_PAGE must be a power of two");
#else
# // sfinae-friendly definition
# define ENTT_ENABLE_ETO(Type) (false && std::is_void_v<Type>)
# define ENTT_SPARSE_PAGE 4096
#endif
#ifdef ENTT_PACKED_PAGE
static_assert(ENTT_PACKED_PAGE && ((ENTT_PACKED_PAGE & (ENTT_PACKED_PAGE - 1)) == 0), "ENTT_PACKED_PAGE must be a power of two");
#else
# define ENTT_PACKED_PAGE 1024
#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
#ifdef ENTT_NO_ETO
# include <type_traits>
# define ENTT_IGNORE_IF_EMPTY std::false_type
#else
# include <type_traits>
# define ENTT_IGNORE_IF_EMPTY std::true_type
#endif
#ifndef ENTT_STANDARD_CPP
# if defined _MSC_VER
# define ENTT_PRETTY_FUNCTION __FUNCSIG__
# define ENTT_PRETTY_FUNCTION_CONSTEXPR ENTT_PRETTY_FUNCTION
# elif defined __clang__ || (defined __GNUC__ && __GNUC__ > 8)
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
# define ENTT_PRETTY_FUNCTION_CONSTEXPR ENTT_PRETTY_FUNCTION
# elif defined __GNUC__
# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__
# 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

View File

@@ -3,8 +3,8 @@
#define ENTT_VERSION_MAJOR 3
#define ENTT_VERSION_MINOR 3
#define ENTT_VERSION_PATCH 2
#define ENTT_VERSION_MINOR 8
#define ENTT_VERSION_PATCH 1
#endif

View File

@@ -58,7 +58,7 @@ struct insertion_sort {
template<typename It, typename Compare = std::less<>>
void operator()(It first, It last, Compare compare = Compare{}) const {
if(first < last) {
for(auto it = first+1; it < last; ++it) {
for(auto it = first + 1; it < last; ++it) {
auto value = std::move(*it);
auto pre = it;
@@ -80,7 +80,7 @@ struct insertion_sort {
*/
template<std::size_t Bit, std::size_t N>
struct radix_sort {
static_assert((N % Bit) == 0);
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.
@@ -111,17 +111,17 @@ struct radix_sort {
std::size_t index[buckets]{};
std::size_t count[buckets]{};
std::for_each(from, to, [&getter, &count, start](const value_type &item) {
++count[(getter(item) >> start) & mask];
});
for(auto it = from; it != to; ++it) {
++count[(getter(*it) >> start) & mask];
}
std::for_each(std::next(std::begin(index)), std::end(index), [index = std::begin(index), count = std::begin(count)](auto &item) mutable {
item = *(index++) + *(count++);
});
for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
index[pos + 1u] = index[pos] + count[pos];
}
std::for_each(from, to, [&getter, &out, &index, start](value_type &item) {
out[index[(getter(item) >> start) & mask]++] = std::move(item);
});
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) {

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

@@ -0,0 +1,456 @@
#ifndef ENTT_CORE_ANY_HPP
#define ENTT_CORE_ANY_HPP
#include <cstddef>
#include <functional>
#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/utility.hpp"
#include "fwd.hpp"
#include "type_info.hpp"
#include "type_traits.hpp"
namespace entt {
/**
* @brief A SBO friendly, type-safe container for single values of any type.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
*/
template<std::size_t Len, std::size_t Align>
class basic_any {
enum class operation: std::uint8_t { COPY, MOVE, DTOR, COMP, ADDR, CADDR, TYPE };
enum class policy: std::uint8_t { OWNER, REF, CREF };
using storage_type = std::aligned_storage_t<Len + !Len, Align>;
using vtable_type = const void *(const operation, const basic_any &, void *);
template<typename Type>
static constexpr bool in_situ = Len && alignof(Type) <= alignof(storage_type) && sizeof(Type) <= sizeof(storage_type) && std::is_nothrow_move_constructible_v<Type>;
template<typename Type>
[[nodiscard]] static constexpr policy type_to_policy() {
if constexpr(std::is_lvalue_reference_v<Type>) {
if constexpr(std::is_const_v<std::remove_reference_t<Type>>) {
return policy::CREF;
} else {
return policy::REF;
}
} else {
return policy::OWNER;
}
}
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;
}
}
template<typename Type>
static const void * basic_vtable([[maybe_unused]] const operation op, [[maybe_unused]] const basic_any &from, [[maybe_unused]] void *to) {
static_assert(std::is_same_v<std::remove_reference_t<std::remove_const_t<Type>>, Type>, "Invalid type");
if constexpr(!std::is_void_v<Type>) {
const Type *instance = (in_situ<Type> && from.mode == policy::OWNER)
? ENTT_LAUNDER(reinterpret_cast<const Type *>(&from.storage))
: static_cast<const Type *>(from.instance);
switch(op) {
case operation::COPY:
if constexpr(std::is_copy_constructible_v<Type>) {
static_cast<basic_any *>(to)->emplace<Type>(*instance);
}
break;
case operation::MOVE:
if constexpr(in_situ<Type>) {
if(from.mode == policy::OWNER) {
return new (&static_cast<basic_any *>(to)->storage) Type{std::move(*const_cast<Type *>(instance))};
}
}
return (static_cast<basic_any *>(to)->instance = std::exchange(const_cast<basic_any &>(from).instance, nullptr));
case operation::DTOR:
if(from.mode == policy::OWNER) {
if constexpr(in_situ<Type>) {
instance->~Type();
} else if constexpr(std::is_array_v<Type>) {
delete[] instance;
} else {
delete instance;
}
}
break;
case operation::COMP:
return compare<Type>(instance, (*static_cast<const basic_any **>(to))->data()) ? to : nullptr;
case operation::ADDR:
if(from.mode == policy::CREF) {
return nullptr;
}
[[fallthrough]];
case operation::CADDR:
return instance;
case operation::TYPE:
*static_cast<type_info *>(to) = type_id<Type>();
break;
}
}
return nullptr;
}
template<typename Type, typename... Args>
void initialize([[maybe_unused]] Args &&... args) {
if constexpr(!std::is_void_v<Type>) {
if constexpr(std::is_lvalue_reference_v<Type>) {
static_assert(sizeof...(Args) == 1u && (std::is_lvalue_reference_v<Args> && ...), "Invalid arguments");
instance = (std::addressof(args), ...);
} else if constexpr(in_situ<Type>) {
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
new (&storage) Type{std::forward<Args>(args)...};
} else {
new (&storage) Type(std::forward<Args>(args)...);
}
} else {
if constexpr(sizeof...(Args) != 0u && std::is_aggregate_v<Type>) {
instance = new Type{std::forward<Args>(args)...};
} else {
instance = new Type(std::forward<Args>(args)...);
}
}
}
}
basic_any(const basic_any &other, const policy pol) ENTT_NOEXCEPT
: instance{other.data()},
vtable{other.vtable},
mode{pol}
{}
public:
/*! @brief Size of the internal storage. */
static constexpr auto length = Len;
/*! @brief Alignment requirement. */
static constexpr auto alignment = Align;
/*! @brief Default constructor. */
basic_any() ENTT_NOEXCEPT
: instance{},
vtable{&basic_vtable<void>},
mode{policy::OWNER}
{}
/**
* @brief Constructs a wrapper by directly initializing the new object.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
*/
template<typename Type, typename... Args>
explicit basic_any(std::in_place_type_t<Type>, Args &&... args)
: instance{},
vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>},
mode{type_to_policy<Type>()}
{
initialize<Type>(std::forward<Args>(args)...);
}
/**
* @brief Constructs a wrapper that holds an unmanaged object.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
*/
template<typename Type>
basic_any(std::reference_wrapper<Type> value) ENTT_NOEXCEPT
: basic_any{}
{
// invokes deprecated assignment operator (and avoids issues with vs2017)
*this = value;
}
/**
* @brief Constructs a wrapper from a given value.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
*/
template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
basic_any(Type &&value)
: instance{},
vtable{&basic_vtable<std::decay_t<Type>>},
mode{policy::OWNER}
{
initialize<std::decay_t<Type>>(std::forward<Type>(value));
}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
basic_any(const basic_any &other)
: instance{},
vtable{&basic_vtable<void>},
mode{policy::OWNER}
{
other.vtable(operation::COPY, other, this);
}
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_any(basic_any &&other) ENTT_NOEXCEPT
: instance{},
vtable{other.vtable},
mode{other.mode}
{
vtable(operation::MOVE, other, this);
}
/*! @brief Frees the internal storage, whatever it means. */
~basic_any() {
vtable(operation::DTOR, *this, nullptr);
}
/**
* @brief Copy assignment operator.
* @param other The instance to copy from.
* @return This any object.
*/
basic_any & operator=(const basic_any &other) {
reset();
other.vtable(operation::COPY, other, this);
return *this;
}
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This any object.
*/
basic_any & operator=(basic_any &&other) ENTT_NOEXCEPT {
std::exchange(vtable, other.vtable)(operation::DTOR, *this, nullptr);
other.vtable(operation::MOVE, other, this);
mode = other.mode;
return *this;
}
/**
* @brief Value assignment operator.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
* @return This any object.
*/
template<typename Type>
[[deprecated("Use std::in_place_type<T &>, entt::make_any<T &>, emplace<Type &> or forward_as_any instead")]]
basic_any & operator=(std::reference_wrapper<Type> value) ENTT_NOEXCEPT {
emplace<Type &>(value.get());
return *this;
}
/**
* @brief Value assignment operator.
* @tparam Type Type of object to use to initialize the wrapper.
* @param value An instance of an object to use to initialize the wrapper.
* @return This any object.
*/
template<typename Type>
std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>, basic_any &>
operator=(Type &&value) {
emplace<std::decay_t<Type>>(std::forward<Type>(value));
return *this;
}
/**
* @brief Returns the 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) {
std::exchange(vtable, &basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>)(operation::DTOR, *this, nullptr);
mode = type_to_policy<Type>();
initialize<Type>(std::forward<Args>(args)...);
}
/*! @brief Destroys contained object */
void reset() {
std::exchange(vtable, &basic_vtable<void>)(operation::DTOR, *this, nullptr);
mode = policy::OWNER;
}
/**
* @brief Returns false if a wrapper is empty, true otherwise.
* @return False if the wrapper is empty, true otherwise.
*/
[[nodiscard]] explicit operator bool() const 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 basic_any &other) const ENTT_NOEXCEPT {
const basic_any *trampoline = &other;
return type() == other.type() && (vtable(operation::COMP, *this, &trampoline) || !other.data());
}
/**
* @brief Aliasing constructor.
* @return A wrapper that shares a reference to an unmanaged object.
*/
[[nodiscard]] basic_any as_ref() ENTT_NOEXCEPT {
return basic_any{*this, (mode == policy::CREF ? policy::CREF : policy::REF)};
}
/*! @copydoc as_ref */
[[nodiscard]] basic_any as_ref() const ENTT_NOEXCEPT {
return basic_any{*this, policy::CREF};
}
/**
* @brief Returns true if a wrapper owns its object, false otherwise.
* @return True if the wrapper owns its object, false otherwise.
*/
[[nodiscard]] bool owner() const ENTT_NOEXCEPT {
return (mode == policy::OWNER);
}
private:
union { const void *instance; storage_type storage; };
vtable_type *vtable;
policy mode;
};
/**
* @brief Checks if two wrappers differ in their content.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
* @param lhs A wrapper, either empty or not.
* @param rhs A wrapper, either empty or not.
* @return True if the two wrappers differ in their content, false otherwise.
*/
template<std::size_t Len, std::size_t Align>
[[nodiscard]] inline bool operator!=(const basic_any<Len, Align> &lhs, const basic_any<Len, Align> &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
/**
* @brief Performs type-safe access to the contained object.
* @tparam Type Type to which conversion is required.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
* @param data Target any object.
* @return The element converted to the requested type.
*/
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(const basic_any<Len, Align> &data) ENTT_NOEXCEPT {
const auto * const instance = any_cast<std::remove_reference_t<Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(basic_any<Len, Align> &data) ENTT_NOEXCEPT {
// forces const on non-reference types to make them work also with wrappers for const references
auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(*instance);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type any_cast(basic_any<Len, Align> &&data) ENTT_NOEXCEPT {
// forces const on non-reference types to make them work also with wrappers for const references
auto * const instance = any_cast<std::remove_reference_t<const Type>>(&data);
ENTT_ASSERT(instance, "Invalid instance");
return static_cast<Type>(std::move(*instance));
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
const Type * any_cast(const basic_any<Len, Align> *data) ENTT_NOEXCEPT {
return (data->type() == type_id<Type>() ? static_cast<const Type *>(data->data()) : nullptr);
}
/*! @copydoc any_cast */
template<typename Type, std::size_t Len, std::size_t Align>
Type * any_cast(basic_any<Len, Align> *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<basic_any<Len, Align>, Type> *>(data)->data()) : nullptr);
}
/**
* @brief Constructs a wrapper from a given type, passing it all arguments.
* @tparam Type Type of object to use to initialize the wrapper.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
* @tparam Args Types of arguments to use to construct the new instance.
* @param args Parameters to use to construct the instance.
* @return A properly initialized wrapper for an object of the given type.
*/
template<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args>
basic_any<Len, Align> make_any(Args &&... args) {
return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...};
}
/**
* @brief Forwards its argument and avoids copies for lvalue references.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
* @tparam Type Type of argument to use to construct the new instance.
* @param value Parameter to use to construct the instance.
* @return A properly initialized and not necessarily owning wrapper.
*/
template<std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename Type>
basic_any<Len, Align> forward_as_any(Type &&value) {
return basic_any<Len, Align>{std::in_place_type<std::conditional_t<std::is_rvalue_reference_v<Type>, std::decay_t<Type>, Type>>, std::forward<Type>(value)};
}
}
#endif

View File

@@ -3,6 +3,7 @@
#include "../config/config.h"
#include "fwd.hpp"
namespace entt {
@@ -17,11 +18,11 @@ namespace entt {
*/
template<typename...>
class family {
inline static ENTT_MAYBE_ATOMIC(ENTT_ID_TYPE) 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>

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

@@ -0,0 +1,27 @@
#ifndef ENTT_CORE_FWD_HPP
#define ENTT_CORE_FWD_HPP
#include <type_traits>
#include "../config/config.h"
namespace entt {
template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(typename std::aligned_storage_t<Len + !Len>)>
class basic_any;
/*! @brief Alias declaration for type identifiers. */
using id_type = ENTT_ID_TYPE;
/*! @brief Alias declaration for the most common use case. */
using any = basic_any<>;
}
#endif

View File

@@ -5,6 +5,7 @@
#include <cstddef>
#include <cstdint>
#include "../config/config.h"
#include "fwd.hpp"
namespace entt {
@@ -44,7 +45,7 @@ struct fnv1a_traits<std::uint64_t> {
/**
* Internal details not to be documented.
* @endcond TURN_OFF_DOXYGEN
* @endcond
*/
@@ -61,7 +62,7 @@ struct fnv1a_traits<std::uint64_t> {
*/
template<typename Char>
class basic_hashed_string {
using traits_type = internal::fnv1a_traits<ENTT_ID_TYPE>;
using traits_type = internal::fnv1a_traits<id_type>;
struct const_wrapper {
// non-explicit constructor on purpose
@@ -70,7 +71,7 @@ class basic_hashed_string {
};
// FowlerNollVo hash function v. 1a - the good
static constexpr ENTT_ID_TYPE helper(const Char *curr) ENTT_NOEXCEPT {
[[nodiscard]] static constexpr id_type helper(const Char *curr) ENTT_NOEXCEPT {
auto value = traits_type::offset;
while(*curr != 0) {
@@ -84,7 +85,19 @@ public:
/*! @brief Character type. */
using value_type = Char;
/*! @brief Unsigned integer type. */
using hash_type = ENTT_ID_TYPE;
using hash_type = id_type;
/**
* @brief Returns directly the numeric representation of a string view.
* @param str Human-readable identifer.
* @param size Length of the string to hash.
* @return The numeric representation of the string.
*/
[[nodiscard]] static constexpr hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
id_type partial{traits_type::offset};
while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
return partial;
}
/**
* @brief Returns directly the numeric representation of a string.
@@ -102,7 +115,7 @@ public:
* @return The numeric representation of the string.
*/
template<std::size_t N>
static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT {
[[nodiscard]] static constexpr hash_type value(const value_type (&str)[N]) ENTT_NOEXCEPT {
return helper(str);
}
@@ -111,22 +124,10 @@ public:
* @param wrapper Helps achieving the purpose by relying on overloading.
* @return The numeric representation of the string.
*/
static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT {
[[nodiscard]] static hash_type value(const_wrapper wrapper) ENTT_NOEXCEPT {
return helper(wrapper.str);
}
/**
* @brief Returns directly the numeric representation of a string view.
* @param str Human-readable identifer.
* @param size Length of the string to hash.
* @return The numeric representation of the string.
*/
static hash_type value(const value_type *str, std::size_t size) ENTT_NOEXCEPT {
ENTT_ID_TYPE partial{traits_type::offset};
while(size--) { partial = (partial^(str++)[0])*traits_type::prime; }
return partial;
}
/*! @brief Constructs an empty hashed string. */
constexpr basic_hashed_string() ENTT_NOEXCEPT
: str{nullptr}, hash{}
@@ -164,7 +165,7 @@ public:
* @brief Returns the human-readable representation of a hashed string.
* @return The string used to initialize the instance.
*/
constexpr const value_type * data() const ENTT_NOEXCEPT {
[[nodiscard]] constexpr const value_type * data() const ENTT_NOEXCEPT {
return str;
}
@@ -172,25 +173,25 @@ 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;
}
/*! @copydoc data */
constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); }
[[nodiscard]] constexpr operator const value_type *() const ENTT_NOEXCEPT { return data(); }
/**
* @brief Returns the numeric representation of a hashed string.
* @return The numeric representation of the instance.
*/
constexpr operator hash_type() const ENTT_NOEXCEPT { return value(); }
[[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 basic_hashed_string &other) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const ENTT_NOEXCEPT {
return hash == other.hash;
}
@@ -211,7 +212,7 @@ private:
* @param str Human-readable identifer.
*/
template<typename Char, std::size_t N>
basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT
basic_hashed_string(const Char (&str)[N])
-> basic_hashed_string<Char>;
@@ -223,7 +224,7 @@ basic_hashed_string(const Char (&str)[N]) ENTT_NOEXCEPT
* @return True if the two hashed strings are identical, false otherwise.
*/
template<typename Char>
constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) ENTT_NOEXCEPT {
return !(lhs == rhs);
}
@@ -236,7 +237,7 @@ using hashed_string = basic_hashed_string<char>;
using hashed_wstring = basic_hashed_string<wchar_t>;
}
inline namespace literals {
/**
@@ -244,7 +245,7 @@ using hashed_wstring = basic_hashed_string<wchar_t>;
* @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};
}
@@ -254,9 +255,15 @@ constexpr entt::hashed_string operator"" ENTT_HS_SUFFIX(const char *str, std::si
* @param str The literal without its suffix.
* @return A properly initialized hashed wstring.
*/
constexpr entt::hashed_wstring operator"" ENTT_HWS_SUFFIX(const wchar_t *str, std::size_t) ENTT_NOEXCEPT {
[[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,11 +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 {
@@ -41,17 +42,15 @@ 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...>) {
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>

View File

@@ -3,6 +3,7 @@
#include "../config/config.h"
#include "fwd.hpp"
namespace entt {
@@ -19,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<ENTT_ID_TYPE>
template<id_type>
struct monostate {
/**
* @brief Assigns a value of a specific type to a given key.
@@ -51,7 +52,7 @@ private:
* @brief Helper variable template.
* @tparam Value Value used to differentiate between different variables.
*/
template<ENTT_ID_TYPE Value>
template<id_type Value>
inline monostate<Value> monostate_v = {};

View File

@@ -2,22 +2,17 @@
#define ENTT_CORE_TYPE_INFO_HPP
#include <string_view>
#include <type_traits>
#include "../config/config.h"
#include "../core/attribute.h"
#include "hashed_string.hpp"
#ifndef ENTT_PRETTY_FUNCTION
# define ENTT_TYPE_ID_API ENTT_API
#else
# define ENTT_TYPE_ID_API
#endif
#include "fwd.hpp"
namespace entt {
#ifndef ENTT_PRETTY_FUNCTION
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
@@ -27,53 +22,238 @@ namespace entt {
namespace internal {
struct ENTT_API type_id_generator {
static ENTT_ID_TYPE next() ENTT_NOEXCEPT {
static ENTT_ID_TYPE value{};
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 TURN_OFF_DOXYGEN
* @endcond
*/
#endif
/**
* @brief Types identifiers.
* @tparam Type Type for which to generate an identifier.
* @brief Type sequential identifier.
* @tparam Type Type for which to generate a sequential identifier.
*/
template<typename Type, typename = void>
struct ENTT_TYPE_ID_API type_info {
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;
}
/*! @copydoc value */
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); }
};
/**
* @brief Type hash.
* @tparam Type Type for which to generate a hash value.
*/
template<typename Type, typename = void>
struct type_hash final {
/**
* @brief Returns the numeric representation of a given type.
* @return The numeric representation of the given type.
*/
#if defined ENTT_PRETTY_FUNCTION_CONSTEXPR
static constexpr ENTT_ID_TYPE id() ENTT_NOEXCEPT {
constexpr auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION_CONSTEXPR);
return value;
}
#elif defined ENTT_PRETTY_FUNCTION
static ENTT_ID_TYPE id() ENTT_NOEXCEPT {
static const auto value = entt::hashed_string::value(ENTT_PRETTY_FUNCTION);
return value;
}
#if defined ENTT_PRETTY_FUNCTION
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
return internal::type_hash<Type>(0);
#else
static ENTT_ID_TYPE id() ENTT_NOEXCEPT {
static const ENTT_ID_TYPE value = internal::type_id_generator::next();
return value;
}
[[nodiscard]] static constexpr id_type value() ENTT_NOEXCEPT {
return type_seq<Type>::value();
#endif
}
/*! @copydoc value */
[[nodiscard]] constexpr operator id_type() const ENTT_NOEXCEPT { return value(); }
};
/**
* @brief Type name.
* @tparam Type Type for which to generate a name.
*/
template<typename Type, typename = void>
struct type_name final {
/**
* @brief Returns the name of a given type.
* @return The name of the given type.
*/
[[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT {
return internal::type_name<Type>(0);
}
/*! @copydoc value */
[[nodiscard]] constexpr operator std::string_view() const ENTT_NOEXCEPT { return value(); }
};
/*! @brief Implementation specific information about a type. */
class type_info final {
template<typename>
friend type_info type_id() ENTT_NOEXCEPT;
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.data() != nullptr;
}
/**
* @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>
[[nodiscard]] type_info type_id() ENTT_NOEXCEPT {
return type_info{
type_seq<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value(),
type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::value()
};
}
}

View File

@@ -3,10 +3,11 @@
#include <cstddef>
#include <utility>
#include <iterator>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/hashed_string.hpp"
#include "fwd.hpp"
namespace entt {
@@ -18,10 +19,10 @@ namespace entt {
*/
template<std::size_t N>
struct choice_t
// Unfortunately, doxygen cannot parse such a construct.
/*! @cond TURN_OFF_DOXYGEN */
: choice_t<N-1>
/*! @endcond TURN_OFF_DOXYGEN */
// Unfortunately, doxygen cannot parse such a construct.
/*! @cond TURN_OFF_DOXYGEN */
: choice_t<N-1>
/*! @endcond */
{};
@@ -35,35 +36,149 @@ struct choice_t<0> {};
* @tparam N Number of choices available.
*/
template<std::size_t N>
constexpr choice_t<N> choice{};
/*! @brief A class to use to push around lists of types, nothing more. */
template<typename...>
struct type_list {};
/*! @brief Primary template isn't defined on purpose. */
template<typename>
struct type_list_size;
inline constexpr choice_t<N> choice{};
/**
* @brief Compile-time number of elements in a type list.
* @tparam Type Types provided by the type list.
* @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_list_size<type_list<Type...>>
: std::integral_constant<std::size_t, sizeof...(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 List Type list.
* @tparam Type The type of which to return the size.
*/
template<class List>
constexpr auto type_list_size_v = type_list_size<List>::value;
template<class Type>
inline constexpr std::size_t size_of_v = size_of<Type>::value;
/**
* @brief Using declaration to be used to _repeat_ the same type a number of
* times equal to the size of a given parameter pack.
* @tparam Type A type to repeat.
*/
template<typename Type, typename>
using unpack_as_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 A class to use to push around lists of types, nothing more.
* @tparam Type Types provided by the type list.
*/
template<typename... Type>
struct type_list {
/*! @brief Type list type. */
using type = type_list;
/*! @brief Compile-time number of elements in the type list. */
static constexpr auto size = sizeof...(Type);
};
/*! @brief Primary template isn't defined on purpose. */
template<std::size_t, typename>
struct type_list_element;
/**
* @brief Provides compile-time indexed access to the types of a type list.
* @tparam Index Index of the type to return.
* @tparam 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. */
@@ -149,25 +264,395 @@ using type_list_unique_t = typename type_list_unique<Type>::type;
/**
* @brief Provides the member constant `value` to true if a given type is
* equality comparable, false otherwise.
* @tparam Type Potentially equality comparable type.
* @brief Provides the member constant `value` to true if a type list contains a
* given type, false otherwise.
* @tparam List Type list.
* @tparam Type Type to look for.
*/
template<typename Type, typename = std::void_t<>>
struct is_equality_comparable: std::false_type {};
template<typename List, typename Type>
struct type_list_contains;
/*! @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 {};
/**
* @copybrief type_list_contains
* @tparam Type Types provided by the type list.
* @tparam Other Type to look for.
*/
template<typename... Type, typename Other>
struct type_list_contains<type_list<Type...>, Other>: std::disjunction<std::is_same<Type, Other>...> {};
/**
* @brief Helper variable template.
* @tparam Type Potentially equality comparable type.
* @tparam List Type list.
* @tparam Type Type to look for.
*/
template<class List, typename Type>
inline constexpr bool type_list_contains_v = type_list_contains<List, Type>::value;
/*! @brief Primary template isn't defined on purpose. */
template<typename...>
struct type_list_diff;
/**
* @brief Computes the difference between two type lists.
* @tparam Type Types provided by the first type list.
* @tparam Other Types provided by the second type list.
*/
template<typename... Type, typename... Other>
struct type_list_diff<type_list<Type...>, type_list<Other...>> {
/*! @brief A type list that is the difference between the two type lists. */
using type = type_list_cat_t<std::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>;
};
/**
* @brief Helper type.
* @tparam List Type lists between which to compute the difference.
*/
template<typename... List>
using type_list_diff_t = typename type_list_diff<List...>::type;
/**
* @brief 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 Same as std::is_invocable, but with tuples. */
template<typename, typename>
struct is_applicable: std::false_type {};
/**
* @copybrief is_applicable
* @tparam Func A valid function type.
* @tparam Tuple Tuple-like type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Func, template<typename...> class Tuple, typename... Args>
struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
/**
* @copybrief is_applicable
* @tparam Func A valid function type.
* @tparam Tuple Tuple-like type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Func, template<typename...> class Tuple, typename... Args>
struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args...> {};
/**
* @brief Helper variable template.
* @tparam Func A valid function type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Func, typename Args>
inline constexpr bool is_applicable_v = is_applicable<Func, Args>::value;
/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */
template<typename, typename, typename>
struct is_applicable_r: std::false_type {};
/**
* @copybrief is_applicable_r
* @tparam Ret The type to which the return type of the function should be
* convertible.
* @tparam Func A valid function type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Ret, typename Func, typename... Args>
struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret, Func, Args...> {};
/**
* @brief Helper variable template.
* @tparam Ret The type to which the return type of the function should be
* convertible.
* @tparam Func A valid function type.
* @tparam Args The list of arguments to use to probe the function type.
*/
template<typename Ret, typename Func, typename Args>
inline constexpr bool is_applicable_r_v = is_applicable_r<Ret, Func, Args>::value;
/**
* @brief Provides the member constant `value` to true if a given type is
* complete, false otherwise.
* @tparam Type The type to test.
*/
template<typename Type, typename = void>
struct is_complete: std::false_type {};
/*! @copydoc is_complete */
template<typename Type>
struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {};
/**
* @brief Helper variable template.
* @tparam Type The type to test.
*/
template<typename Type>
inline constexpr bool is_complete_v = is_complete<Type>::value;
/**
* @brief Provides the member constant `value` to true if a given type is an
* iterator, false otherwise.
* @tparam Type The type to test.
*/
template<typename Type, typename = void>
struct is_iterator: std::false_type {};
/*! @copydoc is_iterator */
template<typename Type>
struct is_iterator<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>
: std::true_type
{};
/**
* @brief Helper variable template.
* @tparam Type The type to test.
*/
template<typename Type>
inline constexpr bool is_iterator_v = is_iterator<Type>::value;
/**
* @brief Provides the member constant `value` to true if a given type is of the
* required iterator type, false otherwise.
* @tparam Type The type to test.
* @tparam It Required iterator type.
*/
template<typename Type, typename It, typename = void>
struct is_iterator_type: std::false_type {};
/*! @copydoc is_iterator_type */
template<typename Type, typename It>
struct is_iterator_type<Type, It, std::enable_if_t<is_iterator_v<Type> && std::is_same_v<Type, It>>>
: std::true_type
{};
/*! @copydoc is_iterator_type */
template<typename Type, typename It>
struct is_iterator_type<Type, It, std::enable_if_t<!std::is_same_v<Type, It>, std::void_t<typename It::iterator_type>>>
: is_iterator_type<Type, typename It::iterator_type>
{};
/**
* @brief Helper variable template.
* @tparam Type The type to test.
* @tparam It Required iterator type.
*/
template<typename Type, typename It>
inline constexpr bool is_iterator_type_v = is_iterator_type<Type, It>::value;
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
template<typename>
[[nodiscard]] constexpr bool is_equality_comparable(...) { return false; }
template<typename Type>
[[nodiscard]] constexpr auto is_equality_comparable(choice_t<0>)
-> decltype(std::declval<Type>() == std::declval<Type>()) { return true; }
template<typename Type>
[[nodiscard]] constexpr auto is_equality_comparable(choice_t<1>)
-> decltype(std::declval<typename Type::value_type>(), std::declval<Type>() == std::declval<Type>()) {
if constexpr(is_iterator_v<Type>) {
return true;
} else if constexpr(std::is_same_v<typename Type::value_type, Type>) {
return is_equality_comparable<Type>(choice<0>);
} else {
return is_equality_comparable<typename Type::value_type>(choice<2>);
}
}
template<typename Type>
[[nodiscard]] constexpr auto is_equality_comparable(choice_t<2>)
-> decltype(std::declval<typename Type::mapped_type>(), std::declval<Type>() == std::declval<Type>()) {
return is_equality_comparable<typename Type::key_type>(choice<2>) && is_equality_comparable<typename Type::mapped_type>(choice<2>);
}
}
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief Provides the member constant `value` to true if a given type is
* equality comparable, false otherwise.
* @tparam Type The type to test.
*/
template<typename Type, typename = void>
struct is_equality_comparable: std::bool_constant<internal::is_equality_comparable<Type>(choice<2>)> {};
/**
* @brief Helper variable template.
* @tparam Type The type to test.
*/
template<class Type>
constexpr auto is_equality_comparable_v = is_equality_comparable<Type>::value;
inline constexpr bool is_equality_comparable_v = is_equality_comparable<Type>::value;
/**
* @brief Transcribes the constness of a type to another type.
* @tparam To The type to which to transcribe the constness.
* @tparam From The type from which to transcribe the constness.
*/
template<typename To, typename From>
struct constness_as {
/*! @brief The type resulting from the transcription of the constness. */
using type = std::remove_const_t<To>;
};
/*! @copydoc constness_as */
template<typename To, typename From>
struct constness_as<To, const From> {
/*! @brief The type resulting from the transcription of the constness. */
using type = 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;
/**
@@ -176,7 +661,7 @@ constexpr auto is_equality_comparable_v = is_equality_comparable<Type>::value;
*/
template<typename Member>
class member_class {
static_assert(std::is_member_pointer_v<Member>);
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...));
@@ -201,29 +686,7 @@ template<typename Member>
using member_class_t = typename member_class<Member>::type;
/**
* @brief Alias template to ease the creation of named values.
* @tparam Value A constant value at least convertible to `ENTT_ID_TYPE`.
*/
template<ENTT_ID_TYPE Value>
using tag = std::integral_constant<ENTT_ID_TYPE, Value>;
}
/**
* @brief Defines an enum class to use for opaque identifiers and a dedicate
* `to_integer` function to convert the identifiers to their underlying type.
* @param clazz The name to use for the enum class.
* @param type The underlying type for the enum class.
*/
#define ENTT_OPAQUE_TYPE(clazz, type)\
enum class clazz: type {};\
constexpr auto to_integral(const clazz id) ENTT_NOEXCEPT {\
return static_cast<std::underlying_type_t<clazz>>(id);\
}\
static_assert(true)
#endif

View File

@@ -18,7 +18,7 @@ struct identity {
* @return The submitted value as-is.
*/
template<class Type>
constexpr Type && operator()(Type &&value) const ENTT_NOEXCEPT {
[[nodiscard]] constexpr Type && operator()(Type &&value) const ENTT_NOEXCEPT {
return std::forward<Type>(value);
}
};
@@ -32,7 +32,7 @@ struct identity {
* @return Pointer to the member.
*/
template<typename Type, typename Class>
constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; }
[[nodiscard]] constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; }
/**
@@ -42,7 +42,7 @@ constexpr auto overload(Type Class:: *member) ENTT_NOEXCEPT { return member; }
* @return Pointer to the function.
*/
template<typename Func>
constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; }
[[nodiscard]] constexpr auto overload(Func *func) ENTT_NOEXCEPT { return func; }
/**
@@ -60,7 +60,8 @@ struct overloaded: Func... {
* @tparam Func Types of function objects.
*/
template<class... Func>
overloaded(Func...) -> overloaded<Func...>;
overloaded(Func...)
-> overloaded<Func...>;
/**

View File

@@ -1,206 +0,0 @@
#ifndef ENTT_ENTITY_ACTOR_HPP
#define ENTT_ENTITY_ACTOR_HPP
#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 the
* entity-component-system architecture.
*
* Tiny wrapper around a registry, for all those users that aren't confident
* with entity-component-system architecture 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;
basic_actor() ENTT_NOEXCEPT
: entt{entt::null}, reg{nullptr}
{}
/**
* @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) ENTT_NOEXCEPT
: entt{other.entt}, reg{other.reg}
{
other.entt = null;
}
/**
* @brief Constructs an actor from a given registry.
* @param ref An instance of the registry class.
*/
explicit basic_actor(registry_type &ref)
: entt{ref.create()}, reg{&ref}
{}
/**
* @brief Constructs an actor from a given entity.
* @param entity A valid entity identifier.
* @param ref An instance of the registry class.
*/
explicit basic_actor(entity_type entity, registry_type &ref) ENTT_NOEXCEPT
: entt{entity}, reg{&ref}
{
ENTT_ASSERT(ref.valid(entity));
}
/*! @brief Default destructor. */
virtual ~basic_actor() {
if(*this) {
reg->destroy(entt);
}
}
/**
* @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) ENTT_NOEXCEPT {
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 components.
* @tparam Component Components for which to perform the check.
* @return True if the actor has all the components, false otherwise.
*/
template<typename... Component>
bool has() const {
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 {
return std::as_const(*reg).template get<Component...>(entt);
}
/*! @copydoc get */
template<typename... Component>
decltype(auto) get() {
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 {
return std::as_const(*reg).template try_get<Component...>(entt);
}
/*! @copydoc try_get */
template<typename... Component>
auto try_get() {
return reg->template try_get<Component...>(entt);
}
/**
* @brief Returns a reference to the underlying registry.
* @return A reference to the underlying registry.
*/
const registry_type & backend() const ENTT_NOEXCEPT {
return *reg;
}
/*! @copydoc backend */
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.
*/
entity_type entity() const ENTT_NOEXCEPT {
return entt;
}
/**
* @brief Checks if an actor refers to a valid entity or not.
* @return True if the actor refers to a valid entity, false otherwise.
*/
explicit operator bool() const {
return reg && reg->valid(entt);
}
private:
entity_type entt;
registry_type *reg;
};
}
#endif

View File

@@ -0,0 +1,34 @@
#ifndef ENTT_ENTITY_COMPONENT_HPP
#define ENTT_ENTITY_COMPONENT_HPP
#include <type_traits>
#include "../config/config.h"
namespace entt {
/*! @brief Commonly used default traits for all types. */
struct basic_component_traits {
/*! @brief Pointer stability, default is `std::false_type`. */
using in_place_delete = std::false_type;
/*! @brief Empty type optimization, default is `ENTT_IGNORE_IF_EMPTY`. */
using ignore_if_empty = ENTT_IGNORE_IF_EMPTY;
};
/**
* @brief Common way to access various properties of components.
* @tparam Type Type of component.
*/
template<typename Type, typename = void>
struct component_traits: basic_component_traits {
static_assert(std::is_same_v<std::decay_t<Type>, Type>, "Unsupported type");
};
}
#endif

View File

@@ -2,103 +2,15 @@
#define ENTT_ENTITY_ENTITY_HPP
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include "../config/config.h"
#include "../core/type_traits.hpp"
namespace entt {
/**
* @brief Entity traits.
*
* Primary template isn't defined on purpose. All the specializations give a
* compile-time error unless the template parameter is an accepted entity type.
*/
template<typename>
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]).
*/
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;
};
/**
* @brief Entity traits for a 32 bits entity identifier.
*
* A 32 bits entity identifier guarantees:
*
* * 20 bits for the entity number (suitable for almost all the games).
* * 12 bit for the version (resets in [0-4095]).
*/
template<>
struct entt_traits<std::uint32_t> {
/*! @brief Underlying entity type. */
using entity_type = std::uint32_t;
/*! @brief Underlying version type. */
using version_type = std::uint16_t;
/*! @brief Difference type. */
using difference_type = std::int64_t;
/*! @brief Mask to use to get the entity number out of an identifier. */
static constexpr std::uint32_t entity_mask = 0xFFFFF;
/*! @brief Mask to use to get the version out of an identifier. */
static constexpr std::uint32_t version_mask = 0xFFF;
/*! @brief Extent of the entity number within an identifier. */
static constexpr auto entity_shift = 20;
};
/**
* @brief Entity traits for a 64 bits entity identifier.
*
* A 64 bits entity identifier guarantees:
*
* * 32 bits for the entity number (an indecently large number).
* * 32 bit for the version (an indecently large number).
*/
template<>
struct entt_traits<std::uint64_t> {
/*! @brief Underlying entity type. */
using entity_type = std::uint64_t;
/*! @brief Underlying version type. */
using version_type = std::uint32_t;
/*! @brief Difference type. */
using difference_type = std::int64_t;
/*! @brief Mask to use to get the entity number out of an identifier. */
static constexpr std::uint64_t entity_mask = 0xFFFFFFFF;
/*! @brief Mask to use to get the version out of an identifier. */
static constexpr std::uint64_t version_mask = 0xFFFFFFFF;
/*! @brief Extent of the entity number within an identifier. */
static constexpr auto entity_shift = 32;
};
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
@@ -108,46 +20,44 @@ struct entt_traits<std::uint64_t> {
namespace internal {
class null {
template<typename Entity>
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
template<typename, typename = void>
struct entt_traits;
public:
template<typename Entity>
constexpr operator Entity() const ENTT_NOEXCEPT {
return Entity{traits_type<Entity>::entity_mask};
}
constexpr bool operator==(null) const ENTT_NOEXCEPT {
return true;
}
template<typename Type>
struct entt_traits<Type, std::enable_if_t<std::is_enum_v<Type>>>
: entt_traits<std::underlying_type_t<Type>>
{};
constexpr bool operator!=(null) const ENTT_NOEXCEPT {
return false;
}
template<typename Entity>
constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
return (to_integral(entity) & traits_type<Entity>::entity_mask) == to_integral(static_cast<Entity>(*this));
}
template<typename Type>
struct entt_traits<Type, std::enable_if_t<std::is_class_v<Type>>>
: entt_traits<typename Type::entity_type>
{};
template<typename Entity>
constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT {
return !(entity == *this);
}
template<>
struct entt_traits<std::uint32_t> {
using entity_type = std::uint32_t;
using version_type = std::uint16_t;
using difference_type = std::int64_t;
static constexpr entity_type entity_mask = 0xFFFFF;
static constexpr entity_type version_mask = 0xFFF;
static constexpr std::size_t entity_shift = 20u;
};
template<typename Entity>
constexpr bool operator==(const Entity entity, null other) ENTT_NOEXCEPT {
return other == entity;
}
template<>
struct entt_traits<std::uint64_t> {
using entity_type = std::uint64_t;
using version_type = std::uint32_t;
using difference_type = std::int64_t;
template<typename Entity>
constexpr bool operator!=(const Entity entity, null other) ENTT_NOEXCEPT {
return other != entity;
}
static constexpr entity_type entity_mask = 0xFFFFFFFF;
static constexpr entity_type version_mask = 0xFFFFFFFF;
static constexpr std::size_t entity_shift = 32u;
};
}
@@ -155,10 +65,266 @@ constexpr bool operator!=(const Entity entity, null other) ENTT_NOEXCEPT {
/**
* Internal details not to be documented.
* @endcond TURN_OFF_DOXYGEN
* @endcond
*/
/**
* @brief Entity traits.
* @tparam Type Type of identifier.
*/
template<typename Type>
class entt_traits: private internal::entt_traits<Type> {
using traits_type = internal::entt_traits<Type>;
public:
/*! @brief Value type. */
using value_type = Type;
/*! @brief Underlying entity type. */
using entity_type = typename traits_type::entity_type;
/*! @brief Underlying version type. */
using version_type = typename traits_type::version_type;
/*! @brief Difference type. */
using difference_type = typename traits_type::difference_type;
/**
* @brief Converts an entity to its underlying type.
* @param value The value to convert.
* @return The integral representation of the given value.
*/
[[nodiscard]] static constexpr entity_type to_integral(const value_type value) ENTT_NOEXCEPT {
return static_cast<entity_type>(value);
}
/**
* @brief Returns the entity part once converted to the underlying type.
* @param value The value to convert.
* @return The integral representation of the entity part.
*/
[[nodiscard]] static constexpr entity_type to_entity(const value_type value) ENTT_NOEXCEPT {
return (to_integral(value) & traits_type::entity_mask);
}
/**
* @brief Returns the version part once converted to the underlying type.
* @param value The value to convert.
* @return The integral representation of the version part.
*/
[[nodiscard]] static constexpr version_type to_version(const value_type value) ENTT_NOEXCEPT {
constexpr auto mask = (traits_type::version_mask << traits_type::entity_shift);
return ((to_integral(value) & mask) >> traits_type::entity_shift);
}
/**
* @brief Constructs an identifier from its parts.
*
* If the version part is not provided, a tombstone is returned.<br/>
* If the entity part is not provided, a null identifier is returned.
*
* @param entity The entity part of the identifier.
* @param version The version part of the identifier.
* @return A properly constructed identifier.
*/
[[nodiscard]] static constexpr value_type construct(const entity_type entity = traits_type::entity_mask, const version_type version = traits_type::version_mask) ENTT_NOEXCEPT {
return value_type{(entity & traits_type::entity_mask) | (static_cast<entity_type>(version) << traits_type::entity_shift)};
}
};
/**
* @brief Converts an entity 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 entt_traits<Entity>::to_integral(entity);
}
/*! @brief Null object for all entity identifiers. */
struct null_t {
/**
* @brief Converts the null object to identifiers of any type.
* @tparam Entity Type of entity identifier.
* @return The null representation for the given type.
*/
template<typename Entity>
[[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT {
return entt_traits<Entity>::construct();
}
/**
* @brief Compares two null objects.
* @param other A null object.
* @return True in all cases.
*/
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const ENTT_NOEXCEPT {
return true;
}
/**
* @brief Compares two null objects.
* @param other A null object.
* @return False in all cases.
*/
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const null_t other) const ENTT_NOEXCEPT {
return false;
}
/**
* @brief Compares a null object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
return entt_traits<Entity>::to_entity(entity) == entt_traits<Entity>::to_entity(*this);
}
/**
* @brief Compares a null object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT {
return !(entity == *this);
}
/**
* @brief Creates a null object from an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier to turn into a null object.
* @return The null representation for the given identifier.
*/
template<typename Entity>
[[nodiscard]] constexpr Entity operator|(const Entity entity) const ENTT_NOEXCEPT {
return entt_traits<Entity>::construct(entt_traits<Entity>::to_entity(*this), entt_traits<Entity>::to_version(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 False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity, const null_t other) ENTT_NOEXCEPT {
return other.operator==(entity);
}
/**
* @brief Compares a null object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @param other A null object yet to be converted.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity, const null_t other) ENTT_NOEXCEPT {
return !(other == entity);
}
/*! @brief Tombstone object for all entity identifiers. */
struct tombstone_t {
/**
* @brief Converts the tombstone object to identifiers of any type.
* @tparam Entity Type of entity identifier.
* @return The tombstone representation for the given type.
*/
template<typename Entity>
[[nodiscard]] constexpr operator Entity() const ENTT_NOEXCEPT {
return entt_traits<Entity>::construct();
}
/**
* @brief Compares two tombstone objects.
* @param other A tombstone object.
* @return True in all cases.
*/
[[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT {
return true;
}
/**
* @brief Compares two tombstone objects.
* @param other A tombstone object.
* @return False in all cases.
*/
[[nodiscard]] constexpr bool operator!=([[maybe_unused]] const tombstone_t other) const ENTT_NOEXCEPT {
return false;
}
/**
* @brief Compares a tombstone object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT {
return entt_traits<Entity>::to_version(entity) == entt_traits<Entity>::to_version(*this);
}
/**
* @brief Compares a tombstone object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT {
return !(entity == *this);
}
/**
* @brief Creates a tombstone object from an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier to turn into a tombstone object.
* @return The tombstone representation for the given identifier.
*/
template<typename Entity>
[[nodiscard]] constexpr Entity operator|(const Entity entity) const ENTT_NOEXCEPT {
return entt_traits<Entity>::construct(entt_traits<Entity>::to_entity(entity));
}
};
/**
* @brief Compares a tombstone 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 tombstone object yet to be converted.
* @return False if the two elements differ, true otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator==(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT {
return other.operator==(entity);
}
/**
* @brief Compares a tombstone object and an entity identifier of any type.
* @tparam Entity Type of entity identifier.
* @param entity Entity identifier with which to compare.
* @param other A tombstone object yet to be converted.
* @return True if the two elements differ, false otherwise.
*/
template<typename Entity>
[[nodiscard]] constexpr bool operator!=(const Entity entity, const tombstone_t other) ENTT_NOEXCEPT {
return !(other == entity);
}
/**
* @brief Compile-time constant for null entities.
*
@@ -166,7 +332,17 @@ constexpr bool operator!=(const Entity entity, null other) ENTT_NOEXCEPT {
* 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{};
/**
* @brief Compile-time constant for tombstone entities.
*
* There exist implicit conversions from this variable to entity identifiers of
* any allowed type. Similarly, there exist comparision operators between the
* tombstone entity and any other entity identifier.
*/
inline constexpr tombstone_t tombstone{};
}

View File

@@ -2,118 +2,143 @@
#define ENTT_ENTITY_FWD_HPP
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include <memory>
#include "../core/fwd.hpp"
namespace entt {
/**
* @brief Alias for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
struct exclude_t: type_list<Type...> {};
template<typename Entity, typename = std::allocator<Entity>>
class basic_sparse_set;
/**
* @brief Variable template for exclusion lists.
* @tparam Type List of types.
*/
template<typename... Type>
constexpr exclude_t<Type...> exclude{};
template<typename, typename Type, typename = std::allocator<Type>>
struct basic_storage;
/**
* @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>
constexpr get_t<Type...> get{};
/*! @class basic_registry */
template <typename>
template<typename>
class basic_registry;
/*! @class basic_view */
template<typename...>
class basic_view;
/*! @class basic_runtime_view */
template<typename...>
struct basic_view;
template<typename>
class basic_runtime_view;
/*! @class basic_group */
template<typename...>
class basic_group;
/*! @class basic_observer */
template<typename>
class basic_observer;
/*! @struct basic_actor */
template <typename>
struct basic_actor;
/*! @class basic_snapshot */
template<typename>
class basic_organizer;
template<typename, typename...>
struct basic_handle;
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. */
ENTT_OPAQUE_TYPE(entity, ENTT_ID_TYPE);
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 observer = basic_observer<entity>;
/*! @brief Alias declaration for the most common use case. */
using actor = basic_actor<entity>;
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 Types 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...>;
}

File diff suppressed because it is too large Load Diff

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

@@ -0,0 +1,355 @@
#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 Type of registry accepted by the handle. */
using registry_type = constness_as_t<basic_registry<std::remove_const_t<Entity>>, Entity>;
/*! @brief Underlying entity identifier. */
using entity_type = typename registry_type::entity_type;
/*! @brief Underlying version type. */
using version_type = typename registry_type::version_type;
/*! @brief Unsigned integer type. */
using size_type = typename registry_type::size_type;
/*! @brief Constructs an invalid handle. */
basic_handle() ENTT_NOEXCEPT
: reg{}, entt{null}
{}
/**
* @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 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.
* @return The number of components actually removed.
*/
template<typename... Component>
size_type remove() const {
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
return reg->template remove<Component...>(entt);
}
/**
* @brief Erases the given components from a handle.
* @sa basic_registry::erase
* @tparam Component Types of components to erase.
*/
template<typename... Component>
void erase() const {
static_assert(sizeof...(Type) == 0 || (type_list_contains_v<type_list<Type...>, Component> && ...), "Invalid type");
reg->template erase<Component...>(entt);
}
/*! @copydoc remove */
template<typename... Component>
[[deprecated("Use ::remove instead")]]
size_type remove_if_exists() const {
return remove<Component...>();
}
/**
* @brief Removes all the components from a handle and makes it orphaned.
* @sa basic_registry::remove_all
*/
[[deprecated("No longer supported")]]
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::all_of
* @tparam Component Components for which to perform the check.
* @return True if the handle has all the components, false otherwise.
*/
template<typename... Component>
[[nodiscard]] decltype(auto) all_of() const {
return reg->template all_of<Component...>(entt);
}
/**
* @brief Checks if a handle has at least one of the given components.
* @sa basic_registry::any_of
* @tparam Component Components for which to perform the check.
* @return True if the handle has at least one of the given components,
* false otherwise.
*/
template<typename... Component>
[[nodiscard]] decltype(auto) any_of() const {
return reg->template any_of<Component...>(entt);
}
/**
* @brief Returns references to the given components for a handle.
* @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

@@ -3,8 +3,10 @@
#include <type_traits>
#include "../core/type_traits.hpp"
#include "../config/config.h"
#include "../core/fwd.hpp"
#include "../core/type_traits.hpp"
#include "../signal/delegate.hpp"
#include "registry.hpp"
#include "fwd.hpp"
@@ -14,13 +16,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.
@@ -35,7 +38,7 @@ struct as_view {
* @return A newly created view.
*/
template<typename Exclude, typename... Component>
operator entt::basic_view<Entity, Exclude, Component...>() const {
operator basic_view<entity_type, Exclude, Component...>() const {
return reg.template view<Component...>(Exclude{});
}
@@ -46,30 +49,30 @@ private:
/**
* @brief Deduction guide.
*
* It allows to deduce the constness of a registry directly from the instance
* provided to the constructor.
*
* @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> &) -> as_view<Entity>;
/*! @copydoc as_view */
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_view(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_view<true, Entity>;
as_view(const basic_registry<Entity> &) -> 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.
@@ -85,8 +88,12 @@ struct as_group {
* @return A newly created group.
*/
template<typename Exclude, typename Get, typename... Owned>
operator entt::basic_group<Entity, Exclude, Get, Owned...>() const {
return reg.template group<Owned...>(Get{}, Exclude{});
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:
@@ -96,19 +103,63 @@ private:
/**
* @brief Deduction guide.
*
* It allows to deduce the constness of a registry directly from the instance
* provided to the constructor.
*
* @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> &) -> as_group<Entity>;
/*! @copydoc as_group */
/**
* @brief Deduction guide.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
as_group(const basic_registry<Entity> &) ENTT_NOEXCEPT -> as_group<true, Entity>;
as_group(const basic_registry<Entity> &) -> as_group<const Entity>;
/**
* @brief Helper to create a listener that directly invokes a member function.
* @tparam Member Member function to invoke on a component of the given type.
* @tparam Entity A valid entity type (see entt_traits for more details).
* @param reg A registry that contains the given entity and its components.
* @param entt Entity from which to get the component.
*/
template<auto Member, typename Entity = entity>
void invoke(basic_registry<Entity> &reg, const Entity entt) {
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 Returns the entity associated with a given component.
*
* @warning
* Currently, this function only works correctly with the default pool as it
* makes assumptions about how the components are laid out.
*
* @tparam Entity A valid entity type (see entt_traits for more details).
* @tparam Component Type of component.
* @param reg A registry that contains the given entity and its components.
* @param instance A valid component instance.
* @return The entity associated with the given component.
*/
template<typename Entity, typename Component>
Entity to_entity(const basic_registry<Entity> &reg, const Component &instance) {
const auto view = reg.template view<const Component>();
const auto *addr = std::addressof(instance);
for(auto it = view.rbegin(), last = view.rend(); it < last; it += ENTT_PACKED_PAGE) {
if(const auto dist = (addr - std::addressof(view.template get<const Component>(*it))); dist >= 0 && dist < ENTT_PACKED_PAGE) {
return *(it + dist);
}
}
return entt::null;
}
}

View File

@@ -9,8 +9,10 @@
#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"
@@ -60,7 +62,7 @@ struct basic_collector<> {
* @return The updated collector.
*/
template<typename AnyOf>
static constexpr auto replace() ENTT_NOEXCEPT {
static constexpr auto update() ENTT_NOEXCEPT {
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>>{};
}
};
@@ -95,7 +97,7 @@ struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule
* @return The updated collector.
*/
template<typename AnyOf>
static constexpr auto replace() ENTT_NOEXCEPT {
static constexpr auto update() ENTT_NOEXCEPT {
return basic_collector<matcher<type_list<>, type_list<>, AnyOf>, current_type, Other...>{};
}
@@ -114,7 +116,7 @@ struct basic_collector<matcher<type_list<Reject...>, type_list<Require...>, Rule
/*! @brief Variable template used to ease the definition of collectors. */
constexpr basic_collector<> collector{};
inline constexpr basic_collector<> collector{};
/**
@@ -129,8 +131,8 @@ constexpr basic_collector<> collector{};
* collector:
*
* * Observing matcher: an observer will return at least all the living entities
* for which one or more of the given components have been explicitly
* replaced and not yet destroyed.
* 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.
@@ -176,20 +178,20 @@ class basic_observer {
template<typename... Reject, typename... Require, typename AnyOf>
struct matcher_handler<matcher<type_list<Reject...>, type_list<Require...>, AnyOf>> {
template<std::size_t Index>
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> &reg, const Entity entt) {
if(reg.template has<Require...>(entt) && !reg.template any<Reject...>(entt)) {
if(auto *comp = obs.view.try_get(entt); !comp) {
obs.view.construct(entt);
static void maybe_valid_if(basic_observer &obs, basic_registry<Entity> &reg, const Entity entt) {
if(reg.template all_of<Require...>(entt) && !reg.template any_of<Reject...>(entt)) {
if(!obs.storage.contains(entt)) {
obs.storage.emplace(entt);
}
obs.view.get(entt) |= (1 << Index);
obs.storage.get(entt) |= (1 << Index);
}
}
template<std::size_t Index>
static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
obs.view.destroy(entt);
static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) {
obs.storage.erase(entt);
}
}
@@ -197,35 +199,42 @@ class basic_observer {
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_replace<AnyOf>().template connect<&maybe_valid_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_replace<AnyOf>().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>
static void maybe_valid_if(basic_observer &obs, const basic_registry<Entity> &reg, const Entity entt) {
if(reg.template has<AllOf..., Require...>(entt) && !reg.template any<NoneOf..., Reject...>(entt)) {
if(auto *comp = obs.view.try_get(entt); !comp) {
obs.view.construct(entt);
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 all_of<AllOf..., Require...>(entt) && !reg.template any_of<NoneOf..., Reject...>(entt);
} else {
return reg.template all_of<AllOf..., Require...>(entt) && ((std::is_same_v<Ignore..., NoneOf> || !reg.template any_of<NoneOf>(entt)) && ...) && !reg.template any_of<Reject...>(entt);
}
}())
{
if(!obs.storage.contains(entt)) {
obs.storage.emplace(entt);
}
obs.view.get(entt) |= (1 << Index);
obs.storage.get(entt) |= (1 << Index);
}
}
template<std::size_t Index>
static void discard_if(basic_observer &obs, const basic_registry<Entity> &, const Entity entt) {
if(auto *value = obs.view.try_get(entt); value && !(*value &= (~(1 << Index)))) {
obs.view.destroy(entt);
static void discard_if(basic_observer &obs, basic_registry<Entity> &, const Entity entt) {
if(obs.storage.contains(entt) && !(obs.storage.get(entt) &= (~(1 << Index)))) {
obs.storage.erase(entt);
}
}
@@ -234,7 +243,7 @@ class basic_observer {
(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>>(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), ...);
}
@@ -250,15 +259,15 @@ class basic_observer {
};
template<typename... Matcher>
static void disconnect(basic_observer &obs, basic_registry<Entity> &reg) {
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);
static_assert(sizeof...(Matcher) < std::numeric_limits<payload_type>::digits, "Too many matchers");
(matcher_handler<Matcher>::template connect<Index>(*this, reg), ...);
release = &basic_observer::disconnect<Matcher...>;
release.template connect<&basic_observer::disconnect<Matcher...>>(reg);
}
public:
@@ -266,12 +275,13 @@ public:
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Input iterator type. */
using iterator_type = typename sparse_set<Entity>::iterator_type;
/*! @brief Random access iterator type. */
using iterator = typename basic_sparse_set<Entity>::iterator;
/*! @brief Default constructor. */
basic_observer()
: target{}, release{}, view{}
: release{},
storage{}
{}
/*! @brief Default copy constructor, deleted on purpose. */
@@ -286,9 +296,7 @@ public:
*/
template<typename... Matcher>
basic_observer(basic_registry<entity_type> &reg, basic_collector<Matcher...>)
: target{&reg},
release{},
view{}
: basic_observer{}
{
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
}
@@ -317,15 +325,14 @@ public:
void connect(basic_registry<entity_type> &reg, basic_collector<Matcher...>) {
disconnect();
connect<Matcher...>(reg, std::index_sequence_for<Matcher...>{});
target = &reg;
view.clear();
storage.clear();
}
/*! @brief Disconnects an observer from the registry it keeps track of. */
void disconnect() {
if(release) {
release(*this, *target);
release = nullptr;
release(*this);
release.reset();
}
}
@@ -333,32 +340,32 @@ public:
* @brief Returns the number of elements in an observer.
* @return Number of elements.
*/
size_type size() const ENTT_NOEXCEPT {
return view.size();
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return storage.size();
}
/**
* @brief Checks whether an observer is empty.
* @return True if the observer is empty, false otherwise.
*/
bool empty() const ENTT_NOEXCEPT {
return view.empty();
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return storage.empty();
}
/**
* @brief Direct access to the list of entities of the observer.
*
* 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 of the entities. Use `begin` and
* `end` if you want to iterate the observer in the expected order.
* Entities are in the reverse order as returned by the `begin`/`end`
* iterators.
*
* @return A pointer to the array of entities.
*/
const entity_type * data() const ENTT_NOEXCEPT {
return view.data();
[[nodiscard]] const entity_type * data() const ENTT_NOEXCEPT {
return storage.data();
}
/**
@@ -369,8 +376,8 @@ public:
*
* @return An iterator to the first entity of the observer.
*/
iterator_type begin() const ENTT_NOEXCEPT {
return view.sparse_set<entity_type>::begin();
[[nodiscard]] iterator begin() const ENTT_NOEXCEPT {
return storage.basic_sparse_set<entity_type>::begin();
}
/**
@@ -383,13 +390,13 @@ public:
* @return An iterator to the entity following the last entity of the
* observer.
*/
iterator_type end() const ENTT_NOEXCEPT {
return view.sparse_set<entity_type>::end();
[[nodiscard]] iterator end() const ENTT_NOEXCEPT {
return storage.basic_sparse_set<entity_type>::end();
}
/*! @brief Clears the underlying container. */
void clear() ENTT_NOEXCEPT {
view.clear();
storage.clear();
}
/**
@@ -407,8 +414,6 @@ public:
*/
template<typename Func>
void each(Func func) const {
static_assert(std::is_invocable_v<Func, entity_type>);
for(const auto entity: *this) {
func(entity);
}
@@ -430,9 +435,8 @@ public:
}
private:
basic_registry<entity_type> *target;
void(* release)(basic_observer &, basic_registry<entity_type> &);
storage<entity_type, payload_type> view;
delegate<void(basic_observer &)> release;
basic_storage<entity_type, payload_type> storage;
};

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,60 @@
#ifndef ENTT_ENTITY_POLY_STORAGE_HPP
#define ENTT_ENTITY_POLY_STORAGE_HPP
#include <cstddef>
#include <tuple>
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../poly/poly.hpp"
#include "fwd.hpp"
namespace entt {
/**
* @brief Basic poly storage implementation.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity>
struct Storage: type_list<type_info() const ENTT_NOEXCEPT> {
/**
* @brief Concept definition.
* @tparam Base Opaque base class from which to inherit.
*/
template<typename Base>
struct type: Base {
/**
* @brief Returns a type info for the contained objects.
* @return The type info for the contained objects.
*/
type_info value_type() const ENTT_NOEXCEPT {
return poly_call<0>(*this);
}
};
/**
* @brief Concept implementation.
* @tparam Type Type for which to generate an implementation.
*/
template<typename Type>
using impl = value_list<&type_id<typename Type::value_type>>;
};
/**
* @brief Defines the poly storage type associate with a given entity type.
* @tparam Entity A valid entity type (see entt_traits for more details).
*/
template<typename Entity, typename = void>
struct poly_storage_traits {
/*! @brief Poly storage type for the given entity type. */
using storage_type = poly<Storage<Entity>>;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,8 @@
#include <algorithm>
#include <type_traits>
#include "../config/config.h"
#include "sparse_set.hpp"
#include "entity.hpp"
#include "sparse_set.hpp"
#include "fwd.hpp"
@@ -55,94 +55,83 @@ namespace entt {
* @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 basic_common_type = basic_sparse_set<Entity>;
using underlying_iterator = typename basic_common_type::iterator;
using underlying_iterator_type = typename sparse_set<Entity>::iterator_type;
class view_iterator final {
[[nodiscard]] bool valid() const {
const auto entt = *it;
class iterator {
friend class basic_runtime_view<Entity>;
return (!stable_storage || (entt != tombstone))
&& std::all_of(pools->begin()++, pools->end(), [entt](const auto *curr) { return curr->contains(entt); })
&& std::none_of(filter->cbegin(), filter->cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
}
using direct_type = std::vector<const sparse_set<Entity> *>;
public:
using difference_type = typename underlying_iterator::difference_type;
using value_type = typename underlying_iterator::value_type;
using pointer = typename underlying_iterator::pointer;
using reference = typename underlying_iterator::reference;
using iterator_category = std::bidirectional_iterator_tag;
iterator(const direct_type *all, underlying_iterator_type curr) ENTT_NOEXCEPT
: pools{all},
it{curr}
view_iterator() ENTT_NOEXCEPT = default;
view_iterator(const std::vector<const basic_common_type *> &cpools, const std::vector<const basic_common_type *> &ignore, underlying_iterator curr) ENTT_NOEXCEPT
: pools{&cpools},
filter{&ignore},
it{curr},
stable_storage{std::any_of(pools->cbegin(), pools->cend(), [](const basic_common_type *cpool) { return (cpool->policy() == deletion_policy::in_place); })}
{
if(it != (*pools)[0]->end() && !valid()) {
++(*this);
}
}
bool valid() const {
return std::all_of(pools->begin()++, pools->end(), [entt = *it](const auto *curr) {
return curr->has(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::bidirectional_iterator_tag;
iterator() ENTT_NOEXCEPT = default;
iterator & operator++() {
view_iterator & operator++() {
while(++it != (*pools)[0]->end() && !valid());
return *this;
}
iterator operator++(int) {
iterator orig = *this;
return operator++(), orig;
view_iterator operator++(int) {
view_iterator orig = *this;
return ++(*this), orig;
}
iterator & operator--() ENTT_NOEXCEPT {
view_iterator & operator--() ENTT_NOEXCEPT {
while(--it != (*pools)[0]->begin() && !valid());
return *this;
}
iterator operator--(int) ENTT_NOEXCEPT {
iterator orig = *this;
view_iterator operator--(int) ENTT_NOEXCEPT {
view_iterator orig = *this;
return operator--(), orig;
}
bool operator==(const iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] bool operator==(const view_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
bool operator!=(const iterator &other) const ENTT_NOEXCEPT {
[[nodiscard]] bool operator!=(const view_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
pointer operator->() const {
[[nodiscard]] pointer operator->() const {
return it.operator->();
}
reference operator*() const {
[[nodiscard]] reference operator*() const {
return *operator->();
}
private:
const direct_type *pools;
underlying_iterator_type it;
const std::vector<const basic_common_type *> *pools;
const std::vector<const basic_common_type *> *filter;
underlying_iterator it;
bool stable_storage;
};
basic_runtime_view(std::vector<const sparse_set<Entity> *> others) ENTT_NOEXCEPT
: pools{std::move(others)}
{
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());
});
// brings the best candidate (if any) on front of the vector
std::rotate(pools.begin(), it, pools.end());
}
bool valid() const {
[[nodiscard]] bool valid() const {
return !pools.empty() && pools.front();
}
@@ -151,23 +140,36 @@ public:
using entity_type = Entity;
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Input iterator type. */
using iterator_type = iterator;
/*! @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 Estimates the number of entities that have the given components.
* @return Estimated number of entities that have the given components.
* @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.
*/
size_type size() const {
return valid() ? pools.front()->size() : size_type{};
basic_runtime_view(std::vector<const basic_common_type *> cpools, std::vector<const basic_common_type *> epools) ENTT_NOEXCEPT
: pools{std::move(cpools)},
filter{std::move(epools)}
{
// brings the best candidate (if any) on front of the vector
std::rotate(pools.begin(), std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
}), pools.end());
}
/**
* @brief Checks if the view is definitely empty.
* @return True if the view is definitely empty, false otherwise.
* @brief Estimates the number of entities iterated by the view.
* @return Estimated number of entities iterated by the view.
*/
bool empty() const {
return !valid() || pools.front()->empty();
[[nodiscard]] size_type size_hint() const {
return valid() ? pools.front()->size() : size_type{};
}
/**
@@ -178,20 +180,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 {
iterator_type it{};
if(valid()) {
it = { &pools, pools[0]->begin() };
}
return it;
[[nodiscard]] iterator begin() const {
return valid() ? iterator{pools, filter, pools[0]->begin()} : iterator{};
}
/**
@@ -202,21 +194,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 {
iterator_type it{};
if(valid()) {
it = { &pools, pools[0]->end() };
}
return it;
[[nodiscard]] iterator end() const {
return valid() ? iterator{pools, filter, pools[0]->end()} : iterator{};
}
/**
@@ -224,10 +206,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 {
return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *view) {
return view->find(entt) != view->end();
});
[[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); });
}
/**
@@ -253,7 +234,8 @@ public:
}
private:
std::vector<const sparse_set<Entity> *> pools;
std::vector<const basic_common_type *> pools;
std::vector<const basic_common_type *> filter;
};

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,49 +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);
using traits_type = entt_traits<std::underlying_type_t<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 {
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));
}
if(reg->template all_of<Component>(entt)) {
std::apply(archive, std::tuple_cat(std::make_tuple(entt), view.get(entt)));
}
}
}
template<typename... Component, typename Archive, typename It, std::size_t... 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 all_of<Component>(entt) ? ++size[Index] : 0u), ...);
}
(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;
@@ -78,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.
@@ -89,36 +91,16 @@ public:
*/
template<typename Archive>
const basic_snapshot & entities(Archive &archive) const {
archive(typename traits_type::entity_type(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(typename traits_type::entity_type(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->released());
return *this;
}
@@ -135,8 +117,14 @@ public:
*/
template<typename... Component, typename Archive>
const basic_snapshot & component(Archive &archive) const {
(component<Component>(archive, reg->template data<Component>(), reg->template data<Component>() + reg->template size<Component>()), ...);
return *this;
if constexpr(sizeof...(Component) == 1u) {
const auto view = reg->template view<const Component...>();
(component<Component>(archive, view.data(), view.data() + view.size()), ...);
return *this;
} else {
(component<Component>(archive), ...);
return *this;
}
}
/**
@@ -160,9 +148,7 @@ public:
}
private:
const basic_registry<Entity> *reg;
const Entity seed;
follow_fn_type *follow;
const basic_registry<entity_type> *reg;
};
@@ -178,55 +164,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);
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
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 discard) const {
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, discard);
}
}
entity_type entt{};
template<typename Type, typename Archive, typename... Args>
void assign(Archive &archive, Args... args) const {
typename traits_type::entity_type length{};
archive(length);
while(length--) {
static constexpr auto discard = 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, discard);
reg->template assign<Type>(args..., entt);
} else {
Type instance{};
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
ENTT_ASSERT(entity == entt, "Entity not available for use");
reg->template emplace<Type>(entity);
}
} else {
Type instance{};
while(length--) {
archive(entt, instance);
force(*reg, entt, discard);
reg->template assign<Type>(args..., entt, std::as_const(instance));
const auto entity = reg->valid(entt) ? entt : reg->create(entt);
ENTT_ASSERT(entity == entt, "Entity not available for use");
reg->template emplace<Type>(entity, std::move(instance));
}
}
}
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(), "Registry must be empty");
}
/*! @brief Default move constructor. */
basic_snapshot_loader(basic_snapshot_loader &&) = default;
@@ -245,25 +225,20 @@ public:
*/
template<typename Archive>
const basic_snapshot_loader & entities(Archive &archive) const {
static constexpr auto discard = false;
assure(archive, discard);
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 discard = true;
assure(archive, discard);
return *this;
}
@@ -298,15 +273,14 @@ public:
*/
const basic_snapshot_loader & orphans() const {
reg->orphans([this](const auto entt) {
reg->destroy(entt);
reg->release(entt);
});
return *this;
}
private:
basic_registry<Entity> *reg;
force_fn_type *force;
basic_registry<entity_type> *reg;
};
@@ -314,7 +288,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.
@@ -328,12 +302,10 @@ private:
*/
template<typename Entity>
class basic_continuous_loader {
using traits_type = entt_traits<std::underlying_type_t<Entity>>;
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);
@@ -347,7 +319,10 @@ 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;
}
@@ -363,12 +338,12 @@ class basic_continuous_loader {
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> && std::is_same_v<second_type, Entity>) {
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>) {
} 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>);
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));
}
}
@@ -380,7 +355,7 @@ class basic_continuous_loader {
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>);
static_assert(std::is_same_v<typename Container::value_type, entity_type>, "Invalid value type");
for(auto &&entt: container) {
entt = map(entt);
@@ -391,7 +366,7 @@ class basic_continuous_loader {
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>) {
} else if constexpr(std::is_same_v<Member, entity_type>) {
instance.*member = map(instance.*member);
} else {
// maybe a container? let's try...
@@ -399,25 +374,13 @@ class basic_continuous_loader {
}
}
template<typename Archive>
void assure(Archive &archive, void(basic_continuous_loader:: *member)(Entity)) {
typename traits_type::entity_type length{};
archive(length);
while(length--) {
Entity entt{};
archive(entt);
(this->*member)(entt);
}
}
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 remove_if_exists<Component>(local);
reg->template remove<Component>(local);
}
}
}
@@ -427,19 +390,22 @@ class basic_continuous_loader {
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));
}
}
}
@@ -449,7 +415,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
@@ -474,23 +440,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 = traits_type::to_entity(entt); 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;
}
@@ -515,7 +482,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;
}
@@ -562,7 +529,7 @@ public:
*/
basic_continuous_loader & orphans() {
reg->orphans([this](const auto entt) {
reg->destroy(entt);
reg->release(entt);
});
return *this;
@@ -573,7 +540,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());
}
@@ -582,7 +549,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;

File diff suppressed because it is too large Load Diff

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

@@ -1,4 +1,6 @@
#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"
@@ -7,21 +9,37 @@
#include "core/type_info.hpp"
#include "core/type_traits.hpp"
#include "core/utility.hpp"
#include "entity/actor.hpp"
#include "entity/component.hpp"
#include "entity/entity.hpp"
#include "entity/group.hpp"
#include "entity/handle.hpp"
#include "entity/helper.hpp"
#include "entity/observer.hpp"
#include "entity/organizer.hpp"
#include "entity/poly_storage.hpp"
#include "entity/registry.hpp"
#include "entity/runtime_view.hpp"
#include "entity/snapshot.hpp"
#include "entity/sparse_set.hpp"
#include "entity/storage.hpp"
#include "entity/utility.hpp"
#include "entity/view.hpp"
#include "locator/locator.hpp"
#include "meta/adl_pointer.hpp"
#include "meta/container.hpp"
#include "meta/ctx.hpp"
#include "meta/factory.hpp"
#include "meta/meta.hpp"
#include "meta/node.hpp"
#include "meta/pointer.hpp"
#include "meta/policy.hpp"
#include "meta/range.hpp"
#include "meta/resolve.hpp"
#include "meta/template.hpp"
#include "meta/type_traits.hpp"
#include "meta/utility.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,5 @@
#include "core/fwd.hpp"
#include "entity/fwd.hpp"
#include "poly/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.
*/
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.
*/
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.
*/
static Service & ref() ENTT_NOEXCEPT {
[[nodiscard]] static Service & ref() ENTT_NOEXCEPT {
return *service;
}
@@ -87,7 +87,7 @@ struct service_locator {
* @param ptr Service to use to replace the current one.
*/
static void set(std::shared_ptr<Service> ptr) {
ENTT_ASSERT(static_cast<bool>(ptr));
ENTT_ASSERT(static_cast<bool>(ptr), "Null service not allowed");
service = std::move(ptr);
}

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

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

@@ -0,0 +1,406 @@
#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 Type of container. */
using type = Container;
};
/**
* @brief Basic STL-compatible container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_container {
/**
* @brief Returns the size of the given container.
* @param cont The container for which to return the size.
* @return The size of the given container.
*/
[[nodiscard]] static typename Container::size_type size(const Container &cont) ENTT_NOEXCEPT {
return cont.size();
}
/**
* @brief Returns an iterator to the first element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator to the first element of the given container.
*/
[[nodiscard]] static typename Container::iterator begin(Container &cont) {
return cont.begin();
}
/**
* @brief Returns an iterator to the first element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator to the first element of the given container.
*/
[[nodiscard]] static typename Container::const_iterator cbegin(const Container &cont) {
return cont.begin();
}
/**
* @brief Returns an iterator past the last element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator past the last element of the given container.
*/
[[nodiscard]] static typename Container::iterator end(Container &cont) {
return cont.end();
}
/**
* @brief Returns an iterator past the last element of the given container.
* @param cont The container for which to return the iterator.
* @return An iterator past the last element of the given container.
*/
[[nodiscard]] static typename Container::const_iterator cend(const Container &cont) {
return cont.end();
}
};
/**
* @brief Basic STL-compatible associative container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_associative_container {
/**
* @brief Returns an iterator to the element with key equivalent to the
* given one, if any.
* @param cont The container in which to search for the element.
* @param key The key of the element to search.
* @return An iterator to the element with the given key, if any.
*/
[[nodiscard]] static typename Container::iterator find(Container &cont, const typename Container::key_type &key) {
return cont.find(key);
}
/*! @copydoc find */
[[nodiscard]] static typename Container::const_iterator cfind(const Container &cont, const typename Container::key_type &key) {
return cont.find(key);
}
};
/**
* @brief Basic STL-compatible dynamic container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_dynamic_container {
/**
* @brief Clears the content of the given container.
* @param cont The container for which to clear the content.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear([[maybe_unused]] Container &cont) {
return cont.clear(), true;
}
};
/**
* @brief Basic STL-compatible dynamic associative container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_dynamic_associative_container {
/**
* @brief Removes the specified element from the given container.
* @param cont The container from which to remove the element.
* @param key The element to remove.
* @return A bool denoting whether the removal took place.
*/
[[nodiscard]] static bool erase([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
const auto sz = cont.size();
return cont.erase(key) != sz;
}
};
/**
* @brief Basic STL-compatible sequence container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct basic_sequence_container {
/**
* @brief Returns a reference to the element at the specified location of
* the given container (no bounds checking is performed).
* @param cont The container from which to get the element.
* @param pos The position of the element to return.
* @return A reference to the requested element.
*/
[[nodiscard]] static typename Container::reference get(Container &cont, typename Container::size_type pos) {
return cont[pos];
}
/*! @copydoc get */
[[nodiscard]] static typename Container::const_reference cget(const Container &cont, typename Container::size_type pos) {
return cont[pos];
}
};
/**
* @brief STL-compatible dynamic associative key-only container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct dynamic_associative_key_only_container {
/**
* @brief Inserts an element into the given container.
* @param cont The container in which to insert the element.
* @param key The element to insert.
* @return A bool denoting whether the insertion took place.
*/
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key) {
return cont.insert(key).second;
}
};
/**
* @brief STL-compatible dynamic key-value associative container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct dynamic_associative_key_value_container {
/**
* @brief Inserts an element (a key/value pair) into the given container.
* @param cont The container in which to insert the element.
* @param key The key of the element to insert.
* @param value The value of the element to insert.
* @return A bool denoting whether the insertion took place.
*/
[[nodiscard]] static bool insert([[maybe_unused]] Container &cont, [[maybe_unused]] const typename Container::key_type &key, [[maybe_unused]] const typename Container::mapped_type &value) {
return cont.insert(std::make_pair(key, value)).second;
}
};
/**
* @brief STL-compatible dynamic sequence container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct dynamic_sequence_container {
/**
* @brief Resizes the given container to contain the given number of
* elements.
* @param cont The container to resize.
* @param sz The new size of the container.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool resize([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::size_type sz) {
return cont.resize(sz), true;
}
/**
* @brief Inserts an element at the specified location of the given
* container.
* @param cont The container into which to insert the element.
* @param it Iterator before which the element will be inserted.
* @param value Element value to insert.
* @return A pair consisting of an iterator to the inserted element (in case
* of success) and a bool denoting whether the insertion took place.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> insert([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it, [[maybe_unused]] const typename Container::value_type &value) {
return { cont.insert(it, value), true };
}
/**
* @brief Removes the element at the specified location from the given
* container.
* @param cont The container from which to remove the element.
* @param it Iterator to the element to remove.
* @return A pair consisting of an iterator following the last removed
* element (in case of success) and a bool denoting whether the insertion
* took place.
*/
[[nodiscard]] static std::pair<typename Container::iterator, bool> erase([[maybe_unused]] Container &cont, [[maybe_unused]] typename Container::const_iterator it) {
return { cont.erase(it), true };
}
};
/**
* @brief STL-compatible fixed sequence container traits
* @tparam Container The type of the container.
*/
template<typename Container>
struct fixed_sequence_container {
/**
* @brief Does nothing.
* @return False to indicate failure in all cases.
*/
[[nodiscard]] static bool resize(const Container &, typename Container::size_type) {
return false;
}
/**
* @brief Does nothing.
* @return False to indicate failure in all cases.
*/
[[nodiscard]] static bool clear(const Container &) {
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 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 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

View File

@@ -2,17 +2,18 @@
#define ENTT_META_FACTORY_HPP
#include <tuple>
#include <array>
#include <cstddef>
#include <utility>
#include <functional>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../core/utility.hpp"
#include "policy.hpp"
#include "meta.hpp"
#include "node.hpp"
#include "policy.hpp"
#include "utility.hpp"
namespace entt {
@@ -27,203 +28,18 @@ namespace entt {
namespace internal {
template<typename>
struct meta_function_helper;
template<typename Ret, typename... Args>
struct meta_function_helper<Ret(Args...)> {
using return_type = std::remove_cv_t<std::remove_reference_t<Ret>>;
using args_type = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
static constexpr std::index_sequence_for<Args...> index_sequence{};
static constexpr auto is_const = false;
static auto arg(typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
return std::array<meta_type_node *, sizeof...(Args)>{{meta_info<Args>::resolve()...}}[index];
}
};
template<typename Ret, typename... Args>
struct meta_function_helper<Ret(Args...) const>: meta_function_helper<Ret(Args...)> {
static constexpr auto is_const = true;
};
template<typename Ret, typename... Args, typename Class>
constexpr meta_function_helper<Ret(Args...)>
to_meta_function_helper(Ret(Class:: *)(Args...));
template<typename Ret, typename... Args, typename Class>
constexpr meta_function_helper<Ret(Args...) const>
to_meta_function_helper(Ret(Class:: *)(Args...) const);
template<typename Ret, typename... Args>
constexpr meta_function_helper<Ret(Args...)>
to_meta_function_helper(Ret(*)(Args...));
constexpr void to_meta_function_helper(...);
template<typename Candidate>
using meta_function_helper_t = decltype(to_meta_function_helper(std::declval<Candidate>()));
template<typename Type, typename... Args, std::size_t... Indexes>
meta_any construct(meta_any * const args, std::index_sequence<Indexes...>) {
[[maybe_unused]] auto direct = std::make_tuple((args+Indexes)->try_cast<Args>()...);
meta_any any{};
if(((std::get<Indexes>(direct) || (args+Indexes)->convert<Args>()) && ...)) {
any = Type{(std::get<Indexes>(direct) ? *std::get<Indexes>(direct) : (args+Indexes)->cast<Args>())...};
}
return any;
template<typename Node>
[[nodiscard]] bool find_if(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
return node && (node == candidate || find_if(candidate, node->next));
}
template<bool Const, typename Type, auto Data>
bool setter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any index, [[maybe_unused]] meta_any value) {
bool accepted = false;
if constexpr(!Const) {
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
using helper_type = meta_function_helper_t<decltype(Data)>;
using data_type = std::tuple_element_t<!std::is_member_function_pointer_v<decltype(Data)>, typename helper_type::args_type>;
static_assert(std::is_invocable_v<decltype(Data), Type &, data_type>);
auto * const clazz = instance.try_cast<Type>();
auto * const direct = value.try_cast<data_type>();
if(clazz && (direct || value.convert<data_type>())) {
std::invoke(Data, *clazz, direct ? *direct : value.cast<data_type>());
accepted = true;
}
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
static_assert(std::is_invocable_v<decltype(Data), Type *>);
auto * const clazz = instance.try_cast<Type>();
if constexpr(std::is_array_v<data_type>) {
using underlying_type = std::remove_extent_t<data_type>;
auto * const direct = value.try_cast<underlying_type>();
auto * const idx = index.try_cast<std::size_t>();
if(clazz && idx && (direct || value.convert<underlying_type>())) {
std::invoke(Data, clazz)[*idx] = direct ? *direct : value.cast<underlying_type>();
accepted = true;
}
} else {
auto * const direct = value.try_cast<data_type>();
if(clazz && (direct || value.convert<data_type>())) {
std::invoke(Data, clazz) = (direct ? *direct : value.cast<data_type>());
accepted = true;
}
}
} else {
static_assert(std::is_pointer_v<decltype(Data)>);
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(*Data)>>;
if constexpr(std::is_array_v<data_type>) {
using underlying_type = std::remove_extent_t<data_type>;
auto * const direct = value.try_cast<underlying_type>();
auto * const idx = index.try_cast<std::size_t>();
if(idx && (direct || value.convert<underlying_type>())) {
(*Data)[*idx] = (direct ? *direct : value.cast<underlying_type>());
accepted = true;
}
} else {
auto * const direct = value.try_cast<data_type>();
if(direct || value.convert<data_type>()) {
*Data = (direct ? *direct : value.cast<data_type>());
accepted = true;
}
}
}
}
return accepted;
}
template<typename Type, auto Data, typename Policy>
meta_any getter([[maybe_unused]] meta_any instance, [[maybe_unused]] meta_any index) {
auto dispatch = [](auto &&value) {
if constexpr(std::is_same_v<Policy, as_void_t>) {
return meta_any{std::in_place_type<void>, std::forward<decltype(value)>(value)};
} else if constexpr(std::is_same_v<Policy, as_alias_t>) {
return meta_any{std::ref(std::forward<decltype(value)>(value))};
} else {
static_assert(std::is_same_v<Policy, as_is_t>);
return meta_any{std::forward<decltype(value)>(value)};
}
};
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>> || std::is_member_function_pointer_v<decltype(Data)>) {
static_assert(std::is_invocable_v<decltype(Data), Type &>);
auto * const clazz = instance.try_cast<Type>();
return clazz ? dispatch(std::invoke(Data, *clazz)) : meta_any{};
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
using data_type = std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>;
static_assert(std::is_invocable_v<decltype(Data), Type *>);
auto * const clazz = instance.try_cast<Type>();
if constexpr(std::is_array_v<data_type>) {
auto * const idx = index.try_cast<std::size_t>();
return (clazz && idx) ? dispatch(std::invoke(Data, clazz)[*idx]) : meta_any{};
} else {
return clazz ? dispatch(std::invoke(Data, clazz)) : meta_any{};
}
template<typename Id, typename Node>
[[nodiscard]] bool find_if_not(const Id id, Node *node, const Node *owner) ENTT_NOEXCEPT {
if constexpr(std::is_pointer_v<Id>) {
return node && ((*node->id == *id && node != owner) || find_if_not(id, node->next, owner));
} else {
static_assert(std::is_pointer_v<std::decay_t<decltype(Data)>>);
if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
auto * const idx = index.try_cast<std::size_t>();
return idx ? dispatch((*Data)[*idx]) : meta_any{};
} else {
return dispatch(*Data);
}
}
}
template<typename Type, auto Candidate, typename Policy, std::size_t... Indexes>
meta_any invoke([[maybe_unused]] meta_any instance, meta_any *args, std::index_sequence<Indexes...>) {
using helper_type = meta_function_helper_t<decltype(Candidate)>;
auto dispatch = [](auto *... params) {
if constexpr(std::is_void_v<typename helper_type::return_type> || std::is_same_v<Policy, as_void_t>) {
std::invoke(Candidate, *params...);
return meta_any{std::in_place_type<void>};
} else if constexpr(std::is_same_v<Policy, as_alias_t>) {
return meta_any{std::ref(std::invoke(Candidate, *params...))};
} else {
static_assert(std::is_same_v<Policy, as_is_t>);
return meta_any{std::invoke(Candidate, *params...)};
}
};
[[maybe_unused]] const auto direct = std::make_tuple([](meta_any *any, auto *value) {
using arg_type = std::remove_reference_t<decltype(*value)>;
if(!value && any->convert<arg_type>()) {
value = any->try_cast<arg_type>();
}
return value;
}(args+Indexes, (args+Indexes)->try_cast<std::tuple_element_t<Indexes, typename helper_type::args_type>>())...);
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Candidate)>>>) {
return (std::get<Indexes>(direct) && ...) ? dispatch(std::get<Indexes>(direct)...) : meta_any{};
} else {
auto * const clazz = instance.try_cast<Type>();
return (clazz && (std::get<Indexes>(direct) && ...)) ? dispatch(clazz, std::get<Indexes>(direct)...) : meta_any{};
return node && ((node->id == id && node != owner) || find_if_not(id, node->next, owner));
}
}
@@ -233,7 +49,7 @@ meta_any invoke([[maybe_unused]] meta_any instance, meta_any *args, std::index_s
/**
* Internal details not to be documented.
* @endcond TURN_OFF_DOXYGEN
* @endcond
*/
@@ -246,7 +62,7 @@ meta_any invoke([[maybe_unused]] meta_any instance, meta_any *args, std::index_s
* there are no subtle errors at runtime.
*/
template<typename...>
class meta_factory;
struct meta_factory;
/**
@@ -255,11 +71,8 @@ class meta_factory;
* @tparam Spec Property specialization pack used to disambiguate overloads.
*/
template<typename Type, typename... Spec>
class meta_factory<Type, Spec...>: public meta_factory<Type> {
bool exists(const meta_any &key, const internal::meta_prop_node *node) ENTT_NOEXCEPT {
return node && (node->key() == key || exists(key, node->next));
}
struct meta_factory<Type, Spec...>: public meta_factory<Type> {
private:
template<std::size_t Step = 0, std::size_t... Index, typename... Property, typename... Other>
void unpack(std::index_sequence<Index...>, std::tuple<Property...> property, Other &&... other) {
unroll<Step>(choice<3>, std::move(std::get<Index>(property))..., std::forward<Other>(other)...);
@@ -291,27 +104,25 @@ class meta_factory<Type, Spec...>: public meta_factory<Type> {
template<std::size_t>
void unroll(choice_t<0>) {}
template<std::size_t = 0, typename Key, typename... Value>
void assign(Key &&key, Value &&... value) {
static const auto property{std::make_tuple(std::forward<Key>(key), std::forward<Value>(value)...)};
template<std::size_t = 0, typename Key>
void assign(Key &&key, meta_any value = {}) {
static meta_any property[2u]{};
static internal::meta_prop_node node{
nullptr,
[]() -> meta_any {
return std::get<0>(property);
},
[]() -> meta_any {
if constexpr(sizeof...(Value) == 0) {
return {};
} else {
return std::get<1>(property);
}
}
property[0u],
property[1u]
};
ENTT_ASSERT(!exists(node.key(), *curr));
node.next = *curr;
*curr = &node;
entt::meta_any instance{std::forward<Key>(key)};
ENTT_ASSERT(!internal::find_if_not(&instance, *curr, &node), "Duplicate key");
property[0u] = std::move(instance);
property[1u] = std::move(value);
if(!internal::find_if(&node, *curr)) {
node.next = *curr;
*curr = &node;
}
}
public:
@@ -319,7 +130,7 @@ public:
* @brief Constructs an extended factory from a given node.
* @param target The underlying node to which to assign the properties.
*/
meta_factory(entt::internal::meta_prop_node **target) ENTT_NOEXCEPT
meta_factory(internal::meta_prop_node **target) ENTT_NOEXCEPT
: curr{target}
{}
@@ -362,7 +173,7 @@ public:
}
private:
entt::internal::meta_prop_node **curr;
internal::meta_prop_node **curr;
};
@@ -371,41 +182,26 @@ private:
* @tparam Type Reflected type for which the factory was created.
*/
template<typename Type>
class meta_factory<Type> {
template<typename Node>
bool exists(const Node *candidate, const Node *node) ENTT_NOEXCEPT {
return node && (node == candidate || exists(candidate, node->next));
}
template<typename Node>
bool exists(const ENTT_ID_TYPE alias, const Node *node) ENTT_NOEXCEPT {
return node && (node->alias == alias || exists(alias, node->next));
}
public:
struct meta_factory<Type> {
/**
* @brief Extends a meta type by assigning it an alias.
* @param value Unique identifier.
* @brief Makes a meta type _searchable_.
* @param id Optional unique identifier.
* @return An extended meta factory for the given type.
*/
auto alias(const ENTT_ID_TYPE value) ENTT_NOEXCEPT {
auto type(const id_type id = type_hash<Type>::value()) {
auto * const node = internal::meta_info<Type>::resolve();
ENTT_ASSERT(!exists(value, *internal::meta_info<>::global));
ENTT_ASSERT(!exists(node, *internal::meta_info<>::global));
node->alias = value;
node->next = *internal::meta_info<>::global;
*internal::meta_info<>::global = node;
ENTT_ASSERT(!internal::find_if_not(id, *internal::meta_context::global(), node), "Duplicate identifier");
node->id = id;
if(!internal::find_if(node, *internal::meta_context::global())) {
node->next = *internal::meta_context::global();
*internal::meta_context::global() = node;
}
return meta_factory<Type, Type>{&node->prop};
}
/*! @copydoc alias */
[[deprecated("Use ::alias instead")]]
auto type(const ENTT_ID_TYPE value) ENTT_NOEXCEPT {
return alias(value);
}
/**
* @brief Assigns a meta base to a meta type.
*
@@ -416,51 +212,22 @@ public:
*/
template<typename Base>
auto base() ENTT_NOEXCEPT {
static_assert(std::is_base_of_v<Base, Type>);
static_assert(std::is_base_of_v<Base, Type>, "Invalid base type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_base_node node{
type,
nullptr,
&internal::meta_info<Base>::resolve,
[](void *instance) ENTT_NOEXCEPT -> void * {
return static_cast<Base *>(static_cast<Type *>(instance));
[](const void *instance) ENTT_NOEXCEPT -> const void * {
return static_cast<const Base *>(static_cast<const Type *>(instance));
}
};
ENTT_ASSERT(!exists(&node, type->base));
node.next = type->base;
type->base = &node;
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta conversion function to a meta type.
*
* The given type must be such that an instance of the reflected type can be
* converted to it.
*
* @tparam To Type of the conversion function to assign to the meta type.
* @return A meta factory for the parent type.
*/
template<typename To>
auto conv() ENTT_NOEXCEPT {
static_assert(std::is_convertible_v<Type, To>);
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_conv_node node{
type,
nullptr,
&internal::meta_info<To>::resolve,
[](const void *instance) -> meta_any {
return static_cast<To>(*static_cast<const Type *>(instance));
}
};
ENTT_ASSERT(!exists(&node, type->conv));
node.next = type->conv;
type->conv = &node;
if(!internal::find_if(&node, type->base)) {
node.next = type->base;
type->base = &node;
}
return meta_factory<Type>{};
}
@@ -478,7 +245,7 @@ public:
* @return A meta factory for the parent type.
*/
template<auto Candidate>
auto conv() ENTT_NOEXCEPT {
std::enable_if_t<std::is_member_function_pointer_v<decltype(Candidate)>, meta_factory<Type>> conv() ENTT_NOEXCEPT {
using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
auto * const type = internal::meta_info<Type>::resolve();
@@ -487,13 +254,68 @@ public:
nullptr,
&internal::meta_info<conv_type>::resolve,
[](const void *instance) -> meta_any {
return std::invoke(Candidate, *static_cast<const Type *>(instance));
return (static_cast<const Type *>(instance)->*Candidate)();
}
};
ENTT_ASSERT(!exists(&node, type->conv));
node.next = type->conv;
type->conv = &node;
if(!internal::find_if(&node, type->conv)) {
node.next = type->conv;
type->conv = &node;
}
return meta_factory<Type>{};
}
/*! @copydoc conv */
template<auto Candidate>
std::enable_if_t<!std::is_member_function_pointer_v<decltype(Candidate)>, meta_factory<Type>> conv() ENTT_NOEXCEPT {
using conv_type = std::invoke_result_t<decltype(Candidate), Type &>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_conv_node node{
type,
nullptr,
&internal::meta_info<conv_type>::resolve,
[](const void *instance) -> meta_any {
return Candidate(*static_cast<const Type *>(instance));
}
};
if(!internal::find_if(&node, type->conv)) {
node.next = type->conv;
type->conv = &node;
}
return meta_factory<Type>{};
}
/**
* @brief Assigns a meta conversion function to a meta type.
*
* The given type must be such that an instance of the reflected type can be
* converted to it.
*
* @tparam To Type of the conversion function to assign to the meta type.
* @return A meta factory for the parent type.
*/
template<typename To>
auto conv() ENTT_NOEXCEPT {
static_assert(std::is_convertible_v<Type, To>, "Could not convert to the required type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_conv_node node{
type,
nullptr,
&internal::meta_info<To>::resolve,
[](const void *instance) -> meta_any {
return static_cast<To>(*static_cast<const Type *>(instance));
}
};
if(!internal::find_if(&node, type->conv)) {
node.next = type->conv;
type->conv = &node;
}
return meta_factory<Type>{};
}
@@ -501,38 +323,41 @@ public:
/**
* @brief Assigns a meta constructor to a meta type.
*
* Free functions can be assigned to meta types in the role of constructors.
* All that is required is that they return an instance of the underlying
* type.<br/>
* Both member functions and free function can be assigned to meta types in
* the role of constructors. All that is required is that they return an
* instance of the underlying type.<br/>
* From a client's point of view, nothing changes if a constructor of a meta
* type is a built-in one or a free function.
* type is a built-in one or not.
*
* @tparam Func The actual function to use as a constructor.
* @tparam Candidate The actual function to use as a constructor.
* @tparam Policy Optional policy (no policy set by default).
* @return An extended meta factory for the parent type.
*/
template<auto Func, typename Policy = as_is_t>
template<auto Candidate, typename Policy = as_is_t>
auto ctor() ENTT_NOEXCEPT {
using helper_type = internal::meta_function_helper_t<decltype(Func)>;
static_assert(std::is_same_v<typename helper_type::return_type, Type>);
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
static_assert(std::is_same_v<std::decay_t<typename descriptor::return_type>, Type>, "The function doesn't return an object of the required type");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_ctor_node node{
type,
nullptr,
nullptr,
helper_type::index_sequence.size(),
&helper_type::arg,
[](meta_any * const any) {
return internal::invoke<Type, Func, Policy>({}, any, helper_type::index_sequence);
descriptor::args_type::size,
[](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
return meta_arg(typename descriptor::args_type{}, index);
},
[](meta_any * const args) {
return meta_invoke<Type, Candidate, Policy>({}, args, std::make_index_sequence<descriptor::args_type::size>{});
}
};
ENTT_ASSERT(!exists(&node, type->ctor));
node.next = type->ctor;
type->ctor = &node;
if(!internal::find_if(&node, type->ctor)) {
node.next = type->ctor;
type->ctor = &node;
}
return meta_factory<Type, std::integral_constant<decltype(Func), Func>>{&node.prop};
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
}
/**
@@ -547,23 +372,26 @@ public:
*/
template<typename... Args>
auto ctor() ENTT_NOEXCEPT {
using helper_type = internal::meta_function_helper_t<Type(*)(Args...)>;
using descriptor = meta_function_helper_t<Type, Type(*)(Args...)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_ctor_node node{
type,
nullptr,
nullptr,
helper_type::index_sequence.size(),
&helper_type::arg,
[](meta_any * const any) {
return internal::construct<Type, std::remove_cv_t<std::remove_reference_t<Args>>...>(any, helper_type::index_sequence);
descriptor::args_type::size,
[](const typename internal::meta_ctor_node::size_type index) ENTT_NOEXCEPT {
return meta_arg(typename descriptor::args_type{}, index);
},
[](meta_any * const args) {
return meta_construct<Type, Args...>(args, std::make_index_sequence<descriptor::args_type::size>{});
}
};
ENTT_ASSERT(!exists(&node, type->ctor));
node.next = type->ctor;
type->ctor = &node;
if(!internal::find_if(&node, type->ctor)) {
node.next = type->ctor;
type->ctor = &node;
}
return meta_factory<Type, Type(Args...)>{&node.prop};
}
@@ -586,21 +414,13 @@ public:
*/
template<auto Func>
auto dtor() ENTT_NOEXCEPT {
static_assert(std::is_invocable_v<decltype(Func), Type &>);
static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_dtor_node node{
type,
[](void *instance) {
if(instance) {
std::invoke(Func, *static_cast<Type *>(instance));
}
}
type->dtor = [](void *instance) {
Func(*static_cast<Type *>(instance));
};
ENTT_ASSERT(!type->dtor);
type->dtor = &node;
return meta_factory<Type>{};
}
@@ -614,72 +434,39 @@ public:
*
* @tparam Data The actual variable to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param alias Unique identifier.
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
*/
template<auto Data, typename Policy = as_is_t>
auto data(const ENTT_ID_TYPE alias) ENTT_NOEXCEPT {
auto * const type = internal::meta_info<Type>::resolve();
internal::meta_data_node *curr = nullptr;
if constexpr(std::is_same_v<Type, decltype(Data)>) {
static_assert(std::is_same_v<Policy, as_is_t>);
static internal::meta_data_node node{
{},
type,
nullptr,
nullptr,
true,
true,
&internal::meta_info<Type>::resolve,
[](meta_any, meta_any, meta_any) { return false; },
[](meta_any, meta_any) -> meta_any { return Data; }
};
curr = &node;
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
using data_type = std::remove_reference_t<decltype(std::declval<Type>().*Data)>;
static internal::meta_data_node node{
{},
type,
nullptr,
nullptr,
std::is_const_v<data_type>,
!std::is_member_object_pointer_v<decltype(Data)>,
&internal::meta_info<data_type>::resolve,
&internal::setter<std::is_const_v<data_type>, Type, Data>,
&internal::getter<Type, Data, Policy>
};
curr = &node;
auto data(const id_type id) ENTT_NOEXCEPT {
if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
return data<Data, Data, Policy>(id);
} else {
static_assert(std::is_pointer_v<std::decay_t<decltype(Data)>>);
using data_type = std::remove_pointer_t<std::decay_t<decltype(Data)>>;
using data_type = std::remove_pointer_t<decltype(Data)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_data_node node{
{},
type,
nullptr,
nullptr,
std::is_const_v<data_type>,
!std::is_member_object_pointer_v<decltype(Data)>,
std::is_same_v<Type, data_type> || std::is_const_v<data_type>,
true,
&internal::meta_info<data_type>::resolve,
&internal::setter<std::is_const_v<data_type>, Type, Data>,
&internal::getter<Type, Data, Policy>
&meta_setter<Type, Data>,
&meta_getter<Type, Data, Policy>
};
curr = &node;
ENTT_ASSERT(!internal::find_if_not(id, type->data, &node), "Duplicate identifier");
node.id = id;
if(!internal::find_if(&node, type->data)) {
node.next = type->data;
type->data = &node;
}
return meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&node.prop};
}
ENTT_ASSERT(!exists(alias, type->data));
ENTT_ASSERT(!exists(curr, type->data));
curr->alias = alias;
curr->next = type->data;
type->data = curr;
return meta_factory<Type, std::integral_constant<decltype(Data), Data>>{&curr->prop};
}
/**
@@ -699,13 +486,12 @@ public:
* @tparam Setter The actual function to use as a setter.
* @tparam Getter The actual function to use as a getter.
* @tparam Policy Optional policy (no policy set by default).
* @param alias Unique identifier.
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
*/
template<auto Setter, auto Getter, typename Policy = as_is_t>
auto data(const ENTT_ID_TYPE alias) ENTT_NOEXCEPT {
using underlying_type = std::invoke_result_t<decltype(Getter), Type &>;
static_assert(std::is_invocable_v<decltype(Setter), Type &, underlying_type>);
auto data(const id_type id) ENTT_NOEXCEPT {
using underlying_type = std::remove_reference_t<std::invoke_result_t<decltype(Getter), Type &>>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_data_node node{
@@ -713,18 +499,20 @@ public:
type,
nullptr,
nullptr,
false,
std::is_same_v<decltype(Setter), std::nullptr_t> || (std::is_member_object_pointer_v<decltype(Setter)> && std::is_const_v<underlying_type>),
false,
&internal::meta_info<underlying_type>::resolve,
&internal::setter<false, Type, Setter>,
&internal::getter<Type, Getter, Policy>
&meta_setter<Type, Setter>,
&meta_getter<Type, Getter, Policy>
};
ENTT_ASSERT(!exists(alias, type->data));
ENTT_ASSERT(!exists(&node, type->data));
node.alias = alias;
node.next = type->data;
type->data = &node;
ENTT_ASSERT(!internal::find_if_not(id, type->data, &node), "Duplicate identifier");
node.id = id;
if(!internal::find_if(&node, type->data)) {
node.next = type->data;
type->data = &node;
}
return meta_factory<Type, std::integral_constant<decltype(Setter), Setter>, std::integral_constant<decltype(Getter), Getter>>{&node.prop};
}
@@ -739,12 +527,12 @@ public:
*
* @tparam Candidate The actual function to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param alias Unique identifier.
* @param id Unique identifier.
* @return An extended meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_is_t>
auto func(const ENTT_ID_TYPE alias) ENTT_NOEXCEPT {
using helper_type = internal::meta_function_helper_t<decltype(Candidate)>;
auto func(const id_type id) ENTT_NOEXCEPT {
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
auto * const type = internal::meta_info<Type>::resolve();
static internal::meta_func_node node{
@@ -752,71 +540,35 @@ public:
type,
nullptr,
nullptr,
helper_type::index_sequence.size(),
helper_type::is_const,
!std::is_member_function_pointer_v<decltype(Candidate)>,
&internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename helper_type::return_type>>::resolve,
&helper_type::arg,
[](meta_any instance, meta_any *args) {
return internal::invoke<Type, Candidate, Policy>(std::move(instance), args, helper_type::index_sequence);
descriptor::args_type::size,
descriptor::is_const,
descriptor::is_static,
&internal::meta_info<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, typename descriptor::return_type>>::resolve,
[](const typename internal::meta_func_node::size_type index) ENTT_NOEXCEPT {
return meta_arg(typename descriptor::args_type{}, index);
},
[](meta_handle instance, meta_any *args) {
return meta_invoke<Type, Candidate, Policy>(std::move(instance), args, std::make_index_sequence<descriptor::args_type::size>{});
}
};
ENTT_ASSERT(!exists(alias, type->func));
ENTT_ASSERT(!exists(&node, type->func));
node.alias = alias;
node.next = type->func;
type->func = &node;
for(auto *it = &type->func; *it; it = &(*it)->next) {
if(*it == &node) {
*it = node.next;
break;
}
}
internal::meta_func_node **it = &type->func;
for(; *it && (*it)->id != id; it = &(*it)->next);
for(; *it && (*it)->id == id && (*it)->arity < node.arity; it = &(*it)->next);
node.id = id;
node.next = *it;
*it = &node;
return meta_factory<Type, std::integral_constant<decltype(Candidate), Candidate>>{&node.prop};
}
/**
* @brief Resets a meta type and all its parts.
*
* This function resets a meta type and all its data members, member
* functions and properties, as well as its constructors, destructors and
* conversion functions if any.<br/>
* Base classes aren't reset but the link between the two types is removed.
*
* @return An extended meta factory for the given type.
*/
auto reset() ENTT_NOEXCEPT {
auto * const node = internal::meta_info<Type>::resolve();
auto **it = internal::meta_info<>::global;
while(*it && *it != node) {
it = &(*it)->next;
}
if(*it) {
*it = (*it)->next;
}
const auto unregister_all = y_combinator{
[](auto &&self, auto **curr, auto... member) {
while(*curr) {
auto *prev = *curr;
(self(&(prev->*member)), ...);
*curr = prev->next;
prev->next = nullptr;
}
}
};
unregister_all(&node->prop);
unregister_all(&node->base);
unregister_all(&node->conv);
unregister_all(&node->ctor, &internal::meta_ctor_node::prop);
unregister_all(&node->data, &internal::meta_data_node::prop);
unregister_all(&node->func, &internal::meta_func_node::prop);
node->alias = {};
node->next = nullptr;
node->dtor = nullptr;
return meta_factory<Type, Type>{&node->prop};
}
};
@@ -829,51 +581,16 @@ public:
* dedicated factory.
*
* @tparam Type Type to reflect.
* @return An meta factory for the given type.
* @return A meta factory for the given type.
*/
template<typename Type>
inline meta_factory<Type> meta() ENTT_NOEXCEPT {
[[nodiscard]] auto meta() ENTT_NOEXCEPT {
auto * const node = internal::meta_info<Type>::resolve();
// extended meta factory to allow assigning properties to opaque meta types
return meta_factory<Type, Type>{&node->prop};
}
/**
* @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>
inline meta_type resolve() ENTT_NOEXCEPT {
return internal::meta_info<Type>::resolve();
}
/**
* @brief Returns the meta type associated with a given alias.
* @param alias Unique identifier.
* @return The meta type associated with the given alias, if any.
*/
inline meta_type resolve(const ENTT_ID_TYPE alias) ENTT_NOEXCEPT {
return internal::find_if([alias](const auto *curr) {
return curr->alias == alias;
}, *internal::meta_info<>::global);
}
/**
* @brief Iterates all the reflected types.
* @tparam Op Type of the function object to invoke.
* @param op A valid function object.
*/
template<typename Op>
inline std::enable_if_t<std::is_invocable_v<Op, meta_type>, void>
resolve(Op op) {
internal::visit<meta_type>(std::move(op), *internal::meta_info<>::global);
}
}

File diff suppressed because it is too large Load Diff

270
src/entt/meta/node.hpp Normal file
View File

@@ -0,0 +1,270 @@
#ifndef ENTT_META_NODE_HPP
#define ENTT_META_NODE_HPP
#include <cstddef>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/attribute.h"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "type_traits.hpp"
namespace entt {
class meta_any;
class meta_type;
struct meta_handle;
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
struct meta_type_node;
struct meta_prop_node {
meta_prop_node * next;
const meta_any &id;
meta_any &value;
};
struct meta_base_node {
meta_type_node * const parent;
meta_base_node * next;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
const void *(* const cast)(const void *) ENTT_NOEXCEPT;
};
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 arity;
meta_type(* const arg)(const 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_const;
const bool is_static;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
bool(* const set)(meta_handle, meta_any);
meta_any(* const get)(meta_handle);
};
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 arity;
const bool is_const;
const bool is_static;
meta_type_node *(* const ret)() ENTT_NOEXCEPT;
meta_type(* const arg)(const size_type) ENTT_NOEXCEPT;
meta_any(* const invoke)(meta_handle, meta_any *);
};
struct meta_template_info {
using size_type = std::size_t;
const bool is_template_specialization;
const size_type arity;
meta_type_node *(* const type)() ENTT_NOEXCEPT;
meta_type_node *(* const arg)(const size_type) ENTT_NOEXCEPT;
};
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 meta_template_info template_info;
const size_type rank;
size_type(* const extent)(const size_type) ENTT_NOEXCEPT ;
meta_type_node *(* const remove_pointer)() ENTT_NOEXCEPT;
meta_type_node *(* const remove_extent)() ENTT_NOEXCEPT;
meta_ctor_node * const def_ctor;
meta_ctor_node *ctor{nullptr};
meta_base_node *base{nullptr};
meta_conv_node *conv{nullptr};
meta_data_node *data{nullptr};
meta_func_node *func{nullptr};
void(* dtor)(void *){nullptr};
};
template<auto Member, typename Op, typename Node>
auto meta_visit(const Op &op, const Node *node)
-> std::decay_t<decltype(node->*Member)> {
for(auto *curr = node->*Member; curr; curr = curr->next) {
if(op(curr)) {
return curr;
}
}
if constexpr(std::is_same_v<Node, meta_type_node>) {
for(auto *curr = node->base; curr; curr = curr->next) {
if(auto *ret = meta_visit<Member>(op, curr->type()); ret) {
return ret;
}
}
}
return nullptr;
}
template<typename... Args>
meta_type_node * meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT;
template<typename Type>
class ENTT_API meta_node {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Invalid type");
template<std::size_t... Index>
[[nodiscard]] static auto extent(const meta_type_node::size_type dim, std::index_sequence<Index...>) ENTT_NOEXCEPT {
meta_type_node::size_type ext{};
((ext = (dim == Index ? std::extent_v<Type, Index> : ext)), ...);
return ext;
}
[[nodiscard]] static meta_ctor_node * meta_default_constructor([[maybe_unused]] meta_type_node *type) ENTT_NOEXCEPT {
if constexpr(std::is_default_constructible_v<Type>) {
static meta_ctor_node node{
type,
nullptr,
nullptr,
0u,
nullptr,
[](meta_any * const) { return meta_any{std::in_place_type<Type>}; }
};
return &node;
} else {
return nullptr;
}
}
[[nodiscard]] static meta_template_info meta_template_descriptor() ENTT_NOEXCEPT {
if constexpr(is_complete_v<meta_template_traits<Type>>) {
return {
true,
meta_template_traits<Type>::args_type::size,
&meta_node<typename meta_template_traits<Type>::class_type>::resolve,
[](const std::size_t index) ENTT_NOEXCEPT {
return meta_arg_node(typename meta_template_traits<Type>::args_type{}, index);
}
};
} else {
return { false, 0u, nullptr, nullptr };
}
}
public:
[[nodiscard]] static meta_type_node * resolve() ENTT_NOEXCEPT {
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>,
is_complete_v<meta_sequence_container_traits<Type>>,
is_complete_v<meta_associative_container_traits<Type>>,
meta_template_descriptor(),
std::rank_v<Type>,
[](meta_type_node::size_type dim) ENTT_NOEXCEPT { return extent(dim, std::make_index_sequence<std::rank_v<Type>>{}); },
&meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_pointer_t<Type>>>>::resolve,
&meta_node<std::remove_cv_t<std::remove_reference_t<std::remove_extent_t<Type>>>>::resolve,
meta_default_constructor(&node),
meta_default_constructor(&node)
};
return &node;
}
};
template<typename Type>
struct meta_info: meta_node<std::remove_cv_t<std::remove_reference_t<Type>>> {};
template<typename... Args>
meta_type_node * meta_arg_node(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
meta_type_node *args[sizeof...(Args) + 1u]{nullptr, internal::meta_info<Args>::resolve()...};
return args[index + 1u];
}
}
/**
* Internal details not to be documented.
* @endcond
*/
}
#endif

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

@@ -0,0 +1,60 @@
#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 Partial specialization used to reject pointers to arrays.
* @tparam Type Type of elements of the array.
* @tparam N Number of elements of the array.
*/
template<typename Type, std::size_t N>
struct is_meta_pointer_like<Type(*)[N]>
: std::false_type
{};
/**
* @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

View File

@@ -5,12 +5,12 @@
namespace entt {
/*! @brief Empty class type used to request the _as alias_ policy. */
struct as_alias_t {};
/*! @brief Empty class type used to request the _as ref_ policy. */
struct as_ref_t {};
/*! @brief Disambiguation tag. */
constexpr as_alias_t as_alias;
/*! @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. */

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>
namespace entt {
/**
* @brief Iterable range to use to iterate all types of meta objects.
* @tparam Type Type of meta objects returned.
* @tparam Node Type of meta nodes iterated.
*/
template<typename Type, typename Node = typename Type::node_type>
class meta_range {
struct range_iterator {
using difference_type = std::ptrdiff_t;
using value_type = Type;
using pointer = void;
using reference = value_type;
using iterator_category = std::input_iterator_tag;
using node_type = Node;
range_iterator() ENTT_NOEXCEPT = default;
range_iterator(node_type *head) ENTT_NOEXCEPT
: it{head}
{}
range_iterator & operator++() ENTT_NOEXCEPT {
return (it = it->next), *this;
}
range_iterator operator++(int) ENTT_NOEXCEPT {
range_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] reference operator*() const ENTT_NOEXCEPT {
return it;
}
[[nodiscard]] bool operator==(const range_iterator &other) const ENTT_NOEXCEPT {
return other.it == it;
}
[[nodiscard]] bool operator!=(const range_iterator &other) const ENTT_NOEXCEPT {
return !(*this == other);
}
private:
node_type *it{};
};
public:
/*! @brief Node type. */
using node_type = Node;
/*! @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

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

@@ -0,0 +1,72 @@
#ifndef ENTT_META_RESOLVE_HPP
#define ENTT_META_RESOLVE_HPP
#include <algorithm>
#include "../core/type_info.hpp"
#include "ctx.hpp"
#include "meta.hpp"
#include "node.hpp"
#include "range.hpp"
namespace entt {
/**
* @brief Returns the meta type associated with a given type.
* @tparam Type Type to use to search for a meta type.
* @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 {
for(auto *curr = *internal::meta_context::global(); curr; curr = curr->next) {
if(curr->id == id) {
return curr;
}
}
return {};
}
/**
* @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 {
for(auto *curr = *internal::meta_context::global(); curr; curr = curr->next) {
if(curr->info == info) {
return curr;
}
}
return {};
}
}
#endif

View File

@@ -0,0 +1,33 @@
#ifndef ENTT_META_TEMPLATE_HPP
#define ENTT_META_TEMPLATE_HPP
#include "../core/type_traits.hpp"
namespace entt {
/*! @brief Utility class to disambiguate class templates. */
template<template<typename...> typename>
struct meta_class_template_tag {};
/**
* @brief General purpose traits class for generating meta template information.
* @tparam Clazz Type of class template.
* @tparam Args Types of template arguments.
*/
template<template<typename...> typename Clazz, typename... Args>
struct meta_template_traits<Clazz<Args...>> {
/*! @brief Wrapped class template. */
using class_type = meta_class_template_tag<Clazz>;
/*! @brief List of template arguments. */
using args_type = type_list<Args...>;
};
}
#endif

View File

@@ -0,0 +1,88 @@
#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
* template information.
*/
template<typename>
struct meta_template_traits;
/**
* @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 a meta associative
* container claims to wrap a key-only type, false otherwise.
* @tparam Type Potentially key-only meta associative container type.
*/
template<typename, typename = void>
struct is_key_only_meta_associative_container: std::true_type {};
/*! @copydoc is_key_only_meta_associative_container */
template<typename Type>
struct is_key_only_meta_associative_container<Type, std::void_t<typename meta_associative_container_traits<Type>::type::mapped_type>>
: std::false_type
{};
/**
* @brief Helper variable template.
* @tparam Type Potentially key-only meta associative container type.
*/
template<typename Type>
inline constexpr auto is_key_only_meta_associative_container_v = is_key_only_meta_associative_container<Type>::value;
/**
* @brief Provides the member constant `value` to true if a given type is a
* pointer-like type from the point of view of the meta system, false otherwise.
* @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

333
src/entt/meta/utility.hpp Normal file
View File

@@ -0,0 +1,333 @@
#ifndef ENTT_META_UTILITY_HPP
#define ENTT_META_UTILITY_HPP
#include <cstddef>
#include <functional>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "../core/type_traits.hpp"
#include "meta.hpp"
#include "node.hpp"
#include "policy.hpp"
namespace entt {
/*! @brief Primary template isn't defined on purpose. */
template<typename, typename>
struct meta_function_descriptor;
/**
* @brief Meta function descriptor.
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Ret Function return type.
* @tparam Class Actual owner of the member function.
* @tparam Args Function arguments.
*/
template<typename Type, typename Ret, typename Class, typename... Args>
struct meta_function_descriptor<Type, Ret(Class:: *)(Args...) const> {
/*! @brief Meta function return type. */
using return_type = Ret;
/*! @brief Meta function arguments. */
using args_type = std::conditional_t<std::is_same_v<Type, Class>, type_list<Args...>, type_list<const Class &, Args...>>;
/*! @brief True if the meta function is const, false otherwise. */
static constexpr auto is_const = true;
/*! @brief True if the meta function is static, false otherwise. */
static constexpr auto is_static = !std::is_same_v<Type, Class>;
};
/**
* @brief Meta function descriptor.
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Ret Function return type.
* @tparam Class Actual owner of the member function.
* @tparam Args Function arguments.
*/
template<typename Type, typename Ret, typename Class, typename... Args>
struct meta_function_descriptor<Type, Ret(Class:: *)(Args...)> {
/*! @brief Meta function return type. */
using return_type = Ret;
/*! @brief Meta function arguments. */
using args_type = std::conditional_t<std::is_same_v<Type, Class>, type_list<Args...>, type_list<Class &, Args...>>;
/*! @brief True if the meta function is const, false otherwise. */
static constexpr auto is_const = false;
/*! @brief True if the meta function is static, false otherwise. */
static constexpr auto is_static = !std::is_same_v<Type, Class>;
};
/**
* @brief Meta function descriptor.
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Ret Function return type.
* @tparam Args Function arguments.
*/
template<typename Type, typename Ret, typename... Args>
struct meta_function_descriptor<Type, Ret(*)(Args...)> {
/*! @brief Meta function return type. */
using return_type = Ret;
/*! @brief Meta function arguments. */
using args_type = type_list<Args...>;
/*! @brief True if the meta function is const, false otherwise. */
static constexpr auto is_const = false;
/*! @brief True if the meta function is static, false otherwise. */
static constexpr auto is_static = true;
};
/**
* @brief Meta function helper.
*
* Converts a function type to be associated with a reflected type into its meta
* function descriptor.
*
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Candidate The actual function to associate with the reflected type.
*/
template<typename Type, typename Candidate>
class meta_function_helper {
template<typename Ret, typename... Args, typename Class>
static constexpr meta_function_descriptor<Type, Ret(Class:: *)(Args...) const> get_rid_of_noexcept(Ret(Class:: *)(Args...) const);
template<typename Ret, typename... Args, typename Class>
static constexpr meta_function_descriptor<Type, Ret(Class:: *)(Args...)> get_rid_of_noexcept(Ret(Class:: *)(Args...));
template<typename Ret, typename... Args>
static constexpr meta_function_descriptor<Type, Ret(*)(Args...)> get_rid_of_noexcept(Ret(*)(Args...));
public:
/*! @brief The meta function descriptor of the given function. */
using type = decltype(get_rid_of_noexcept(std::declval<Candidate>()));
};
/**
* @brief Helper type.
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Candidate The actual function to associate with the reflected type.
*/
template<typename Type, typename Candidate>
using meta_function_helper_t = typename meta_function_helper<Type, Candidate>::type;
/**
* @brief Returns the meta type of the i-th element of a list of arguments.
* @tparam Args Actual types of arguments.
* @return The meta type of the i-th element of the list of arguments.
*/
template<typename... Args>
[[nodiscard]] static meta_type meta_arg(type_list<Args...>, const std::size_t index) ENTT_NOEXCEPT {
return internal::meta_arg_node(type_list<Args...>{}, index);
}
/**
* @brief Constructs an instance given a list of erased parameters, if possible.
* @tparam Type Actual type of the instance to construct.
* @tparam Args Types of arguments expected.
* @tparam Index Indexes to use to extract erased arguments from their list.
* @param args Parameters to use to construct the instance.
* @return A meta any containing the new instance, if any.
*/
template<typename Type, typename... Args, std::size_t... Index>
[[nodiscard]] meta_any meta_construct(meta_any * const args, std::index_sequence<Index...>) {
if(((args+Index)->allow_cast<Args>() && ...)) {
return Type{(args+Index)->cast<Args>()...};
}
return {};
}
/**
* @brief Sets the value of a given variable.
* @tparam Type Reflected type to which the variable is associated.
* @tparam Data The actual variable to set.
* @param instance An opaque instance of the underlying type, if required.
* @param value Parameter to use to set the variable.
* @return True in case of success, false otherwise.
*/
template<typename Type, auto Data>
[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any value) {
if constexpr(!std::is_same_v<decltype(Data), Type> && !std::is_same_v<decltype(Data), std::nullptr_t>) {
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
using data_type = type_list_element_t<1u, typename meta_function_helper_t<Type, decltype(Data)>::args_type>;
if(auto * const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
Data(*clazz, value.cast<data_type>());
return true;
}
} else if constexpr(std::is_member_function_pointer_v<decltype(Data)>) {
using data_type = type_list_element_t<0u, typename meta_function_helper_t<Type, decltype(Data)>::args_type>;
if(auto * const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
(clazz->*Data)(value.cast<data_type>());
return true;
}
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
using data_type = std::remove_reference_t<decltype(std::declval<Type>().*Data)>;
if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
if(auto * const clazz = instance->try_cast<Type>(); clazz && value.allow_cast<data_type>()) {
clazz->*Data = value.cast<data_type>();
return true;
}
}
} else {
using data_type = std::remove_reference_t<decltype(*Data)>;
if constexpr(!std::is_array_v<data_type> && !std::is_const_v<data_type>) {
if(value.allow_cast<data_type>()) {
*Data = value.cast<data_type>();
return true;
}
}
}
}
return false;
}
/**
* @brief Wraps a value depending on the given policy.
* @tparam Policy Optional policy (no policy set by default).
* @tparam Type Type of value to wrap.
* @param value Value to wrap.
* @return A meta any containing the returned value.
*/
template<typename Policy = as_is_t, typename Type>
meta_any meta_dispatch(Type &&value) {
if constexpr(std::is_same_v<Policy, as_void_t>) {
return meta_any{std::in_place_type<void>, std::forward<Type>(value)};
} else if constexpr(std::is_same_v<Policy, as_ref_t>) {
return meta_any{std::in_place_type<Type>, std::forward<Type>(value)};
} else if constexpr(std::is_same_v<Policy, as_cref_t>) {
static_assert(std::is_lvalue_reference_v<Type>, "Invalid type");
return meta_any{std::in_place_type<const std::remove_reference_t<Type> &>, std::as_const(value)};
} else {
static_assert(std::is_same_v<Policy, as_is_t>, "Policy not supported");
return meta_any{std::forward<Type>(value)};
}
}
/**
* @brief Gets the value of a given variable.
* @tparam Type Reflected type to which the variable is associated.
* @tparam Data The actual variable to get.
* @tparam Policy Optional policy (no policy set by default).
* @param instance An opaque instance of the underlying type, if required.
* @return A meta any containing the value of the underlying variable.
*/
template<typename Type, auto Data, typename Policy = as_is_t>
[[nodiscard]] meta_any meta_getter([[maybe_unused]] meta_handle instance) {
if constexpr(std::is_function_v<std::remove_reference_t<std::remove_pointer_t<decltype(Data)>>>) {
auto * const clazz = instance->try_cast<std::conditional_t<std::is_invocable_v<decltype(Data), const Type &>, const Type, Type>>();
return clazz ? meta_dispatch<Policy>(Data(*clazz)) : meta_any{};
} else if constexpr(std::is_member_function_pointer_v<decltype(Data)>) {
auto * const clazz = instance->try_cast<std::conditional_t<std::is_invocable_v<decltype(Data), const Type &>, const Type, Type>>();
return clazz ? meta_dispatch<Policy>((clazz->*Data)()) : meta_any{};
} else if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
if constexpr(!std::is_array_v<std::remove_cv_t<std::remove_reference_t<decltype(std::declval<Type>().*Data)>>>) {
if(auto * clazz = instance->try_cast<Type>(); clazz) {
return meta_dispatch<Policy>(clazz->*Data);
} else if(auto * fallback = instance->try_cast<const Type>(); fallback) {
return meta_dispatch<Policy>(fallback->*Data);
}
}
return meta_any{};
} else if constexpr(std::is_pointer_v<decltype(Data)>) {
if constexpr(std::is_array_v<std::remove_pointer_t<decltype(Data)>>) {
return meta_any{};
} else {
return meta_dispatch<Policy>(*Data);
}
} else {
return meta_dispatch<Policy>(Data);
}
}
/**
* @brief Invokes a function given a list of erased parameters, if possible.
* @tparam Type Reflected type to which the function is associated.
* @tparam Candidate The actual function to invoke.
* @tparam Policy Optional policy (no policy set by default).
* @tparam Index Indexes to use to extract erased arguments from their list.
* @param instance An opaque instance of the underlying type, if required.
* @param args Parameters to use to invoke the function.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, auto Candidate, typename Policy = as_is_t, std::size_t... Index>
[[nodiscard]] std::enable_if_t<!std::is_invocable_v<decltype(Candidate)>, meta_any> meta_invoke([[maybe_unused]] meta_handle instance, meta_any *args, std::index_sequence<Index...>) {
using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
const auto invoke = [](auto &&maybe_clazz, auto &&... other) {
if constexpr(std::is_member_function_pointer_v<decltype(Candidate)>) {
if constexpr(std::is_void_v<typename descriptor::return_type>) {
(std::forward<decltype(maybe_clazz)>(maybe_clazz).*Candidate)(std::forward<decltype(other)>(other)...);
return meta_any{std::in_place_type<void>};
} else {
return meta_dispatch<Policy>((std::forward<decltype(maybe_clazz)>(maybe_clazz).*Candidate)(std::forward<decltype(other)>(other)...));
}
} else {
if constexpr(std::is_void_v<typename descriptor::return_type>) {
Candidate(std::forward<decltype(maybe_clazz)>(maybe_clazz), std::forward<decltype(other)>(other)...);
return meta_any{std::in_place_type<void>};
} else {
return meta_dispatch<Policy>(Candidate(std::forward<decltype(maybe_clazz)>(maybe_clazz), std::forward<decltype(other)>(other)...));
}
}
};
if constexpr(std::is_invocable_v<decltype(Candidate), const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
if(const auto * const clazz = instance->try_cast<const Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return invoke(*clazz, (args+Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
} else if constexpr(std::is_invocable_v<decltype(Candidate), Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
if(auto * const clazz = instance->try_cast<Type>(); clazz && ((args+Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return invoke(*clazz, (args+Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
} else {
if(((args+Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return invoke((args+Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
}
return meta_any{};
}
/**
* @brief Invokes a function given a list of erased parameters, if possible.
* @tparam Type Reflected type to which the function is associated.
* @tparam Candidate The actual function to invoke.
* @tparam Policy Optional policy (no policy set by default).
* @tparam Index Indexes to use to extract erased arguments from their list.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, auto Candidate, typename Policy = as_is_t, std::size_t... Index>
[[nodiscard]] std::enable_if_t<std::is_invocable_v<decltype(Candidate)>, meta_any> meta_invoke(meta_handle, meta_any *, std::index_sequence<Index...>) {
if constexpr(std::is_void_v<decltype(Candidate())>) {
Candidate();
return meta_any{std::in_place_type<void>};
} else {
return meta_dispatch<Policy>(Candidate());
}
}
}
#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

26
src/entt/poly/fwd.hpp Normal file
View File

@@ -0,0 +1,26 @@
#ifndef ENTT_POLY_FWD_HPP
#define ENTT_POLY_FWD_HPP
#include <type_traits>
namespace entt {
template<typename, std::size_t Len, std::size_t = alignof(typename std::aligned_storage_t<Len + !Len>)>
class basic_poly;
/**
* @brief Alias declaration for the most common use case.
* @tparam Concept Concept descriptor.
*/
template<typename Concept>
using poly = basic_poly<Concept, sizeof(double[2])>;
}
#endif

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

@@ -0,0 +1,341 @@
#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"
#include "fwd.hpp"
namespace entt {
/*! @brief Inspector class used to infer the type of the virtual table. */
struct poly_inspector {
/**
* @brief Generic conversion operator (definition only).
* @tparam Type Type to which conversion is requested.
*/
template <class Type>
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.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Alignment requirement.
*/
template<typename Concept, std::size_t Len, std::size_t Align>
class poly_vtable {
using inspector = typename Concept::template type<poly_inspector>;
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(*)(inspector &, Args...)) -> Ret(*)(basic_any<Len, Align> &, Args...);
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(*)(const inspector &, Args...)) -> Ret(*)(const basic_any<Len, Align> &, Args...);
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(*)(Args...)) -> Ret(*)(const basic_any<Len, Align> &, Args...);
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(inspector:: *)(Args...)) -> Ret(*)(basic_any<Len, Align> &, Args...);
template<typename Ret, typename... Args>
static auto vtable_entry(Ret(inspector:: *)(Args...) const) -> Ret(*)(const basic_any<Len, Align> &, Args...);
template<auto... Candidate>
static auto make_vtable(value_list<Candidate...>)
-> decltype(std::make_tuple(vtable_entry(Candidate)...));
template<typename... Func>
[[nodiscard]] static constexpr auto make_vtable(type_list<Func...>) {
if constexpr(sizeof...(Func) == 0) {
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 &instance, Args... args) -> Ret {
return static_cast<Ret>(std::invoke(Candidate, any_cast<constness_as_t<Type, Any> &>(instance), 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.
* @tparam Len Size of the storage reserved for the small buffer optimization.
* @tparam Align Optional alignment requirement.
*/
template<typename Concept, std::size_t Len, std::size_t Align>
class basic_poly: private Concept::template type<poly_base<basic_poly<Concept, Len, Align>>> {
/*! @brief A poly base is allowed to snoop into a poly object. */
friend struct poly_base<basic_poly>;
using vtable_type = typename poly_vtable<Concept, Len, Align>::type;
public:
/*! @brief Concept type. */
using concept_type = typename Concept::template type<poly_base<basic_poly>>;
/*! @brief Default constructor. */
basic_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 basic_poly(std::in_place_type_t<Type>, Args &&... args)
: storage{std::in_place_type<Type>, std::forward<Args>(args)...},
vtable{poly_vtable<Concept, Len, Align>::template instance<std::remove_const_t<std::remove_reference_t<Type>>>()}
{}
/**
* @brief Constructs a poly 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>>, basic_poly>>>
basic_poly(Type &&value) ENTT_NOEXCEPT
: basic_poly{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)}
{}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
basic_poly(const basic_poly &other) = default;
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
basic_poly(basic_poly &&other) ENTT_NOEXCEPT
: basic_poly{}
{
swap(*this, other);
}
/**
* @brief Assignment operator.
* @param other The instance to assign from.
* @return This poly object.
*/
basic_poly & operator=(basic_poly other) {
swap(other, *this);
return *this;
}
/**
* @brief Returns the type of the contained object.
* @return The type of the contained object, if any.
*/
[[nodiscard]] type_info type() const ENTT_NOEXCEPT {
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) {
*this = basic_poly{std::in_place_type<Type>, std::forward<Args>(args)...};
}
/*! @brief Destroys contained object */
void reset() {
*this = basic_poly{};
}
/**
* @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(basic_poly &lhs, basic_poly &rhs) {
using std::swap;
swap(lhs.storage, rhs.storage);
swap(lhs.vtable, rhs.vtable);
}
/**
* @brief Aliasing constructor.
* @return A poly that shares a reference to an unmanaged object.
*/
[[nodiscard]] basic_poly as_ref() ENTT_NOEXCEPT {
basic_poly ref = std::as_const(*this).as_ref();
ref.storage = storage.as_ref();
return ref;
}
/*! @copydoc as_ref */
[[nodiscard]] basic_poly as_ref() const ENTT_NOEXCEPT {
basic_poly ref{};
ref.storage = storage.as_ref();
ref.vtable = vtable;
return ref;
}
private:
basic_any<Len, Align> storage;
const vtable_type *vtable;
};
}
#endif

View File

@@ -78,44 +78,41 @@ class process {
SUCCEEDED,
FAILED,
ABORTED,
FINISHED
FINISHED,
REJECTED
};
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:
/**
@@ -172,7 +169,7 @@ public:
/*! @brief Default destructor. */
virtual ~process() {
static_assert(std::is_base_of_v<process, Derived>);
static_assert(std::is_base_of_v<process, Derived>, "Incorrect use of the class template");
}
/**
@@ -197,7 +194,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 +202,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 finished() const ENTT_NOEXCEPT {
return current == state::FINISHED;
}
@@ -213,7 +210,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,8 +218,8 @@ 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 {
return stopped;
[[nodiscard]] bool rejected() const ENTT_NOEXCEPT {
return current == state::REJECTED;
}
/**
@@ -233,11 +230,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,18 +244,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>{});
current = state::FINISHED;
stopped = true;
next(std::integral_constant<state, state::FAILED>{});
current = state::REJECTED;
break;
case state::ABORTED:
tick(0, state_value_t<state::ABORTED>{});
current = state::FINISHED;
stopped = true;
next(std::integral_constant<state, state::ABORTED>{});
current = state::REJECTED;
break;
default:
// suppress warnings
@@ -268,7 +263,6 @@ public:
private:
state current{state::UNINITIALIZED};
bool stopped{false};
};

View File

@@ -57,13 +57,11 @@ class scheduler {
struct continuation {
continuation(process_handler *ref)
: handler{ref}
{
ENTT_ASSERT(handler);
}
{}
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,23 +78,23 @@ 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);
auto dead = process->dead();
if(dead) {
if(handler.next && !process->rejected()) {
if(process->rejected()) {
return true;
} else if(process->finished()) {
if(handler.next) {
handler = std::move(*handler.next);
// forces the process to exit the uninitialized state
dead = handler.update(handler, {}, nullptr);
} else {
handler.instance.reset();
return handler.update(handler, {}, nullptr);
}
return true;
}
return dead;
return false;
}
template<typename Proc>
@@ -126,7 +124,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 +132,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 +173,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
@@ -252,19 +250,17 @@ public:
* @param data Optional data.
*/
void update(const Delta delta, void *data = nullptr) {
bool clean = false;
auto sz = handlers.size();
for(auto pos = handlers.size(); pos; --pos) {
auto &handler = handlers[pos-1];
const bool dead = handler.update(handler, delta, data);
clean = clean || dead;
if(const auto dead = handler.update(handler, delta, data); dead) {
std::swap(handler, handlers[--sz]);
}
}
if(clean) {
handlers.erase(std::remove_if(handlers.begin(), handlers.end(), [](auto &handler) {
return !handler.instance;
}), handlers.end());
}
handlers.erase(handlers.begin() + sz, handlers.end());
}
/**

View File

@@ -2,11 +2,11 @@
#define ENTT_RESOURCE_CACHE_HPP
#include <memory>
#include <utility>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include "../config/config.h"
#include "../core/fwd.hpp"
#include "handle.hpp"
#include "loader.hpp"
#include "fwd.hpp"
@@ -26,28 +26,26 @@ namespace entt {
* @tparam Resource Type of resources managed by a cache.
*/
template<typename Resource>
struct cache {
struct resource_cache {
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Type of resources managed by a cache. */
using resource_type = Resource;
/*! @brief Unique identifier type for resources. */
using id_type = ENTT_ID_TYPE;
/*! @brief Default constructor. */
cache() = default;
resource_cache() = default;
/*! @brief Default move constructor. */
cache(cache &&) = default;
resource_cache(resource_cache &&) = default;
/*! @brief Default move assignment operator. @return This cache. */
cache & operator=(cache &&) = default;
resource_cache & operator=(resource_cache &&) = default;
/**
* @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();
}
@@ -55,7 +53,7 @@ struct cache {
* @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();
}
@@ -92,20 +90,16 @@ struct cache {
* @return A handle for the given resource.
*/
template<typename Loader, typename... Args>
entt::handle<Resource> load(const id_type id, Args &&... args) {
static_assert(std::is_base_of_v<loader<Loader, Resource>, Loader>);
entt::handle<Resource> resource{};
resource_handle<Resource> load(const id_type id, Args &&... args) {
if(auto it = resources.find(id); it == resources.cend()) {
if(auto instance = Loader{}.get(std::forward<Args>(args)...); instance) {
resources[id] = instance;
resource = std::move(instance);
if(auto handle = temp<Loader>(std::forward<Args>(args)...); handle) {
return (resources[id] = std::move(handle));
}
} else {
resource = it->second;
return it->second;
}
return resource;
return {};
}
/**
@@ -132,7 +126,7 @@ struct cache {
* @return A handle for the given resource.
*/
template<typename Loader, typename... Args>
entt::handle<Resource> reload(const id_type id, Args &&... args) {
resource_handle<Resource> reload(const id_type id, Args &&... args) {
return (discard(id), load<Loader>(id, std::forward<Args>(args)...));
}
@@ -149,8 +143,8 @@ struct cache {
* @return A handle for the given resource.
*/
template<typename Loader, typename... Args>
entt::handle<Resource> temp(Args &&... args) const {
return { Loader{}.get(std::forward<Args>(args)...) };
[[nodiscard]] resource_handle<Resource> temp(Args &&... args) const {
return Loader{}.get(std::forward<Args>(args)...);
}
/**
@@ -161,14 +155,17 @@ struct cache {
* cache contains the resource itself. Otherwise the returned handle is
* uninitialized and accessing it results in undefined behavior.
*
* @sa handle
* @sa resource_handle
*
* @param id Unique resource identifier.
* @return A handle for the given resource.
*/
entt::handle<Resource> handle(const id_type id) const {
auto it = resources.find(id);
return { it == resources.end() ? nullptr : it->second };
[[nodiscard]] resource_handle<Resource> handle(const id_type id) const {
if(auto it = resources.find(id); it != resources.cend()) {
return it->second;
}
return {};
}
/**
@@ -176,7 +173,7 @@ struct cache {
* @param id Unique resource identifier.
* @return True if the cache contains the resource, false otherwise.
*/
bool contains(const id_type id) const {
[[nodiscard]] bool contains(const id_type id) const {
return (resources.find(id) != resources.cend());
}
@@ -203,9 +200,9 @@ struct cache {
* forms:
*
* @code{.cpp}
* void(const id_type);
* void(handle<Resource>);
* void(const id_type, handle<Resource>);
* 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.
@@ -221,16 +218,16 @@ struct cache {
if constexpr(std::is_invocable_v<Func, id_type>) {
func(curr->first);
} else if constexpr(std::is_invocable_v<Func, entt::handle<Resource>>) {
func(entt::handle{ curr->second });
} else if constexpr(std::is_invocable_v<Func, resource_handle<Resource>>) {
func(curr->second);
} else {
func(curr->first, entt::handle{ curr->second });
func(curr->first, curr->second);
}
}
}
private:
std::unordered_map<id_type, std::shared_ptr<Resource>> resources;
std::unordered_map<id_type, resource_handle<Resource>> resources;
};

View File

@@ -5,17 +5,16 @@
namespace entt {
/*! @struct cache */
template<typename>
struct cache;
struct resource_cache;
/*! @class handle */
template<typename>
class handle;
class resource_handle;
/*! @class loader */
template<typename, typename>
class loader;
class resource_loader;
}

View File

@@ -3,6 +3,7 @@
#include <memory>
#include <type_traits>
#include <utility>
#include "../config/config.h"
#include "fwd.hpp"
@@ -24,68 +25,148 @@ namespace entt {
* @tparam Resource Type of resource managed by a handle.
*/
template<typename Resource>
class handle {
/*! @brief Resource handles are friends of their caches. */
friend struct cache<Resource>;
handle(std::shared_ptr<Resource> res) ENTT_NOEXCEPT
: resource{std::move(res)}
{}
class resource_handle {
/*! @brief Resource handles are friends with each other. */
template<typename>
friend class resource_handle;
public:
/*! @brief Default constructor. */
handle() ENTT_NOEXCEPT = default;
resource_handle() ENTT_NOEXCEPT = default;
/**
* @brief Creates a handle from a shared pointer, namely a resource.
* @param res A pointer to a properly initialized resource.
*/
resource_handle(std::shared_ptr<Resource> res) ENTT_NOEXCEPT
: resource{std::move(res)}
{}
/**
* @brief Copy constructor.
* @param other The instance to copy from.
*/
resource_handle(const resource_handle<Resource> &other) ENTT_NOEXCEPT = default;
/**
* @brief Move constructor.
* @param other The instance to move from.
*/
resource_handle(resource_handle<Resource> &&other) ENTT_NOEXCEPT = default;
/**
* @brief Copy constructs a handle which shares ownership of the resource.
* @tparam Other Type of resource managed by the received handle.
* @param other The handle to copy from.
*/
template<typename Other, typename = std::enable_if_t<!std::is_same_v<Other, Resource> && std::is_base_of_v<Resource, Other>>>
resource_handle(const resource_handle<Other> &other) ENTT_NOEXCEPT
: resource{other.resource}
{}
/**
* @brief Move constructs a handle which takes ownership of the resource.
* @tparam Other Type of resource managed by the received handle.
* @param other The handle to move from.
*/
template<typename Other, typename = std::enable_if_t<!std::is_same_v<Other, Resource> && std::is_base_of_v<Resource, Other>>>
resource_handle(resource_handle<Other> &&other) ENTT_NOEXCEPT
: resource{std::move(other.resource)}
{}
/**
* @brief Copy assignment operator.
* @param other The instance to copy from.
* @return This resource handle.
*/
resource_handle & operator=(const resource_handle<Resource> &other) ENTT_NOEXCEPT = default;
/**
* @brief Move assignment operator.
* @param other The instance to move from.
* @return This resource handle.
*/
resource_handle & operator=(resource_handle<Resource> &&other) ENTT_NOEXCEPT = default;
/**
* @brief Copy assignment operator from foreign handle.
* @tparam Other Type of resource managed by the received handle.
* @param other The handle to copy from.
* @return This resource handle.
*/
template<typename Other>
std::enable_if_t<!std::is_same_v<Other, Resource> && std::is_base_of_v<Resource, Other>, resource_handle &>
operator=(const resource_handle<Other> &other) ENTT_NOEXCEPT {
resource = other.resource;
return *this;
}
/**
* @brief Move assignment operator from foreign handle.
* @tparam Other Type of resource managed by the received handle.
* @param other The handle to move from.
* @return This resource handle.
*/
template<typename Other>
std::enable_if_t<!std::is_same_v<Other, Resource> && std::is_base_of_v<Resource, Other>, resource_handle &>
operator=(resource_handle<Other> &&other) ENTT_NOEXCEPT {
resource = std::move(other.resource);
return *this;
}
/**
* @brief Gets a reference to the managed resource.
*
* @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 {
ENTT_ASSERT(static_cast<bool>(resource));
[[nodiscard]] const Resource & get() const ENTT_NOEXCEPT {
ENTT_ASSERT(static_cast<bool>(resource), "Invalid resource");
return *resource;
}
/*! @copydoc get */
Resource & get() ENTT_NOEXCEPT {
[[nodiscard]] Resource & get() ENTT_NOEXCEPT {
return const_cast<Resource &>(std::as_const(*this).get());
}
/*! @copydoc get */
operator const Resource & () const ENTT_NOEXCEPT { return get(); }
[[nodiscard]] operator const Resource & () const ENTT_NOEXCEPT {
return get();
}
/*! @copydoc get */
operator Resource & () ENTT_NOEXCEPT { return get(); }
[[nodiscard]] operator Resource & () ENTT_NOEXCEPT {
return get();
}
/*! @copydoc get */
const Resource & operator *() const ENTT_NOEXCEPT { return get(); }
[[nodiscard]] const Resource & operator *() const ENTT_NOEXCEPT {
return get();
}
/*! @copydoc get */
Resource & operator *() ENTT_NOEXCEPT { return get(); }
[[nodiscard]] Resource & operator *() ENTT_NOEXCEPT {
return get();
}
/**
* @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.
* 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.
*/
const Resource * operator->() const ENTT_NOEXCEPT {
ENTT_ASSERT(static_cast<bool>(resource));
[[nodiscard]] const Resource * operator->() const ENTT_NOEXCEPT {
return resource.get();
}
/*! @copydoc operator-> */
Resource * operator->() ENTT_NOEXCEPT {
[[nodiscard]] Resource * operator->() ENTT_NOEXCEPT {
return const_cast<Resource *>(std::as_const(*this).operator->());
}
@@ -93,7 +174,7 @@ public:
* @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 ENTT_NOEXCEPT {
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return static_cast<bool>(resource);
}

View File

@@ -2,8 +2,8 @@
#define ENTT_RESOURCE_LOADER_HPP
#include <memory>
#include "fwd.hpp"
#include "handle.hpp"
namespace entt {
@@ -15,14 +15,14 @@ namespace entt {
* Resource loaders must inherit from this class and stay true to the CRTP
* idiom. Moreover, a resource loader must expose a public, const member
* function named `load` that accepts a variable number of arguments and returns
* a shared pointer to the resource just created.<br/>
* a handle to the resource just created.<br/>
* As an example:
*
* @code{.cpp}
* struct my_resource {};
*
* struct my_loader: entt::loader<my_loader, my_resource> {
* std::shared_ptr<my_resource> load(int) const {
* struct my_loader: entt::resource_loader<my_loader, my_resource> {
* resource_handle<my_resource> load(int value) const {
* // use the integer value somehow
* return std::make_shared<my_resource>();
* }
@@ -42,9 +42,10 @@ namespace entt {
* @tparam Resource Type of resource for which to use the loader.
*/
template<typename Loader, typename Resource>
class loader {
class resource_loader {
/*! @brief Resource loaders are friends of their caches. */
friend struct cache<Resource>;
template<typename Other>
friend struct resource_cache;
/**
* @brief Loads the resource and returns it.
@@ -53,7 +54,7 @@ class 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]] resource_handle<Resource> get(Args &&... args) const {
return static_cast<const Loader *>(this)->load(std::forward<Args>(args)...);
}
};

View File

@@ -7,6 +7,7 @@
#include <utility>
#include <functional>
#include <type_traits>
#include "../core/type_traits.hpp"
#include "../config/config.h"
@@ -47,7 +48,7 @@ using function_pointer_t = decltype(internal::function_pointer(std::declval<Type
template<typename... Class, typename Ret, typename... Args>
constexpr auto index_sequence_for(Ret(*)(Args...)) {
[[nodiscard]] constexpr auto index_sequence_for(Ret(*)(Args...)) {
return std::index_sequence_for<Class..., Args...>{};
}
@@ -57,7 +58,7 @@ constexpr auto index_sequence_for(Ret(*)(Args...)) {
/**
* Internal details not to be documented.
* @endcond TURN_OFF_DOXYGEN
* @endcond
*/
@@ -68,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{};
/**
@@ -95,37 +96,39 @@ class delegate;
*/
template<typename Ret, typename... Args>
class delegate<Ret(Args...)> {
using proto_fn_type = Ret(const void *, Args...);
template<auto Candidate, std::size_t... Index>
auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
[[nodiscard]] auto wrap(std::index_sequence<Index...>) ENTT_NOEXCEPT {
return [](const void *, Args... args) -> Ret {
const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
return Ret(std::invoke(Candidate, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
[[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>
auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
[[nodiscard]] auto wrap(Type &, std::index_sequence<Index...>) ENTT_NOEXCEPT {
return [](const void *payload, Args... args) -> Ret {
const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
return Ret(std::invoke(Candidate, *curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
[[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>
auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
[[nodiscard]] auto wrap(Type *, std::index_sequence<Index...>) ENTT_NOEXCEPT {
return [](const void *payload, Args... args) -> Ret {
const auto arguments = std::forward_as_tuple(std::forward<Args>(args)...);
Type *curr = static_cast<Type *>(const_cast<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
return Ret(std::invoke(Candidate, curr, std::forward<std::tuple_element_t<Index, std::tuple<Args...>>>(std::get<Index>(arguments))...));
[[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
@@ -138,9 +141,7 @@ public:
* @tparam Candidate Function or member to connect to the delegate.
*/
template<auto Candidate>
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
: delegate{}
{
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT {
connect<Candidate>();
}
@@ -152,12 +153,20 @@ public:
* @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{}
{
delegate(connect_arg_t<Candidate>, Type &&value_or_instance) ENTT_NOEXCEPT {
connect<Candidate>(std::forward<Type>(value_or_instance));
}
/**
* @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.
*/
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.
@@ -171,7 +180,7 @@ public:
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<std::tuple_element_t<0, std::tuple<Args...>>>(internal::function_pointer_t<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)>{}));
}
@@ -183,7 +192,7 @@ public:
*
* 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.
@@ -198,7 +207,7 @@ public:
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<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
return Ret(std::invoke(Candidate, *curr, std::forward<Args>(args)...));
};
} else {
@@ -222,7 +231,7 @@ public:
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<std::conditional_t<std::is_const_v<Type>, const void *, void *>>(payload));
Type *curr = static_cast<Type *>(const_cast<constness_as_t<void, Type> *>(payload));
return Ret(std::invoke(Candidate, curr, std::forward<Args>(args)...));
};
} else {
@@ -230,6 +239,24 @@ public:
}
}
/**
* @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;
}
/**
* @brief Resets a delegate.
*
@@ -244,7 +271,7 @@ public:
* @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;
}
@@ -255,15 +282,13 @@ 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);
ENTT_ASSERT(static_cast<bool>(*this), "Uninitialized delegate");
return fn(data, std::forward<Args>(args)...);
}
@@ -271,7 +296,7 @@ public:
* @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 == nullptr);
}
@@ -281,12 +306,12 @@ public:
* @param other Delegate with which to compare.
* @return False if the two contents differ, true otherwise.
*/
bool operator==(const delegate<Ret(Args...)> &other) const ENTT_NOEXCEPT {
[[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;
};
@@ -300,7 +325,7 @@ private:
* @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);
}
@@ -310,7 +335,7 @@ bool operator!=(const delegate<Ret(Args...)> &lhs, const delegate<Ret(Args...)>
* @tparam Candidate Function or member to connect to the delegate.
*/
template<auto Candidate>
delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
delegate(connect_arg_t<Candidate>)
-> delegate<std::remove_pointer_t<internal::function_pointer_t<decltype(Candidate)>>>;
@@ -320,10 +345,20 @@ delegate(connect_arg_t<Candidate>) ENTT_NOEXCEPT
* @tparam Type Type of class or type of payload.
*/
template<auto Candidate, typename Type>
delegate(connect_arg_t<Candidate>, Type &&) ENTT_NOEXCEPT
delegate(connect_arg_t<Candidate>, Type &&)
-> 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)
-> delegate<Ret(Args...)>;
}

View File

@@ -2,12 +2,13 @@
#define ENTT_SIGNAL_DISPATCHER_HPP
#include <vector>
#include <memory>
#include <cstddef>
#include <utility>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "sigh.hpp"
@@ -22,7 +23,7 @@ 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 dispatcher creates instances of the `sigh` class internally. Refer to the
* documentation of the latter for more details.
@@ -31,13 +32,15 @@ class dispatcher {
struct basic_pool {
virtual ~basic_pool() = default;
virtual void publish() = 0;
virtual void disconnect(void *) = 0;
virtual void clear() ENTT_NOEXCEPT = 0;
virtual ENTT_ID_TYPE type_id() const ENTT_NOEXCEPT = 0;
};
template<typename Event>
struct pool_handler: basic_pool {
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 {
@@ -50,26 +53,31 @@ class dispatcher {
events.erase(events.cbegin(), events.cbegin()+length);
}
void disconnect(void *instance) override {
sink().disconnect(instance);
}
void clear() ENTT_NOEXCEPT override {
events.clear();
}
sink_type sink() ENTT_NOEXCEPT {
[[nodiscard]] sink_type sink() ENTT_NOEXCEPT {
return entt::sink{signal};
}
template<typename... Args>
void trigger(Args &&... args) {
signal.publish(Event{std::forward<Args>(args)...});
Event instance{std::forward<Args>(args)...};
signal.publish(instance);
}
template<typename... Args>
void enqueue(Args &&... args) {
events.emplace_back(std::forward<Args>(args)...);
}
ENTT_ID_TYPE type_id() const ENTT_NOEXCEPT override {
return type_info<Event>::id();
if constexpr(std::is_aggregate_v<Event>) {
events.push_back(Event{std::forward<Args>(args)...});
} else {
events.emplace_back(std::forward<Args>(args)...);
}
}
private:
@@ -78,30 +86,38 @@ class dispatcher {
};
template<typename Event>
pool_handler<Event> & assure() {
static_assert(std::is_same_v<Event, std::decay_t<Event>>);
static std::size_t index{pools.size()};
[[nodiscard]] pool_handler<Event> & assure() {
const auto index = type_seq<Event>::value();
if(const auto length = pools.size(); !(index < length) || pools[index]->type_id() != type_info<Event>::id()) {
for(index = {}; index < length && pools[index]->type_id() != type_info<Event>::id(); ++index);
if(!(index < pools.size())) {
pools.resize(std::size_t(index)+1u);
}
if(index == pools.size()) {
pools.emplace_back(new pool_handler<Event>{});
}
if(!pools[index]) {
pools[index].reset(new pool_handler<Event>{});
}
return static_cast<pool_handler<Event> &>(*pools[index]);
}
public:
/*! @brief Default constructor. */
dispatcher() = default;
/*! @brief Default move constructor. */
dispatcher(dispatcher &&) = default;
/*! @brief Default move assignment operator. @return This dispatcher. */
dispatcher & operator=(dispatcher &&) = default;
/**
* @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.
@@ -112,7 +128,7 @@ public:
* @return A temporary sink object.
*/
template<typename Event>
auto sink() {
[[nodiscard]] auto sink() {
return assure<Event>().sink();
}
@@ -174,6 +190,32 @@ public:
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.
*
@@ -186,7 +228,9 @@ public:
void clear() {
if constexpr(sizeof...(Event) == 0) {
for(auto &&cpool: pools) {
cpool->clear();
if(cpool) {
cpool->clear();
}
}
} else {
(assure<Event>().clear(), ...);
@@ -216,7 +260,9 @@ public:
*/
void update() const {
for(auto pos = pools.size(); pos; --pos) {
pools[pos-1]->publish();
if(auto &&cpool = pools[pos-1]; cpool) {
cpool->publish();
}
}
}

View File

@@ -2,15 +2,16 @@
#define ENTT_SIGNAL_EMITTER_HPP
#include <type_traits>
#include <functional>
#include <algorithm>
#include <utility>
#include <memory>
#include <vector>
#include <list>
#include <functional>
#include <iterator>
#include <list>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
@@ -32,9 +33,9 @@ namespace entt {
* 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.
*/
@@ -44,17 +45,18 @@ class emitter {
virtual ~basic_pool() = default;
virtual bool empty() const ENTT_NOEXCEPT = 0;
virtual void clear() ENTT_NOEXCEPT = 0;
virtual ENTT_ID_TYPE type_id() const ENTT_NOEXCEPT = 0;
};
template<typename Event>
struct pool_handler: basic_pool {
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) &&
@@ -94,7 +96,7 @@ class emitter {
}
}
void publish(const Event &event, Derived &ref) {
void publish(Event &event, Derived &ref) {
container_type swap_list;
once_list.swap(swap_list);
@@ -113,10 +115,6 @@ class emitter {
on_list.remove_if([](auto &&element) { return element.first; });
}
ENTT_ID_TYPE type_id() const ENTT_NOEXCEPT override {
return type_info<Event>::id();
}
private:
bool publishing{false};
container_type once_list{};
@@ -124,24 +122,24 @@ class emitter {
};
template<typename Event>
const pool_handler<Event> & assure() const {
static_assert(std::is_same_v<Event, std::decay_t<Event>>);
static std::size_t index{pools.size()};
[[nodiscard]] pool_handler<Event> * assure() {
const auto index = type_seq<Event>::value();
if(const auto length = pools.size(); !(index < length) || pools[index]->type_id() != type_info<Event>::id()) {
for(index = {}; index < length && pools[index]->type_id() != type_info<Event>::id(); ++index);
if(index == pools.size()) {
pools.emplace_back(new pool_handler<Event>{});
}
if(!(index < pools.size())) {
pools.resize(std::size_t(index)+1u);
}
return static_cast<pool_handler<Event> &>(*pools[index]);
if(!pools[index]) {
pools[index].reset(new pool_handler<Event>{});
}
return static_cast<pool_handler<Event> *>(pools[index].get());
}
template<typename Event>
pool_handler<Event> & assure() {
return const_cast<pool_handler<Event> &>(std::as_const(*this).template assure<Event>());
[[nodiscard]] const pool_handler<Event> * assure() const {
const auto index = type_seq<Event>::value();
return (!(index < pools.size()) || !pools[index]) ? nullptr : static_cast<const pool_handler<Event> *>(pools[index].get());
}
public:
@@ -180,7 +178,7 @@ public:
/*! @brief Default destructor. */
virtual ~emitter() {
static_assert(std::is_base_of_v<emitter<Derived>, Derived>);
static_assert(std::is_base_of_v<emitter<Derived>, Derived>, "Incorrect use of the class template");
}
/*! @brief Default move constructor. */
@@ -202,7 +200,8 @@ public:
*/
template<typename Event, typename... Args>
void publish(Args &&... args) {
assure<Event>().publish(Event{std::forward<Args>(args)...}, *static_cast<Derived *>(this));
Event instance{std::forward<Args>(args)...};
assure<Event>()->publish(instance, *static_cast<Derived *>(this));
}
/**
@@ -214,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
@@ -227,7 +226,7 @@ public:
*/
template<typename Event>
connection<Event> on(listener<Event> instance) {
return assure<Event>().on(std::move(instance));
return assure<Event>()->on(std::move(instance));
}
/**
@@ -239,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
@@ -252,7 +251,7 @@ public:
*/
template<typename Event>
connection<Event> once(listener<Event> instance) {
return assure<Event>().once(std::move(instance));
return assure<Event>()->once(std::move(instance));
}
/**
@@ -266,7 +265,7 @@ public:
*/
template<typename Event>
void erase(connection<Event> conn) {
assure<Event>().erase(std::move(conn));
assure<Event>()->erase(std::move(conn));
}
/**
@@ -279,7 +278,7 @@ public:
*/
template<typename Event>
void clear() {
assure<Event>().clear();
assure<Event>()->clear();
}
/**
@@ -290,7 +289,9 @@ public:
*/
void clear() ENTT_NOEXCEPT {
for(auto &&cpool: pools) {
cpool->clear();
if(cpool) {
cpool->clear();
}
}
}
@@ -300,22 +301,23 @@ public:
* @return True if there are no listeners registered, false otherwise.
*/
template<typename Event>
bool empty() const {
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 {
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return std::all_of(pools.cbegin(), pools.cend(), [](auto &&cpool) {
return cpool->empty();
return !cpool || cpool->empty();
});
}
private:
mutable std::vector<std::unique_ptr<basic_pool>> pools{};
std::vector<std::unique_ptr<basic_pool>> pools{};
};

View File

@@ -5,28 +5,27 @@
namespace entt {
/*! @class delegate */
template<typename>
class delegate;
/*! @class dispatcher */
class dispatcher;
/*! @class emitter */
template<typename>
class emitter;
/*! @class connection */
class connection;
/*! @class scoped_connection */
struct scoped_connection;
/*! @class sink */
template<typename>
class sink;
/*! @class sigh */
template<typename>
class sigh;

View File

@@ -64,7 +64,7 @@ public:
/*! @brief Unsigned integer type. */
using size_type = std::size_t;
/*! @brief Sink type. */
using sink_type = entt::sink<Ret(Args...)>;
using sink_type = sink<Ret(Args...)>;
/**
* @brief Instance type when it comes to connecting member functions.
@@ -77,7 +77,7 @@ public:
* @brief Number of listeners connected to the signal.
* @return Number of listeners currently connected.
*/
size_type size() const ENTT_NOEXCEPT {
[[nodiscard]] size_type size() const ENTT_NOEXCEPT {
return calls.size();
}
@@ -85,7 +85,7 @@ public:
* @brief Returns false if at least a listener is connected to the signal.
* @return True if the signal has no listeners connected, false otherwise.
*/
bool empty() const ENTT_NOEXCEPT {
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return calls.empty();
}
@@ -166,7 +166,7 @@ public:
* @brief Checks whether a connection is properly initialized.
* @return True if the connection is properly initialized, false otherwise.
*/
explicit operator bool() const ENTT_NOEXCEPT {
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return static_cast<bool>(disconnect);
}
@@ -233,7 +233,7 @@ struct scoped_connection {
* @brief Checks whether a scoped connection is properly initialized.
* @return True if the connection is properly initialized, false otherwise.
*/
explicit operator bool() const ENTT_NOEXCEPT {
[[nodiscard]] explicit operator bool() const ENTT_NOEXCEPT {
return static_cast<bool>(conn);
}
@@ -258,6 +258,10 @@ private:
* as private data member without exposing the publish functionality to the
* users of the class.
*
* @warning
* Lifetime of a sink must not overcome that of the signal to which it refers.
* In any other case, attempting to use a sink results in undefined behavior.
*
* @tparam Ret Return type of a function type.
* @tparam Args Types of arguments of a function type.
*/
@@ -290,7 +294,7 @@ public:
* @brief Returns false if at least a listener is connected to the sink.
* @return True if the sink has no listeners connected, false otherwise.
*/
bool empty() const ENTT_NOEXCEPT {
[[nodiscard]] bool empty() const ENTT_NOEXCEPT {
return signal->calls.empty();
}
@@ -301,7 +305,7 @@ public:
* @return A properly initialized sink object.
*/
template<auto Function>
sink before() {
[[nodiscard]] sink before() {
delegate<Ret(Args...)> call{};
call.template connect<Function>();
@@ -322,9 +326,9 @@ public:
* @return A properly initialized sink object.
*/
template<auto Candidate, typename Type>
sink before(Type &&value_or_instance) {
[[nodiscard]] sink before(Type &&value_or_instance) {
delegate<Ret(Args...)> call{};
call.template connect<Candidate>(std::forward<Type>(value_or_instance));
call.template connect<Candidate>(value_or_instance);
const auto &calls = signal->calls;
const auto it = std::find(calls.cbegin(), calls.cend(), std::move(call));
@@ -342,7 +346,7 @@ public:
* @return A properly initialized sink object.
*/
template<typename Type>
sink before(Type &value_or_instance) {
[[nodiscard]] sink before(Type &value_or_instance) {
return before(&value_or_instance);
}
@@ -354,7 +358,7 @@ public:
* @return A properly initialized sink object.
*/
template<typename Type>
sink before(Type *value_or_instance) {
[[nodiscard]] sink before(Type *value_or_instance) {
sink other{*this};
if(value_or_instance) {
@@ -373,7 +377,7 @@ public:
* @brief Returns a sink that connects before anything else.
* @return A properly initialized sink object.
*/
sink before() {
[[nodiscard]] sink before() {
sink other{*this};
other.offset = signal->calls.size();
return other;
@@ -454,7 +458,7 @@ public:
void disconnect(Type &&value_or_instance) {
auto &calls = signal->calls;
delegate<Ret(Args...)> call{};
call.template connect<Candidate>(std::forward<Type>(value_or_instance));
call.template connect<Candidate>(value_or_instance);
calls.erase(std::remove(calls.begin(), calls.end(), std::move(call)), calls.end());
}
@@ -506,7 +510,8 @@ private:
* @tparam Args Types of arguments of a function type.
*/
template<typename Ret, typename... Args>
sink(sigh<Ret(Args...)> &) ENTT_NOEXCEPT -> sink<Ret(Args...)>;
sink(sigh<Ret(Args...)> &)
-> sink<Ret(Args...)>;
}

View File

@@ -7,7 +7,7 @@ include(FetchContent)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
if(FIND_GTEST_PACKAGE)
if(ENTT_FIND_GTEST_PACKAGE)
find_package(GTest REQUIRED)
else()
FetchContent_Declare(
@@ -40,21 +40,39 @@ function(SETUP_TARGET TARGET_NAME)
set_target_properties(${TARGET_NAME} PROPERTIES CXX_EXTENSIONS OFF)
target_link_libraries(${TARGET_NAME} PRIVATE EnTT)
target_compile_options(
if(MSVC)
target_compile_options(
${TARGET_NAME}
PRIVATE
/EHsc /W1 /wd4996 /w14800
$<$<CONFIG:Debug>:/Od>
$<$<CONFIG:Release>:/O2>
)
else()
target_compile_options(
${TARGET_NAME}
PRIVATE
-pedantic -fvisibility=hidden -Wall -Wshadow -Wno-deprecated-declarations
$<$<CONFIG:Debug>:-O0 -g>
$<$<CONFIG:Release>:-O2>
)
endif()
target_compile_definitions(
${TARGET_NAME}
PRIVATE
$<$<NOT:$<PLATFORM_ID:Windows>>:-pedantic -fvisibility=hidden -Wall -Wshadow -Wno-deprecated-declarations>
$<$<PLATFORM_ID:Windows>:/EHsc /W1 /wd4996 /w14800>
_ENABLE_EXTENDED_ALIGNED_STORAGE
NOMINMAX
${ARGN}
)
target_compile_options(
${TARGET_NAME}
PRIVATE
$<$<AND:$<CONFIG:Debug>,$<NOT:$<PLATFORM_ID:Windows>>>:-O0 -g>
$<$<AND:$<CONFIG:Release>,$<NOT:$<PLATFORM_ID:Windows>>>:-O2>
$<$<AND:$<CONFIG:Debug>,$<PLATFORM_ID:Windows>>:/Od>
$<$<AND:$<CONFIG:Release>,$<PLATFORM_ID:Windows>>:/O2>
)
if(ENTT_BUILD_UINT64)
target_compile_definitions(
${TARGET_NAME}
PRIVATE
ENTT_ID_TYPE=std::uint64_t
)
endif()
endfunction()
add_library(odr OBJECT odr.cpp)
@@ -63,39 +81,42 @@ SETUP_TARGET(odr)
function(SETUP_BASIC_TEST TEST_NAME TEST_SOURCES)
add_executable(${TEST_NAME} $<TARGET_OBJECTS:odr> ${TEST_SOURCES})
target_link_libraries(${TEST_NAME} PRIVATE GTest::Main Threads::Threads)
SETUP_TARGET(${TEST_NAME})
SETUP_TARGET(${TEST_NAME} ${ARGN})
add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME})
endfunction()
function(SETUP_LIB_TEST TEST_NAME)
add_library(_${TEST_NAME} SHARED lib/${TEST_NAME}/lib.cpp)
SETUP_TARGET(_${TEST_NAME})
SETUP_BASIC_TEST(lib_${TEST_NAME} lib/${TEST_NAME}/main.cpp)
target_compile_definitions(_${TEST_NAME} PRIVATE ENTT_API_EXPORT ${ARGV1})
target_compile_definitions(lib_${TEST_NAME} PRIVATE ENTT_API_IMPORT ${ARGV1})
add_library(_${TEST_NAME} SHARED $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/lib.cpp)
SETUP_TARGET(_${TEST_NAME} ENTT_API_EXPORT)
SETUP_BASIC_TEST(lib_${TEST_NAME} lib/${TEST_NAME}/main.cpp ENTT_API_IMPORT)
target_link_libraries(lib_${TEST_NAME} PRIVATE _${TEST_NAME})
endfunction()
function(SETUP_PLUGIN_TEST TEST_NAME)
add_library(_${TEST_NAME} MODULE lib/${TEST_NAME}/plugin.cpp)
SETUP_TARGET(_${TEST_NAME})
SETUP_BASIC_TEST(lib_${TEST_NAME} lib/${TEST_NAME}/main.cpp)
add_library(_${TEST_NAME} MODULE $<TARGET_OBJECTS:odr> lib/${TEST_NAME}/plugin.cpp)
SETUP_TARGET(_${TEST_NAME} ${ARGVN})
SETUP_BASIC_TEST(lib_${TEST_NAME} lib/${TEST_NAME}/main.cpp PLUGIN="$<TARGET_FILE:_${TEST_NAME}>" ${ARGVN})
target_include_directories(_${TEST_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_include_directories(lib_${TEST_NAME} PRIVATE ${cr_INCLUDE_DIR})
target_compile_definitions(lib_${TEST_NAME} PRIVATE NOMINMAX PLUGIN="$<TARGET_FILE:_${TEST_NAME}>" ${ARGV1})
target_compile_definitions(_${TEST_NAME} PRIVATE NOMINMAX ${ARGV1})
target_link_libraries(lib_${TEST_NAME} PRIVATE ${CMAKE_DL_LIBS})
endfunction()
# Test benchmark
if(BUILD_BENCHMARK)
if(ENTT_BUILD_BENCHMARK)
SETUP_BASIC_TEST(benchmark benchmark/benchmark.cpp)
endif()
# Test example
if(ENTT_BUILD_EXAMPLE)
SETUP_BASIC_TEST(custom_identifier example/custom_identifier.cpp)
SETUP_BASIC_TEST(signal_less example/signal_less.cpp)
endif()
# Test lib
if(BUILD_LIB)
if(ENTT_BUILD_LIB)
FetchContent_Declare(
cr
GIT_REPOSITORY https://github.com/fungos/cr.git
@@ -115,25 +136,17 @@ if(BUILD_LIB)
SETUP_LIB_TEST(meta)
SETUP_LIB_TEST(registry)
SETUP_LIB_TEST(dispatcher_std ENTT_STANDARD_CPP)
SETUP_LIB_TEST(emitter_std ENTT_STANDARD_CPP)
SETUP_LIB_TEST(meta_std ENTT_STANDARD_CPP)
SETUP_LIB_TEST(registry_std ENTT_STANDARD_CPP)
SETUP_PLUGIN_TEST(dispatcher_plugin)
SETUP_PLUGIN_TEST(emitter_plugin)
SETUP_PLUGIN_TEST(meta_plugin)
SETUP_PLUGIN_TEST(registry_plugin)
SETUP_PLUGIN_TEST(dispatcher_plugin_std ENTT_STANDARD_CPP)
SETUP_PLUGIN_TEST(emitter_plugin_std ENTT_STANDARD_CPP)
SETUP_PLUGIN_TEST(meta_plugin_std ENTT_STANDARD_CPP)
SETUP_PLUGIN_TEST(registry_plugin_std ENTT_STANDARD_CPP)
endif()
# Test snapshot
if(BUILD_SNAPSHOT)
if(ENTT_BUILD_SNAPSHOT)
FetchContent_Declare(
cereal
GIT_REPOSITORY https://github.com/USCiLab/cereal.git
@@ -155,6 +168,7 @@ endif()
# Test core
SETUP_BASIC_TEST(algorithm entt/core/algorithm.cpp)
SETUP_BASIC_TEST(any entt/core/any.cpp)
SETUP_BASIC_TEST(family entt/core/family.cpp)
SETUP_BASIC_TEST(hashed_string entt/core/hashed_string.cpp)
SETUP_BASIC_TEST(ident entt/core/ident.cpp)
@@ -165,12 +179,15 @@ SETUP_BASIC_TEST(utility entt/core/utility.cpp)
# Test entity
SETUP_BASIC_TEST(actor entt/entity/actor.cpp)
SETUP_BASIC_TEST(entity entt/entity/entity.cpp)
SETUP_BASIC_TEST(group entt/entity/group.cpp)
SETUP_BASIC_TEST(handle entt/entity/handle.cpp)
SETUP_BASIC_TEST(helper entt/entity/helper.cpp)
SETUP_BASIC_TEST(observer entt/entity/observer.cpp)
SETUP_BASIC_TEST(poly_storage entt/entity/poly_storage.cpp)
SETUP_BASIC_TEST(organizer entt/entity/organizer.cpp)
SETUP_BASIC_TEST(registry entt/entity/registry.cpp)
SETUP_BASIC_TEST(registry_no_eto entt/entity/registry_no_eto.cpp ENTT_NO_ETO)
SETUP_BASIC_TEST(runtime_view entt/entity/runtime_view.cpp)
SETUP_BASIC_TEST(snapshot entt/entity/snapshot.cpp)
SETUP_BASIC_TEST(sparse_set entt/entity/sparse_set.cpp)
@@ -183,7 +200,25 @@ SETUP_BASIC_TEST(locator entt/locator/locator.cpp)
# Test meta
SETUP_BASIC_TEST(meta entt/meta/meta.cpp)
SETUP_BASIC_TEST(meta_any entt/meta/meta_any.cpp)
SETUP_BASIC_TEST(meta_base entt/meta/meta_base.cpp)
SETUP_BASIC_TEST(meta_container entt/meta/meta_container.cpp)
SETUP_BASIC_TEST(meta_conv entt/meta/meta_conv.cpp)
SETUP_BASIC_TEST(meta_ctor entt/meta/meta_ctor.cpp)
SETUP_BASIC_TEST(meta_data entt/meta/meta_data.cpp)
SETUP_BASIC_TEST(meta_dtor entt/meta/meta_dtor.cpp)
SETUP_BASIC_TEST(meta_func entt/meta/meta_func.cpp)
SETUP_BASIC_TEST(meta_handle entt/meta/meta_handle.cpp)
SETUP_BASIC_TEST(meta_pointer entt/meta/meta_pointer.cpp)
SETUP_BASIC_TEST(meta_prop entt/meta/meta_prop.cpp)
SETUP_BASIC_TEST(meta_range entt/meta/meta_range.cpp)
SETUP_BASIC_TEST(meta_template entt/meta/meta_template.cpp)
SETUP_BASIC_TEST(meta_type entt/meta/meta_type.cpp)
# Test poly
SETUP_BASIC_TEST(poly_deduced entt/poly/poly_deduced.cpp)
SETUP_BASIC_TEST(poly_defined entt/poly/poly_defined.cpp)
# Test process

File diff suppressed because it is too large Load Diff

View File

@@ -13,8 +13,8 @@ TEST(Algorithm, StdSort) {
sort(arr.begin(), arr.end());
for(typename decltype(arr)::size_type i = 0; i < (arr.size() - 1); ++i) {
ASSERT_LT(arr[i], arr[i+1]);
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
ASSERT_LT(arr[i], arr[i+1u]);
}
}
@@ -27,8 +27,8 @@ TEST(Algorithm, StdSortBoxedInt) {
return lhs.value > rhs.value;
});
for(typename decltype(arr)::size_type i = 0; i < (arr.size() - 1); ++i) {
ASSERT_GT(arr[i].value, arr[i+1].value);
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
ASSERT_GT(arr[i].value, arr[i+1u].value);
}
}
@@ -38,8 +38,8 @@ TEST(Algorithm, InsertionSort) {
sort(arr.begin(), arr.end());
for(typename decltype(arr)::size_type i = 0; i < (arr.size() - 1); ++i) {
ASSERT_LT(arr[i], arr[i+1]);
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
ASSERT_LT(arr[i], arr[i+1u]);
}
}
@@ -51,8 +51,8 @@ TEST(Algorithm, InsertionSortBoxedInt) {
return lhs.value > rhs.value;
});
for(typename decltype(arr)::size_type i = 0; i < (arr.size() - 1); ++i) {
ASSERT_GT(arr[i].value, arr[i+1].value);
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
ASSERT_GT(arr[i].value, arr[i+1u].value);
}
}
@@ -71,8 +71,8 @@ TEST(Algorithm, RadixSort) {
return value;
});
for(typename decltype(arr)::size_type i = 0; i < (arr.size() - 1); ++i) {
ASSERT_LT(arr[i], arr[i+1]);
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
ASSERT_LT(arr[i], arr[i+1u]);
}
}
@@ -84,8 +84,8 @@ TEST(Algorithm, RadixSortBoxedInt) {
return instance.value;
});
for(typename decltype(arr)::size_type i = 0; i < (arr.size() - 1); ++i) {
ASSERT_GT(arr[i].value, arr[i+1].value);
for(auto i = 0u; i < (arr.size() - 1u); ++i) {
ASSERT_GT(arr[i].value, arr[i+1u].value);
}
}

1153
test/entt/core/any.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,28 @@
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
template<typename>
struct foobar_t;
template<>
struct foobar_t<std::uint32_t> {
static constexpr auto value = 0xbf9cf968;
};
template<>
struct foobar_t<std::uint64_t> {
static constexpr auto value = 0x85944171f73967e8;
};
inline constexpr auto foobar_v = foobar_t<entt::id_type>::value;
TEST(BasicHashedString, DeductionGuide) {
static_assert(std::is_same_v<decltype(entt::basic_hashed_string{"foo"}), entt::hashed_string>);
static_assert(std::is_same_v<decltype(entt::basic_hashed_string{L"foo"}), entt::hashed_wstring>);
}
TEST(HashedString, Functionalities) {
using namespace entt::literals;
using hash_type = entt::hashed_string::hash_type;
const char *bar = "bar";
@@ -23,11 +44,21 @@ TEST(HashedString, Functionalities) {
entt::hashed_string hs{"foobar"};
ASSERT_EQ(static_cast<hash_type>(hs), 0xbf9cf968);
ASSERT_EQ(hs.value(), 0xbf9cf968);
ASSERT_EQ(static_cast<hash_type>(hs), foobar_v);
ASSERT_EQ(hs.value(), foobar_v);
ASSERT_EQ(foo_hs, "foo"_hs);
ASSERT_NE(bar_hs, "foo"_hs);
entt::hashed_string empty_hs{};
ASSERT_EQ(empty_hs, entt::hashed_string{});
ASSERT_NE(empty_hs, foo_hs);
empty_hs = foo_hs;
ASSERT_NE(empty_hs, entt::hashed_string{});
ASSERT_EQ(empty_hs, foo_hs);
}
TEST(HashedString, Empty) {
@@ -39,31 +70,31 @@ TEST(HashedString, Empty) {
ASSERT_EQ(static_cast<const char *>(hs), nullptr);
}
TEST(HashedString, Constexprness) {
using hash_type = entt::hashed_string::hash_type;
// how would you test a constexpr otherwise?
(void)std::integral_constant<hash_type, entt::hashed_string{"quux"}>{};
(void)std::integral_constant<hash_type, "quux"_hs>{};
ASSERT_TRUE(true);
}
TEST(HashedString, ToValue) {
using hash_type = entt::hashed_string::hash_type;
TEST(HashedString, Correctness) {
const char *foobar = "foobar";
std::string_view view{"foobar__", 6};
ASSERT_EQ(entt::hashed_string::value(foobar), 0xbf9cf968);
// how would you test a constexpr otherwise?
(void)std::integral_constant<hash_type, entt::hashed_string::value("quux")>{};
ASSERT_EQ(entt::hashed_string{foobar}, foobar_v);
ASSERT_EQ(entt::hashed_string::value(foobar), foobar_v);
ASSERT_EQ(entt::hashed_string::value(view.data(), view.size()), foobar_v);
}
TEST(HashedString, StringView) {
std::string str{"__foobar__"};
std::string_view view{str.data()+2, 6};
ASSERT_EQ(entt::hashed_string::value(view.data(), view.size()), 0xbf9cf968);
TEST(HashedString, Constexprness) {
using namespace entt::literals;
constexpr std::string_view view{"foobar__", 6};
static_assert(entt::hashed_string{"quux"} == "quux"_hs);
static_assert(entt::hashed_string{"foobar"} == foobar_v);
static_assert(entt::hashed_string::value("quux") == "quux"_hs);
static_assert(entt::hashed_string::value("foobar") == foobar_v);
static_assert(entt::hashed_string::value("quux", 4) == "quux"_hs);
static_assert(entt::hashed_string::value(view.data(), view.size()) == foobar_v);
}
TEST(HashedWString, Functionalities) {
using namespace entt::literals;
using hash_type = entt::hashed_wstring::hash_type;
const wchar_t *bar = L"bar";
@@ -82,8 +113,8 @@ TEST(HashedWString, Functionalities) {
entt::hashed_wstring hws{L"foobar"};
ASSERT_EQ(static_cast<hash_type>(hws), 0xbf9cf968);
ASSERT_EQ(hws.value(), 0xbf9cf968);
ASSERT_EQ(static_cast<hash_type>(hws), foobar_v);
ASSERT_EQ(hws.value(), foobar_v);
ASSERT_EQ(foo_hws, L"foo"_hws);
ASSERT_NE(bar_hws, L"foo"_hws);
@@ -98,31 +129,25 @@ TEST(HashedWString, Empty) {
ASSERT_EQ(static_cast<const wchar_t *>(hws), nullptr);
}
TEST(HashedWString, Constexprness) {
using hash_type = entt::hashed_wstring::hash_type;
// how would you test a constexpr otherwise?
(void)std::integral_constant<hash_type, entt::hashed_wstring{L"quux"}>{};
(void)std::integral_constant<hash_type, L"quux"_hws>{};
ASSERT_TRUE(true);
}
TEST(HashedWString, ToValue) {
using hash_type = entt::hashed_wstring::hash_type;
TEST(HashedWString, Correctness) {
const wchar_t *foobar = L"foobar";
std::wstring_view view{L"foobar__", 6};
ASSERT_EQ(entt::hashed_wstring::value(foobar), 0xbf9cf968);
// how would you test a constexpr otherwise?
(void)std::integral_constant<hash_type, entt::hashed_wstring::value(L"quux")>{};
ASSERT_EQ(entt::hashed_wstring{foobar}, foobar_v);
ASSERT_EQ(entt::hashed_wstring::value(foobar), foobar_v);
ASSERT_EQ(entt::hashed_wstring::value(view.data(), view.size()), foobar_v);
}
TEST(HashedWString, StringView) {
std::wstring str{L"__foobar__"};
std::wstring_view view{str.data()+2, 6};
ASSERT_EQ(entt::hashed_wstring::value(view.data(), view.size()), 0xbf9cf968);
}
TEST(HashedWString, Constexprness) {
using namespace entt::literals;
constexpr std::wstring_view view{L"foobar__", 6};
TEST(BasicHashedString, DeductionGuide) {
static_assert(std::is_same_v<decltype(entt::basic_hashed_string{"foo"}), entt::hashed_string>);
static_assert(std::is_same_v<decltype(entt::basic_hashed_string{L"foo"}), entt::hashed_wstring>);
static_assert(entt::hashed_wstring{L"quux"} == L"quux"_hws);
static_assert(entt::hashed_wstring{L"foobar"} == foobar_v);
static_assert(entt::hashed_wstring::value(L"quux") == L"quux"_hws);
static_assert(entt::hashed_wstring::value(L"foobar") == foobar_v);
static_assert(entt::hashed_wstring::value(L"quux", 4) == L"quux"_hws);
static_assert(entt::hashed_wstring::value(view.data(), view.size()) == foobar_v);
}

View File

@@ -3,6 +3,8 @@
#include <entt/core/monostate.hpp>
TEST(Monostate, Functionalities) {
using namespace entt::literals;
const bool b_pre = entt::monostate<entt::hashed_string{"foobar"}>{};
const int i_pre = entt::monostate<"foobar"_hs>{};

View File

@@ -1,9 +1,84 @@
#include <string_view>
#include <type_traits>
#include <gtest/gtest.h>
#include <entt/core/hashed_string.hpp>
#include <entt/core/type_info.hpp>
#include <entt/core/type_traits.hpp>
TEST(TypeId, Functionalities) {
ASSERT_NE(entt::type_info<int>::id(), entt::type_info<const int>::id());
ASSERT_NE(entt::type_info<int>::id(), entt::type_info<char>::id());
ASSERT_EQ(entt::type_info<int>::id(), entt::type_info<int>::id());
template<>
struct entt::type_name<float> final {
[[nodiscard]] static constexpr std::string_view value() ENTT_NOEXCEPT {
return std::string_view{""};
}
};
TEST(TypeSeq, Functionalities) {
ASSERT_EQ(entt::type_seq<int>::value(), entt::type_seq<int>::value());
ASSERT_NE(entt::type_seq<int>::value(), entt::type_seq<char>::value());
ASSERT_NE(entt::type_seq<int>::value(), entt::type_seq<int &&>::value());
ASSERT_NE(entt::type_seq<int &>::value(), entt::type_seq<const int &>::value());
ASSERT_EQ(static_cast<entt::id_type>(entt::type_seq<int>{}), entt::type_seq<int>::value());
}
TEST(TypeHash, Functionalities) {
ASSERT_NE(entt::type_hash<int>::value(), entt::type_hash<const int>::value());
ASSERT_NE(entt::type_hash<int>::value(), entt::type_hash<char>::value());
ASSERT_EQ(entt::type_hash<int>::value(), entt::type_hash<int>::value());
ASSERT_EQ(static_cast<entt::id_type>(entt::type_hash<int>{}), entt::type_hash<int>::value());
}
TEST(TypeName, Functionalities) {
ASSERT_EQ(entt::type_name<int>::value(), std::string_view{"int"});
ASSERT_TRUE((entt::type_name<entt::integral_constant<3>>::value() == std::string_view{"std::integral_constant<int, 3>"})
|| (entt::type_name<entt::integral_constant<3>>::value() == std::string_view{"std::__1::integral_constant<int, 3>"})
|| (entt::type_name<entt::integral_constant<3>>::value() == std::string_view{"struct std::integral_constant<int,3>"}));
ASSERT_TRUE(((entt::type_name<entt::type_list<entt::type_list<int, char>, double>>::value()) == std::string_view{"entt::type_list<entt::type_list<int, char>, double>"})
|| ((entt::type_name<entt::type_list<entt::type_list<int, char>, double>>::value()) == std::string_view{"struct entt::type_list<struct entt::type_list<int,char>,double>"}));
ASSERT_EQ(static_cast<std::string_view>(entt::type_name<int>{}), entt::type_name<int>::value());
}
TEST(TypeInfo, Functionalities) {
static_assert(std::is_default_constructible_v<entt::type_info>);
static_assert(std::is_copy_constructible_v<entt::type_info>);
static_assert(std::is_move_constructible_v<entt::type_info>);
static_assert(std::is_copy_assignable_v<entt::type_info>);
static_assert(std::is_move_assignable_v<entt::type_info>);
ASSERT_EQ(entt::type_info{}, entt::type_info{});
ASSERT_NE(entt::type_id<int>(), entt::type_info{});
ASSERT_NE(entt::type_id<int>(), entt::type_id<char>());
const auto info = entt::type_id<int>();
const auto unnamed = entt::type_id<float>();
entt::type_info empty{};
ASSERT_NE(info, empty);
ASSERT_TRUE(info == info);
ASSERT_FALSE(info != info);
ASSERT_EQ(info.seq(), entt::type_seq<int>::value());
ASSERT_EQ(info.hash(), entt::type_hash<int>::value());
ASSERT_EQ(info.name(), entt::type_name<int>::value());
ASSERT_TRUE(info);
ASSERT_TRUE(unnamed);
ASSERT_FALSE(empty);
empty = info;
ASSERT_TRUE(empty);
ASSERT_EQ(empty.hash(), info.hash());
empty = {};
ASSERT_FALSE(empty);
ASSERT_NE(empty.hash(), info.hash());
empty = std::move(info);
ASSERT_TRUE(empty);
ASSERT_EQ(empty.hash(), info.hash());
}

View File

@@ -1,43 +1,172 @@
#include <iterator>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <vector>
#include <gtest/gtest.h>
#include <entt/config/config.h>
#include <entt/core/hashed_string.hpp>
#include <entt/core/type_traits.hpp>
TEST(Choice, Functionalities) {
ASSERT_TRUE((std::is_base_of_v<entt::choice_t<0>, entt::choice_t<1>>));
ASSERT_FALSE((std::is_base_of_v<entt::choice_t<1>, entt::choice_t<0>>));
struct not_comparable {
bool operator==(const not_comparable &) const = delete;
};
struct nlohmann_json_like {
using value_type = nlohmann_json_like;
bool operator==(const nlohmann_json_like &) const { return true; }
};
TEST(TypeTraits, SizeOf) {
static_assert(entt::size_of_v<void> == 0u);
static_assert(entt::size_of_v<char> == sizeof(char));
static_assert(entt::size_of_v<int[]> == 0u);
static_assert(entt::size_of_v<int[3]> == sizeof(int[3]));
}
TEST(TypeList, Functionalities) {
TEST(TypeTraits, UnpackAsType) {
ASSERT_EQ([](auto &&... args) {
return [](entt::unpack_as_t<int, decltype(args)>... value) {
return (value + ... + 0);
};
}('c', 42., true)(1, 2, 3), 6);
}
TEST(TypeTraits, UnpackAsValue) {
ASSERT_EQ([](auto &&... args) {
return (entt::unpack_as_v<2, decltype(args)> + ... + 0);
}('c', 42., true), 6);
}
TEST(TypeTraits, IntegralConstant) {
entt::integral_constant<3> constant{};
static_assert(std::is_same_v<typename entt::integral_constant<3>::value_type, int>);
static_assert(constant.value == 3);
}
TEST(TypeTraits, Choice) {
static_assert(std::is_base_of_v<entt::choice_t<0>, entt::choice_t<1>>);
static_assert(!std::is_base_of_v<entt::choice_t<1>, entt::choice_t<0>>);
}
TEST(TypeTraits, TypeList) {
using type = entt::type_list<int, char>;
using other = entt::type_list<double>;
ASSERT_EQ(entt::type_list_size_v<type>, 2u);
ASSERT_EQ(entt::type_list_size_v<other>, 1u);
ASSERT_TRUE((std::is_same_v<entt::type_list_cat_t<type, other, type, other>, entt::type_list<int, char, double, int, char, double>>));
ASSERT_TRUE((std::is_same_v<entt::type_list_cat_t<type, other>, entt::type_list<int, char, double>>));
ASSERT_TRUE((std::is_same_v<entt::type_list_cat_t<type, type>, entt::type_list<int, char, int, char>>));
ASSERT_TRUE((std::is_same_v<entt::type_list_unique_t<entt::type_list_cat_t<type, type>>, entt::type_list<int, char>>));
static_assert(type::size == 2u);
static_assert(other::size == 1u);
static_assert(std::is_same_v<decltype(type{} + other{}), entt::type_list<int, char, double>>);
static_assert(std::is_same_v<entt::type_list_cat_t<type, other, type, other>, entt::type_list<int, char, double, int, char, double>>);
static_assert(std::is_same_v<entt::type_list_cat_t<type, other>, entt::type_list<int, char, double>>);
static_assert(std::is_same_v<entt::type_list_cat_t<type, type>, entt::type_list<int, char, int, char>>);
static_assert(std::is_same_v<entt::type_list_unique_t<entt::type_list_cat_t<type, type>>, entt::type_list<int, char>>);
static_assert(entt::type_list_contains_v<type, int>);
static_assert(entt::type_list_contains_v<type, char>);
static_assert(!entt::type_list_contains_v<type, double>);
static_assert(std::is_same_v<entt::type_list_element_t<0u, type>, int>);
static_assert(std::is_same_v<entt::type_list_element_t<1u, type>, char>);
static_assert(std::is_same_v<entt::type_list_element_t<0u, other>, double>);
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<float, bool>>, entt::type_list<int, char, double>>);
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<int, char, double>>, entt::type_list<>>);
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<int, char>>, entt::type_list<double>>);
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<char, double>>, entt::type_list<int>>);
static_assert(std::is_same_v<entt::type_list_diff_t<entt::type_list<int, char, double>, entt::type_list<char>>, entt::type_list<int, double>>);
}
TEST(IsEqualityComparable, Functionalities) {
ASSERT_TRUE(entt::is_equality_comparable_v<int>);
ASSERT_FALSE(entt::is_equality_comparable_v<void>);
TEST(TypeTraits, ValueList) {
using value = entt::value_list<0, 2>;
using other = entt::value_list<1>;
static_assert(value::size == 2u);
static_assert(other::size == 1u);
static_assert(std::is_same_v<decltype(value{} + other{}), entt::value_list<0, 2, 1>>);
static_assert(std::is_same_v<entt::value_list_cat_t<value, other, value, other>, entt::value_list<0, 2, 1, 0, 2, 1>>);
static_assert(std::is_same_v<entt::value_list_cat_t<value, other>, entt::value_list<0, 2, 1>>);
static_assert(std::is_same_v<entt::value_list_cat_t<value, value>, entt::value_list<0, 2, 0, 2>>);
static_assert(entt::value_list_element_v<0u, value> == 0);
static_assert(entt::value_list_element_v<1u, value> == 2);
static_assert(entt::value_list_element_v<0u, other> == 1);
}
TEST(MemberClass, Functionalities) {
TEST(TypeTraits, IsEqualityComparable) {
static_assert(entt::is_equality_comparable_v<int>);
static_assert(entt::is_equality_comparable_v<std::vector<int>>);
static_assert(entt::is_equality_comparable_v<std::vector<std::vector<int>>>);
static_assert(entt::is_equality_comparable_v<std::unordered_map<int, int>>);
static_assert(entt::is_equality_comparable_v<std::unordered_map<int, std::unordered_map<int, char>>>);
static_assert(entt::is_equality_comparable_v<std::vector<not_comparable>::iterator>);
static_assert(entt::is_equality_comparable_v<nlohmann_json_like>);
static_assert(!entt::is_equality_comparable_v<not_comparable>);
static_assert(!entt::is_equality_comparable_v<std::vector<not_comparable>>);
static_assert(!entt::is_equality_comparable_v<std::vector<std::vector<not_comparable>>>);
static_assert(!entt::is_equality_comparable_v<std::unordered_map<int, not_comparable>>);
static_assert(!entt::is_equality_comparable_v<std::unordered_map<int, std::unordered_map<int, not_comparable>>>);
static_assert(!entt::is_equality_comparable_v<void>);
}
TEST(TypeTraits, IsApplicable) {
static_assert(entt::is_applicable_v<void(int, char), std::tuple<double, char>>);
static_assert(!entt::is_applicable_v<void(int, char), std::tuple<int>>);
static_assert(entt::is_applicable_r_v<float, int(int, char), std::tuple<double, char>>);
static_assert(!entt::is_applicable_r_v<float, void(int, char), std::tuple<double, char>>);
static_assert(!entt::is_applicable_r_v<int, int(int, char), std::tuple<void>>);
}
TEST(TypeTraits, IsComplete) {
static_assert(!entt::is_complete_v<void>);
static_assert(entt::is_complete_v<int>);
}
TEST(TypeTraits, IsIterator) {
static_assert(!entt::is_iterator_v<void>);
static_assert(!entt::is_iterator_v<int>);
static_assert(entt::is_iterator_v<int *>);
static_assert(entt::is_iterator_v<std::vector<int>::iterator>);
static_assert(entt::is_iterator_v<std::vector<int>::const_iterator>);
static_assert(entt::is_iterator_v<std::vector<int>::reverse_iterator>);
}
TEST(TypeTraits, IsIteratorType) {
static_assert(!entt::is_iterator_type_v<void, std::vector<int>::iterator>);
static_assert(!entt::is_iterator_type_v<std::vector<int>::iterator, std::vector<int>::const_iterator>);
static_assert(!entt::is_iterator_type_v<std::vector<int>::iterator, int *>);
static_assert(entt::is_iterator_type_v<std::vector<int>::iterator, std::vector<int>::iterator>);
static_assert(entt::is_iterator_type_v<std::vector<int>::iterator, std::reverse_iterator<std::vector<int>::iterator>>);
static_assert(entt::is_iterator_type_v<std::vector<int>::iterator, std::reverse_iterator<std::reverse_iterator<std::vector<int>::iterator>>>);
}
TEST(TypeTraits, ConstnessAs) {
static_assert(std::is_same_v<entt::constness_as_t<int, char>, int>);
static_assert(std::is_same_v<entt::constness_as_t<const int, char>, int>);
static_assert(std::is_same_v<entt::constness_as_t<int, const char>, const int>);
static_assert(std::is_same_v<entt::constness_as_t<const int, const char>, const int>);
}
TEST(TypeTraits, MemberClass) {
struct clazz {
char foo(int) { return {}; }
int bar(double, float) const { return {}; }
bool quux;
};
ASSERT_TRUE((std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::foo)>>));
ASSERT_TRUE((std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::bar)>>));
ASSERT_TRUE((std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::quux)>>));
static_assert(std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::foo)>>);
static_assert(std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::bar)>>);
static_assert(std::is_same_v<clazz, entt::member_class_t<decltype(&clazz::quux)>>);
}
TEST(Tag, Functionalities) {
ASSERT_EQ(entt::tag<"foobar"_hs>::value, entt::hashed_string::value("foobar"));
ASSERT_TRUE((std::is_same_v<typename entt::tag<"foobar"_hs>::value_type, ENTT_ID_TYPE>));
TEST(TypeTraits, Tag) {
using namespace entt::literals;
static_assert(entt::tag<"foobar"_hs>::value == entt::hashed_string::value("foobar"));
static_assert(std::is_same_v<typename entt::tag<"foobar"_hs>::value_type, entt::id_type>);
}

View File

@@ -2,7 +2,7 @@
#include <gtest/gtest.h>
#include <entt/core/utility.hpp>
struct Functions {
struct functions {
static void foo(int) {}
static void foo() {}
@@ -19,19 +19,19 @@ TEST(Utility, Identity) {
}
TEST(Utility, Overload) {
ASSERT_EQ(entt::overload<void(int)>(&Functions::foo), static_cast<void(*)(int)>(&Functions::foo));
ASSERT_EQ(entt::overload<void()>(&Functions::foo), static_cast<void(*)()>(&Functions::foo));
ASSERT_EQ(entt::overload<void(int)>(&functions::foo), static_cast<void(*)(int)>(&functions::foo));
ASSERT_EQ(entt::overload<void()>(&functions::foo), static_cast<void(*)()>(&functions::foo));
ASSERT_EQ(entt::overload<void(int)>(&Functions::bar), static_cast<void(Functions:: *)(int)>(&Functions::bar));
ASSERT_EQ(entt::overload<void()>(&Functions::bar), static_cast<void(Functions:: *)()>(&Functions::bar));
ASSERT_EQ(entt::overload<void(int)>(&functions::bar), static_cast<void(functions:: *)(int)>(&functions::bar));
ASSERT_EQ(entt::overload<void()>(&functions::bar), static_cast<void(functions:: *)()>(&functions::bar));
Functions instance;
functions instance;
ASSERT_NO_THROW(entt::overload<void(int)>(&Functions::foo)(0));
ASSERT_NO_THROW(entt::overload<void()>(&Functions::foo)());
ASSERT_NO_FATAL_FAILURE(entt::overload<void(int)>(&functions::foo)(0));
ASSERT_NO_FATAL_FAILURE(entt::overload<void()>(&functions::foo)());
ASSERT_NO_THROW((instance.*entt::overload<void(int)>(&Functions::bar))(0));
ASSERT_NO_THROW((instance.*entt::overload<void()>(&Functions::bar))());
ASSERT_NO_FATAL_FAILURE((instance.*entt::overload<void(int)>(&functions::bar))(0));
ASSERT_NO_FATAL_FAILURE((instance.*entt::overload<void()>(&functions::bar))());
}
TEST(Utility, Overloaded) {
@@ -51,7 +51,7 @@ TEST(Utility, Overloaded) {
}
TEST(Utility, YCombinator) {
entt::y_combinator gauss([](auto &&self, unsigned int value) -> unsigned int {
entt::y_combinator gauss([](const auto &self, auto value) -> unsigned int {
return value ? (value + self(value-1u)) : 0;
});

View File

@@ -1,92 +0,0 @@
#include <functional>
#include <gtest/gtest.h>
#include <entt/entity/actor.hpp>
#include <entt/entity/registry.hpp>
TEST(Actor, Component) {
entt::registry registry;
entt::actor actor{registry};
ASSERT_EQ(&registry, &actor.backend());
ASSERT_EQ(&registry, &std::as_const(actor).backend());
ASSERT_TRUE(registry.empty<int>());
ASSERT_FALSE(registry.empty());
ASSERT_FALSE(actor.has<int>());
const auto &cint = actor.assign<int>();
const auto &cchar = actor.assign<char>();
ASSERT_EQ(&cint, &actor.get<int>());
ASSERT_EQ(&cchar, &std::as_const(actor).get<char>());
ASSERT_EQ(&cint, &std::get<0>(actor.get<int, char>()));
ASSERT_EQ(&cchar, &std::get<1>(actor.get<int, char>()));
ASSERT_EQ(&cint, std::get<0>(actor.try_get<int, char, double>()));
ASSERT_EQ(&cchar, std::get<1>(actor.try_get<int, char, double>()));
ASSERT_EQ(nullptr, std::get<2>(actor.try_get<int, char, double>()));
ASSERT_EQ(nullptr, actor.try_get<double>());
ASSERT_EQ(&cchar, actor.try_get<char>());
ASSERT_EQ(&cint, actor.try_get<int>());
ASSERT_FALSE(registry.empty<int>());
ASSERT_FALSE(registry.empty());
ASSERT_TRUE((actor.has<int, char>()));
ASSERT_FALSE(actor.has<double>());
actor.remove<int>();
ASSERT_TRUE(registry.empty<int>());
ASSERT_FALSE(registry.empty());
ASSERT_FALSE(actor.has<int>());
}
TEST(Actor, FromEntity) {
entt::registry registry;
const auto entity = registry.create();
registry.assign<int>(entity, 42);
registry.assign<char>(entity, 'c');
entt::actor actor{entity, registry};
ASSERT_TRUE(actor);
ASSERT_EQ(entity, actor.entity());
ASSERT_TRUE((actor.has<int, char>()));
ASSERT_EQ(actor.get<int>(), 42);
ASSERT_EQ(actor.get<char>(), 'c');
}
TEST(Actor, EntityLifetime) {
entt::registry registry;
entt::actor actor{};
ASSERT_FALSE(actor);
actor = entt::actor{registry};
actor.assign<int>();
ASSERT_TRUE(actor);
ASSERT_FALSE(registry.empty<int>());
ASSERT_FALSE(registry.empty());
registry.destroy(actor.entity());
ASSERT_FALSE(actor);
}
TEST(Actor, ActorLifetime) {
entt::registry registry;
auto *actor = new entt::actor{registry};
actor->assign<int>();
ASSERT_FALSE(registry.empty<int>());
ASSERT_FALSE(registry.empty());
registry.each([actor](const auto entity) {
ASSERT_EQ(actor->entity(), entity);
});
delete actor;
ASSERT_TRUE(registry.empty<int>());
ASSERT_TRUE(registry.empty());
}

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