doc: minor changes
This commit is contained in:
@@ -22,8 +22,8 @@ respects. These variables are just one of the many ways to customize how it
|
||||
works.<br/>
|
||||
In the vast majority of cases, users will have no interest in changing the
|
||||
default parameters. For all other cases, the list of possible configurations
|
||||
with which it is possible to adjust the behavior of the library at runtime can be
|
||||
found below.
|
||||
with which it is possible to adjust the behavior of the library at runtime can
|
||||
be found below.
|
||||
|
||||
# Definitions
|
||||
|
||||
@@ -57,8 +57,9 @@ default type if necessary.
|
||||
|
||||
## ENTT_SPARSE_PAGE
|
||||
|
||||
It is known that the ECS module of `EnTT` is based on _sparse sets_. What is less
|
||||
known perhaps is that the sparse arrays are paged to reduce memory usage.<br/>
|
||||
It is known that the ECS module of `EnTT` is based on _sparse sets_. What is
|
||||
less known perhaps is that the sparse arrays are paged to reduce memory
|
||||
usage.<br/>
|
||||
Default size of pages (that is, the number of elements they contain) is 4096 but
|
||||
users can adjust it if appropriate. In all cases, the chosen value **must** be a
|
||||
power of 2.
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
# Introduction
|
||||
|
||||
The standard C++ library offers a wide range of containers and adaptors already.
|
||||
It is really difficult to do better (although it is very easy to do worse, as many
|
||||
examples available online demonstrate).<br/>
|
||||
It is really difficult to do better (although it is very easy to do worse, as
|
||||
many examples available online demonstrate).<br/>
|
||||
`EnTT` does not 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 functionalities by
|
||||
@@ -21,7 +21,8 @@ making available some containers and adaptors initially developed for internal
|
||||
use.
|
||||
|
||||
This section of the library is likely to grow larger over time. However, for the
|
||||
moment it is quite small and mainly aimed at satisfying some internal needs.<br/>
|
||||
moment it is quite small and mainly aimed at satisfying some internal
|
||||
needs.<br/>
|
||||
For all containers and adaptors made available, full test coverage and stability
|
||||
over time is guaranteed as usual.
|
||||
|
||||
|
||||
@@ -118,8 +118,8 @@ The type is also used internally when comparing two `any` objects:
|
||||
if(any == empty) { /* ... */ }
|
||||
```
|
||||
|
||||
In this case, before proceeding with a comparison, it is verified that the _type_
|
||||
of the two objects is actually the same.<br/>
|
||||
In this case, before proceeding with a comparison, it is 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 the possible risks of a comparison.
|
||||
|
||||
@@ -161,9 +161,9 @@ In particular, the `data` member function invoked on a non-const instance of
|
||||
|
||||
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`, they will not raise exceptions
|
||||
but will only trigger an assert in debug mode, otherwise resulting in undefined
|
||||
behavior in case of misuse in release mode.
|
||||
The only difference is that, in the case of `EnTT`, they will not raise
|
||||
exceptions but will only trigger an assert in debug mode, otherwise resulting in
|
||||
undefined behavior in case of misuse in release mode.
|
||||
|
||||
## Small buffer optimization
|
||||
|
||||
@@ -188,8 +188,8 @@ and always dynamically allocates objects (except for aliasing cases).
|
||||
|
||||
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/>
|
||||
It is provided as an optional second parameter following the desired size for the
|
||||
internal storage:
|
||||
It is provided as an optional second parameter following the desired size for
|
||||
the internal storage:
|
||||
|
||||
```cpp
|
||||
using my_any = entt::basic_any<sizeof(double[4]), alignof(double[4])>;
|
||||
@@ -234,14 +234,14 @@ entt::compressed_pair pair{0, 3.};
|
||||
pair.first() = 42;
|
||||
```
|
||||
|
||||
There is not much to describe then. It is recommended to rely on documentation and
|
||||
intuition. At the end of the day, it is just a pair and nothing more.
|
||||
There is not much to describe then. It is recommended to rely on documentation
|
||||
and intuition. At the end of the day, it is just a pair and nothing more.
|
||||
|
||||
# Enum as bitmask
|
||||
|
||||
Sometimes it is useful to be able to use enums as bitmasks. However, enum classes
|
||||
are not really suitable for the purpose. Main problem is that they do not convert
|
||||
implicitly to their underlying type.<br/>
|
||||
Sometimes it is useful to be able to use enums as bitmasks. However, enum
|
||||
classes are not really suitable for the purpose. Main problem is that they do
|
||||
not convert implicitly to their underlying type.<br/>
|
||||
The choice is then between using old-fashioned enums (with all their problems
|
||||
that I do not want to discuss here) or writing _ugly_ code.
|
||||
|
||||
@@ -379,8 +379,8 @@ make this hard work easier.
|
||||
## Input iterator pointer
|
||||
|
||||
When writing an input iterator that returns in-place constructed values if
|
||||
dereferenced, it is not always straightforward to figure out what `value_type` is
|
||||
and how to make it behave like a full-fledged pointer.<br/>
|
||||
dereferenced, it is not always straightforward to figure out what `value_type`
|
||||
is and how to make it behave like a full-fledged pointer.<br/>
|
||||
Conversely, it would be very useful to have an `operator->` available on the
|
||||
iterator itself that always works without too much complexity.
|
||||
|
||||
@@ -551,8 +551,8 @@ Basically, the whole system relies on a handful of classes. In particular:
|
||||
```
|
||||
|
||||
In general, the `value` function exposed by `type_hash` is also `constexpr`
|
||||
but this is not guaranteed for all compilers and platforms (although it is valid
|
||||
with the most well-known and popular ones).
|
||||
but this is not guaranteed for all compilers and platforms (although it is
|
||||
valid with the most well-known and popular ones).
|
||||
|
||||
This function **can** use non-standard features of the language for its own
|
||||
purposes. This makes it possible to provide compile-time identifiers that
|
||||
@@ -685,8 +685,9 @@ value for the two types.<br/>
|
||||
Fortunately, there are several easy ways to deal with this:
|
||||
|
||||
* The most trivial one is to define the `ENTT_STANDARD_CPP` macro. Runtime
|
||||
identifiers do not suffer from the same problem in fact. However, this solution
|
||||
does not work well with a plugin system, where the libraries are not linked.
|
||||
identifiers do not suffer from the same problem in fact. However, this
|
||||
solution does not work well with a plugin system, where the libraries are not
|
||||
linked.
|
||||
|
||||
* Another possibility is to specialize the `type_name` class for one of the
|
||||
conflicting types, in order to assign it a custom identifier. This is probably
|
||||
@@ -695,8 +696,8 @@ Fortunately, there are several easy ways to deal with this:
|
||||
* A fully customized identifier generation policy (based for example on enum
|
||||
classes or preprocessing steps) may represent yet another option.
|
||||
|
||||
These are just some examples of possible approaches to the problem, but there are
|
||||
many others. As already mentioned above, since users have full control over
|
||||
These are just some examples of possible approaches to the problem, but there
|
||||
are many others. As already mentioned above, since users have full control over
|
||||
their types, this problem is in any case easy to solve and should not worry too
|
||||
much.<br/>
|
||||
In all likelihood, it will never happen to run into a conflict anyway.
|
||||
@@ -840,9 +841,9 @@ lists. We therefore have `value_list_element[_v]` as well as
|
||||
|
||||
Sometimes it is useful to be able to give unique, sequential numeric identifiers
|
||||
to types either at compile-time or runtime.<br/>
|
||||
There are plenty of different solutions for this out there, and I could have used
|
||||
one of them. However, I decided to spend my time to define a couple of tools
|
||||
that fully embrace what modern C++ has to offer.
|
||||
There are plenty of different solutions for this out there, and I could have
|
||||
used one of them. However, I decided to spend my time to define a couple of
|
||||
tools that fully embrace what modern C++ has to offer.
|
||||
|
||||
## Compile-time generator
|
||||
|
||||
@@ -872,12 +873,13 @@ contains a numeric identifier for the given type. It can be used in any context
|
||||
where constant expressions are required.
|
||||
|
||||
As long as the list remains unchanged, identifiers are also guaranteed to be
|
||||
stable across different runs. In case they have been used in a production
|
||||
environment, and a type has to be removed. One can just use a placeholder to
|
||||
leave the other identifiers unchanged:
|
||||
stable across different runs. If used in a production environment where a type
|
||||
needs to be removed, a placeholder can help to leave the other identifiers the
|
||||
same:
|
||||
|
||||
```cpp
|
||||
template<typename> struct ignore_type {};
|
||||
template<typename>
|
||||
struct ignore_type {};
|
||||
|
||||
using id = entt::ident<
|
||||
a_type_still_valid,
|
||||
@@ -964,7 +966,8 @@ life of developers:
|
||||
callable object that supports multiple types at once.
|
||||
|
||||
* `entt::y_combinator`: this is a C++ implementation of **the** _y-combinator_.
|
||||
If it is not clear what it is, there is probably no need for this utility.<br/>
|
||||
If it is not clear what it is, there is probably no need for this
|
||||
utility.<br/>
|
||||
Below is a small example to show its use:
|
||||
|
||||
```cpp
|
||||
@@ -979,5 +982,5 @@ life of developers:
|
||||
the language does not make it possible to do much better.
|
||||
|
||||
This is a rundown of the (actually few) utilities made available by `EnTT`. The
|
||||
list will probably grow over time, but the size of each will remain rather small,
|
||||
as has been the case so far.
|
||||
list will probably grow over time, but the size of each will remain rather
|
||||
small, as has been the case so far.
|
||||
|
||||
@@ -99,8 +99,8 @@ It does not attempt in any way to take over on the user codebase, nor to control
|
||||
its main loop or process scheduling.<br/>
|
||||
Unlike other more or less well known models, it also makes use of independent
|
||||
pools that are extended via _static mixins_. The built-in signal support is an
|
||||
example of this flexible design: defined as a mixin, it is easily disabled if not
|
||||
needed. Similarly, the storage class has a specialization that shows how
|
||||
example of this flexible design: defined as a mixin, it is easily disabled if
|
||||
not needed. Similarly, the storage class has a specialization that shows how
|
||||
everything is customizable down to the smallest detail.
|
||||
|
||||
## Pay per use
|
||||
@@ -404,9 +404,9 @@ There are also some limitations on what a listener can and cannot do:
|
||||
|
||||
Please, refer to the documentation of the signal class to know about all the
|
||||
features it offers.<br/>
|
||||
There are many useful but less known functionalities that are not described here,
|
||||
such as the connection objects or the possibility to attach listeners with a
|
||||
list of parameters that are shorter than that of the signal itself.
|
||||
There are many useful but less known functionalities that are not described
|
||||
here, such as the connection objects or the possibility to attach listeners with
|
||||
a list of parameters that is shorter than that of the signal itself.
|
||||
|
||||
### Entity lifecycle
|
||||
|
||||
@@ -421,9 +421,9 @@ Since entity storage is unique within a registry, if a _name_ is provided it is
|
||||
ignored and therefore discarded.<br/>
|
||||
As for the function signature, this is exactly the same as the components.
|
||||
|
||||
Entities support all types of signals: construct, destroy, and update. The latter
|
||||
is perhaps ambiguous as an entity is not truly _updated_. Rather, its identifier
|
||||
is created and finally released.<br/>
|
||||
Entities support all types of signals: construct, destroy, and update. The
|
||||
latter is perhaps ambiguous as an entity is not truly _updated_. Rather, its
|
||||
identifier is created and finally released.<br/>
|
||||
Indeed, the update signal is meant to send _general notifications_ regarding an
|
||||
entity. It can be triggered via the `patch` function, as is the case with
|
||||
components:
|
||||
@@ -443,8 +443,8 @@ making it difficult for the user to write component listeners.
|
||||
|
||||
The destruction order of the storage classes and therefore the disconnection of
|
||||
the listeners is completely random.<br/>
|
||||
There are no guarantees today, and while the logic is easily discerned, it is not
|
||||
guaranteed that it will remain so in the future.
|
||||
There are no guarantees today, and while the logic is easily discerned, it is
|
||||
not guaranteed that it will remain so in the future.
|
||||
|
||||
For example, a listener getting disconnected after a component is discarded as a
|
||||
result of pool destruction is most likely a recipe for problems.<br/>
|
||||
@@ -499,8 +499,8 @@ auto &storage = registry.storage<entt::reactive>("observer"_hs);
|
||||
|
||||
In the latter case, there is the advantage that, in the event of destruction of
|
||||
an entity, this storage is also automatically cleaned up.<br/>
|
||||
Also note that, unlike all other storage, these classes do not support signals by
|
||||
default (although they can be enabled if necessary).
|
||||
Also note that, unlike all other storage, these classes do not support signals
|
||||
by default (although they can be enabled if necessary).
|
||||
|
||||
Once it has been created and associated with a registry, the reactive mixin
|
||||
needs to be informed about what it should _observe_.<br/>
|
||||
@@ -517,8 +517,8 @@ storage
|
||||
.on_destroy<renderable>();
|
||||
```
|
||||
|
||||
It goes without saying that it is possible to observe multiple events of the same
|
||||
type or of different types with the same storage.<br/>
|
||||
It goes without saying that it is possible to observe multiple events of the
|
||||
same type or of different types with the same storage.<br/>
|
||||
For example, to know which entities have been assigned or updated a component of
|
||||
a certain type:
|
||||
|
||||
@@ -749,8 +749,8 @@ const auto entity = registry.create();
|
||||
const bool tombstone = (entity == entt::tombstone);
|
||||
```
|
||||
|
||||
Be aware that `entt::tombstone` and entity 0 are different. Likewise, a
|
||||
zero initialized entity is not the same as `entt::tombstone`. Therefore, although
|
||||
Be aware that `entt::tombstone` and entity 0 are different. Likewise, a zero
|
||||
initialized entity is not the same as `entt::tombstone`. Therefore, although
|
||||
`entt::entity{}` is in some sense an alias for entity 0, none of them are used
|
||||
to create tombstones.
|
||||
|
||||
@@ -894,8 +894,8 @@ clazz instance;
|
||||
organizer.emplace(+[](const void *, entt::registry &) { /* ... */ }, &instance);
|
||||
```
|
||||
|
||||
In all cases, it is also possible to associate a name with the task when creating
|
||||
it. For example:
|
||||
In all cases, it is also possible to associate a name with the task when
|
||||
creating it. For example:
|
||||
|
||||
```cpp
|
||||
organizer.emplace<&free_function>("func");
|
||||
@@ -911,8 +911,8 @@ constant reference to it, it is considered a read-only access. Otherwise, it is
|
||||
considered as read-write access. All functions have the registry among their
|
||||
resources.
|
||||
|
||||
When registering a function, users can also require resources that are not in the
|
||||
list of parameters of the function itself. These are declared as template
|
||||
When registering a function, users can also require resources that are not in
|
||||
the list of parameters of the function itself. These are declared as template
|
||||
parameters:
|
||||
|
||||
```cpp
|
||||
@@ -1015,8 +1015,8 @@ registry.ctx().erase<my_type>("my_variable"_hs);
|
||||
A context variable must be both default constructible and movable. If the
|
||||
supplied type does not match that of the variable when using a _name_, the
|
||||
operation fails.<br/>
|
||||
For all users who want to use the context but do not want to create elements, the
|
||||
`contains` and `find` functions are also available:
|
||||
For all users who want to use the context but do not want to create elements,
|
||||
the `contains` and `find` functions are also available:
|
||||
|
||||
```cpp
|
||||
const bool contains = registry.ctx().contains<my_type>();
|
||||
@@ -1280,8 +1280,9 @@ a well known library for serialization as an archive. It uses
|
||||
[`Cereal C++`](https://uscilab.github.io/cereal/) under the hood, mainly
|
||||
because I wanted to learn how it works at the time I was writing the code.
|
||||
|
||||
The code **is not** production-ready and it is not neither the only nor (probably)
|
||||
the best way to do it. However, feel free to use it at your own risk.<br/>
|
||||
The code **is not** production-ready and it is not neither the only nor
|
||||
(probably) the best way to do it. However, feel free to use it at your own
|
||||
risk.<br/>
|
||||
The basic idea is to store everything in a group of queues in memory, then bring
|
||||
everything back to the registry with different loaders.
|
||||
|
||||
@@ -1337,9 +1338,9 @@ performance and memory usage. However, this also has consequences that are worth
|
||||
mentioning.
|
||||
|
||||
When an empty type is detected, it is not instantiated by default. Therefore,
|
||||
only the entities to which it is assigned are made available. There does not exist
|
||||
a way to _get_ empty types from a storage or a registry. Views and groups never
|
||||
return their instances too (for example, during a call to `each`).<br/>
|
||||
only the entities to which it is assigned are made available. There does not
|
||||
exist a way to _get_ empty types from a storage or a registry. Views and groups
|
||||
never return their instances too (for example, during a call to `each`).<br/>
|
||||
On the other hand, iterations are faster because only the entities to which the
|
||||
type is assigned are considered. Moreover, less memory is used, mainly because
|
||||
there does not exist any instance of the component, no matter how many entities
|
||||
@@ -1362,8 +1363,8 @@ empty types when their optimization is enabled. Pagination is disabled as well
|
||||
as pointer stability (as not necessary).<br/>
|
||||
However, this should be preferred to using a simple sparse set. In particular,
|
||||
a void storage offers all those feature normally offered by other storage types.
|
||||
Therefore, it is a perfectly valid pool for use with views and groups or within a
|
||||
registry.
|
||||
Therefore, it is a perfectly valid pool for use with views and groups or within
|
||||
a registry.
|
||||
|
||||
## Entity storage
|
||||
|
||||
@@ -1418,8 +1419,8 @@ equivalent to the following:
|
||||
auto &storage = registry.storage<entt::entity>();
|
||||
```
|
||||
|
||||
Because entity storage does not have a name, it cannot be retrieved via the opaque
|
||||
`storage` function either.<br/>
|
||||
Because entity storage does not have a name, it cannot be retrieved via the
|
||||
opaque `storage` function either.<br/>
|
||||
It would make no sense to try anyway, given that the type of the registry and
|
||||
therefore its entity type are known regardless.
|
||||
|
||||
@@ -1507,16 +1508,16 @@ struct transform {
|
||||
|
||||
Furthermore, it is quite common for a group of elements to be created close in
|
||||
time and therefore fallback into adjacent positions, thus favoring locality even
|
||||
on random accesses. Locality that is not sacrificed over time given the stability
|
||||
of storage positions, with undoubted performance advantages.
|
||||
on random accesses. Locality that is not sacrificed over time given the
|
||||
stability of storage positions, with undoubted performance advantages.
|
||||
|
||||
# Meet the runtime
|
||||
|
||||
`EnTT` takes advantage of what the language offers at compile-time. However,
|
||||
this can have its downsides (well known to those familiar with type erasure
|
||||
techniques).<br/>
|
||||
To fill the gap, the library also provides a bunch of utilities and features that
|
||||
are invaluable to handle types and pools at runtime.
|
||||
To fill the gap, the library also provides a bunch of utilities and features
|
||||
that are invaluable to handle types and pools at runtime.
|
||||
|
||||
## A base class to rule them all
|
||||
|
||||
@@ -1665,8 +1666,8 @@ different APIs.
|
||||
Single type views are specialized to give a performance boost in all cases.
|
||||
There is nothing as fast as a single type view. They just walk through packed
|
||||
(actually paged) arrays of elements and return them directly.<br/>
|
||||
This kind of views also allows getting the exact number of elements they are going
|
||||
to return.<br/>
|
||||
This kind of views also allows getting the exact number of elements they are
|
||||
going to return.<br/>
|
||||
Refer to the inline documentation for all the details.
|
||||
|
||||
Multi type views iterate entities that have at least all the given components.
|
||||
@@ -1871,8 +1872,8 @@ for(auto entity: registry.view<positon, velocity>()) {
|
||||
|
||||
Moreover, the order of types when constructing a view does not matter. Neither
|
||||
does the order of views in a view pack.<br/>
|
||||
However, it is possible to _enforce_ iteration of a view by given component order
|
||||
by means of the `use` function:
|
||||
However, it is possible to _enforce_ iteration of a view by given component
|
||||
order by means of the `use` function:
|
||||
|
||||
```cpp
|
||||
auto view = registry.view<position, velocity>();
|
||||
@@ -1904,8 +1905,8 @@ Multi type views iterate entities that have at least all the given components.
|
||||
During construction, they look at the number of elements available in each pool
|
||||
and use the smallest set in order to speed up iterations.<br/>
|
||||
They offer more or less the same functionalities of a multi type view. However,
|
||||
they do not expose a `get` member function and users should refer to the registry
|
||||
that generated the view to access components.<br/>
|
||||
they do not expose a `get` member function and users should refer to the
|
||||
registry that generated the view to access components.<br/>
|
||||
Refer to the inline documentation for all the details.
|
||||
|
||||
Runtime views are pretty cheap to construct and should not be stored aside in
|
||||
@@ -2196,8 +2197,8 @@ identifiers.
|
||||
|
||||
## What is allowed and what is not
|
||||
|
||||
Most of the _ECS_ available out there do not allow to create and destroy entities
|
||||
and components during iterations, nor to have pointer stability.<br/>
|
||||
Most of the _ECS_ available out there do not allow to create and destroy
|
||||
entities and components during iterations, nor to have pointer stability.<br/>
|
||||
`EnTT` partially solves the problem with a few limitations:
|
||||
|
||||
* Creating entities and components is allowed during iterations in most cases
|
||||
@@ -2230,16 +2231,16 @@ registry.view<position>().each([&](const auto entity, auto &pos) {
|
||||
});
|
||||
```
|
||||
|
||||
The `each` member function will not break (because iterators remain valid) nor will
|
||||
any reference be invalidated. Instead, more attention should be paid to the
|
||||
The `each` member function will not break (because iterators remain valid) nor
|
||||
will any reference be invalidated. Instead, more attention should be paid to the
|
||||
destruction of entities or the removal of components.<br/>
|
||||
Use a common range-for loop and get components directly from the view or move
|
||||
the deletion of entities and components at the end of the function to avoid
|
||||
dangling pointers.
|
||||
|
||||
For all types that do not offer stable pointers, iterators are also invalidated
|
||||
and the behavior is undefined if an entity is modified or destroyed and it is not
|
||||
the one currently returned by the iterator nor a newly created one.<br/>
|
||||
and the behavior is undefined if an entity is modified or destroyed and it is
|
||||
not the one currently returned by the iterator nor a newly created one.<br/>
|
||||
To work around it, possible approaches are:
|
||||
|
||||
* Store aside the entities and the components to be removed and perform the
|
||||
@@ -2261,8 +2262,8 @@ nature and the scope of the groups, it is not something in which it will happen
|
||||
to come across probably, but it is good to know it anyway.
|
||||
|
||||
First of all, it must be said that creating components while iterating a group
|
||||
is not a problem at all and is done freely as it happens with the views. The same
|
||||
applies to the destruction of components and entities, for which the rules
|
||||
is not a problem at all and is done freely as it happens with the views. The
|
||||
same applies to the destruction of components and entities, for which the rules
|
||||
mentioned above apply.
|
||||
|
||||
The additional limitation arises instead when a given component that is owned by
|
||||
@@ -2293,13 +2294,13 @@ groups or as free types with multi type views and groups in general.
|
||||
|
||||
# Multithreading
|
||||
|
||||
In general, the entire registry is not thread safe as it is. Thread safety is not
|
||||
something that users should want out of the box for several reasons. Just to
|
||||
In general, the entire registry is not thread safe as it is. Thread safety is
|
||||
not something that users should want out of the box for several reasons. Just to
|
||||
mention one of them: performance.<br/>
|
||||
Views, groups and consequently the approach adopted by `EnTT` are the great
|
||||
exception to the rule. It is true that views, groups and iterators in general
|
||||
are not thread safe by themselves. Because of this users should not try to iterate
|
||||
a set of components and modify the same set concurrently. However:
|
||||
are not thread safe by themselves. Because of this users should not try to
|
||||
iterate a set of components and modify the same set concurrently. However:
|
||||
|
||||
* As long as a thread iterates the entities that have the component `X` or
|
||||
assign and removes that component from a set of entities, another thread can
|
||||
@@ -2316,9 +2317,9 @@ a set of components and modify the same set concurrently. However:
|
||||
|
||||
This kind of entity-component systems can be used in single-threaded
|
||||
applications as well as along with async stuff or multiple threads. Moreover,
|
||||
typical thread based models for _ECS_ do not require a fully thread-safe registry
|
||||
to work. Actually, users can reach the goal with the registry as it is while
|
||||
working with most of the common models.
|
||||
typical thread based models for _ECS_ do not require a fully thread-safe
|
||||
registry to work. Actually, users can reach the goal with the registry as it is
|
||||
while working with most of the common models.
|
||||
|
||||
Because of the few reasons mentioned above and many others not mentioned, users
|
||||
are completely responsible for synchronization whether required. On the other
|
||||
@@ -2378,8 +2379,8 @@ registry.
|
||||
Returned views are always valid and behave as expected in the context of the
|
||||
caller. However, they may contain dangling references to non-existing storage
|
||||
when created from a const registry.<br/>
|
||||
As a result, such a view may misbehave over time if it is kept aside for a second
|
||||
use.<br/>
|
||||
As a result, such a view may misbehave over time if it is kept aside for a
|
||||
second use.<br/>
|
||||
Therefore, if the general advice is to create views when necessary and discard
|
||||
them immediately afterwards, this becomes almost a rule when it comes to views
|
||||
generated from a const registry.
|
||||
@@ -2400,5 +2401,5 @@ things could be forgotten, others could have been omitted on purpose to reduce
|
||||
the size of this file. Unfortunately, some parts may even be outdated and still
|
||||
to be updated.
|
||||
|
||||
For further information, it is recommended to refer to the documentation included
|
||||
in the code itself or join the official channels to ask a question.
|
||||
For further information, it is recommended to refer to the documentation
|
||||
included in the code itself or join the official channels to ask a question.
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
This is a constantly updated section where I am trying to put the answers to the
|
||||
most frequently asked questions.<br/>
|
||||
If you do not find your answer here, there are two cases: nobody has done it yet,
|
||||
or this section needs updating. In both cases, you can
|
||||
If you do not find your answer here, there are two cases: nobody has done it
|
||||
yet, or this section needs updating. In both cases, you can
|
||||
[open a new issue](https://github.com/skypjack/entt/issues/new) or enter either
|
||||
the [gitter channel](https://gitter.im/skypjack/entt) or the
|
||||
[discord server](https://discord.gg/5BjPWBd) to ask for help.<br/>
|
||||
@@ -30,8 +30,8 @@ part of the documentation.
|
||||
|
||||
`EnTT` is an experimental project that I also use to keep me up-to-date with the
|
||||
latest revision of the language and the standard library. For this reason, it is
|
||||
likely that some classes you are working with are using standard containers under
|
||||
the hood.<br/>
|
||||
likely that some classes you are working with are using standard containers
|
||||
under the hood.<br/>
|
||||
Unfortunately, it is known that the standard containers are not particularly
|
||||
performing in debugging (the reasons for this go beyond this document) and are
|
||||
even less so on Windows, apparently. Fortunately, this can also be mitigated a
|
||||
@@ -119,9 +119,9 @@ more details.
|
||||
## The standard and the non-copyable types
|
||||
|
||||
`EnTT` uses internally the trait `std::is_copy_constructible_v` to check if a
|
||||
component is actually copyable. However, this trait does not really check whether
|
||||
a type is actually copyable. Instead, it just checks that a suitable copy
|
||||
constructor and copy operator exist.<br/>
|
||||
component is actually copyable. However, this trait does not really check
|
||||
whether a type is actually copyable. Instead, it just checks that a suitable
|
||||
copy constructor and copy operator exist.<br/>
|
||||
This can lead to surprising results due to some idiosyncrasies of the standard.
|
||||
|
||||
For example, `std::vector` defines a copy constructor that is conditionally
|
||||
@@ -184,9 +184,9 @@ owned by the entity that is destroyed.
|
||||
|
||||
## Duplicate storage for the same component
|
||||
|
||||
It is rare, but you can see double sometimes, especially when it comes to storage.
|
||||
This can be caused by a conflict in the hash assigned to the various component
|
||||
types (one of a kind) or by bugs in your compiler
|
||||
It is rare, but you can see double sometimes, especially when it comes to
|
||||
storage. This can be caused by a conflict in the hash assigned to the various
|
||||
component types (one of a kind) or by bugs in your compiler
|
||||
([more common](https://github.com/skypjack/entt/issues/1063) apparently).<br/>
|
||||
Regardless of the cause, `EnTT` offers a customization point that also serves as
|
||||
a solution in this case:
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
|
||||
# Introduction
|
||||
|
||||
`EnTT` does not aim to offer everything one needs to work with graphs. Therefore,
|
||||
anyone looking for this in the _graph_ submodule will be disappointed.<br/>
|
||||
`EnTT` does not aim to offer everything one needs to work with graphs.
|
||||
Therefore, anyone looking for this in the _graph_ submodule will be
|
||||
disappointed.<br/>
|
||||
Quite the opposite is true though. This submodule is minimal and contains only
|
||||
the data structures and algorithms strictly necessary for the development of
|
||||
some tools such as the _flow builder_.
|
||||
@@ -182,8 +183,8 @@ user wants to rely on that.<br/>
|
||||
However, being an integral value, it leaves the user full freedom to rely on his
|
||||
own tools if necessary.
|
||||
|
||||
Once a task is associated with the flow builder, it has also assigned read-only or
|
||||
read-write resources as appropriate:
|
||||
Once a task is associated with the flow builder, it has also assigned read-only
|
||||
or read-write resources as appropriate:
|
||||
|
||||
```cpp
|
||||
builder
|
||||
@@ -249,7 +250,7 @@ What happens here is that the resource first _sees_ a read-only access request
|
||||
from the first task, then a read-only request from the second task and finally
|
||||
a read-write 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
|
||||
graph may be unexpected. In fact, this consists of a single edge outgoing from
|
||||
the second task and directed to the first task.<br/>
|
||||
To intuitively understand what happens, it is enough to think of the fact that a
|
||||
task never has an edge pointing to itself.
|
||||
@@ -279,15 +280,15 @@ otherwise inaccessible.
|
||||
|
||||
## Fake resources and order of execution
|
||||
|
||||
The flow builder does not offer the ability to specify when a task should execute
|
||||
The flow builder does not offer the ability to specify when a task should run
|
||||
before or after another task.<br/>
|
||||
In fact, the order of _registration_ on the resources also determines the order
|
||||
in which the tasks are processed during the generation of the execution graph.
|
||||
|
||||
However, there is a way to _force_ the execution order of two processes.<br/>
|
||||
Briefly, since accessing a resource in opposite modes requires sequential rather
|
||||
than parallel scheduling, it is possible to make use of fake resources to rule on
|
||||
the execution order:
|
||||
than parallel scheduling, it is possible to make use of fake resources to rule
|
||||
on the execution order:
|
||||
|
||||
```cpp
|
||||
builder
|
||||
@@ -361,6 +362,6 @@ for(auto &&vertex: graph) {
|
||||
}
|
||||
```
|
||||
|
||||
Then it is 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.
|
||||
Then it is 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.
|
||||
|
||||
@@ -20,14 +20,12 @@ Fortunately, nowadays `EnTT` works smoothly across boundaries.
|
||||
Many classes in `EnTT` make extensive use of type erasure for their purposes.
|
||||
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 arouses little interest.
|
||||
The only exception is when a conflict between identifiers occurs
|
||||
(definitely uncommon though) or when the default solution proposed by `EnTT`
|
||||
is not suitable for the user's purposes.<br/>
|
||||
available to the rest of the library. In general, this class arouses little
|
||||
interest. The only exception is when a conflict between identifiers occurs
|
||||
(definitely uncommon though) or when the default solution proposed by `EnTT` is
|
||||
not suitable for the user's purposes.<br/>
|
||||
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.
|
||||
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` are to import or export symbols, so as to make everything work
|
||||
@@ -44,9 +42,9 @@ However, what is offered should hopefully serve as a basis for all of them.
|
||||
|
||||
The runtime reflection system deserves a special mention when it comes to using
|
||||
it across boundaries.<br/>
|
||||
Since it is linked already to a static context to which the elements are attached
|
||||
and different contexts do not relate to each other, they must be _shared_ to
|
||||
allow the use of meta types across boundaries.
|
||||
Since it is linked already to a static context to which the elements are
|
||||
attached and different contexts do not relate to each other, they must be
|
||||
_shared_ to allow the use of meta types across boundaries.
|
||||
|
||||
Fortunately, sharing a context is also trivial to do. First of all, the local
|
||||
one is acquired in the main space:
|
||||
@@ -62,8 +60,8 @@ thus discarding or storing aside the local one:
|
||||
entt::locator<entt::meta_ctx>::reset(handle);
|
||||
```
|
||||
|
||||
From now on, both spaces refer to the same context and to it are all
|
||||
new meta-types attached, no matter where they are created.<br/>
|
||||
From now on, both spaces refer to the same context and to it are all new meta
|
||||
types attached, no matter where they are created.<br/>
|
||||
Note that _replacing_ the main context does not 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.
|
||||
@@ -83,7 +81,8 @@ is unknown to the former, a dedicated pool is created within the registry on
|
||||
first use.<br/>
|
||||
As one can guess, this pool is instantiated on a different side of the boundary
|
||||
from the `registry`. Therefore, the instance is now managing memory from
|
||||
different spaces, and this can quickly lead to crashes if not properly addressed.
|
||||
different spaces, and this can quickly lead to crashes if not properly
|
||||
addressed.
|
||||
|
||||
To overcome the risk, it is recommended to use well-defined interfaces that make
|
||||
fundamental types pass through the boundaries, isolating the instances of the
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
`EnTT` is widely used in private and commercial applications. I cannot even
|
||||
mention most of them because of some signatures I put on some documents time
|
||||
ago. Fortunately, there are also people who took the time to implement open
|
||||
source projects based on `EnTT` and did not hold back when it came to documenting
|
||||
them.
|
||||
source projects based on `EnTT` and did not hold back when it came to
|
||||
documenting them.
|
||||
|
||||
Below an incomplete list of games, applications and articles that can be used as
|
||||
a reference.<br/>
|
||||
@@ -97,7 +97,8 @@ I hope the following lists can grow much more in the future.
|
||||
by Quake.
|
||||
* [Destroid](https://github.com/tyrannicaltoucan/destroid): _one-bazillionth_
|
||||
arcade game about shooting dirty rocks in space, inspired by Asteroids.
|
||||
* [Wanderer](https://github.com/albin-johansson/wanderer): a 2D exploration-based indie game.
|
||||
* [Wanderer](https://github.com/albin-johansson/wanderer): a 2D
|
||||
exploration-based indie game.
|
||||
* [Spelunky® Classic remake](https://github.com/dbeef/spelunky-psp): a truly
|
||||
multiplatform experience with a rewrite from scratch.
|
||||
* [CubbyTower](https://github.com/utilForever/CubbyTower): a simple tower
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
|
||||
# Introduction
|
||||
|
||||
Usually, service locators are tightly bound to the services they expose.
|
||||
It is hard to define a general purpose solution.<br/>
|
||||
Usually, service locators are tightly bound to the services they expose. It is
|
||||
hard to define a general purpose solution.<br/>
|
||||
This tiny class tries to fill the gap and gets rid of the burden of defining a
|
||||
different specific locator for each application.
|
||||
|
||||
@@ -74,9 +74,9 @@ and use them with other locators. Of course, all a user will get is to have an
|
||||
uninitialized service elsewhere as well.
|
||||
|
||||
Note that exporting a service allows users to _share_ the object currently set
|
||||
in a locator. Replacing it will not replace the element, even where a service has
|
||||
been configured with a handle to the previous item.<br/>
|
||||
in a locator. Replacing it will not replace the element, even where a service
|
||||
has been configured with a handle to the previous item.<br/>
|
||||
In other words, if an audio service is replaced with a null object to silence an
|
||||
application and the original service was shared, this operation will not propagate
|
||||
to the other locators. Therefore, a module that shares the ownership of the
|
||||
original audio service is still able to emit sounds.
|
||||
application and the original service was shared, this operation will not
|
||||
propagate to the other locators. Therefore, a module that shares the ownership
|
||||
of the original audio service is still able to emit sounds.
|
||||
|
||||
238
docs/md/meta.md
238
docs/md/meta.md
@@ -29,19 +29,19 @@ looked for a third-party library that met my needs on the subject, but I always
|
||||
came across some details that I did not like: macros, being intrusive, too many
|
||||
allocations, and so on.<br/>
|
||||
I finally decided to write a built-in, non-intrusive and macro-free runtime
|
||||
reflection system for `EnTT`. Maybe I did not do better than others or maybe yes,
|
||||
time will tell me, but at least I can model this tool around the library to
|
||||
reflection system for `EnTT`. Maybe I did not do better than others or maybe
|
||||
yes, time will tell me, but at least I can model this tool around the library to
|
||||
which it belongs and not the opposite.
|
||||
|
||||
# Names and identifiers
|
||||
|
||||
The meta system does not force users to rely on the tools provided by the library
|
||||
when it comes to working with names and identifiers. It does this by offering an
|
||||
API that works with opaque identifiers that may or may not be generated by means
|
||||
of a hashed string.<br/>
|
||||
This means that users can assign any type of identifier to the meta-objects, as
|
||||
long as they are numeric. It does not matter if they are generated at runtime, at
|
||||
compile-time or with custom functions.
|
||||
The meta system does not force users to rely on the tools provided by the
|
||||
library when it comes to working with names and identifiers. It does this by
|
||||
offering an API that works with opaque identifiers that may or may not be
|
||||
generated by means of a hashed string.<br/>
|
||||
This means that users can assign any type of identifier to the meta objects, as
|
||||
long as they are numeric. It does not matter if they are generated at runtime,
|
||||
at compile-time or with custom functions.
|
||||
|
||||
That being said, the examples in the following sections are all based on the
|
||||
`hashed_string` class as provided by this library. Therefore, where an
|
||||
@@ -74,20 +74,20 @@ entt::meta_factory<my_type> factory{};
|
||||
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
|
||||
By default, a meta type is associated with the identifier returned by the
|
||||
runtime type identification system built-in in `EnTT`.<br/>
|
||||
However, it is also possible to assign custom identifiers to meta-types:
|
||||
However, it is also possible to assign custom identifiers to meta types:
|
||||
|
||||
```cpp
|
||||
entt::meta_factory<my_type>{}.type("reflected_type"_hs);
|
||||
```
|
||||
|
||||
Identifiers are used to _retrieve_ meta-types at runtime by _name_ other than by
|
||||
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 do not want
|
||||
to also make the type _searchable_. In this case, it is sufficient not to invoke
|
||||
`type`.
|
||||
the reflection system can use it correctly under the hood, while they do not
|
||||
want to also make the type _searchable_. In this case, it is sufficient not to
|
||||
invoke `type`.
|
||||
|
||||
A factory is such that all its member functions return the factory itself. It is
|
||||
generally used to create the following:
|
||||
@@ -101,7 +101,7 @@ generally used to create the following:
|
||||
entt::meta_factory<my_type>{}.ctor<int, char>().ctor<&factory>();
|
||||
```
|
||||
|
||||
Meta-default constructors are implicitly generated, if possible.
|
||||
Meta default constructors are implicitly generated, if possible.
|
||||
|
||||
* _Destructors_. Both free functions and member functions are valid destructors:
|
||||
|
||||
@@ -114,7 +114,7 @@ generally used to create the following:
|
||||
A function should neither delete nor explicitly invoke the destructor of a
|
||||
given instance.
|
||||
|
||||
* _Data members_. Meta-data members are actual data members of the underlying
|
||||
* _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:
|
||||
@@ -126,7 +126,7 @@ generally used to create the following:
|
||||
.data<&global_variable>("global"_hs);
|
||||
```
|
||||
|
||||
The `data` function requires the identifier to use for the meta-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
|
||||
@@ -154,7 +154,7 @@ generally used to create the following:
|
||||
.func<&free_function>("free"_hs);
|
||||
```
|
||||
|
||||
The `func` function requires the identifier to use for the meta-data function.
|
||||
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.
|
||||
@@ -177,15 +177,15 @@ generally used to create the following:
|
||||
entt::meta_factory<double>{}.conv<int>();
|
||||
```
|
||||
|
||||
This is everything users need to create meta-types.
|
||||
Refer to the inline documentation for further details.
|
||||
This is everything users need to create meta types. Refer to the inline
|
||||
documentation for further details.
|
||||
|
||||
## Any to the rescue
|
||||
|
||||
The reflection system offers a kind of _extended version_ of the `entt::any`
|
||||
class (see the core module for more details).<br/>
|
||||
The purpose is to add some feature on top of those already present, so as to
|
||||
integrate it with the meta-type system without having to duplicate the code.
|
||||
integrate it with the meta type system without having to duplicate the code.
|
||||
|
||||
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
|
||||
@@ -243,21 +243,21 @@ for(auto &&[id, type]: entt::resolve()) {
|
||||
```
|
||||
|
||||
In all cases, the returned value is an instance of `meta_type` (possibly with
|
||||
its id). This kind of objects offers an API to know their _runtime identifiers_,
|
||||
to iterate all the meta-objects associated with them and even to build instances
|
||||
of the underlying type.<br/>
|
||||
Meta-data members and functions are accessed by name:
|
||||
its id). These objects offer an API to know their _runtime identifiers_, to
|
||||
iterate all the meta objects associated with them and even to build instances of
|
||||
the underlying type.<br/>
|
||||
Meta data members and functions are accessed by name:
|
||||
|
||||
* Meta-data members:
|
||||
* Meta data members:
|
||||
|
||||
```cpp
|
||||
auto data = entt::resolve<my_type>().data("member"_hs);
|
||||
```
|
||||
|
||||
The returned type is `meta_data` and may be invalid if there is no meta-data
|
||||
The returned type is `meta_data` and may be invalid if there is no meta data
|
||||
object associated with the given identifier.<br/>
|
||||
A meta-data object offers an API to query the underlying type (for example, to
|
||||
know if it is a const or a static one), to get the meta-type of the variable
|
||||
A meta data object offers an API to query the underlying type (for example, to
|
||||
know if it is a const or a static one), to get the meta type of the variable
|
||||
and to set or get the contained value.
|
||||
|
||||
* Meta function members:
|
||||
@@ -270,11 +270,11 @@ Meta-data members and functions are accessed by name:
|
||||
function object associated with the given identifier.<br/>
|
||||
A meta function object offers an API to query the underlying type (for
|
||||
example, to know if it is a const or a static function), to know the number of
|
||||
arguments, the meta return type and the meta-types of the parameters. In
|
||||
arguments, the meta return type and the meta types of the parameters. In
|
||||
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 explicitly convert
|
||||
All the meta objects thus obtained as well as the meta types explicitly convert
|
||||
to a boolean value to check for validity:
|
||||
|
||||
```cpp
|
||||
@@ -283,9 +283,9 @@ if(auto func = entt::resolve<my_type>().func("member"_hs); func) {
|
||||
}
|
||||
```
|
||||
|
||||
Furthermore, all of them (and a few more, like meta-basis) are returned by a bunch
|
||||
of overloads that provide the caller with iterable ranges of top-level elements.
|
||||
As an example:
|
||||
Furthermore, all of them (and a few more, like meta basis) are returned by a
|
||||
bunch of overloads that provide the caller with iterable ranges of top-level
|
||||
elements. As an example:
|
||||
|
||||
```cpp
|
||||
for(auto &&[id, type]: entt::resolve<my_type>().base()) {
|
||||
@@ -293,22 +293,22 @@ for(auto &&[id, type]: entt::resolve<my_type>().base()) {
|
||||
}
|
||||
```
|
||||
|
||||
Meta-types are also used to `construct` actual instances of the underlying
|
||||
Meta types 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 was found
|
||||
or not.
|
||||
|
||||
There is no object that wraps the destructor of a meta-type nor a `destroy`
|
||||
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 would not have member functions to expose
|
||||
anyway.<br/>
|
||||
they have no name, cannot be searched and would not have member functions to
|
||||
expose anyway.<br/>
|
||||
Similarly, conversion functions are not directly accessible. They are used
|
||||
internally by `meta_any` and the meta-objects when needed.
|
||||
internally by `meta_any` and the meta objects when needed.
|
||||
|
||||
Meta-types and meta-objects in general contain much more than what was said.
|
||||
Meta types and meta objects in general contain much more than what was said.
|
||||
Refer to the inline documentation for further details.
|
||||
|
||||
## Container support
|
||||
@@ -316,7 +316,7 @@ Refer to the inline documentation for further details.
|
||||
The runtime reflection system also supports containers of all types.<br/>
|
||||
Moreover, _containers_ does not necessarily mean those offered by the C++
|
||||
standard library. In fact, user defined data structures can also work with the
|
||||
meta-system in many cases.
|
||||
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
|
||||
@@ -334,10 +334,10 @@ particular:
|
||||
It is important to include the header file `container.hpp` to make these
|
||||
specializations available to the compiler when needed.<br/>
|
||||
The same file also contains many examples for the users that are interested in
|
||||
making their own containers available to the meta-system.
|
||||
making their own containers available to the meta system.
|
||||
|
||||
When a specialization of the `meta_sequence_container_traits` class exists, the
|
||||
meta-system treats the wrapped type as a sequence container. In a similar way,
|
||||
meta system treats the wrapped type as a sequence container. In a similar way,
|
||||
a type is treated as an associative container if a specialization of the
|
||||
`meta_associative_container_traits` class is found for it.<br/>
|
||||
Proxy objects are returned by dedicated members of the `meta_any` class. The
|
||||
@@ -358,24 +358,24 @@ 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 is not necessary to perform a double check actually. Instead, it is enough to
|
||||
query the meta-type or verify that the proxy object is valid. In fact, proxies
|
||||
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 is not a container.<br/>
|
||||
In all cases, users are not expected to _reflect_ containers explicitly. It is
|
||||
sufficient to assign a container for which a specialization of the trait
|
||||
sufficient to assign a container for which a specialization of the _traits_
|
||||
classes exists to a `meta_any` object to be able to get its proxy object.
|
||||
|
||||
The interface of the `meta_sequence_container` proxy object is the same for all
|
||||
types of sequence containers, although the available features differ from case
|
||||
to case. In particular:
|
||||
|
||||
* The `value_type` member function returns the meta-type of the elements.
|
||||
* The `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.
|
||||
|
||||
* The `resize` member function allows resizing the wrapped container and
|
||||
returns true in case of success.<br/>
|
||||
* The `resize` member function allows resizing the wrapped container and returns
|
||||
true in case of success.<br/>
|
||||
For example, it is not possible to resize fixed size containers.
|
||||
|
||||
* The `clear` member function allows clearing the wrapped container and returns
|
||||
@@ -398,8 +398,8 @@ to case. In particular:
|
||||
In all cases, given an underlying container of type `C`, the returned element
|
||||
contains an object of type `C::value_type` which therefore depends on the
|
||||
actual container.<br/>
|
||||
All meta iterators are input iterators and do not offer an indirection operator
|
||||
on purpose.
|
||||
All meta iterators are input iterators and do not offer an indirection
|
||||
operator on purpose.
|
||||
|
||||
* The `insert` member function is used to add elements to the container. It
|
||||
accepts a meta iterator and the element to insert:
|
||||
@@ -456,15 +456,15 @@ differences in behavior in the case of key-only containers. In particular:
|
||||
* The `key_only` member function returns true if the wrapped container is a
|
||||
key-only one.
|
||||
|
||||
* The `key_type` member function returns the meta-type of the keys.
|
||||
* The `key_type` member function returns the meta type of the keys.
|
||||
|
||||
* The `mapped_type` member function returns an invalid meta-type for key-only
|
||||
containers and the meta-type of the mapped values for all other types of
|
||||
* The `mapped_type` member function returns an invalid meta type for key-only
|
||||
containers and the meta type of the mapped values for all other types of
|
||||
containers.
|
||||
|
||||
* The `value_type` member function returns the meta-type of the elements.<br/>
|
||||
For example, it returns the meta-type of `int` for `std::set<int>` while it
|
||||
returns the meta-type of `std::pair<const int, char>` for
|
||||
* The `value_type` member function returns the meta type of the elements.<br/>
|
||||
For example, it returns the meta type of `int` for `std::set<int>` while it
|
||||
returns the meta type of `std::pair<const int, char>` for
|
||||
`std::map<int, char>`.
|
||||
|
||||
* The `size` member function returns the number of elements in the container as
|
||||
@@ -490,8 +490,8 @@ differences in behavior in the case of key-only containers. In particular:
|
||||
is a key-value pair where the key has type `C::key_type` and the value has
|
||||
type `C::mapped_type`. Since key-only containers do not have a mapped type,
|
||||
their _value_ is nothing more than an invalid `meta_any` object.<br/>
|
||||
All meta iterators are input iterators and do not offer an indirection operator
|
||||
on purpose.
|
||||
All meta iterators are input iterators and do not offer an indirection
|
||||
operator on purpose.
|
||||
|
||||
While the accessed key is usually constant in the associative containers and
|
||||
is therefore returned by copy, the value (if any) is wrapped by an instance of
|
||||
@@ -499,7 +499,7 @@ differences in behavior in the case of key-only containers. In particular:
|
||||
modifies the element inside the container.
|
||||
|
||||
* The `insert` member function is used to add elements to a container. It gets
|
||||
two arguments, respectively, the key and the value to insert:
|
||||
two arguments, the key and the value to insert:
|
||||
|
||||
```cpp
|
||||
auto last = view.end();
|
||||
@@ -519,8 +519,8 @@ 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. A call to `erase` may fail when the argument is not at least
|
||||
convertible to the required type.
|
||||
successful or not. A call to `erase` may fail when the argument is not at
|
||||
least convertible to the required type.
|
||||
|
||||
* The `operator[]` is used to access elements in a container. It gets a single
|
||||
argument, the key of the element to return:
|
||||
@@ -537,11 +537,11 @@ Container support is minimal but likely sufficient to satisfy all needs.
|
||||
|
||||
## Pointer-like types
|
||||
|
||||
As with containers, it is also possible to _tell_ to the meta-system which types
|
||||
As with containers, it is 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
|
||||
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:
|
||||
|
||||
@@ -553,25 +553,25 @@ specializations available to the compiler when needed.<br/>
|
||||
The same file also contains many examples for the users that are interested in
|
||||
making their own pointer-like types available to the meta system.
|
||||
|
||||
When a type is recognized as a pointer-like one by the meta-system, it is
|
||||
When a type is recognized as a pointer-like one by the meta system, it is
|
||||
possible to dereference the instances of `meta_any` that contain these objects.
|
||||
The following is a deliberately verbose example to show how to use this feature:
|
||||
|
||||
```cpp
|
||||
int value = 42;
|
||||
// meta-type equivalent to that of int *
|
||||
// meta type equivalent to that of int *
|
||||
entt::meta_any any{&value};
|
||||
|
||||
if(any.type().is_pointer_like()) {
|
||||
// meta-type equivalent to that of int
|
||||
// meta type equivalent to that of int
|
||||
if(entt::meta_any ref = *any; ref) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
It is not necessary to perform a double check. Instead, it is enough to query the
|
||||
meta-type or verify that the returned object is valid. For example, invalid
|
||||
It is not necessary to perform a double check. Instead, it is enough to query
|
||||
the meta type or verify that the returned object is valid. For example, invalid
|
||||
instances are returned when the wrapped object is not 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
|
||||
@@ -580,8 +580,8 @@ 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 do not offer an `operator*`. In particular:
|
||||
|
||||
* It is possible to exploit a solution based on ADL lookup by offering a function
|
||||
(also a template one) named `dereference_meta_pointer_like`:
|
||||
* It is possible to exploit a solution based on ADL lookup by implementing a
|
||||
function (also a template one) named `dereference_meta_pointer_like`:
|
||||
|
||||
```cpp
|
||||
template<typename Type>
|
||||
@@ -608,24 +608,24 @@ 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 is a class template.<br/>
|
||||
By default, this works out of the box and requires no user action. However, it is
|
||||
important to include the header file `template.hpp` to make this information
|
||||
By default, this works out of the box and requires no user action. However, it
|
||||
is important to include the header file `template.hpp` to make this information
|
||||
available to the compiler when needed.
|
||||
|
||||
Meta-template information is easily found:
|
||||
Meta template information is easily found:
|
||||
|
||||
```cpp
|
||||
// this method returns true if the type is recognized as a class template specialization
|
||||
if(auto type = entt::resolve<std::shared_ptr<my_type>>(); type.is_template_specialization()) {
|
||||
// meta-type of the class template conveniently wrapped by entt::meta_class_template_tag
|
||||
// meta type of the class template conveniently wrapped by entt::meta_class_template_tag
|
||||
auto class_type = type.template_type();
|
||||
|
||||
// number of template arguments
|
||||
std::size_t arity = type.template_arity();
|
||||
|
||||
// meta-type of the i-th argument
|
||||
// meta type of the i-th argument
|
||||
auto arg_type = type.template_arg(0u);
|
||||
}
|
||||
```
|
||||
@@ -657,8 +657,8 @@ struct entt::meta_template_traits<function_type<Ret(Args...)>> {
|
||||
};
|
||||
```
|
||||
|
||||
The reflection system does not verify the accuracy of the information nor infer a
|
||||
correspondence between real types and meta-types.<br/>
|
||||
The reflection system does not verify the accuracy of the information nor infer
|
||||
a correspondence between real types and meta types.<br/>
|
||||
Therefore, the specialization is used as is and the information it contains is
|
||||
associated with the appropriate type when required.
|
||||
|
||||
@@ -698,7 +698,7 @@ double value = any.cast<double>();
|
||||
```
|
||||
|
||||
With no need for registration, the conversion takes place automatically under
|
||||
the hood. The same goes for a call to `allow_cast` involving a meta-type:
|
||||
the hood. The same goes for a call to `allow_cast` involving a meta type:
|
||||
|
||||
```cpp
|
||||
entt::meta_type type = entt::resolve<int>();
|
||||
@@ -715,21 +715,21 @@ always preferred over the automatic ones.
|
||||
## Implicitly generated default constructor
|
||||
|
||||
Creating objects of default constructible types through the reflection system
|
||||
while not having to explicitly register the meta-type or its default constructor
|
||||
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 default constructible types only, default constructors are automatically
|
||||
defined and associated with their meta-types, whether they are explicitly or
|
||||
defined and associated with their meta types, whether they are explicitly or
|
||||
implicitly generated.<br/>
|
||||
Therefore, this is all needed to construct an integer from its meta-type:
|
||||
Therefore, this is all needed to construct an integer from its meta type:
|
||||
|
||||
```cpp
|
||||
entt::resolve<int>().construct();
|
||||
```
|
||||
|
||||
Where the meta-type is, 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
|
||||
@@ -737,7 +737,7 @@ 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.
|
||||
Sometimes all a user has is an opaque pointer to an object of a known meta type.
|
||||
It would be handy in this case to be able to construct a `meta_any` element from
|
||||
it.<br/>
|
||||
For this purpose, the `meta_type` class offers a `from_void` member function
|
||||
@@ -770,10 +770,10 @@ There are a few alternatives available at the moment:
|
||||
since it is implicitly selected if no other policy is specified.<br/>
|
||||
In this case, the return values of the functions as well as the properties
|
||||
exposed as data members are always returned by copy in a dedicated wrapper and
|
||||
therefore associated with their original meta-types.
|
||||
therefore associated with their original meta types.
|
||||
|
||||
* The _as-void_ policy, associated with the type `entt::as_void_t`.<br/>
|
||||
Its purpose is to discard the return value of a meta-object, whatever it is,
|
||||
Its purpose is to discard the return value of a meta object, whatever it is,
|
||||
thus making it appear as if its type were `void`:
|
||||
|
||||
```cpp
|
||||
@@ -810,8 +810,8 @@ obvious corner cases that can in turn be solved with the use of policies.
|
||||
|
||||
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_
|
||||
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/>
|
||||
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
|
||||
@@ -827,8 +827,8 @@ entt::meta_factory<my_enum>{}
|
||||
entt::meta_factory<int>{}.data<2048>("max_int"_hs);
|
||||
```
|
||||
|
||||
Accessing them is trivial as well. It is a matter of doing the following, as with
|
||||
any other data member of a meta-type:
|
||||
Accessing them is trivial as well. It is 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>();
|
||||
@@ -841,7 +841,7 @@ object optimization performed by the `meta_any` class.
|
||||
## User defined data
|
||||
|
||||
Sometimes (for example, when it comes to creating an editor) it might be useful
|
||||
to attach _traits_ or arbitrary _custom data_ to the meta-objects created.
|
||||
to attach _traits_ or arbitrary _custom data_ to the meta objects created.
|
||||
|
||||
The main difference between them is that:
|
||||
|
||||
@@ -852,7 +852,7 @@ The main difference between them is that:
|
||||
* Custom data are stored in a generic quick access area reserved for the user
|
||||
and which the library will never use under any circumstances.
|
||||
|
||||
In all cases, this support is currently available only for meta-types, meta-data
|
||||
In all cases, this support is currently available only for meta types, meta data
|
||||
and meta functions.
|
||||
|
||||
### Traits
|
||||
@@ -863,14 +863,14 @@ User-defined traits are set via a meta factory:
|
||||
entt::meta_factory<my_type>{}.traits(my_traits::required | my_traits::hidden);
|
||||
```
|
||||
|
||||
In the example above, `EnTT` bitmask enum support is used, but any integral value
|
||||
is fine, as long as it does not exceed 16 bits.<br/>
|
||||
It is not possible to assign traits at different times. Therefore, multiple calls
|
||||
to the `traits` function overwrite previous values. However, traits can be read
|
||||
from meta-objects and used to update existing data with a factory, effectively
|
||||
extending them as needed.<br/>
|
||||
Likewise, users can also set traits on meta-objects later if needed, as long as
|
||||
the factory is reset to the meta-object of interest:
|
||||
In the example above, `EnTT` bitmask enum support is used, but any integral
|
||||
value is fine, as long as it does not exceed 16 bits.<br/>
|
||||
It is not possible to assign traits at different times. Therefore, multiple
|
||||
calls to the `traits` function overwrite previous values. However, traits can be
|
||||
read from meta objects and used to update existing data with a factory,
|
||||
effectively extending them as needed.<br/>
|
||||
Likewise, users can also set traits on meta objects later if needed, as long as
|
||||
the factory is reset to the meta object of interest:
|
||||
|
||||
```cpp
|
||||
entt::meta_factory<my_type>{}
|
||||
@@ -878,7 +878,7 @@ entt::meta_factory<my_type>{}
|
||||
.traits(my_traits::internal);
|
||||
```
|
||||
|
||||
Once created, all meta-objects offer a member function named `traits` to get the
|
||||
Once created, all meta objects offer a member function named `traits` to get the
|
||||
currently set value:
|
||||
|
||||
```cpp
|
||||
@@ -891,7 +891,7 @@ correctly.
|
||||
|
||||
### Custom data
|
||||
|
||||
Custom arbitrary data are set via a meta-factory:
|
||||
Custom arbitrary data are set via a meta factory:
|
||||
|
||||
```cpp
|
||||
entt::meta_factory<my_type>{}.custom<type_data>("name");
|
||||
@@ -901,10 +901,10 @@ The way to do this is by specifying the data type to the `custom` function and
|
||||
passing the necessary arguments to construct it correctly.<br/>
|
||||
It is not possible to assign custom data at different times. Therefore, multiple
|
||||
calls to the `custom` function overwrite previous values. However, this value
|
||||
can be read from meta-objects and used to update existing data with a factory,
|
||||
can be read from meta objects and used to update existing data with a factory,
|
||||
effectively updating them as needed.<br/>
|
||||
Likewise, users can also set custom data on meta-objects later if needed, as
|
||||
long as the factory is reset to the meta-object of interest:
|
||||
Likewise, users can also set custom data on meta objects later if needed, as
|
||||
long as the factory is reset to the meta object of interest:
|
||||
|
||||
```cpp
|
||||
entt::meta_factory<my_type>{}
|
||||
@@ -912,7 +912,7 @@ entt::meta_factory<my_type>{}
|
||||
.custom<function_data>("tooltip");
|
||||
```
|
||||
|
||||
Once created, all meta-objects offer a member function named `custom` to get the
|
||||
Once created, all meta objects offer a member function named `custom` to get the
|
||||
currently set value as a reference or as a pointer to an element:
|
||||
|
||||
```cpp
|
||||
@@ -930,8 +930,8 @@ 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 are not unregistered as well, since they do not
|
||||
necessarily depend on it.<br/>
|
||||
Roughly speaking, unregistering a type means disconnecting all associated
|
||||
meta-objects from it and making its identifier no longer available:
|
||||
Roughly speaking, unregistering a type means disconnecting all associated meta
|
||||
objects from it and making its identifier no longer available:
|
||||
|
||||
```cpp
|
||||
entt::meta_reset<my_type>();
|
||||
@@ -944,7 +944,7 @@ entt::meta_reset("my_type"_hs);
|
||||
```
|
||||
|
||||
Finally, there exists a non-template overload of the `meta_reset` function that
|
||||
does not accept arguments and resets all meta-types at once:
|
||||
does not accept arguments and resets all meta types at once:
|
||||
|
||||
```cpp
|
||||
entt::meta_reset();
|
||||
@@ -954,7 +954,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
|
||||
All meta types and their parts are created at runtime and stored in a default
|
||||
_context_. This is obtained via a service locator as:
|
||||
|
||||
```cpp
|
||||
@@ -971,12 +971,12 @@ std::swap(context, other);
|
||||
```
|
||||
|
||||
This is useful for testing purposes or to define multiple context objects with
|
||||
different meta-types to use as appropriate.
|
||||
different meta types to use as appropriate.
|
||||
|
||||
If _replacing_ the default context is not enough, `EnTT` also offers the ability
|
||||
to use multiple and externally managed contexts with the runtime reflection
|
||||
system.<br/>
|
||||
For example, to create new meta-types within a context other than the default
|
||||
For example, to create new meta types within a context other than the default
|
||||
one, simply pass it as an argument to the `meta_factory` constructor:
|
||||
|
||||
```cpp
|
||||
@@ -984,7 +984,7 @@ entt::meta_ctx context{};
|
||||
entt::meta_factory<my_type>{context}.type("reflected_type"_hs);
|
||||
```
|
||||
|
||||
By doing so, the new meta-type is not available in the default context but is
|
||||
By doing so, the new meta type is not 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:
|
||||
|
||||
@@ -992,7 +992,7 @@ new `meta_any` object:
|
||||
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,
|
||||
Similarly, to search for meta types in a context other than the default one,
|
||||
it is necessary to pass it to the `resolve` function:
|
||||
|
||||
```cpp
|
||||
@@ -1002,8 +1002,8 @@ entt::meta_type type = entt::resolve(context, "reflected_type"_hs)
|
||||
More generally, when using externally managed contexts, it is always required to
|
||||
provide the system with the context to use, at least at the _entry point_.<br/>
|
||||
For example, once the `meta_type` instant is obtained, it is no longer necessary
|
||||
to pass the context around as the meta-type takes the information with it and
|
||||
to pass the context around as the meta type takes the information with it and
|
||||
eventually propagates it to all its parts.<br/>
|
||||
On the other hand, it is necessary to instruct the library on where meta-types
|
||||
On the other hand, it is necessary to instruct the library on where meta types
|
||||
are to be fetched when `meta_any`s and `meta_handle`s are constructed, a factory
|
||||
created or a meta-type resolved.
|
||||
created or a meta type resolved.
|
||||
|
||||
@@ -253,8 +253,8 @@ in appending the new functions to the previous list.
|
||||
|
||||
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 is useful to declare a function that allows to convert a _concept_
|
||||
into its underlying `type_list` object:
|
||||
To do this, it is useful to declare a function that allows to convert a
|
||||
_concept_ into its underlying `type_list` object:
|
||||
|
||||
```cpp
|
||||
template<typename... Type>
|
||||
@@ -320,7 +320,8 @@ drawable other = instance.as_ref();
|
||||
```
|
||||
|
||||
In both cases, although the interface of the `poly` object does not change, it
|
||||
does not construct any element or take care of destroying the referenced objects.
|
||||
does not 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/>
|
||||
@@ -342,9 +343,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, and by default such that it is
|
||||
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
|
||||
is the most stringent (the largest) for any object whose size is at most equal
|
||||
to the one provided.<br/>
|
||||
It is 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.
|
||||
|
||||
@@ -22,8 +22,8 @@ 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 is not required to define a function unless the derived class wants
|
||||
to _override_ the default behavior):
|
||||
(note that it is not required to define a function unless the derived class
|
||||
wants to _override_ the default behavior):
|
||||
|
||||
* `void update(Delta, void *);`
|
||||
|
||||
@@ -36,8 +36,8 @@ to _override_ the default behavior):
|
||||
* `void init();`
|
||||
|
||||
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 is a
|
||||
top level one, otherwise when it replaces its parent if it is a _continuation_.
|
||||
happens usually when the process is attached to the scheduler if it is a top
|
||||
level one, or when it replaces its parent if it is a _continuation_.
|
||||
|
||||
* `void succeeded();`
|
||||
|
||||
@@ -87,8 +87,8 @@ private:
|
||||
|
||||
## Adaptor
|
||||
|
||||
Lambdas and functors cannot be used directly with a scheduler because they are not
|
||||
properly defined processes with managed life cycles.<br/>
|
||||
Lambdas and functors cannot be used directly with a scheduler because they are
|
||||
not 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.
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@ I hope the following lists can grow much more in the future.
|
||||
|
||||
# Similar projects
|
||||
|
||||
Below an incomplete list of similar projects that I have come across so far.<br/>
|
||||
Below an incomplete list of similar projects that I have come across so
|
||||
far.<br/>
|
||||
If some terms or designs are not clear, I recommend referring to the
|
||||
[_ECS Back and Forth_](https://skypjack.github.io/tags/#ecs) series for all the
|
||||
details.
|
||||
@@ -56,7 +57,7 @@ details.
|
||||
* [Massive ECS](https://github.com/nilpunch/massive): sparse set based ECS
|
||||
featuring rollbacks.
|
||||
* [Svelto.ECS](https://github.com/sebas77/Svelto.ECS): a very interesting
|
||||
platform-agnostic- and table-based ECS framework.
|
||||
platform-agnostic and table-based ECS framework.
|
||||
|
||||
* Go:
|
||||
* [gecs](https://github.com/tutumagi/gecs): a sparse sets based ECS inspired
|
||||
|
||||
@@ -31,7 +31,8 @@ The _resource_ is an image, an audio, a video or any other type:
|
||||
struct my_resource { const int value; };
|
||||
```
|
||||
|
||||
The _loader_ is a callable type, the aim of which is to load a specific resource:
|
||||
The _loader_ is a callable type, the aim of which is to load a specific
|
||||
resource:
|
||||
|
||||
```cpp
|
||||
struct my_loader final {
|
||||
@@ -68,8 +69,8 @@ discarded when a player leaves it.
|
||||
|
||||
## Resource handle
|
||||
|
||||
Resources are not returned directly to the caller. Instead, they are wrapped in a
|
||||
_resource handle_, an instance of the `entt::resource` class template.<br/>
|
||||
Resources are not returned directly to the caller. Instead, they are wrapped in
|
||||
a _resource handle_, an instance of the `entt::resource` class template.<br/>
|
||||
For those who know the _flyweight design pattern_ already, that is exactly what
|
||||
it is. To all others, this is the time to brush up on some notions instead.
|
||||
|
||||
@@ -98,8 +99,8 @@ When using the default handle, it expects a resource type which is convertible
|
||||
to or suitable for constructing an `std::shared_ptr<Type>` (where `Type` is the
|
||||
actual resource type).<br/>
|
||||
In other terms, the loader should return shared pointers to the given resource
|
||||
type. However, this is not mandatory. Users can easily get around this constraint
|
||||
by specializing both the handle and the loader.
|
||||
type. However, this is not mandatory. Users can easily get around this
|
||||
constraint by specializing both the handle and the loader.
|
||||
|
||||
A cache forwards all its arguments to the loader if required. This means that
|
||||
loaders can also support tag dispatching to offer different loading policies:
|
||||
@@ -158,9 +159,9 @@ functions (such as `contains` or `erase`).
|
||||
Set aside the part of the API that this class _shares_ with a map, it also adds
|
||||
something on top of it in order to address the most common requirements of a
|
||||
resource cache.<br/>
|
||||
In particular, it does not have an `emplace` member function which is replaced by
|
||||
`load` and `force_load` instead (where the former loads a new resource only if
|
||||
not present while the second triggers a forced loading in any case):
|
||||
In particular, it does not have an `emplace` member function which is replaced
|
||||
by `load` and `force_load` instead (where the former loads a new resource only
|
||||
if not present while the second triggers a forced loading in any case):
|
||||
|
||||
```cpp
|
||||
auto ret = cache.load("resource/id"_hs);
|
||||
@@ -181,5 +182,5 @@ operators return resource handles rather than instances of the mapped type.<br/>
|
||||
Since the cache has no control over the loader and a resource is not required to
|
||||
also be convertible to bool, these handles can be invalid. This usually means an
|
||||
error in the user logic, but it may also be an _expected_ event.<br/>
|
||||
It is therefore recommended to verify handles validity with a check in debug (for
|
||||
example, when loading) or an appropriate logic in retail.
|
||||
It is therefore recommended to verify handles validity with a check in debug
|
||||
(for example, when loading) or an appropriate logic in retail.
|
||||
|
||||
@@ -476,8 +476,8 @@ parameter for it but rather a different function:
|
||||
dispatcher.enqueue_hint<an_event>("custom"_hs, 42);
|
||||
```
|
||||
|
||||
This is mainly due to the template argument deduction rules, and unfortunately,
|
||||
there is no real (elegant) way to avoid it.
|
||||
This is mainly due to the template argument deduction rules, and there is no
|
||||
real (elegant) way to avoid it.
|
||||
|
||||
# Event emitter
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ this point, C++17 support should be in place.<br/>
|
||||
Try to compile the project to ensure it works as expected before following
|
||||
further steps.
|
||||
|
||||
Note that updating a *project* to C++17 does not necessarily mean that the IDE in
|
||||
use will also start to recognize its syntax.<br/>
|
||||
Note that updating a *project* to C++17 does not necessarily mean that the IDE
|
||||
in use will also start to recognize its syntax.<br/>
|
||||
If the plan is to use C++17 in the project too, check the specific instructions
|
||||
for the IDE in use.
|
||||
|
||||
@@ -62,8 +62,8 @@ Source
|
||||
\---entt (GitHub repository content inside)
|
||||
```
|
||||
|
||||
To make this happen, create the folder `ThirdParty` under `Source` if it does not
|
||||
exist already. Then, add an `EnTT` folder under `ThirdParty`.<br/>
|
||||
To make this happen, create the folder `ThirdParty` under `Source` if it does
|
||||
not exist already. Then, add an `EnTT` folder under `ThirdParty`.<br/>
|
||||
Within the latter, create a new file `EnTT.Build.cs` with the following content:
|
||||
|
||||
```cs
|
||||
|
||||
Reference in New Issue
Block a user