Squashed 'external/entt/entt/' changes from fef921132..344e03ac6

344e03ac6 update single include file to v3.12.2
da56665b0 registry: make ::valid backward compatible
f6f01ef1b snapshot: avoid warnings due to deprecated functions
0ed514628 now working on v3.12.2
a41421d86 update single include file to v3.12.1
c1f6b11f7 snapshot: reintroduce support to storage listeners
b2233064a now working on version v3.12.1
cb974bf56 adjacency_matrix: fix in_edges() is off by 1 in some cases (close #1019)
7b7d82e6f doc: snapshot (close #984)
05c6898fc test: self-fixing archive example for snapshot classes
7ffa459a6 snapshot: drop ::get member template parameter
93e8e94e6 test: basic continuous loader
c4e241662 snapshot: review basic_continuous_loader (and drop shrink)
9c25419b9 test: more on basic_snapshot_loader
1879830df snapshot: drop pointless assert
29298c0eb test: guarantee code coverage, we'll update the test later on
247abef1d test: rollback for code coverage purposes on the snapshot class
6994d98d2 test: typo
9a600ece2 test: snapshot
f91226ef4 snapshot: share ::orphans implementation (to deprecate in future though)
e366ffbd3 doc: snapshot
63b300d39 snapshot: again, dense_map::contains is a thing
afb70d157 test: avoid warnings due to unused variables
49534eec0 snapshot: dense_map::contains is a thing fortunately
3f1277f7b snapshot: use the right allocator for the remote-local mapping
26fad4c38 test: basic snapshot loader
25b3afacf test: basic snapshot
2d25bbb09 snapshot: check registry type
0eb834582 snapshot: small cleanup
124a44052 test: use the new snapshot get functions in the test suite
5c704636e test: use the new snapshot get functions in the test suite
31fd94cc3 snapshot: cleanup to get ready to drop an internal function
573e43272 snapshot: reduce storage lookups
1d8943481 snapshot: drop useless function
e0a1ef7c1 snapshot: check on member type class
48ac0e0eb snapshot: add basic_continuous_loader::get, deprecate ::entities and ::component
bcb6234d9 snapshot: add basic_snapshot_loader::get, deprecate ::entities and ::component
f96796326 snapshot: reject entity type in the range-get (now get instead of get_sparse)
b22c55dd2 doc: typo
4ff5a536c snapshot: add basic_snapshot::get, deprecate ::entities and ::component
fff5f578a test: avoid using deprecated functions in an example
0f44c8c92 doc: reflect recent changes
0b6ad0315 snapshot: * single element only archive functions required * avoid iterating elements more than once
2450b0bc6 test: minor changes (waiting for a rework)
fc8eebf36 snapshot: use component_traits instead of is_empty_v
e4f51f2b7 snapshot: avoid multiple lookups of the same storage
2c2216a89 doc: typo
cafe85180 snapshot: deprecate multi-type component loading function
35e338cc9 snapshot: deprecate multi-type component loading function
8feeaaef7 doc: minor changes
e7a3c4e37 snapshot: add missing [[deprecate(...)]]
ea5c558bd snapshot: cleanup (waiting for further improvements)
94f0ed179 snapshot: deprecate multi-type component loading function
244c35949 snapshot: deprecate multi-type component loading function
1f24fea21 type_traits: formatting
8deaa09b2 test: perform static checks at compile-time
85bffb714 type_traits: std::tuple traits specialization for entt::type_list and entt::value_list (#1011)
325ca310d view: updated ::refresh
d903e268f snapshot: minor changes
f4b26756c snapshot: improved basic_snapshot::component
fb3a34ee9 *: updated TODO
6902bb6c4 doc: typo
379819b2b test: cleanup
59abfbfb5 meta: refine policy check on value types for non-member data
6e2d87184 registry: avoid casting return types directly to better support empty storage
57ec3c85c registry: erase_if (close #977)
4afdf287f doc: minor changes
2810ac7cb registry: suppress a warning on msvc
e0d27f9bf *: updated TODO
de303c999 test: reverse-each for storage entity
1619e780f test: reverse each for plain storage classes
a1e37eca6 storage: reverse-each
c345e7456 doc: note on reverse iterations
d166c026f snapshot: minor changes
5e639996d doc: minor changes
dac2ef5a9 doc: typo
71d7888e8 snapshot: drop redundant check
84a4df9c4 doc: exclude-only views
95bc20319 doc: entity lifecycle
5a9f6d211 doc: cleanup
a29302faa test: more on entity signals
75efa72c6 registry: cleanup ::erase
58a84665b registry: cleanup ::remove
a5263384d doc: drop redundant comments
c0e6759c6 doc: cleanup a little further
d754f7431 doc: cleanup
1df539943 doc: drop pointless tags
c284e6fee doc: minor changes
500239758 test: typo
319ecd808 organizer: fix organizer::vertex::prepare not creating component pools (#1014)
d7891fabc doc: mention named pools support when registering listeners
e287dd041 helper: minor changes
4dee9dde1 registry: named pools support for on_construct/on_update/on_destroy
9bae6e67b doc: update connection helper doc
aa7a7ce25 doc: minor changes
a969468c5 registry: de-deprecate :) on_construct/on_update/on_destroy
a1e76fc63 doc: more about entity storage
d8ed4ca35 registry: refine how entity storage is used internally
3248e3f91 helper: make sigh_helper work with named pools
f00687e6f doc: updated registry documentation
5240c6b60 registry: deprecate on_construct/on_update/on_destroy
67604a88e natvis: update registry snippet
4242dfb8b registry: use entity storage directly as much as possible
f96d8ee83 registry: prepare to split component storage and entity storage
c147ec37c test: try to make gcc happy again
094ddbba3 meta: avoid shadow warnings
634630ca2 test: add missing template keywords (thanks msvc for ignoring them)
d78c26f26 *: updated TODO
fabc6c9bd test: full cross-registry entity-copy example with meta (not strictly required)
b6e8ddd2a meta: fight against the small nuances of the language :)
cf2bbae6e mixin: make it simpler to modify the underlying type
08799616d *: updated TODO
58bebf78d meta: reduce symbols and their sizes if possible
d534fad3e doc: more about views
871dc7a40 doc: drop references to storage placeholders
1fe7c78f7 test: minor changes
22a65f80f test: cleanup
756ea8a38 *: updated TODO
12186cb40 registry: drop internal static storage variables from ::assure
aa9ffb9ee registry: const ::storage<T>(...) returns a pointer to possibly null storage
dcb5aed90 registry: lazily/partially initialize views in the ::view const function
34f6a747a registry: add support for non-existent pools to try_get
912cb2ad5 snapshot: constness review
885488b3d registry: any_of supports non-existing pools now
3d3d3ef2d registry: all_of supports non-existing pools now
a7120b340 registry: coding style
51915205b test: cover stable multi-type model
4a3ee042e view: refine ::storage function
88a1b8d0d view: stable multi-type view ::each(cb) function
7e18a0f96 view: update ::use function
c367082dd view: unchecked_refresh function
9f94b5306 view: double check on none_of
44ed10c50 view: stable multi type view ::find/::back/::front functions
1b2280941 view: stable multi type view ::begin/::end functions
bdabbaa63 view: stable multi type view ::contains function
c79c109b7 view: stable multi type view ::size_hint function
f1a213382 registry: prepare to remove static storage from const assure
17dc06149 view: stable single type view ::each(cb) function
3b8d82330 view: drop unused return
a20829e70 view: ::handle returns a pointer rather than a reference
5be2fdc15 view: stable single type view ::each() function
873b107e6 -: updated TODO
356bbbe53 view: stable single type view ::find function
e3ce4e156 view: stable single type view ::front/::back functions
e02050c51 view: stable single type view ::rbegin/::rend functions
26930633f view: stable single type view ::begin/::end functions
b7a485767 view: stable single type view ::contains function
f54cdccd4 view: stable single type view ::empty function
41c9a32f3 view: stable single type view ::size function
736ef3580 view: make operator bool work properly with partially initialized views
0128cbb4f test: minor changes
ff0a40715 test: prepare test suite for safe invalid views
34f440386 view: avoid using storage, further prepare for empty safe views
b1c78efb6 nativs: updated signal file
28f03ff9c meta: add missing checks on factory<...>::data
a5fe61adb *: minor changes
457f5e59e view: rollback handle() usage and prepare to safe empty views
422fd284e group: refine group ::find function
6f3222573 view: refine single type view ::find function
366bbceb0 doc: use doxygen-awesome-css
7b7f81e08 doc: update reference.md
cfe955f97 doc: update links.md
684ddc9de doc: minor changes
f5d38a9ae doc: drop redundant doxy variable
447e3693f doc: updated doxy file (doxygen 1.9.6)
909490bf6 view: try to make g++ happy again
d90363e4a view: make view pack also work with empty views
ee5de744c view: add missing [[nodiscard]]
d401c88a0 view: assert on null handles
80563b955 view: allow swapping storage elements of a view
c74900057 sigh_mixin: avoid shadow warnings
78867d5c9 group: make msvc happy with constness on virtual functions
d435fc779 basic_entt_traits: suppress a warning by gcc
e6f76e0f9 view: try to make VS happy again :)
1c6b53360 test: minor changes
5c3d8360c view: turn ::use into a self-contained, non-const function
3882c7d9a view: turn ::refresh into a self contained, non-const function
15726218b view: doc
869bfc82c test: minor changes
0eb3d54b2 group: change signature of ::storage to return a (maybe null) pointer rather than a reference
f83290f76 view: change signature of ::storage to return a (maybe null) pointer rather than a reference
686a3b9d7 registry: make storage_for_type available to the final user
4d57d5c32 registry: make ::storage<T> return type explicit
36c21cf7f registry: drop redundant traits usage
7ab10e193 test: minor changes
41467d35a -: updated TODO
d351252a1 doc: entity storage
c6cd4f701 doc: refine storage section
65889cca4 doc: brief mention of void storage
f1914fd94 doc: rearrange a few things
e53af7bef registry: minor changes
b910cd261 *: updated TODO
58d331ca0 registry: minor changes
17f5b0a33 registry: avoid bumping version on destroy if not requested
de386292b registry: deprecate ::each
88bf26a2f registry: deprecate ::assign
3caad4100 mixin: common internal owner_or_assert function
916203a24 test: stress assert on entity limit
62f1971f7 test: minor changes
4fde96357 natvis: updated registry snippet
c3730b65f group: * unified model * drop group handler's size function (no longer required)
1ea072cd3 group: back to the unified model for group handlers
bbe4582ee meta: minor changes
89ab5c328 meta: operator==/!= for meta_func
3a4672793 meta: operator==/!= for meta_prop
0a0446f35 meta: operator==/!= for meta_data (close #1002)
fc58ff74b meta: operator==/!= for meta_handle (see #1002)
fed6831cd locator: support to opaque structures (close #956)
1605c8d9d natvis: updated entity file
d6641c7d8 -: updated TODO file
5079f38e9 storage: allow on_update signals on entity storage
1eab2a4a8 meta: fix constness detection for static functions in meta_type::invoke
c33110765 test: cleanup
117b0bd67 test: more about storage<...>::patch
9b4a6f877 storage: use allocator_traits::destroy rather than destroy_at
f4e6f2b37 group: suppress shadow warning
5971fb7aa -: updated TODO
10dfe7e93 sigh: allow disconnecting listeners during iterations (close #986)
a9208a956 doc: fixed typo
1cc5b32ca test: cleanup
f8a972a3c signal: drop sink::before
5b7cc2002 group: rollback some (no longer required) changes to the owning_group_descriptor
bd34e7f2c group: drop nested groups support, prepare to the large group review and multi storage support
46fe29c3f group: make matching functions virtual for owning groups
c50e2815c group: make owning_group_descriptor depend on the storage base type
fbfee632d group: minor changes
77c59aabf group: group_handler::size function for owning groups
ebb1e8a72 group: single check function for group handlers
1646217f0 group: make types explicit for the next/prev functions
645edfb2b group: decouple constructing and setting prev/next links
61f28298c group/registry: minor changes
d19f97bf2 group: use ::handle() if possible
70c611a84 group: cleanup
286428c19 group: make common_type base of non-owning group handlers
6ec719bcf group: reduce the footprint of non-owning group handlers
11f9bb2d7 registry: use shared_ptr<void> for non-owning groups (prepare to drop the basic handler dependency)
5a1ba5ad7 regisrtry: decouple container types for groups
cf094e7ef registry: finally split owning and non-owning groups as it ought to be
31808bd9a sigh: flip the last commit on its head and drop redundant functions rather than merging them
61a5173a7 sigh: merge a couple of functions
ed6fe9e65 sigh/sink: refine internal definition
e30fa8520 doc: cleanup
ca1069e18 snapshot: avoid allocations if possible
70f73a094 snapshot: drop pointless checks
710fff0e3 entity: make get_t, exclude_t and owned_t constexpr constructible
660bc5843 entity: turn get_t, exclude_t and owned_t into proper classes (close #998)
13295a14e type_traits: v141 toolset workaround for value_list_diff
9ce07ff61 type_traits: value_list_diff[_t]
b272e04ba type_traits: value_list_contains[_v]
28b11912a test: cleanup
b9f096d12 type_traits: value_list_unique[_t]
8c60faa1d type_traits: value_list_index[_v]
1f93ea4ee snapshot: avoid unnecessary lookups
7ca77e53f snapshot: avoid unnecessary lookups
69397f365 snapshot: avoid unnecessary lookups
f907bc066 snapshot: drop redundant checks and avoid unnecessary lookups
bda52701f snapshot: avoid unnecessary lookups
d26f7684c snapshot: minor changes
63d6c2bff snapshot: avoid unnecessary lookups
cc45e7341 snapshot: also avoid using views if not required
5d092bcb1 snapshot: avoid unnecessary lookups
295c68841 snapshot: review ::orphans functions
2664b5255 observer: allocator support
dd3632833 observer: configurable mask type
c8c929e4a group: use type members properly
d1ef7bf15 view: use type members properly
1ab23f17d group: early exit on signal races
a72eb4693 group: minor changes
67579d062 -: updated TODO
766a233f3 view: base_type -> common_type
905671c23 runtime_view: base_type -> common_type
27c1383e4 group: base_type -> common_type
029ccc8f7 registry: base_type -> common_type
cde40d586 group: drop unused using decl
6a16a8a20 group: auto init for owning groups
1a12dede6 group: auto init for non-owning groups
35a78b65e group: cleanup
ada19432f group: support for index based sort
4998e9087 doc: minor changes
471c11c6d sparse_set: respect -> sort_as (naming is hard, you know)
3e13e0b59 group: sort/respect -> sort_as (also decoupled from group types)
53cd105f2 group: reuse pools as much as possible
24b31c379 group: reuse pools as much as possible
def82b534 group: index based get
a424f4ebf view: review get
b8f0a8d8e doc: a couple of interesting articles/series (close #994)
7941226ef group: try to reuse pools when sorting and also please all compilers out there at the same time (aka me figthing ICEs again)
86bbb2f6b group: reuse pools when sorting
3c176f725 test: suppress warnings due to unused variables
3642c8a78 registry: drop [[nodiscard]] from ::group (close #991)
0e80d90a7 group: use storage<idx> as much as possible
4fdf2dccd group: update doc
f8a997e6c group: minor changes
40f676ed1 test: drop unused include
5e346748e test: code coverage for groups and registry
3ef61fe01 meta: support meta member functions on primitive types
3885d280d test: cleanup
f41b91419 meta: allow updating values on meta properties
e0684f634 registry: cleanup/minor changes
fb980a78c registry: further refine the group function(s)
c2430ab48 doc: minor changes
d36d9cb39 registry: further cleanup group functions
0017c08bb group: get pools from handlers
e737ff747 group: get filter from handlers
945dc4093 group: split group handler functions
7ef008511 registry: drop group_data
d2fa68813 registry/group: prepare to get rid of group_data
f22a09a9a group: in-between change to simplify dropping group_data
b0aba79a5 snapshot: minor changes
7c23e4a2f registry: minor changes
7fe035ce4 group: move group size from registry group_data to basic_group_handler
3e7160eda group: minor changes
aaeb686ec group: common base class for group handlers
3fdf4884d group: prepare for group handler common base class
1b23ff4b9 registry: use common group handler types as keys for the group set
88dac318e group: wrap the len of owning groups to avoid changing it by mistake
520c2e660 group: make group handlers work with multiple storage of the same type
f5d0d451b group: split pools and filter in the group handlers
8af6fc0cc group: use ::handle internally if possible
c04b97a31 group: add ::handle function to all group types
1d85414dc doc: drop refs to registry::version (close #992)
c6533827f group: fight with clang format from time to time :)
b5803451b group: make owning groups work with their handlers
3417d66b2 group: make non-owning groups work with their handlers
1e61204e8 registry: deduce group handler type from group type
19c4857ef group: cleanup
66ea94898 registry/group: move group handler to group file as it ought to be
ced6d21c3 registry: break dependency between registry and group handlers
429c7c45c registry: further cleanup things
c03b1111a registry: small cleanup
ebd7d3acd registry: storage based model with pools for groups
5aeec60cf registry: prepare to switch to storage based group handlers
620b4f751 registry: pass handlers to group callbacks
6d58004c1 registry: minor changes to simplify the implementation slightly
df6d926de registry: prepare for a storage based group handler
e63af24cb registry: turn the non-owning group handler in a storage
068d9f8ae registry: discard unused arguments from listeners if possible
c19c848c4 test: suppress warnings due to unused variables
0bf0a0a8f doc: delegate
743e8678e delegate: also support functions that skip first elements (on second attempt only)
a7ad1c06f delegate: prepare to support filtering on both sides
b1af70e70 registry: avoid checking pools in the group handler if possible
c87c3533e registry: avoid checking pools in the group handler if possible
4839a0ee6 registry: cleanup
a0f0c44e6 registry: minor changes
74691dc1d group: just use meaningful names :)
e4957badb registry: split group handler to further refine group management
46791c4c3 registry: turn group handler functions into static ones
56c391784 registry: prepare to rework groups
1fb13d3e9 doc: minor changes
535beb4e2 storage: drop unnecessary use of integral_constant
2d318b88c -: updated TODO
b7f0b76ce entity/mixin: add missing include
d30312f51 entity/helper: add missing include, drop unnecessary traits calls
30772848e meta: avoid unnecessary calls to std::move
eca01a397 doc: add vcpkg badge and vcpkg.link (#985)
35ef0b7ac core: reduces the number of instantiations a bit
19ccba3a6 meta: reduces the number of instantiations a bit
207b7674a doc: fix typo
631c55ba9 storage: minor changes/tests
e7b30fd36 storage: return iterator to elements rather than entities and only if it makes sense
3e959007b storage: ::insert returns an iterator to the range of inserted entities
07ec4ca23 -: updated TODO
6e4946b68 storage: uniform interface to simplify mixin implementation
47ea16f17 test: signals on entity creation/destruction
722857fc0 test: get rid of pointless template parameters
2125b3838 test: minor changes
289de7d57 test: exclude only views
25ecd8e79 test: minor changes
319dfdb07 test: filtered registry view
9dbbcac01 -: updated TODO
f545c8e05 registry: deprecate ::release
c68fa6a65 registry: make ::destroy work without ::release (the latter to be deprecated)
d288ecd70 registry: make ::release use ::bump return value
312d3aba8 sparse_set: bump returns the version in use (for convenience)
4d2b2c6de registry: use traits_type::next if possible
80d55a226 test: increase code coverage
d86a53935 test: suppress warnings due to unused variables
0f7098d0e -: updated TODO
8c96be1e9 registry: deprecate a bunch of functions because of the entity storage
37f396bfe registry: make entity storage storage as any other
75894dc40 storage: update traits_type for entity storage
cdee000ce any: rollback a change that turns vs toolset v141 crazy
54ca62600 dispatcher: refine aggregate check
6f4280ed5 any: refine aggregate check
ddf56b78c storage: backward compatibility on component requirements
53a854f54 any: just cleanup the code to make it easier to work with
4896acac7 storage: typo
e3defeba2 test: suppress warnings due to unused variables
62079908c storage: use proper value type for entity storage
e65a8f2e5 doc: add link to koala engine :)
9f27fb1e5 registry: further prepare to turn the entity storage into a plain pool
04d734e76 registry: prepare to turn the entity pool in a plain storage
df50fa1b5 natvis: cleanup
051872b8c natvis: update registry definition
57ab9e7be registry: avoid using assure if not required
69d95ba75 test: more bench to stress a little an upcoming feature
9caf66d7c test: cleanup
74cb0d40c test: internal rework
deac7f34b dispatcher: refine aggregate support
a9883f27c storage: refine transparent aggregate support
85b1e57d8 sparse_set: drop fast_compact, expect full clear
b7d8e0186 storage: make the entity storage perform a full clear rather than a fake one (still viable via erase)
390a56176 -: updated TODO file
a1b888cce natvis: add optiona storage length item for entity storage
2107dd689 natvis: fix already existing errors due to renaming or design changes
1fca56afe storage: make it easier to refine the natvis file
c0762a6a5 storage: add get/get_as_tuple to entity storage to make it suitable for use with views
f48de1bac test: stress get/get_as_tuple for empty types
c7dfce89e sigh_mixin: refine pop_all
822fafcd4 view: uniform implementation to simplify upcoming changes
1476d4ea9 sparse_set: refine ::respect
c1c63777e -: updated TODO
2fab25ae8 registry: refine internal check
75d449152 -: updated TODO
c7866fb21 storage: use entt traits next function if possible
87987bacd entity: added basic_entt_traits::next (with tests)
bde0219fe snapshot: review basic_continuous_loader::entities
ad64c849b storage: suppress warnings
b808bb83b test: suppress warnings
d0090d35f snapshot: try to make sizes an opaque value to the caller
7a1a06a24 sigh_mixin: avoid shadow warnings
000b17881 -: updated TODO
068b6ed49 registry: first (almost) backward compatible version with opaque hidden entity storage
0187fb48a test: sigh mixin for entity storage types
35a2b3844 sigh_mixin: also support entity storage types
4747c9a4c registry: extended checks to support swap-only entity storage types
7be8d8327 registry: make a couple of conditions opaque
a5d6757d6 registry: prepare to get rid of the vector of entities
3f09d47c8 storage: remove redundant typename keyword
9c06d6ba0 registry: use type member names
b7c819bf4 test: entity storage
9f31803ba storage: swap-only entity storage
1e7deff9c test: drop redundant checks
04ac15d8d test: minor changes
376218991 sigh_mixin: make pop_all use narrow view iterators if any
18d6e466d -: [[nodiscard]]  as appropriate
095ecf314 group: extended_group_iterator::base to return the underlying iterator
433ed863e view: extended_view_iterator::base to return the underlying iterator
0dba68e75 storage: coding style/minor changes
1ab281582 storage: extended_storage_iterator::base to return the underlying iterator
2af5a725e doc: * updated copyright * udpated TODO list
a86bf1332 test: try to make lcov happy
831054bff test: share as much as possible
f94de1c06 test: rework lib stuff to share common files
a3d9503a1 test: try to make lcov happy
3f2b15f9f test: try to make lcov happy
e48817d51 test: try to make lcov happy
d11cebe30 view: uniform design to also help natvis without having to poke into stl internals
77a5efb32 natvis: updated to_entity intrinsic
851006efe -: updated TODO
6fc6b2fb3 sigh_mixin: further improve ::pop_all
ed17a2c48 sparse_set: ::contiguous function
bd00e797a sparse_set: further refine pop_all to make it even faster
e645c4928 -: updated TODO
a425878e8 sparse_set/storage: clear is backward compatible now
f3cd9d374 storage: fixed clear_all counter
b3e93b084 registry: naming convention
314c189c4 test: minor changes
2bb2c5566 build: try to make lcov happy again
d13c126e9 view: avoid name clashes
9b54ee37a flow: propagate allocator to generated graph + internal rework
e1ead9d3e build: update coverage workflow
cf61068dc mixin: suppress a warning with gcc11
82863f829 test: code coverage for range functionalities
e4de59827 test: try to make lcov happy
ccea4c920 memory: code coverage
89166f0e4 build: refine analyzer workflow
7a05a16c5 registry: slightly better destroy (yet not quite there though)
d0854646c test: yet another test to stress the upcoming changes
1e9c9fe5f registry: better, faster range-remove + refine range-erase
80fac8d8e test: minor changes
c774b9838 -: updated TODO
3fd0403cc registry: faster, better range-erase
6eb3347a3 test: a couple of extra functions to stress the upcoming changes
89bceaff7 -: updated TODO
dc25c9c1a sparse_set: invoke release_sparse_pages before clearing the sparse array
e68ba5870 sigh_mixin: add a missing include
c68cb3375 entity: make deletion_policy publicly available via fwd.hpp
59f807fd0 sparse_set: suppress warnings due to unused expressions
232ffebc1 sparse_set: internal clear_all function
3cea845a0 sparse_set: sparse_set_iterator::data function
295f3b32e registry: a couple of extra move calls here and there
254da2c3c sparse_set: better, faster range remove
ecd3b8d93 sparse_set: prevent rework errors as much as possible
c673b9b17 sigh_mixin: slightly improved pop + review insert
cd28de0d6 test: clear-stable bench
672f6a711 test: minor changes
3b50672b7 storage: restore storage_for/storage_type duality, it turned out to be very useful in practice
f0613b1c6 sparse_set/storage: minor changes to reuse type members
2197e160e -: drop file pushed by mistake :)
2dccd9016 handle: discard entity on destruction
2f873f2dd -: storage_mixin.hpp -> mixin.hpp (non-storage mixins are also a thing)
fde1a524e sparse_set: ::get -> ::value (to avoid hiding from derived classes)
055801047 doc: drop references to docsforge + minor changes
79a054a52 sigh_mixin: scope base_type properly
d94e443a1 doc: drop outdated section
3862184e8 sigh_mixin: support self managed storage classes
f40fa3c2f test: * use range destroy * avoid compiler optimizations
01bc93459 test (bench): the new entity storage enables the fast path in all cases
151bd0739 sparse_set: revert optmized range push, it prevents self-managed storage classes
935393aae sparse_set: better, faster range push
fbfde4347 snapshot: avoid unused variable warnings
2ffbe115b component_traits: revert entity customization support
645973eb7 sparse_set: insert -> push
133230797 sparse_set: emplace -> push
b700f5eb5 doc: typo
e60dbdc52 sparse_set/storage: * rename swap_at in swap_or_move to capture the real purpose * define swap_at as a protected function to allow swapping from above
c66623b33 sigh_mixin: avoid hiding basic_iterator type meber
62246d879 storage: avoid hiding basic_iterator type meber
b35f13130 sparse_set: support swap-only mixins
3dd82633a -: drop storage_mixin.cpp, I forgot to do it a couple of commits ago :)
00231bf8a storage: make swap_at non-final to support checks on derived classes
58d392e81 -: minor changes
1d4d99d09 mixin: sigh_storage_mixin -> sigh_mixin
fe3edf2c8 -: minor changes
0864ba042 -: drop useless typename
3a9698001 build: minor changes
423f7a555 is_equality_comparable: detect C-style arrays directly
5db8ad53a build: update gh workflow
c2ab35780 view: make also VS toolset v141 happy
4fb558f14 view: further reduce instantiations
5762a8a08 view: reuse internal functions if possible
ed4c67521 sparse_set/storage: drop move_element
f15789846 config: ENTT_FAIL(msg) -> ENTT_ASSERT(false, msg)
6d20709e0 storage: minor changes
a9a9853c0 sigh_storage_mixin: use entity_type from Type
af14aa4c9 doc: more about signals (sigh_storage_mixin)
24d6b9881 test: minor changes
899f4baa6 storage: * drop storage_for]_t] * make storage_type[_t] deal with constness
c1ab7ba02 sigh_storage_mixin: make all virtual member functions final
9d38f6020 registry: thanks MSVC for accepting invalid C++ code
0efa25cf6 sigh: cool, I keep doing the same error again and again apparently :)
6316b6045 registry: make it work with storage<void> also in C++17
f268fb60a entity: avoid breaking changes due to type members renaming
3520d6915 entity: add base_type
4da7a8451 entity: make checks work with 64b identifiers :)
382dfc3bb entity: strict check on entity/version masks
b6dcdc816 entity: * also expose entity_mask and version mask to the final user * avoid default args with entt_traits::construct for backward compatibility
c9d544089 doc: review/cleanup entity.md a bit (done)
3eb5faeed doc: review/cleanup entity.md a bit (work in progress)
7a328c7ed doc: updated links
6567aa195 doc: a note about listeners disconnection (close #958)
92319f011 entt_traits: split basic impl, simplify def
782d86b6e entt_traits: value_type -> type (cuz it's not a value type after all)
c2cae37c1 entity_traits: make page_size type explicit
1026d26ec entt_traits: drop reserved value
7156803db test: local non-static constexpr variables
f54ed5424 helper: local non-static constexpr variables
f30b50195 algorithm: local non-static constexpr variables
c90ab9aff sparse_set: * break dependency on traits_type::reserved * use a tombstone if all I need is a tombstone
c2f6ca43f doc: graph (close #957)
3e5e41d88 test: cover some corner cases of the flow class
9eafc0431 flow: minor changes
0a82b777b component_traits: support specializations based on entity type
32bcc01a4 component: * make component_traits treat void properly * drop ignore_as_empty_v
9c3fe3546 nativs: entity module
83f8aed58 helper: use traits_type from storage class directly
2fd660274 snapshot: use public registry traits_type member type
a554d406e registry: * public traits_type member type * break dependency on component_traits * use public storage traits_type member type
5f12f872e test: minor changes
be4eb68a3 helper: * break dependency on component_traits * use public storage traits_type member type
df5284d9e view: * break dependency on component_traits * use public storage traits_type member type
0e27d33e7 storage: public traits_type member type
fe6e6ae73 sparse_set: public traits_type member type
9d29713ea entity: naming convention
270d0277d group: cleanup
0bd06c8d5 hashed_string: naming convention
733f215cc storage: break dependency between component_traits and storage_iterator
ad01a69fe *: renaming/coding style
dd9c1dade sparse_set: no need to differentiate template args for sparse_set_iterator
b8f70519f doc: fixed typo
9b9d212dd *: coding style
3fe15969d doc: cleanup
ec4bf222c meta: avoid the +1u trick for 0-sized arrays
1173908ee meta: avoid rebinding when forwarding requests
2595b8a92 doc: sigh_helper
f4e2a8c76 sigh_builder: add all missing .template that msvc kindly accepted anyway
66e1a0565 entity: sigh_helper utility with tests (close #928)
87283dc41 storage: simplified impl in order to introduce multi-type storage more easily
a802ebffe storage: * move storage_type[_t] and storage_for[_t] to fwd.hpp * no need to include storage.hpp when forward defining views
b84b09421 doc: add Arch ECS to references.md (#954)
940fd0939 todo: add a note for a (soon to be released) change
920338be5 doc: add ecsact to links.md (thanks @zaucy for pointing this out)
bcd1155b7 gh: add more gcc and clang versions
1dc88109e gh: update workflows
262c1f53c cmake: only enable -Wdocumentation for clang-cl
4af0a3a0d doc: cleanup
be1641828 doc: cleanup
b54a52fbf doc: fixed typo
ae8815995 doc: fixed typo
62c764f68 doc: fixed typo
2c48cc10a cmake: enable documentation diagnostic for clang
82f286678 sigh: drop redundant function
d56e5a269 registry: propagate allocator to context
1517b2951 doc: document delegate raw access
bea7b43a1 delegate: target member function
2f878f8b5 sigh: refine ::collect
fc68c1b29 view/group: cleanup
9081c185d meta: minor changes
7c4493f23 group: make filter storage available
da4e73ab8 view: make filter storage available
f3e7f98b4 registry: extra check when moving a registry
3925fc612 emitter: extra allocator check when moving
c639130c1 dispatcher: extra allocator check when moving
75c311600 registry: cleanup
e9e14eb49 meta: [[nodiscard]]
d1558304f any: [[nodiscard]]
0531b530b snapshot: minor changes
f9d0178dd workflow: bump iwyu version
b66b8d37e test: suppress warning
05ef4c29d storage: minor changes
9c3d75669 test: cleanup include directives
93651e46f registry: drop [[deprecated]] functions
ea901cbfa test: code coverage
d5dc4f43e doc: meta.md
498e02f15 doc: core.md
d0ea8f4f9 cmake: suppress some warnings for clang-cl, it goes a little wrong otherwise
dec3b7bb3 test: suppress warnings
10bc8b05a test: use /W1 with VS (but for toolset v141, too bugged for that)
ad77b54dc cmake: bump version to get some cool feature/update
b6724b028 group: pass filter storage to groups (in-between change for full storage access)
54270b103 group: make them easily copyable/movable
31dc732a7 doc: graph.md
f0e02d6d3 doc: container.md
156d6e4ea doc: poly.md
4375c1c3d doc: lib.md
24a9cd67e scheduler: forgot to add the fwd file to the previous commit :)
ba8d522c1 doc: add the worst engine (love the name) to the list of links
3ae46214a doc: review process.md
5119fe8d7 scheduler: basic type model with default for common cases
ed0319cdd view: avoid shadow warnings
bc50da6a7 storage: suppress warnings with non copyable nor default constructible types
52b3b4c24 group: suppress warnings for unused variables in case of empty types
74bab529d test: minor changes
b1b143917 meta: [[maybe_unused]] variable to avoid warnings with corner cases
7beb4c85c test: suppress a few warnings (entity)
f3beb5670 test: suppress a few warnings (container)
446c67b69 test: suppress a few warnings (resource)
c4507bd17 test: suppress a few warnings (poly)
61e872bb4 test: suppress a few warnings (meta)
9f22a3e23 test: suppress a few warnings (memory)
653dd5cd4 test: suppress a few warnings (tuple)
bc53ed3be test: suppress a few warnings (flow)
f935bbcce dense_set: suppress warnings due to possible narrowing conversions
c7d505353 dense_map: suppress warnings due to possible narrowing conversions
ea78f1d97 now working on version 3.12
REVERT: fef921132 update single include file
REVERT: e52a93f8a ready to cut v3.11.1
REVERT: cd541f335 storage: * move storage_type[_t] and storage_for[_t] to fwd.hpp * no need to include storage.hpp when forward defining views
REVERT: 255b8be8c view: avoid shadow warnings
REVERT: 8cd7f064a storage: suppress warnings with non copyable nor default constructible types
REVERT: 58ae4117c group: suppress warnings for unused variables in case of empty types
REVERT: cfa1e805b meta: [[maybe_unused]] variable to avoid warnings with corner cases
REVERT: ccedacec8 dense_set: suppress warnings due to possible narrowing conversions
REVERT: 17578dc8c dense_map: suppress warnings due to possible narrowing conversions

git-subtree-dir: external/entt/entt
git-subtree-split: 344e03ac64a1f78424ab1150e2d4778e8df8431d
This commit is contained in:
2023-10-02 15:30:10 +02:00
parent 5c7231b7a3
commit 90ce4bda4e
153 changed files with 24263 additions and 14220 deletions

View File

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

View File

@ -1,4 +1,4 @@
# Doxyfile 1.9.4
# Doxyfile 1.9.6
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
@ -19,7 +19,8 @@
# configuration file:
# doxygen -x [configFile]
# Use doxygen to compare the used configuration file with the template
# configuration file without replacing the environment variables:
# configuration file without replacing the environment variables or CMake type
# replacement variables:
# doxygen -x_noenv [configFile]
#---------------------------------------------------------------------------
@ -85,7 +86,7 @@ CREATE_SUBDIRS = NO
# level increment doubles the number of directories, resulting in 4096
# directories at level 8 which is the default and also the maximum value. The
# sub-directories are organized in 2 levels, the first level always has a fixed
# numer of 16 directories.
# number of 16 directories.
# Minimum value: 0, maximum value: 8, default value: 8.
# This tag requires that the tag CREATE_SUBDIRS is set to YES.
@ -557,7 +558,8 @@ HIDE_UNDOC_MEMBERS = NO
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# will also hide undocumented C++ concepts if enabled. This option has no effect
# if EXTRACT_ALL is enabled.
# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
@ -595,7 +597,8 @@ INTERNAL_DOCS = NO
# 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.
# Possible values are: SYSTEM, NO and YES.
# The default value is: SYSTEM.
CASE_SENSE_NAMES = YES
@ -847,6 +850,14 @@ WARN_IF_INCOMPLETE_DOC = YES
WARN_NO_PARAMDOC = YES
# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about
# undocumented enumeration values. If set to NO, doxygen will accept
# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: NO.
WARN_IF_UNDOC_ENUM_VAL = NO
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# 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
@ -905,10 +916,21 @@ INPUT = @DOXY_SOURCE_DIRECTORY@ \
# 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.
# See also: INPUT_FILE_ENCODING
# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# This tag can be used to specify the character encoding of the source files
# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify
# character encoding on a per file pattern basis. Doxygen will compare the file
# name with each pattern and apply the encoding instead of the default
# INPUT_ENCODING) if there is a match. The character encodings are a list of the
# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding
# "INPUT_ENCODING" for further information on supported encodings.
INPUT_FILE_ENCODING =
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
@ -945,7 +967,7 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE = @DOXY_DEPS_DIRECTORY@
EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@ -1015,6 +1037,11 @@ IMAGE_PATH =
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
#
# Note that doxygen will use the data processed and written to standard output
# for further processing, therefore nothing else, like debug statements or used
# commands (so in case of a Windows batch file always use @echo OFF), should be
# written to standard output.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
@ -1056,6 +1083,15 @@ FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE = @PROJECT_SOURCE_DIR@/README.md
# The Fortran standard specifies that for fixed formatted Fortran code all
# characters from position 72 are to be considered as comment. A common
# extension is to allow longer lines before the automatic comment starts. The
# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can
# be processed before the automatic comment starts.
# Minimum value: 7, maximum value: 10000, default value: 72.
FORTRAN_COMMENT_AFTER = 72
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
@ -1193,10 +1229,11 @@ CLANG_DATABASE_PATH =
ALPHABETICAL_INDEX = YES
# 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
# while generating the index headers.
# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes)
# that should be ignored while generating the index headers. The IGNORE_PREFIX
# tag works for classes, function and member names. The entity will be placed in
# the alphabetical list under the first letter of the entity name that remains
# after removing the prefix.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
@ -1265,7 +1302,7 @@ HTML_FOOTER =
# obsolete.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_STYLESHEET =
HTML_STYLESHEET = @DOXY_CSS_DIRECTORY@/doxygen-awesome.css
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# cascading style sheets that are included after the standard style sheets
@ -1275,7 +1312,12 @@ HTML_STYLESHEET =
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# list).
# Note: Since the styling of scrollbars can currently not be overruled in
# Webkit/Chromium, the styling will be left out of the default doxygen.css if
# one or more extra stylesheets have been specified. So if scrollbar
# customization is desired it has to be added explicitly. For an example see the
# documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_STYLESHEET =
@ -1290,6 +1332,19 @@ HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output
# should be rendered with a dark or light theme.
# Possible values are: LIGHT always generate light mode output, DARK always
# generate dark mode output, AUTO_LIGHT automatically set the mode according to
# the user preference, use light mode if no preference is set (the default),
# AUTO_DARK automatically set the mode according to the user preference, use
# dark mode if no preference is set and TOGGLE allow to user to switch between
# light and dark mode via a button.
# The default value is: AUTO_LIGHT.
# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE = LIGHT
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a color-wheel, see
@ -1653,17 +1708,6 @@ HTML_FORMULA_FORMAT = png
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
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.
@ -2379,26 +2423,38 @@ HAVE_DOT = YES
DOT_NUM_THREADS = 0
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
# setting DOT_FONTPATH to the directory containing the font.
# The default value is: Helvetica.
# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of
# subgraphs. When you want a differently looking font in the dot files that
# doxygen generates you can specify fontname, fontcolor and fontsize attributes.
# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node,
# Edge and Graph Attributes specification</a> You need to make sure dot is able
# to find the font, which can be done by putting it in a standard location or by
# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
# directory containing the font. Default graphviz fontsize is 14.
# The default value is: fontname=Helvetica,fontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica
DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10"
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
# dot graphs.
# Minimum value: 4, maximum value: 24, default value: 10.
# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can
# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a
# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about
# arrows shapes.</a>
# The default value is: labelfontname=Helvetica,labelfontsize=10.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10"
# By default doxygen will tell dot to use the default font as specified with
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
# the path where dot can find it using this tag.
# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes
# around nodes set 'shape=plain' or 'shape=plaintext' <a
# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a>
# The default value is: shape=box,height=0.2,width=0.4.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4"
# You can set the path where dot can find font specified with fontname in
# DOT_COMMON_ATTR and others dot attributes.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
@ -2641,18 +2697,6 @@ DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem
# to support this out of the box.
#
# Warning: Depending on the platform used, enabling this option may lead to
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
# read).
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support

View File

@ -17,7 +17,6 @@
* [ENTT_DISABLE_ASSERT](#entt_disable_assert)
* [ENTT_NO_ETO](#entt_no_eto)
* [ENTT_STANDARD_CPP](#entt_standard_cpp)
<!--
@endcond TURN_OFF_DOXYGEN
-->

View File

@ -9,7 +9,6 @@
* [Containers](#containers)
* [Dense map](#dense-map)
* [Dense set](#dense-set)
<!--
@endcond TURN_OFF_DOXYGEN
-->
@ -21,7 +20,7 @@ difficult to do better (although it's very easy to do worse, as many examples
available online demonstrate).<br/>
`EnTT` doesn't try in any way to replace what is offered by the standard. Quite
the opposite, given the widespread use that is made of standard containers.<br/>
However, the library also tries to fill a gap in features and functionality by
However, the library also tries to fill a gap in features and functionalities by
making available some containers initially developed for internal use.
This section of the library is likely to grow larger over time. However, for the
@ -40,7 +39,7 @@ The implementation is based on _sparse sets_ and each bucket is identified by an
implicit list within the packed array itself.
The interface is very close to its counterpart in the standard library, that is,
`std::unordered_map`.<br/>
the `std::unordered_map` class.<br/>
However, both local and non-local iterators returned by a dense map belong to
the input iterator category although they respectively model the concepts of a
_forward iterator_ type and a _random access iterator_ type.<br/>
@ -63,5 +62,5 @@ The implementation is based on _sparse sets_ and each bucket is identified by an
implicit list within the packed array itself.
The interface is in all respects similar to its counterpart in the standard
library, that is, `std::unordered_set`.<br/>
library, that is, the `std::unordered_set` class.<br/>
Therefore, there is no need to go into the API description.

View File

@ -46,25 +46,24 @@
# Introduction
`EnTT` comes with a bunch of core functionalities mostly used by the other parts
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.
of the library.<br/>
Many of these tools are also useful in everyday work. Therefore, it's worth
describing them so as not to reinvent the wheel in case of need.
# Any as in any type
`EnTT` comes with its own `any` type. It may seem redundant considering that
C++17 introduced `std::any`, but it is not (hopefully).<br/>
`EnTT` offers its own `any` type. It may seem redundant considering that C++17
introduced `std::any`, but it is not (hopefully).<br/>
First of all, the _type_ returned by an `std::any` is a const reference to an
`std::type_info`, an implementation defined class that's not something everyone
wants to see in a software. Furthermore, there is no way to 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.
wants to see in a software. Furthermore, there is no way to bind it to the type
system of the library and therefore with its integrated RTTI support.
The 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.
The `any` API is very similar to that of its most famous counterpart, mainly
because this class serves the same purpose of being an opaque container for any
type of value.<br/>
Instances also minimize the number of allocations by relying on a well known
technique called _small buffer optimization_ and a fake vtable.
Creating an object of the `any` type, whether empty or not, is trivial:
@ -93,8 +92,8 @@ Furthermore, an instance of `any` isn't tied to an actual type. Therefore, the
wrapper is reconfigured when it's assigned a new object of a type other than
the one it contains.
There exists also a way to directly assign a value to the variable contained by
an `entt::any`, without necessarily replacing it. This is especially useful when
There is also a way to directly assign a value to the variable contained by an
`entt::any`, without necessarily replacing it. This is especially useful when
the object is used in _aliasing mode_, as described below:
```cpp
@ -108,15 +107,15 @@ any.assign(value);
any.assign(std::move(value));
```
The `any` class will also perform a check on the type information and whether or
not the original type was copy or move assignable, as appropriate.<br/>
In all cases, the `assign` function returns a boolean value to indicate the
success or failure of the operation.
The `any` class performs a check on the type information and whether or not the
original type was copy or move assignable, as appropriate.<br/>
In all cases, the `assign` function returns a boolean value that is true in case
of success and false otherwise.
When in doubt about the type of object contained, the `type` member function of
`any` returns a const reference to the `type_info` associated with its element,
or `type_id<void>()` if the container is empty. The type is also used internally
when comparing two `any` objects:
When in doubt about the type of object contained, the `type` member function
returns a const reference to the `type_info` associated with its element, or
`type_id<void>()` if the container is empty.<br/>
The type is also used internally when comparing two `any` objects:
```cpp
if(any == empty) { /* ... */ }
@ -125,7 +124,7 @@ if(any == empty) { /* ... */ }
In this case, before proceeding with a comparison, it's verified that the _type_
of the two objects is actually the same.<br/>
Refer to the `EnTT` type system documentation for more details about how
`type_info` works and on possible risks of a comparison.
`type_info` works and the possible risks of a comparison.
A particularly interesting feature of this class is that it can also be used as
an opaque container for const and non-const references:
@ -153,22 +152,19 @@ 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.
object or is as a reference for unmanaged elements already. The new instance
thus created doesn't create copies and only serves as a reference for the
original item.
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/>
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.
`any` that wraps a const reference returns a null pointer in all cases.
To cast an instance of `any` to a type, the library offers a set of `any_cast`
functions in all respects similar to their most famous counterparts.<br/>
The only difference is that, in the case of `EnTT`, these won't raise exceptions
The only difference is that, in the case of `EnTT`, they won't raise exceptions
but will only trigger an assert in debug mode, otherwise resulting in undefined
behavior in case of misuse in release mode.
@ -188,31 +184,23 @@ 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.
In other terms, if the size is 0, `any` suppresses the small buffer optimization
and always dynamically allocates objects (except for aliasing cases).
## Alignment requirement
The alignment requirement is optional and by default the most stringent (the
largest) for any object whose size is at most equal to the one provided.<br/>
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:
It's provided as an optional second parameter following the desired size for the
internal storage:
```cpp
using my_any = entt::basic_any<sizeof(double[4]), alignof(double[4])>;
```
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.
The `basic_any` class template inspects the alignment requirements in each case,
even when not provided and may decide not to use the small buffer optimization
in order to meet them.
# Compressed pair
@ -225,8 +213,8 @@ is more important than having some cool and probably useless feature.
Although the API is very close to that of `std::pair` (apart from the fact that
the template parameters are inferred from the constructor and therefore there is
no` entt::make_compressed_pair`), the major difference is that `first` and
`second` are functions for implementation needs:
no `entt::make_compressed_pair`), the major difference is that `first` and
`second` are functions for implementation requirements:
```cpp
entt::compressed_pair pair{0, 3.};
@ -239,16 +227,15 @@ intuition. At the end of the day, it's just a pair and nothing more.
# Enum as bitmask
Sometimes it's useful to be able to use enums as bitmasks. However, enum classes
aren't really suitable for the purpose out of the box. Main problem is that they
don't convert implicitly to their underlying type.<br/>
All that remains is to make a choice between using old-fashioned enums (with all
their problems that I don't want to discuss here) or writing _ugly_ code.
aren't really suitable for the purpose. Main problem is that they don't convert
implicitly to their underlying type.<br/>
The choice is then between using old-fashioned enums (with all their problems
that I don't want to discuss here) or writing _ugly_ code.
Fortunately, there is also a third way: adding enough operators in the global
scope to treat enum classes as bitmask transparently.<br/>
The ultimate goal is to be able to write code like the following (or maybe
something more meaningful, but this should give a grasp and remain simple at the
same time):
scope to treat enum classes as bitmasks transparently.<br/>
The ultimate goal is to write code like the following (or maybe something more
meaningful, but this should give a grasp and remain simple at the same time):
```cpp
enum class my_flag {
@ -261,11 +248,11 @@ const my_flag flags = my_flag::enabled;
const bool is_enabled = !!(flags & my_flag::enabled);
```
The problem with adding all operators to the global scope is that these will
come into play even when not required, with the risk of introducing errors that
are difficult to deal with.<br/>
The problem with adding all operators to the global scope is that these come
into play even when not required, with the risk of introducing errors that are
difficult to deal with.<br/>
However, C++ offers enough tools to get around this problem. In particular, the
library requires users to register all enum classes for which bitmask support
library requires users to register the enum classes for which bitmask support
should be enabled:
```cpp
@ -276,7 +263,7 @@ struct entt::enum_as_bitmask<my_flag>
```
This is handy when dealing with enum classes defined by third party libraries
and over which the users have no control. However, it's also verbose and can be
and over which the user has no control. However, it's also verbose and can be
avoided by adding a specific value to the enum class itself:
```cpp
@ -289,23 +276,21 @@ enum class my_flag {
```
In this case, there is no need to specialize the `enum_as_bitmask` traits, since
`EnTT` will automatically detect the flag and enable the bitmask support.<br/>
Once the enum class has been registered (in one way or the other) all the most
common operators will be available, such as `&`, `|` but also `&=` and `|=`.
`EnTT` automatically detects the flag and enables the bitmask support.<br/>
Once the enum class is registered (in one way or the other), the most common
operators such as `&`, `|` but also `&=` and `|=` are available for use.
Refer to the official documentation for the full list of operators.
# Hashed strings
A hashed string is a zero overhead unique identifier. Users can use
human-readable identifiers in the codebase while using their numeric
counterparts at runtime, thus without affecting performance.<br/>
Hashed strings are human-readable identifiers in the codebase that turn into
numeric values at runtime, thus without affecting performance.<br/>
The class has an implicit `constexpr` constructor that chews a bunch of
characters. Once created, all what one can do with it is getting back the
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.
characters. Once created, one can get the original string by means of the `data`
member function or convert the instance into a number.<br/>
A hashed string is well suited wherever a constant expression is required. No
_string-to-number_ conversion will take place at runtime if used carefully.
Example of use:
@ -318,19 +303,18 @@ auto resource = load(entt::hashed_string{"gui/background"});
```
There is also a _user defined literal_ dedicated to hashed strings to make them
more user-friendly:
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:
User defined literals in `EnTT` are enclosed in the `entt::literals` namespace.
Therefore, the entire namespace or selectively the literal of interest must be
explicitly included before each use, a bit like `std::literals`.<br/>
The class also offers the necessary functionalities to create hashed strings at
runtime:
```cpp
std::string orig{"text"};
@ -343,16 +327,14 @@ 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
takes place at runtime and no longer at compile-time. It could therefore affect
performance to some degrees.
## Wide characters
The hashed string has a design that is close to that of an `std::basic_string`.
It means that `hashed_string` is nothing more than an alias for
`basic_hashed_string<char>`. For those who want to use the C++ type for wide
character representation, there exists also the alias `hashed_wstring` for
`basic_hashed_string<wchar_t>`.<br/>
The `hashed_string` class is an alias for `basic_hashed_string<char>`. To use
the C++ type for wide character representations, there exists also the alias
`hashed_wstring` for `basic_hashed_string<wchar_t>`.<br/>
In this case, the user defined literal to use to create hashed strings on the
fly is `_hws`:
@ -360,16 +342,15 @@ fly is `_hws`:
constexpr auto str = L"text"_hws;
```
Note that the hash type of the `hashed_wstring` is the same of its counterpart.
The hash type of `hashed_wstring` is the same as its counterpart.
## Conflicts
The hashed string class uses internally FNV-1a to compute the numeric
counterpart of a string. Because of the _pigeonhole principle_, conflicts are
possible. This is a fact.<br/>
The hashed string class uses FNV-1a internally to hash strings. Because of the
_pigeonhole principle_, conflicts are possible. This is a fact.<br/>
There is no silver bullet to solve the problem of conflicts when dealing with
hashing functions. In this case, the best solution seemed to be to give up.
That's all.<br/>
hashing functions. In this case, the best solution is likely to give up. That's
all.<br/>
After all, human-readable unique identifiers aren't something strictly defined
and over which users have not the control. Choosing a slightly different
identifier is probably the best solution to make the conflict disappear in this
@ -377,8 +358,8 @@ case.
# Iterators
Writing and working with iterators isn't always easy and more often than not
leads to duplicated code.<br/>
Writing and working with iterators isn't always easy. More often than not it
also leads to duplicated code.<br/>
`EnTT` tries to overcome this problem by offering some utilities designed to
make this hard work easier.
@ -431,7 +412,7 @@ user.
## Iterable adaptor
Typically, a container class provides `begin` and `end` member functions (with
their const counterparts) to be iterated by the user.<br/>
their const counterparts) for iteration.<br/>
However, it can happen that a class offers multiple iteration methods or allows
users to iterate different sets of _elements_.
@ -452,8 +433,8 @@ by returning an iterable object for the purpose.
There are a handful of tools within `EnTT` to interact with memory in one way or
another.<br/>
Some are geared towards simplifying the implementation of (internal or external)
allocator aware containers. Others, on the other hand, are designed to help the
developer with everyday problems.
allocator aware containers. Others are designed to help the developer with
everyday problems.
The former are very specific and for niche problems. These are tools designed to
unwrap fancy or plain pointers (`to_address`) or to help forget the meaning of
@ -481,7 +462,7 @@ modulus and for this reason preferred in many areas.
A nasty thing in C++ (at least up to C++20) is the fact that shared pointers
support allocators while unique pointers don't.<br/>
There is a proposal at the moment that also shows among the other things how
There is a proposal at the moment that also shows (among the other things) how
this can be implemented without any compiler support.
The `allocate_unique` function follows this proposal, making a virtue out of
@ -498,13 +479,16 @@ the same feature.
# Monostate
The monostate pattern is often presented as an alternative to a singleton based
configuration system. This is exactly its purpose in `EnTT`. Moreover, this
implementation is thread safe by design (hopefully).<br/>
Keys are represented by hashed strings, values are basic types like `int`s or
`bool`s. Values of different types can be associated to each key, even more than
one at a time. Because of this, users must pay attention to use the same type
both during an assignment and when they try to read back their data. Otherwise,
they will probably incur in unexpected results.
configuration system.<br/>
This is exactly its purpose in `EnTT`. Moreover, this implementation is thread
safe by design (hopefully).
Keys are integral values (easily obtained by hashed strings), values are basic
types like `int`s or `bool`s. Values of different types can be associated with
each key, even more than one at a time.<br/>
Because of this, one should pay attention to use the same type both during an
assignment and when trying to read back the data. Otherwise, there is the risk
to incur in unexpected results.
Example of use:
@ -542,17 +526,10 @@ Basically, the whole system relies on a handful of classes. In particular:
auto index = entt::type_index<a_type>::value();
```
The returned value isn't guaranteed to be stable across different runs.
The returned value isn't guaranteed to be stable across different runs.<br/>
However, it can be very useful as index in associative and unordered
associative containers or for positional accesses in a vector or an array.
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_index` can be
specialized by type and is also _sfinae-friendly_ in order to allow more
refined specializations such as:
@ -566,7 +543,7 @@ Basically, the whole system relies on a handful of classes. In particular:
};
```
Note that indexes **must** still be generated sequentially in this case.<br/>
Indexes **must** be sequentially generated in this case.<br/>
The tool is widely used within `EnTT`. Generating indices not sequentially
would break an assumption and would likely lead to undesired behaviors.
@ -583,14 +560,14 @@ Basically, the whole system relies on a handful of classes. In particular:
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
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_index`, also `type_hash` is a _sfinae-friendly_ class that can be
specialized in order to customize its behavior globally or on a per-type or
per-traits basis.
As it happens with `type_index`, also `type_hash` is a _sfinae-friendly_ class
that can be specialized in order to customize its behavior globally or on a
per-type or per-traits basis.
* The name associated with a given type:
@ -598,10 +575,9 @@ Basically, the whole system relies on a handful of classes. In particular:
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/>
This value is extracted from some information generally made available by the
compiler in use. Therefore, it may differ depending on the compiler and may be
empty in the event that this information isn't available.<br/>
For example, given the following class:
```cpp
@ -612,21 +588,20 @@ Basically, the whole system relies on a handful of classes. In particular:
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.
modify it as needed, for example by removing the word `struct` to normalize
the result. `EnTT` doesn't do this for obvious reasons, since it would be
creating a new string at runtime otherwise.
This function **can** use non-standard features of the language for its own
purposes. Users can prevent the library from using non-standard features by
means of the `ENTT_STANDARD_CPP` definition. In this case, the name will be
empty by default.
purposes. Users can prevent the library from using these features by means of
the `ENTT_STANDARD_CPP` definition. In this case, the name is just empty.
As for `type_index`, also `type_name` is a _sfinae-friendly_ class that can be
specialized in order to customize its behavior globally or on a per-type or
per-traits basis.
As it happens with `type_index`, also `type_name` is a _sfinae-friendly_ class
that can be specialized in order to customize its behavior globally or on a
per-type or per-traits basis.
These are then combined into utilities that aim to offer an API that is somewhat
similar to that offered by the language.
similar to that made available by the standard library.
### Type info
@ -708,8 +683,8 @@ In fact, although this is quite rare, it's not entirely excluded.
Another case where two types are assigned the same identifier is when classes
from different contexts (for example two or more libraries loaded at runtime)
have the same fully qualified name. In this case, also `type_name` will return
the same value for the two types.<br/>
have the same fully qualified name. In this case, `type_name` returns the same
value for the two types.<br/>
Fortunately, there are several easy ways to deal with this:
* The most trivial one is to define the `ENTT_STANDARD_CPP` macro. Runtime
@ -739,9 +714,9 @@ offered by this module.
### Size of
The standard operator `sizeof` complains when users provide it for example with
function or incomplete types. On the other hand, it's guaranteed that its result
is always nonzero, even if applied to an empty class type.<br/>
The standard operator `sizeof` complains if users provide it with functions or
incomplete types. On the other hand, it's guaranteed that its result is always
non-zero, even if applied to an empty class type.<br/>
This small class combines the two and offers an alternative to `sizeof` that
works under all circumstances, returning zero if the type isn't supported:
@ -777,8 +752,8 @@ A utility to easily transfer the constness of a type to another 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.
The trait is subject to the rules of the language. For example, _transferring_
constness between references won't give the desired effect.
### Member class type
@ -798,7 +773,7 @@ A utility to quickly find the n-th argument of a function, member function or
data member (for blind operations on opaque types):
```cpp
using type = entt::nt_argument_t<1u, &clazz::member>;
using type = entt::nth_argument_t<1u, &clazz::member>;
```
Disambiguation of overloaded functions is the responsibility of the user, should
@ -825,8 +800,8 @@ 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/>
Type `id_type` is very important and widely used in `EnTT`. Therefore, there is
a more user-friendly shortcut for the creation of constants based on it.<br/>
This shortcut is the alias template `entt::tag`.
If used in combination with hashed strings, it helps to use human-readable names
@ -918,8 +893,8 @@ Perhaps a bit ugly to see in a codebase but it gets the job done at least.
## Runtime generator
To generate sequential numeric identifiers at runtime, `EnTT` offers the
`family` class template:
The `family` class template helps to generate sequential numeric identifiers for
types at runtime:
```cpp
// defines a custom generator
@ -936,8 +911,8 @@ 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 stable across different
runs. Indeed it mostly depends on the flow of execution.
Identifiers aren't guaranteed to be stable across different runs. Indeed it
mostly depends on the flow of execution.
# Utilities

File diff suppressed because it is too large Load Diff

View File

@ -193,7 +193,7 @@ to mitigate the problem makes it manageable.
## Which functions trigger which signals
The `registry` class offers three signals that are emitted following specific
Storage classes offer three _signals_ that are emitted following specific
operations. Maybe not everyone knows what these operations are, though.<br/>
If this isn't clear, below you can find a _vademecum_ for this purpose:

View File

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

View File

@ -19,14 +19,12 @@
general and on GNU/Linux when default visibility was set to hidden. The
limitation was mainly due to a custom utility used to assign unique, sequential
identifiers with different types.<br/>
Fortunately, nowadays using `EnTT` across boundaries is much easier.
Fortunately, nowadays `EnTT` works smoothly across boundaries.
## Smooth until proven otherwise
Many classes in `EnTT` make extensive use of type erasure for their purposes.
This isn't a problem on itself (in fact, it's the basis of an API so convenient
to use). However, a way is needed to recognize the objects whose type has been
erased on the other side of a boundary.<br/>
This raises the need to identify objects whose type has been erased.<br/>
The `type_hash` class template is how identifiers are generated and thus made
available to the rest of the library. In general, this class doesn't arouse much
interest. The only exception is when a conflict between identifiers occurs
@ -36,13 +34,13 @@ The section dedicated to `type_info` contains all the details to get around the
issue in a concise and elegant way. Please refer to the specific documentation.
When working with linked libraries, compile definitions `ENTT_API_EXPORT` and
`ENTT_API_IMPORT` can be used where there is a need to import or export symbols,
so as to make everything work nicely across boundaries.<br/>
`ENTT_API_IMPORT` are to import or export symbols, so as to make everything work
nicely across boundaries.<br/>
On the other hand, everything should run smoothly when working with plugins or
shared libraries that don't export any symbols.
For anyone who needs more details, the test suite contains multiple examples
covering the most common cases (see the `lib` directory for all details).<br/>
For those who need more details, the test suite contains many examples covering
the most common cases (see the `lib` directory for all details).<br/>
It goes without saying that it's impossible to cover **all** possible cases.
However, what is offered should hopefully serve as a basis for all of them.
@ -70,8 +68,8 @@ entt::locator<entt::meta_ctx>::reset(handle);
From now on, both spaces refer to the same context and on it are attached all
new meta types, no matter where they are created.<br/>
Note that resetting the main context doesn't also propagate changes across
boundaries. In other words, resetting a context results in the decoupling of the
Note that _replacing_ the main context doesn't also propagate changes across
boundaries. In other words, replacing a context results in the decoupling of the
two sides and therefore a divergence in the contents.
## Memory Management

View File

@ -1,5 +1,22 @@
# EnTT in Action
<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents
* [Introduction](#introduction)
* [EnTT in Action](#entt-in-action)
* [Games](#games)
* [Engines and the like](#engines-and-the-like)
* [Articles, videos and blog posts](#articles-videos-and-blog-posts)
* [Any Other Business](#any-other-business)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
`EnTT` is widely used in private and commercial applications. I cannot even
mention most of them because of some signatures I put on some documents time
ago. Fortunately, there are also people who took the time to implement open
@ -7,13 +24,18 @@ source projects based on `EnTT` and didn't hold back when it came to documenting
them.
Below an incomplete list of games, applications and articles that can be used as
a reference. Where I put the word _apparently_ means that the use of `EnTT` is
documented but the authors didn't make explicit announcements or contacted me
directly.
a reference.<br/>
Where I put the word _apparently_ means that the use of `EnTT` is documented but
the authors didn't make explicit announcements or contacted me directly.
I hope this list can grow much more in the future:
If you know of other resources out there that are about `EnTT`, feel free to
open an issue or a PR and I'll be glad to add them to this page.<br/>
I hope the following lists can grow much more in the future.
# EnTT in Action
## Games
* Games:
* [Minecraft](https://minecraft.net/en-us/attribution/) by
[Mojang](https://mojang.com/): of course, **that** Minecraft, see the
open source attributions page for more details.
@ -103,7 +125,8 @@ I hope this list can grow much more in the future:
* [Confetti Party](https://github.com/hexerei/entt-confetti): C++ sample
application as a starting point using `EnTT` and `SDL2`.
* Engines and the like:
## Engines and the like:
* [Aether Engine](https://hadean.com/spatial-simulation/)
[v1.1+](https://docs.hadean.com/v1.1/Licenses/) by
[Hadean](https://hadean.com/): a library designed for spatially partitioning
@ -168,8 +191,19 @@ I hope this list can grow much more in the future:
engine based on `SDL2` and `EnTT`.
* [Ducktape](https://github.com/DucktapeEngine/Ducktape): an open source C++
2D & 3D game engine that focuses on being fast and powerful.
* [The Worst Engine](https://github.com/Parasik72/TWE): a game engine based on
OpenGL.
* [Ecsact](https://ecsact.dev/): a language aimed at describing ECS, with a
[runtime implementation](https://github.com/ecsact-dev/ecsact_rt_entt) based
on `EnTT`.
* [AGE (Arc Game Engine)](https://github.com/MohitSethi99/ArcGameEngine): an
open-source engine for building 2D & 3D real-time rendering and interactive
contents.
* [Kengine](https://github.com/phisko/kengine): the _Koala engine_ is a game
engine entirely implemented as an entity-component-ystem.
## Articles, videos and blog posts:
* 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.
@ -193,6 +227,12 @@ I hope this list can grow much more in the future:
- ... And so on.
[Check out](https://www.youtube.com/channel/UCQ-W1KE9EYfdxhL6S4twUNw) the
_Game Engine Series_ by The Cherno for more videos.
* [Warmonger Dynasty devlog series](https://david-delassus.medium.com/list/warmonger-dynasty-devlogs-f64b71f556de)
by [linkdd](https://github.com/linkdd): an interesting walkthrough of
developing a game (also) with EnTT.
* [Use EnTT When You Need An ECS](https://www.codingwiththomas.com/blog/use-entt-when-you-need-an-ecs)
by [Thomas](https://www.codingwiththomas.com/): I couldn't have said it
better.
* [Space Battle: Huge edition](http://victor.madtriangles.com/code%20experiment/2018/06/11/post-ecs-battle-huge.html):
huge space battle built entirely from scratch.
* [Space Battle](https://github.com/vblanco20-1/ECS_SpaceBattle): huge space
@ -219,7 +259,8 @@ I hope this list can grow much more in the future:
MMO(RPG)s and its [follow-up](https://youtu.be/yGlZeopx2hU) episode about
player bots and full external ECS: a series definitely worth looking at.
* Any Other Business:
## Any Other Business:
* [ArcGIS Runtime SDKs](https://developers.arcgis.com/arcgis-runtime/) by
[Esri](https://www.esri.com/): they use `EnTT` for the internal ECS and the
cross platform C++ rendering engine. The SDKs are utilized by a lot of
@ -261,6 +302,3 @@ I hope this list can grow much more in the future:
* GitHub contains also
[many other examples](https://github.com/search?o=desc&q=%22skypjack%2Fentt%22&s=indexed&type=Code)
of use of `EnTT` from which to take inspiration if interested.
If you know of other resources out there that are about `EnTT`, feel free to
open an issue or a PR and I'll be glad to add them to this page.

View File

@ -67,17 +67,15 @@ recommended.
# Reflection in a nutshell
Reflection always starts from real types (users cannot reflect imaginary types
and it would not make much sense, we wouldn't be talking about reflection
anymore).<br/>
To create a meta node, the library provides the `meta` function that accepts a
type to reflect as a template parameter:
Reflection always starts from actual C++ types. Users cannot reflect _imaginary_
types.<br/>
The `meta` function is where it all starts:
```cpp
auto factory = entt::meta<my_type>();
```
The returned value is a factory object to use to continue building the meta
The returned value is a _factory object_ to use to continue building the meta
type.
By default, a meta type is associated with the identifier returned by the
@ -88,45 +86,42 @@ However, it's also possible to assign custom identifiers to meta types:
auto factory = entt::meta<my_type>().type("reflected_type"_hs);
```
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`.
Identifiers are used to _retrieve_ meta types at runtime by _name_ other than by
type.<br/>
However, users can be interested in adding features to a reflected type so that
the reflection system can use it correctly under the hood, while they don't want
to also make the type _searchable_. In this case, it's sufficient not to invoke
`type`.
A factory is such that all its member functions return the factory itself or a
decorated version of it. This object can be used to add the following:
A factory is such that all its member functions return the factory itself. It's
generally used to create the following:
* _Constructors_. Actual constructors can be assigned to a reflected type by
specifying their list of arguments. Free functions (namely, factories) can be
used as well, as long as the return type is the expected one. From a client's
point of view, nothing changes if a constructor is a free function or an
actual constructor.<br/>
Use the `ctor` member function for this purpose:
* _Constructors_. A constructors is assigned to a reflected type by specifying
its _list of arguments_. Free functions are also accepted if the return type
is the expected one. From a client perspective, nothing changes between a free
function or an actual constructor:
```cpp
entt::meta<my_type>().ctor<int, char>().ctor<&factory>();
```
* _Destructors_. Free functions and member functions can be used as destructors
of reflected types. The purpose is to give users the ability to free up
resources that require special treatment before an object is actually
destroyed.<br/>
Use the `dtor` member function for this purpose:
Meta default constructors are implicitly generated, if possible.
* _Destructors_. Both free functions and member functions are valid destructors:
```cpp
entt::meta<my_type>().dtor<&destroy>();
```
The purpose is to offer the possibility to free up resources that require
_special treatment_ before an object is actually destroyed.<br/>
A function should neither delete nor explicitly invoke the destructor of a
given instance.
* _Data members_. Both real data members of the underlying type and static and
global variables, as well as constants of any kind, can be attached to a meta
type. From the point of view of the client, all the variables associated with
the reflected type will appear as if they were part of the type itself.<br/>
Use the `data` member function for this purpose:
* _Data members_. Meta data members are actual data members of the underlying
type but also static and global variables or constants of any kind. From the
point of view of the client, all the variables associated with the reflected
type appear as if they were part of the type itself:
```cpp
entt::meta<my_type>()
@ -135,13 +130,11 @@ decorated version of it. This object can be used to add the following:
.data<&global_variable>("global"_hs);
```
The function requires as an argument the identifier to give to the meta data
once created. Users can then access meta data at runtime by searching for them
by _name_.<br/>
Data members can also be defined by means of a setter and getter pair. Setters
and getters can be either free functions, class members or a mix of them, as
long as they respect the required signatures. This approach is also convenient
to create a read-only variable from a non-const data member:
The `data` function requires the identifier to use for the meta data member.
Users can then access it by _name_ at runtime.<br/>
Data members are also defined by means of a setter and getter pair. These are
either free functions, class members or a mix of them. This approach is also
convenient to create read-only properties from a non-const data member:
```cpp
entt::meta<my_type>().data<nullptr, &my_type::data_member>("member"_hs);
@ -153,13 +146,10 @@ decorated version of it. This object can be used to add the following:
entt::meta<my_type>().data<entt::value_list<&from_int, &from_string>, &my_type::data_member>("member"_hs);
```
Refer to the inline documentation for all the details.
* _Member functions_. Both real member functions of the underlying type and free
functions can be attached to a meta type. From the point of view of the
client, all the functions associated with the reflected type will appear as if
they were part of the type itself.<br/>
Use the `func` member function for this purpose:
* _Member functions_. Meta member functions are actual member functions of the
underlying type but also plain free functions. From the point of view of the
client, all the functions associated with the reflected type appear as if they
were part of the type itself:
```cpp
entt::meta<my_type>()
@ -168,40 +158,31 @@ decorated version of it. This object can be used to add the following:
.func<&free_function>("free"_hs);
```
The function requires as an argument the identifier to give to the meta
function once created. Users can then access meta functions at runtime by
searching for them by _name_.<br/>
The `func` function requires the identifier to use for the meta data function.
Users can then access it by _name_ at runtime.<br/>
Overloading of meta functions is supported. Overloaded functions are resolved
at runtime by the reflection system according to the types of the arguments.
* _Base classes_. A base class is such that the underlying type is actually
derived from it. In this case, the reflection system tracks the relationship
and allows for implicit casts at runtime when required.<br/>
Use the `base` member function for this purpose:
derived from it:
```cpp
entt::meta<derived_type>().base<base_type>();
```
From now on, wherever a `base_type` is required, an instance of `derived_type`
will also be accepted.
The reflection system tracks the relationship and allows for implicit casts at
runtime when required. In other terms, wherever a `base_type` is required, an
instance of `derived_type` is also accepted.
* _Conversion functions_. Actual types can be converted, this is a fact. Just
think of the relationship between a `double` and an `int` to see it. Similar
to bases, conversion functions allow users to define conversions that will be
implicitly performed by the reflection system when required.<br/>
Use the `conv` member function for this purpose:
* _Conversion functions_. Conversion functions allow users to define conversions
that are implicitly performed by the reflection system when required:
```cpp
entt::meta<double>().conv<int>();
```
That's all, everything users need to create meta types and enjoy the reflection
system. At first glance it may not seem that much, but users usually learn to
appreciate it over time.<br/>
Also, do not forget what these few lines hide under the hood: a built-in,
non-intrusive and macro-free system for reflection in C++. Features that are
definitely worth the price, at least for me.
This is everything users need to create meta types. Refer to the inline
documentation for further details.
## Any to the rescue
@ -214,13 +195,13 @@ The API is very similar to that of the `any` type. The class `meta_any` _wraps_
many of the feature to infer a meta node, before forwarding some or all of the
arguments to the underlying storage.<br/>
Among the few relevant differences, `meta_any` adds support for containers and
pointer-like types (see the following sections for more details), while `any`
does not.<br/>
Similar to `any`, this class can also be used to create _aliases_ for unmanaged
pointer-like types, while `any` doesn't.<br/>
Similar to `any`, this class is also used to create _aliases_ for unmanaged
objects either with `forward_as_meta` or using the `std::in_place_type<T &>`
disambiguation tag, as well as from an existing object by means of the `as_ref`
member function. However, unlike `any`, `meta_any` treats an empty instance and
one initialized with `void` differently:
member function.<br/>
Unlike `any` instead, `meta_any` treats an empty instance and one initialized
with `void` differently:
```cpp
entt::meta_any empty{};
@ -229,21 +210,19 @@ entt::meta_any other{std::in_place_type<void>};
While `any` considers both as empty, `meta_any` treats objects initialized with
`void` as if they were _valid_ ones. This allows to differentiate between failed
function calls and function calls that are successful but return nothing.<br/>
function calls and function calls that are successful but return nothing.
Finally, the member functions `try_cast`, `cast` and `allow_cast` are used to
cast the underlying object to a given type (either a reference or a value type)
or to _convert_ a `meta_any` in such a way that a cast becomes viable for the
resulting object. There is in fact no `any_cast` equivalent for `meta_any`.
resulting object.<br/>
There is in fact no `any_cast` equivalent for `meta_any`.
## Enjoy the runtime
Once the web of reflected types has been constructed, it's a matter of using it
at runtime where required.<br/>
All this has the great merit that the reflection system stands in fact as a
non-intrusive tool for the runtime, unlike the vast majority of the things
offered by this library and closely linked to the compile-time.
To search for a reflected type there are a few options:
Once the web of reflected types is constructed, it's a matter of using it at
runtime where required.<br/>
There are a few options to search for a reflected type:
```cpp
// direct access to a reflected type
@ -257,8 +236,8 @@ auto by_type_id = entt::resolve(entt::type_id<my_type>());
```
There exists also an overload of the `resolve` function to use to iterate all
the reflected types at once. It returns an iterable object that can be used in a
range-for loop:
reflected types at once. It returns an iterable object to be used in a range-for
loop:
```cpp
for(auto &&[id, type]: entt::resolve()) {
@ -270,9 +249,7 @@ In all cases, the returned value is an instance of `meta_type` (possibly with
its id). This kind of objects offer an API to know their _runtime identifiers_,
to iterate all the meta objects associated with them and even to build instances
of the underlying type.<br/>
Refer to the inline documentation for all the details.
Meta data members and functions are accessed by name among the other things:
Meta data members and functions are accessed by name:
* Meta data members:
@ -297,11 +274,11 @@ Meta data members and functions are accessed by name among the other things:
A meta function object offers an API to query the underlying type (for
example, to know if it's a const or a static function), to know the number of
arguments, the meta return type and the meta types of the parameters. In
addition, a meta function object can be used to invoke the underlying function
and then get the return value in the form of a `meta_any` object.
addition, a meta function object is used to invoke the underlying function and
then get the return value in the form of a `meta_any` object.
All the meta objects thus obtained as well as the meta types can be explicitly
converted to a boolean value to check if they are valid:
All the meta objects thus obtained as well as the meta types explicitly convert
to a boolean value to check for validity:
```cpp
if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
@ -319,26 +296,23 @@ for(auto &&[id, type]: entt::resolve<my_type>().base()) {
}
```
A meta type can also be used to `construct` actual instances of the underlying
Meta type are also used to `construct` actual instances of the underlying
type.<br/>
In particular, the `construct` member function accepts a variable number of
arguments and searches for a match. It then returns a `meta_any` object that may
or may not be initialized, depending on whether a suitable constructor has been
found or not.
or may not be initialized, depending on whether a suitable constructor was found
or not.
There is no object that wraps the destructor of a meta type nor a `destroy`
member function in its API. Destructors are invoked implicitly by `meta_any`
behind the scenes and users have not to deal with them explicitly. Furthermore,
they have no name, cannot be searched and wouldn't have member functions to
expose anyway.<br/>
Similarly, conversion functions aren't directly accessible. They are used
they've no name, cannot be searched and wouldn't have member functions to expose
anyway.<br/>
Similarly, conversion functions aren't directly accessible. They're used
internally by `meta_any` and the meta objects when needed.
Meta types and meta objects in general contain much more than what is said: a
plethora of functions in addition to those listed whose purposes and uses go
unfortunately beyond the scope of this document.<br/>
I invite anyone interested in the subject to look at the code, experiment and
read the inline documentation to get the best out of this powerful tool.
Meta types and meta objects in general contain much more than what was said.
Refer to the inline documentation for further details.
## Container support
@ -349,7 +323,7 @@ meta system in many cases.
To make a container be recognized as such by the meta system, users are required
to provide specializations for either the `meta_sequence_container_traits` class
or the `meta_associative_container_traits` class, according to the actual type
or the `meta_associative_container_traits` class, according to the actual _type_
of the container.<br/>
`EnTT` already exports the specializations for some common classes. In
particular:
@ -386,11 +360,10 @@ if(any.type().is_sequence_container()) {
The method to use to get a proxy object for associative containers is
`as_associative_container` instead.<br/>
It goes without saying that it's not necessary to perform a double check.
Instead, it's sufficient to query the meta type or verify that the proxy object
is valid. In fact, proxies are contextually convertible to bool to know if they
are valid. For example, invalid proxies are returned when the wrapped object
isn't a container.<br/>
It's not necessary to perform a double check actually. Instead, it's enough to
query the meta type or verify that the proxy object is valid. In fact, proxies
are contextually convertible to bool to check for validity. For example, invalid
proxies are returned when the wrapped object isn't a container.<br/>
In all cases, users aren't expected to _reflect_ containers explicitly. It's
sufficient to assign a container for which a specialization of the traits
classes exists to a `meta_any` object to be able to get its proxy object.
@ -402,32 +375,18 @@ to case. In particular:
* The `value_type` member function returns the meta type of the elements.
* The `size` member function returns the number of elements in the container as
an unsigned integer value:
```cpp
const auto size = view.size();
```
an unsigned integer value.
* The `resize` member function allows to resize the wrapped container and
returns true in case of success:
```cpp
const bool ok = view.resize(3u);
```
returns true in case of success.<br/>
For example, it's not possible to resize fixed size containers.
* The `clear` member function allows to clear the wrapped container and returns
true in case of success:
```cpp
const bool ok = view.clear();
```
true in case of success.<br/>
For example, it's not possible to clear fixed size containers.
* The `begin` and `end` member functions return opaque iterators that can be
used to iterate the container directly:
* The `begin` and `end` member functions return opaque iterators that is used to
iterate the container directly:
```cpp
for(entt::meta_any element: view) {
@ -441,7 +400,7 @@ to case. In particular:
All meta iterators are input iterators and don't offer an indirection operator
on purpose.
* The `insert` member function can be used to add elements to the container. It
* The `insert` member function is used to add elements to the container. It
accepts a meta iterator and the element to insert:
```cpp
@ -451,15 +410,15 @@ to case. In particular:
```
This function returns a meta iterator pointing to the inserted element and a
boolean value to indicate whether the operation was successful or not. Note
that a call to `insert` may silently fail in case of fixed size containers or
whether the arguments aren't at least convertible to the required types.<br/>
Since the meta iterators are contextually convertible to bool, users can rely
on them to know if the operation has failed on the actual container or
upstream, for example for an argument conversion problem.
boolean value to indicate whether the operation was successful or not. A call
to `insert` may silently fail in case of fixed size containers or whether the
arguments aren't at least convertible to the required types.<br/>
Since meta iterators are contextually convertible to bool, users can rely on
them to know if the operation failed on the actual container or upstream, for
example due to an argument conversion problem.
* The `erase` member function can be used to remove elements from the container.
It accepts a meta iterator to the element to remove:
* The `erase` member function is used to remove elements from the container. It
accepts a meta iterator to the element to remove:
```cpp
auto first = view.begin();
@ -468,11 +427,11 @@ to case. In particular:
```
This function returns a meta iterator following the last removed element and a
boolean value to indicate whether the operation was successful or not. Note
that a call to `erase` may silently fail in case of fixed size containers.
boolean value to indicate whether the operation was successful or not. A call
to `erase` may silently fail in case of fixed size containers.
* The `operator[]` can be used to access elements in a container. It accepts a
single argument, that is the position of the element to return:
* The `operator[]` is used to access container elements. It accepts a single
argument, the position of the element to return:
```cpp
for(std::size_t pos{}, last = view.size(); pos < last; ++pos) {
@ -482,8 +441,8 @@ to case. In particular:
```
The function returns instances of `meta_any` that directly refer to the actual
elements. Modifying the returned object will then directly modify the element
inside the container.<br/>
elements. Modifying the returned object directly modifies the element inside
the container.<br/>
Depending on the underlying sequence container, this operation may not be as
efficient. For example, in the case of an `std::list`, a positional access
translates to a linear visit of the list itself (probably not what the user
@ -508,21 +467,13 @@ differences in behavior in the case of key-only containers. In particular:
`std::map<int, char>`.
* The `size` member function returns the number of elements in the container as
an unsigned integer value:
```cpp
const auto size = view.size();
```
an unsigned integer value.
* The `clear` member function allows to clear the wrapped container and returns
true in case of success:
true in case of success.
```cpp
const bool ok = view.clear();
```
* The `begin` and `end` member functions return opaque iterators that can be
used to iterate the container directly:
* The `begin` and `end` member functions return opaque iterators that are used
to iterate the container directly:
```cpp
for(std::pair<entt::meta_any, entt::meta_any> element: view) {
@ -539,11 +490,11 @@ differences in behavior in the case of key-only containers. In particular:
While the accessed key is usually constant in the associative containers and
is therefore returned by copy, the value (if any) is wrapped by an instance of
`meta_any` that directly refers to the actual element. Modifying it will then
directly modify the element inside the container.
`meta_any` that directly refers to the actual element. Modifying it directly
modifies the element inside the container.
* The `insert` member function can be used to add elements to the container. It
accepts two arguments, respectively the key and the value to be inserted:
* The `insert` member function is used to add elements to a container. It gets
two arguments, respectively the key and the value to insert:
```cpp
auto last = view.end();
@ -552,39 +503,39 @@ differences in behavior in the case of key-only containers. In particular:
```
This function returns a boolean value to indicate whether the operation was
successful or not. Note that a call to `insert` may fail when the arguments
aren't at least convertible to the required types.
successful or not. A call to `insert` may fail when the arguments aren't at
least convertible to the required types.
* The `erase` member function can be used to remove elements from the container.
It accepts a single argument, that is the key to be removed:
* The `erase` member function is used to remove elements from a container. It
gets a single argument, the key to remove:
```cpp
view.erase(42);
```
This function returns a boolean value to indicate whether the operation was
successful or not. Note that a call to `erase` may fail when the argument
isn't at least convertible to the required type.
successful or not. A call to `erase` may fail when the argument isn't at least
convertible to the required type.
* The `operator[]` can be used to access elements in a container. It accepts a
single argument, that is the key of the element to return:
* The `operator[]` is used to access elements in a container. It gets a single
argument, the key of the element to return:
```cpp
entt::meta_any value = view[42];
```
The function returns instances of `meta_any` that directly refer to the actual
elements. Modifying the returned object will then directly modify the element
inside the container.
elements. Modifying the returned object directly modifies the element inside
the container.
Container support is minimal but likely sufficient to satisfy all needs.
## Pointer-like types
As with containers, it's also possible to communicate to the meta system which
types to consider _pointers_. This will allow to dereference instances of
`meta_any`, thus obtaining light _references_ to the pointed objects that are
also correctly associated with their meta types.<br/>
As with containers, it's also possible to _tell_ to the meta system which types
are _pointers_. This makes it possible to dereference instances of `meta_any`,
thus obtaining light _references_ to pointed objects that are also correctly
associated with their meta types.<br/>
To make the meta system recognize a type as _pointer-like_, users can specialize
the `is_meta_pointer_like` class. `EnTT` already exports the specializations for
some common classes. In particular:
@ -614,13 +565,12 @@ if(any.type().is_pointer_like()) {
}
```
Of course, it's not necessary to perform a double check. Instead, it's enough to
query the meta type or verify that the returned object is valid. For example,
invalid instances are returned when the wrapped object isn't a pointer-like
type.<br/>
Note that dereferencing a pointer-like object returns an instance of `meta_any`
which refers to the pointed object and allows users to modify it directly
(unless the returned element is const, of course).
It's not necessary to perform a double check. Instead, it's enough to query the
meta type or verify that the returned object is valid. For example, invalid
instances are returned when the wrapped object isn't a pointer-like type.<br/>
Dereferencing a pointer-like object returns an instance of `meta_any` which
_refers_ to the pointed object. Modifying it means modifying the pointed object
directly (unless the returned element is const).
In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However,
`EnTT` also supports classes that don't offer an `operator*`. In particular:
@ -648,12 +598,12 @@ In general, _dereferencing_ a pointer-like type boils down to a `*ptr`. However,
};
```
In all other cases, that is, when dereferencing a pointer works as expected and
regardless of the pointed type, no user intervention is required.
In all other cases and when dereferencing a pointer works as expected regardless
of the pointed type, no user intervention is required.
## Template information
Meta types also provide a minimal set of information about the nature of the
Meta types also provide a minimal set of information about the _nature_ of the
original type in case it's a class template.<br/>
By default, this works out of the box and requires no user action. However, it's
important to include the header file `template.hpp` to make this information
@ -688,9 +638,9 @@ template<typename Ret, typename... Args>
struct function_type<Ret(Args...)> {};
```
In this case, rather than the function type, the user might want the return type
and unpacked arguments as if they were different template parameters for the
original class template.<br/>
In this case, rather than the function type, it might be useful to provide the
return type and unpacked arguments as if they were different template parameters
for the original class template.<br/>
To achieve this, users must enter the library internals and provide their own
specialization for the class template `entt::meta_template_traits`, such as:
@ -704,8 +654,8 @@ struct entt::meta_template_traits<function_type<Ret(Args...)>> {
The reflection system doesn't verify the accuracy of the information nor infer a
correspondence between real types and meta types.<br/>
Therefore, the specialization will be used as is and the information it contains
will be associated with the appropriate type when required.
Therefore, the specialization is used as is and the information it contains is
associated with the appropriate type when required.
## Automatic conversions
@ -752,29 +702,29 @@ any.allow_cast(type);
int value = any.cast<int>();
```
This should make working with arithmetic types and scoped or unscoped enums as
easy as it is in C++.<br/>
It's also worth noting that it's still possible to set up conversion functions
manually and these will always be preferred over the automatic ones.
This makes working with arithmetic types and scoped or unscoped enums as easy as
it is in C++.<br/>
It's still possible to set up conversion functions manually and these are always
preferred over the automatic ones.
## Implicitly generated default constructor
In many cases, it's useful to be able to create objects of default constructible
types through the reflection system, while not having to explicitly register the
meta type or the default constructor.<br/>
Creating objects of default constructible types through the reflection system
while not having to explicitly register the meta type or its default constructor
is also possible.<br/>
For example, in the case of primitive types like `int` or `char`, but not just
them.
For this reason and only for default constructible types, default constructors
are automatically defined and associated with their meta types, whether they are
explicitly or implicitly generated.<br/>
For default constructible types only, default constructors are automatically
defined and associated with their meta types, whether they are explicitly or
implicitly generated.<br/>
Therefore, this is all is needed to construct an integer from its meta type:
```cpp
entt::resolve<int>().construct();
```
Where the meta type can be for example the one returned from a meta container,
Where the meta type is for example the one returned from a meta container,
useful for building keys without knowing or having to register the actual types.
In all cases, when users register default constructors, they are preferred both
@ -783,8 +733,8 @@ during searches and when the `construct` member function is invoked.
## From void to any
Sometimes all a user has is an opaque pointer to an object of a known meta type.
It would be handy in this case to be able to construct a `meta_any` object from
them.<br/>
It would be handy in this case to be able to construct a `meta_any` element from
it.<br/>
For this purpose, the `meta_type` class offers a `from_void` member function
designed to convert an opaque pointer into a `meta_any`:
@ -792,9 +742,8 @@ designed to convert an opaque pointer into a `meta_any`:
entt::meta_any any = entt::resolve(id).from_void(element);
```
It goes without saying that it's not possible to do a check on the actual type.
Therefore, this call can be considered as a _static cast_ with all the problems
and undefined behaviors of the case following errors.<br/>
Unfortunately, it's not possible to do a check on the actual type. Therefore,
this call can be considered as a _static cast_ with all its _problems_.<br/>
On the other hand, the ability to construct a `meta_any` from an opaque pointer
opens the door to some pretty interesting uses that are worth exploring.
@ -826,17 +775,17 @@ There are a few alternatives available at the moment:
entt::meta<my_type>().func<&my_type::member_function, entt::as_void_t>("member"_hs);
```
If the use with functions is obvious, it must be said that it's also possible
to use this policy with constructors and data members. In the first case, the
constructor will be invoked but the returned wrapper will actually be empty.
In the second case, instead, the property will not be accessible for reading.
If the use with functions is obvious, perhaps less so is use with constructors
and data members. In the first case, the returned wrapper is always empty even
though the constructor is still invoked. In the second case, the property
isn't accessible for reading instead.
* The _as-ref_ and _as-cref_ policies, associated with the types
`entt::as_ref_t` and `entt::as_cref_t`.<br/>
They allow to build wrappers that act as references to unmanaged objects.
Accessing the object contained in the wrapper for which the _reference_ was
requested will make it possible to directly access the instance used to
initialize the wrapper itself:
requested makes it possible to directly access the instance used to initialize
the wrapper itself:
```cpp
entt::meta<my_type>().data<&my_type::data_member, entt::as_ref_t>("member"_hs);
@ -854,21 +803,16 @@ obvious corner cases that can in turn be solved with the use of policies.
## Named constants and enums
A special mention should be made for constant values and enums. It wouldn't be
necessary, but it will help distracted readers.
As mentioned, the `data` member function can be used to reflect constants of any
type among the other things.<br/>
This allows users to create meta types for enums that will work exactly like any
other meta type built from a class. Similarly, arithmetic types can be enriched
As mentioned, the `data` member function is used to reflect constants of any
type.<br/>
This allows users to create meta types for enums that work exactly like any
other meta type built from a class. Similarly, arithmetic types are _enriched_
with constants of special meaning where required.<br/>
Personally, I find it very useful not to export what is the difference between
enums and classes in C++ directly in the space of the reflected types.
All values thus exported appear to users as if they were constant data members
of the reflected types. This avoids the need to _export_ what is the difference
between enums and classes in C++ directly in the space of the reflected types.
All the values thus exported will appear to users as if they were constant data
members of the reflected types.
Exporting constant values or elements from an enum is as simple as ever:
Exposing constant values or elements from an enum is quite simple:
```cpp
entt::meta<my_enum>()
@ -878,28 +822,22 @@ entt::meta<my_enum>()
entt::meta<int>().data<2048>("max_int"_hs);
```
It goes without saying that accessing them is trivial as well. It's a matter of
doing the following, as with any other data member of a meta type:
Accessing them is trivial as well. It's a matter of doing the following, as with
any other data member of a meta type:
```cpp
auto value = entt::resolve<my_enum>().data("a_value"_hs).get({}).cast<my_enum>();
auto max = entt::resolve<int>().data("max_int"_hs).get({}).cast<int>();
```
As a side note, remember that all this happens behind the scenes without any
allocation because of the small object optimization performed by the `meta_any`
class.
All this happens behind the scenes without any allocation because of the small
object optimization performed by the `meta_any` class.
## Properties and meta objects
Sometimes (for example, when it comes to creating an editor) it might be useful
to attach properties to the meta objects created. Fortunately, this is possible
for most of them.<br/>
For the meta objects that support properties, the member functions of the
factory used for registering them will return an extended version of the factory
itself. The latter can be used to attach properties to the last created meta
object.<br/>
Apparently, it's more difficult to say than to do:
for most of them:
```cpp
entt::meta<my_type>().type("reflected_type"_hs).prop("tooltip"_hs, "message");
@ -914,10 +852,10 @@ Key only properties are also supported out of the box:
entt::meta<my_type>().type("reflected_type"_hs).prop(my_enum::key_only);
```
To attach multiple properties to a meta object, it's possible to invoke `prop`
more than once.<br/>
It's also possible to invoke `prop` at different times, as long as the factory
is reset to the meta object of interest.
To attach multiple properties to a meta object, just invoke `prop` more than
once.<br/>
It's also possible to call `prop` at different times, as long as the factory is
reset to the meta object of interest.
The meta objects for which properties are supported are currently meta types,
meta data and meta functions.<br/>
@ -940,7 +878,7 @@ form of a `meta_any` object.
## Unregister types
A type registered with the reflection system can also be unregistered. This
A type registered with the reflection system can also be _unregistered_. This
means unregistering all its data members, member functions, conversion functions
and so on. However, base classes aren't unregistered as well, since they don't
necessarily depend on it.<br/>
@ -969,7 +907,7 @@ A type can be re-registered later with a completely different name and form.
## Meta context
All meta types and their parts are created at runtime and stored in a default
_context_. This can be reached via a service locator as:
_context_. This is obtained via a service locator as:
```cpp
auto &&context = entt::locator<entt::meta_context>::value_or();
@ -984,8 +922,8 @@ auto &&context = entt::locator<entt::meta_context>::value_or();
std::swap(context, other);
```
This can be useful for testing purposes or to define multiple contexts with
different meta objects to be used as appropriate.
This is useful for testing purposes or to define multiple context objects with
different meta type to use as appropriate.
If _replacing_ the default context isn't enough, `EnTT` also offers the ability
to use multiple and externally managed contexts with the runtime reflection
@ -998,16 +936,16 @@ entt::meta_ctx context{};
auto factory = entt::meta<my_type>(context).type("reflected_type"_hs);
```
By doing so, the new meta type won't be available in the default context but
will be usable by passing around the new context when needed, such as when
creating a new `meta_any` object:
By doing so, the new meta type isn't available in the default context but is
usable by passing around the new context when needed, such as when creating a
new `meta_any` object:
```cpp
entt::meta_any any{context, std::in_place_type<my_type>};
```
Similarly, to search for meta types in a context other than the default one, it
will be necessary to pass it to the `resolve` function:
Similarly, to search for meta types in a context other than the default one,
it's necessary to pass it to the `resolve` function:
```cpp
entt::meta_type type = entt::resolve(context, "reflected_type"_hs)

View File

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

View File

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

View File

@ -1,18 +1,35 @@
# Similar projects
<!--
@cond TURN_OFF_DOXYGEN
-->
# Table of Contents
* [Introduction](#introduction)
* [Similar projects](#similar-projects)
<!--
@endcond TURN_OFF_DOXYGEN
-->
# Introduction
There are many projects similar to `EnTT`, both open source and not.<br/>
Some even borrowed some ideas from this library and expressed them in different
languages.<br/>
Others developed different architectures from scratch and therefore offer
alternative solutions with their pros and cons.
Below an incomplete list of those that I've come across so far.<br/>
If you know of other similar projects out there, feel free to open an issue or a
PR and I'll be glad to add them to this page.<br/>
I hope the following lists can grow much more in the future.
# Similar projects
Below an incomplete list of similar projects that I've come across so far.<br/>
If some terms or designs aren't clear, I recommend referring to the
[_ECS Back and Forth_](https://skypjack.github.io/tags/#ecs) series for all the
details.
I hope this list can grow much more in the future:
* C:
* [destral_ecs](https://github.com/roig/destral_ecs): a single-file ECS based
on sparse sets.
@ -34,6 +51,8 @@ I hope this list can grow much more in the future:
solution between an ECS and dynamic mixins.
* C#
* [Arch](https://github.com/genaray/Arch): a simple, fast and _unity entities_
inspired archetype ECS with optional multithreading.
* [Entitas](https://github.com/sschmid/Entitas-CSharp): the ECS framework for
C# and Unity, where _reactive systems_ were invented.
* [LeoECS](https://github.com/Leopotam/ecs): simple lightweight C# Entity
@ -70,6 +89,3 @@ I hope this list can grow much more in the future:
* 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

@ -9,6 +9,7 @@
* [Delegate](#delegate)
* [Runtime arguments](#runtime-arguments)
* [Lambda support](#lambda-support)
* [Raw access](#raw-access)
* [Signals](#signals)
* [Event dispatcher](#event-dispatcher)
* [Named queues](#named-queues)
@ -38,7 +39,7 @@ lightweight classes to solve the same and many other problems.
# Delegate
A delegate can be used as a general purpose invoker with no memory overhead for
free functions and member functions provided along with an instance on which to
free functions, lambdas and members provided along with an instance on which to
invoke them.<br/>
It doesn't claim to be a drop-in replacement for an `std::function`, so don't
expect to use it whenever an `std::function` fits well. That said, it's most
@ -92,9 +93,9 @@ delegate.connect<&g>(c);
delegate(42);
```
The function `g` is invoked with a reference to `c` and `42`. However, the
function type of the delegate is still `void(int)`. This is also the signature
of its function call operator.<br/>
Function `g` is invoked with a reference to `c` and `42`. However, the function
type of the delegate is still `void(int)`. This is also the signature of its
function call operator.<br/>
Another interesting aspect of the delegate class is that it accepts functions
with a list of parameters that is shorter than that of its function type:
@ -105,9 +106,15 @@ delegate(42);
```
Where the function type of the delegate is `void(int)` as above. It goes without
saying that the extra arguments are silently discarded internally.<br/>
This is a nice-to-have feature in a lot of cases, as an example when the
`delegate` class is used as a building block of a signal-slot system.
saying that the extra arguments are silently discarded internally. This is a
nice-to-have feature in a lot of cases, as an example when the `delegate` class
is used as a building block of a signal-slot system.<br/>
In fact, this filtering works both ways. The class tries to pass its first
_count_ arguments **first**, then the last _count_. Watch out for conversion
rules if in doubt when connecting a listener!<br/>
Arbitrary functions that pull random arguments from the delegate list aren't
supported instead. Other feature were preferred, such as support for functions
with compatible argument lists although not equal to those of the delegate.
To create and initialize a delegate at once, there are a few specialized
constructors. Because of the rules of the language, the listener is provided by
@ -231,6 +238,24 @@ As above, the first parameter (`const void *`) isn't part of the function type
of the delegate and is used to dispatch arbitrary user data back and forth. In
other terms, the function type of the delegate above is `int(int)`.
## Raw access
While not recommended, a delegate also allows direct access to the stored
callable function target and underlying data, if any.<br/>
This makes it possible to bypass the behavior of the delegate itself and force
calls on different instances:
```cpp
my_struct other;
delegate.target(&other, 42);
```
It goes without saying that this type of approach is **very** risky, especially
since there is no way of knowing whether the contained function was originally a
member function of some class, a free function or a lambda.<br/>
Another possible (and meaningful) use of this feature is that of identifying a
particular delegate through its descriptive _traits_ instead.
# Signals
Signal handlers work with references to classes, function pointers and pointers
@ -290,7 +315,7 @@ sink.disconnect<&foo>();
sink.disconnect<&listener::bar>(instance);
// disconnect all member functions of an instance, if any
sink.disconnect(instance);
sink.disconnect(&instance);
// discards all listeners at once
sink.disconnect();
@ -300,15 +325,6 @@ As shown above, listeners don't have to strictly follow the signature of the
signal. As long as a listener can be invoked with the given arguments to yield a
result that is convertible to the given return type, everything works just
fine.<br/>
It's also possible to connect a listener before other elements already contained
by the signal. The `before` function returns a `sink` object that is correctly
initialized for the purpose and can be used to connect one or more listeners in
order and in the desired position:
```cpp
sink.before<&foo>().connect<&listener::bar>(instance);
```
In all cases, the `connect` member function returns by default a `connection`
object to be used as an alternative to break a connection by means of its
`release` member function.<br/>
@ -409,7 +425,7 @@ of them at once:
```cpp
dispatcher.sink<an_event>().disconnect<&listener::receive>(listener);
dispatcher.sink<another_event>().disconnect(listener);
dispatcher.sink<another_event>().disconnect(&listener);
```
The `trigger` member function serves the purpose of sending an immediate event