doc: review/cleanup entity.md a bit (done)
This commit is contained in:
@@ -43,8 +43,8 @@
|
||||
* [One example to rule them all](#one-example-to-rule-them-all)
|
||||
* [Views and Groups](#views-and-groups)
|
||||
* [Views](#views)
|
||||
* [Iteration order](#iteration-order)
|
||||
* [View pack](#view-pack)
|
||||
* [Iteration order](#iteration-order)
|
||||
* [Runtime views](#runtime-views)
|
||||
* [Groups](#groups)
|
||||
* [Full-owning groups](#full-owning-groups)
|
||||
@@ -1112,8 +1112,8 @@ if(entt::type_id<velocity>() == base.type()) {
|
||||
```
|
||||
|
||||
Furthermore, all features rely on internal functions that forward the calls to
|
||||
the mixins. The latter can then make use of any information, which can be set
|
||||
via `bind`:
|
||||
the mixins. The latter can then make use of any information, which is set via
|
||||
`bind`:
|
||||
|
||||
```cpp
|
||||
base.bind(entt::forward_as_any(registry));
|
||||
@@ -1192,8 +1192,8 @@ _reach_ manually created ones:
|
||||
registry.destroy(entity);
|
||||
```
|
||||
|
||||
Finally, a storage of this type can be used with any view (which also accepts
|
||||
multiple storages of the same type, if necessary):
|
||||
Finally, a storage of this type works with any view (which also accepts multiple
|
||||
storages of the same type, if necessary):
|
||||
|
||||
```cpp
|
||||
// direct initialization
|
||||
@@ -1415,27 +1415,17 @@ everything back to the registry with different loaders.
|
||||
|
||||
# Views and Groups
|
||||
|
||||
First of all, it's worth answering a question: why views and groups?<br/>
|
||||
Briefly, they're a good tool to enforce single responsibility. A system that has
|
||||
access to a registry can create and destroy entities, as well as assign and
|
||||
remove components. On the other side, a system that has access to a view or a
|
||||
group can only iterate, read and update entities and components.<br/>
|
||||
It is a subtle difference that can help designing a better software sometimes.
|
||||
|
||||
More in details:
|
||||
|
||||
* Views are a non-intrusive tool to access entities and components without
|
||||
affecting other functionalities or increasing the memory consumption.
|
||||
|
||||
* Groups are an intrusive tool that allows to reach higher performance along
|
||||
critical paths but has also a price to pay for that.
|
||||
Views are a non-intrusive tool for working with entities and components without
|
||||
affecting other functionalities or increasing memory consumption.<br/>
|
||||
Groups are an intrusive tool to use to improve performance along critical paths
|
||||
but which also has a price to pay for that.
|
||||
|
||||
There are mainly two kinds of views: _compile-time_ (also known as `view`) and
|
||||
runtime (also known as `runtime_view`).<br/>
|
||||
The former requires a compile-time list of component types and can make several
|
||||
optimizations because of that. The latter can be constructed at runtime instead
|
||||
using numerical type identifiers and are a bit slower to iterate.<br/>
|
||||
In both cases, creating and destroying a view isn't expensive at all since they
|
||||
The former requires a compile-time list of component (or storage) types and can
|
||||
make several optimizations because of that. The latter is constructed at runtime
|
||||
using numerical type identifiers instead and is a bit slower to iterate.<br/>
|
||||
In both cases, creating and destroying views isn't expensive at all since they
|
||||
don't have any type of initialization.
|
||||
|
||||
Groups come in three different flavors: _full-owning groups_, _partial-owning
|
||||
@@ -1444,39 +1434,33 @@ performance.<br/>
|
||||
Groups can literally _own_ one or more component types. They are allowed to
|
||||
rearrange pools so as to speed up iterations. Roughly speaking: the more
|
||||
components a group owns, the faster it is to iterate them.<br/>
|
||||
A given component can belong to multiple groups only if they are _nested_, so
|
||||
users have to define groups carefully to get the best out of them.
|
||||
A given component can belong to multiple groups only if they are _nested_. Users
|
||||
have to define groups carefully to get the best out of them.
|
||||
|
||||
## Views
|
||||
|
||||
A view behaves differently if it's constructed for a single component or if it
|
||||
has been created to iterate multiple components. Even the API is slightly
|
||||
different in the two cases.
|
||||
Single type views and multi type views behave differently and also have slightly
|
||||
different APIs.
|
||||
|
||||
Single type views are specialized to give a boost in terms of performance in all
|
||||
the situations. This kind of views can access the underlying data structures
|
||||
directly and avoid superfluous checks. There is nothing as fast as a single type
|
||||
view. In fact, they walk through a packed (actually paged) array of components
|
||||
and return them one at a time.<br/>
|
||||
Views also offer a bunch of functionalities to get the number of entities and
|
||||
components they are going to return. It's also possible to ask a view if it
|
||||
contains a given entity.<br/>
|
||||
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 allow to get 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 in
|
||||
their bags. During construction, these views look at the number of entities
|
||||
available for each component and pick up a reference to the smallest set of
|
||||
candidates in order to speed up iterations.<br/>
|
||||
They offer fewer functionalities than single type views. In particular, a multi
|
||||
type view exposes utility functions to get the estimated number of entities it
|
||||
is going to return and to know if it contains a given entity.<br/>
|
||||
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/>
|
||||
This kind of views only allow to get the estimated number of elements they are
|
||||
going to return.<br/>
|
||||
Refer to the inline documentation for all the details.
|
||||
|
||||
There is no need to store views aside as they are extremely cheap to construct.
|
||||
In fact, this is even discouraged when creating a view from a const registry.
|
||||
Since all storage are lazily initialized, they may not exist when the view is
|
||||
built. Therefore, the view itself will refer to an empty _placeholder_ and will
|
||||
never be re-assigned the actual storage.<br/>
|
||||
Storing aside views isn't required as they are extremely cheap to construct. In
|
||||
fact, this is even discouraged when creating a view from a const registry. Since
|
||||
all storage are lazily initialized, they may not exist when the view is created.
|
||||
Therefore, the view can refer to empty _placeholders_ and is never re-assigned
|
||||
the actual storage.<br/>
|
||||
In all cases, views return newly created and correctly initialized iterators for
|
||||
the storage they refer to when `begin` or `end` are invoked.
|
||||
|
||||
@@ -1539,8 +1523,8 @@ any case.
|
||||
|
||||
As a side note, in the case of single type views, `get` accepts but doesn't
|
||||
strictly require a template parameter, since the type is implicitly defined.
|
||||
However, when the type isn't specified, for consistency with the multi type
|
||||
view, the instance will be returned using a tuple:
|
||||
However, when the type isn't specified, the instance is returned using a tuple
|
||||
for consistency with multi type views:
|
||||
|
||||
```cpp
|
||||
auto view = registry.view<const renderable>();
|
||||
@@ -1554,10 +1538,31 @@ for(auto entity: view) {
|
||||
**Note**: prefer the `get` member function of a view instead of that of a
|
||||
registry during iterations to get the types iterated by the view itself.
|
||||
|
||||
### View pack
|
||||
|
||||
Views are combined with each other to create new and more specific queries.<br/>
|
||||
The type returned when combining multiple views together is itself a view, more
|
||||
in general a multi component one.
|
||||
|
||||
Combining different views tries to mimic C++20 ranges:
|
||||
|
||||
```cpp
|
||||
auto view = registry.view<position>();
|
||||
auto other = registry.view<velocity>();
|
||||
|
||||
auto pack = view | other;
|
||||
```
|
||||
|
||||
The constness of the types is preserved and their order depends on the order in
|
||||
which the views are combined. For example, the pack above returns an instance of
|
||||
`position` first and then one of `velocity`.<br/>
|
||||
Since combining views generates views, a chain can be of arbitrary length and
|
||||
the above type order rules apply sequentially.
|
||||
|
||||
### Iteration order
|
||||
|
||||
By default, a view is iterated along the pool that contains the smallest number
|
||||
of components.<br/>
|
||||
of elements.<br/>
|
||||
For example, if the registry contains fewer `velocity`s than it contains
|
||||
`position`s, then the order of the elements returned by the following view
|
||||
depends on how the `velocity` components are arranged in their pool:
|
||||
@@ -1594,39 +1599,14 @@ Unfortunately, multi type views don't offer reverse iterators. Therefore, in
|
||||
this case it's a must to implement this functionality manually or to use single
|
||||
type views to lead the iteration.
|
||||
|
||||
### View pack
|
||||
|
||||
Views are combined with each other to create new and more specific types.<br/>
|
||||
The type returned when combining multiple views together is itself a view, more
|
||||
in general a multi component one.
|
||||
|
||||
Combining different views tries to mimic C++20 ranges:
|
||||
|
||||
```cpp
|
||||
auto view = registry.view<position>();
|
||||
auto other = registry.view<velocity>();
|
||||
|
||||
auto pack = view | other;
|
||||
```
|
||||
|
||||
The constness of the types is preserved and their order depends on the order in
|
||||
which the views are combined. Therefore, the pack in the example above will
|
||||
return an instance of `position` first and then one of `velocity`.<br/>
|
||||
Since combining views generates views, a chain can be of arbitrary length and
|
||||
the above type order rules apply sequentially.
|
||||
|
||||
### Runtime views
|
||||
|
||||
Runtime views iterate entities that have at least all the given components in
|
||||
their bags. During construction, these views look at the number of entities
|
||||
available for each component and pick up a reference to the smallest set of
|
||||
candidates in order to speed up iterations.<br/>
|
||||
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 don't expose a `get` member function and users should refer to the registry
|
||||
that generated the view to access components. In particular, a runtime view
|
||||
exposes utility functions to get the estimated number of entities it is going to
|
||||
return and to know whether it's empty or not. It's also possible to ask a
|
||||
runtime view if it contains a given entity.<br/>
|
||||
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
|
||||
@@ -1671,7 +1651,7 @@ useful in this regard.
|
||||
Groups are meant to iterate multiple components at once and to offer a faster
|
||||
alternative to multi type views.<br/>
|
||||
Groups overcome the performance of the other tools available but require to get
|
||||
the ownership of components. This sets some constraints on the pools. On the
|
||||
the ownership of components. This sets some constraints on their pools. On the
|
||||
other hand, groups aren't an automatism that increases memory consumption,
|
||||
affects functionalities and tries to optimize iterations for all the possible
|
||||
combinations of components. Users can decide when to pay for groups and to what
|
||||
@@ -1691,24 +1671,19 @@ avoided as long as possible.
|
||||
All groups affect to an extent the creation and destruction of their components.
|
||||
This is due to the fact that they must _observe_ changes in the pools of
|
||||
interest and arrange data _correctly_ when needed for the types they own.<br/>
|
||||
That being said, the way groups operate is beyond the scope of this document.
|
||||
However, it's unlikely that users will be able to appreciate the impact of
|
||||
groups on the other functionalities of a registry.
|
||||
|
||||
Groups offer a bunch of functionalities to get the number of entities and
|
||||
components they are going to return. It's also possible to ask a group if it
|
||||
contains a given entity.<br/>
|
||||
In all cases, a group allows to get the exact number of elements it's going to
|
||||
return.<br/>
|
||||
Refer to the inline documentation for all the details.
|
||||
|
||||
There is no need to store groups aside for they are extremely cheap to create,
|
||||
even though valid groups can be copied without problems and reused freely.<br/>
|
||||
Storing aside groups isn't required as they are extremely cheap to create, even
|
||||
though valid groups can be copied without problems and reused freely.<br/>
|
||||
A group performs an initialization step the very first time it's requested and
|
||||
this could be quite costly. To avoid it, consider creating the group when no
|
||||
components have been assigned yet. If the registry is empty, preparation is
|
||||
extremely fast. Groups also return newly created and correctly initialized
|
||||
iterators whenever `begin` or `end` are invoked.
|
||||
|
||||
To iterate groups, either use them in a range-for loop:
|
||||
To iterate a group, either use it in a range-for loop:
|
||||
|
||||
```cpp
|
||||
auto group = registry.group<position>(entt::get<velocity, renderable>);
|
||||
@@ -1756,9 +1731,10 @@ registry during iterations to get the types iterated by the group itself.
|
||||
|
||||
A full-owning group is the fastest tool a user can expect to use to iterate
|
||||
multiple components at once. It iterates all the components directly, no
|
||||
indirection required. This type of groups performs more or less as if users are
|
||||
accessing sequentially a bunch of packed arrays of components all sorted
|
||||
identically, with no jumps nor branches.
|
||||
indirection required.<br/>
|
||||
This type of groups performs more or less as if users are accessing sequentially
|
||||
a bunch of packed arrays of components all sorted identically, with no jumps nor
|
||||
branches.
|
||||
|
||||
A full-owning group is created as:
|
||||
|
||||
@@ -1776,15 +1752,15 @@ Once created, the group gets the ownership of all the components specified in
|
||||
the template parameter list and arranges their pools as needed.
|
||||
|
||||
Sorting owned components is no longer allowed once the group has been created.
|
||||
However, full-owning groups can be sorted by means of their `sort` member
|
||||
functions. Sorting a full-owning group affects all its instances.
|
||||
However, full-owning groups are sorted using their `sort` member functions.
|
||||
Sorting a full-owning group affects all its instances.
|
||||
|
||||
### Partial-owning groups
|
||||
|
||||
A partial-owning group works similarly to a full-owning group for the components
|
||||
it owns, but relies on indirection to get components owned by other groups. This
|
||||
isn't as fast as a full-owning group, but it's already much faster than views
|
||||
when there are only one or two free components to retrieve (the most common
|
||||
it owns, but relies on indirection to get components owned by other groups.<br/>
|
||||
This isn't as fast as a full-owning group, but it's already much faster than a
|
||||
view when there are only one or two free components to retrieve (the most common
|
||||
cases likely). In the worst case, it's not slower than views anyway.
|
||||
|
||||
A partial-owning group is created as:
|
||||
@@ -1804,15 +1780,15 @@ the template parameter list and arranges their pools as needed. The ownership of
|
||||
the types provided via `entt::get` doesn't pass to the group instead.
|
||||
|
||||
Sorting owned components is no longer allowed once the group has been created.
|
||||
However, partial-owning groups can be sorted by means of their `sort` member
|
||||
functions. Sorting a partial-owning group affects all its instances.
|
||||
However, partial-owning groups are sorted using their `sort` member functions.
|
||||
Sorting a partial-owning group affects all its instances.
|
||||
|
||||
### Non-owning groups
|
||||
|
||||
Non-owning groups are usually fast enough, for sure faster than views and well
|
||||
suited for most of the cases. However, they require custom data structures to
|
||||
work properly and they increase memory consumption. As a rule of thumb, users
|
||||
should avoid using non-owning groups, if possible.
|
||||
work properly and they increase memory consumption.<br/>
|
||||
As a rule of thumb, users should avoid using non-owning groups, if possible.
|
||||
|
||||
A non-owning group is created as:
|
||||
|
||||
@@ -1830,8 +1806,8 @@ The group doesn't receive the ownership of any type of component in this
|
||||
case. This type of groups is therefore the least performing in general, but also
|
||||
the only one that can be used in any situation to slightly improve performance.
|
||||
|
||||
Non-owning groups can be sorted by means of their `sort` member functions.
|
||||
Sorting a non-owning group affects all its instances.
|
||||
Non-owning groups are sorted using their `sort` member functions. Sorting a
|
||||
non-owning group affects all its instances.
|
||||
|
||||
### Nested groups
|
||||
|
||||
@@ -1853,8 +1829,7 @@ Two nested groups are such that they own at least one component type and the lis
|
||||
of component types involved by one of them is contained entirely in that of the
|
||||
other. More specifically, this applies independently to all component lists used
|
||||
to define a group.<br/>
|
||||
Therefore, the rules for defining whether two or more groups are nested can be
|
||||
summarized as:
|
||||
Therefore, the rules for defining whether two or more groups are nested is:
|
||||
|
||||
* One of the groups involves one or more additional component types with respect
|
||||
to the other, whether they are owned, observed or excluded.
|
||||
@@ -1863,8 +1838,8 @@ summarized as:
|
||||
contains entirely that of the others. This also applies to the list of
|
||||
observed and excluded components.
|
||||
|
||||
It means that nested groups _extend_ their parents by adding more conditions in
|
||||
the form of new components.
|
||||
This means that nested groups _extend_ their parents by adding more conditions
|
||||
in the form of new components.
|
||||
|
||||
As mentioned, the components don't necessarily have to be all _owned_ so that
|
||||
two groups can be considered nested. The following definitions are fully valid:
|
||||
@@ -1888,12 +1863,10 @@ They are treated as if users were defining the following groups:
|
||||
Where `not_rotation` is an empty tag present only when `rotation` is not.
|
||||
|
||||
Because of this, to define a new group that is more restrictive than an existing
|
||||
one, it's enough to take the list of component types of the latter and extend it
|
||||
by adding new component types either owned, observed or excluded, without any
|
||||
precautions depending on the case.<br/>
|
||||
The opposite is also true. To define a _larger_ group, it will be enough to take
|
||||
an existing one and remove _constraints_ from it, in whatever form they are
|
||||
expressed.<br/>
|
||||
one, it's enough to extend the component list of another group by adding new
|
||||
types that are either owned, observed or excluded.<br/>
|
||||
The opposite is also true. To define a _larger_ group, it's enough to remove
|
||||
_constraints_ from its parent.<br/>
|
||||
Note that the greater the number of component types involved by a group, the
|
||||
more restrictive it is.
|
||||
|
||||
@@ -1911,7 +1884,7 @@ less restrictive ones and ordering the latter would invalidate the former.<br/>
|
||||
However, given a family of nested groups, it's still possible to sort the most
|
||||
restrictive of them. To prevent users from having to remember which of their
|
||||
groups is the most restrictive, the registry class offers the `sortable` member
|
||||
function to know if a group can be sorted or not.
|
||||
function to know if a group supports sorting it or not.
|
||||
|
||||
## Types: const, non-const and all in between
|
||||
|
||||
@@ -1919,8 +1892,8 @@ The `registry` class offers two overloads when it comes to constructing views
|
||||
and groups: a const version and a non-const one. The former accepts only const
|
||||
types as template parameters, the latter accepts both const and non-const types
|
||||
instead.<br/>
|
||||
It means that views and groups can be constructed from a const registry and they
|
||||
propagate the constness of the registry to the types involved. As an example:
|
||||
It means that views and groups generated by a const registry also propagate the
|
||||
constness to the types involved. As an example:
|
||||
|
||||
```cpp
|
||||
entt::view<const position, const velocity> view = std::as_const(registry).view<const position, const velocity>();
|
||||
@@ -1932,7 +1905,7 @@ Consider the following definition for a non-const view instead:
|
||||
entt::view<position, const velocity> view = registry.view<position, const velocity>();
|
||||
```
|
||||
|
||||
In the example above, `view` can be used to access either read-only or writable
|
||||
In the example above, `view` is used to access either read-only or writable
|
||||
`position` components while `velocity` components are read-only in all
|
||||
cases.<br/>
|
||||
Similarly, these statements are all valid:
|
||||
@@ -1946,7 +1919,7 @@ std::tuple<const position &, const velocity &> ctup = view.get<const position, c
|
||||
```
|
||||
|
||||
It's not possible to get non-const references to `velocity` components from the
|
||||
same view instead and these will result in compilation errors:
|
||||
same view instead. Therefore, these result in compilation errors:
|
||||
|
||||
```cpp
|
||||
velocity &cpos = view.get<velocity>(entity);
|
||||
@@ -1998,7 +1971,7 @@ registry.each([®istry](auto entity) {
|
||||
|
||||
In general, iterating all entities can result in poor performance. It should not
|
||||
be done frequently to avoid the risk of a performance hit.<br/>
|
||||
However, it can be convenient when initializing an editor or to reclaim pending
|
||||
However, it's convenient when initializing an editor or to reclaim pending
|
||||
identifiers.
|
||||
|
||||
## What is allowed and what is not
|
||||
@@ -2065,16 +2038,16 @@ nature and the scope of the groups, it isn't something in which it will happen
|
||||
to come across probably, but it's good to know it anyway.
|
||||
|
||||
First of all, it must be said that creating components while iterating a group
|
||||
isn't a problem at all and can be done freely as it happens with the views. The
|
||||
same applies to the destruction of components and entities, for which the rules
|
||||
isn't 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 pops out instead when a given component that is owned
|
||||
by a group is iterated outside of it. In this case, adding components that are
|
||||
part of the group itself may invalidate the iterators. There are no further
|
||||
The additional limitation arises instead when a given component that is owned by
|
||||
a group is iterated outside of it. In this case, adding components that are part
|
||||
of the group itself may invalidate the iterators. There are no further
|
||||
limitations to the destruction of components and entities.<br/>
|
||||
Fortunately, this isn't always true. In fact, it almost never is and this
|
||||
happens only under certain conditions. In particular:
|
||||
Fortunately, this isn't always true. In fact, it almost never is and only
|
||||
happens under certain conditions. In particular:
|
||||
|
||||
* Iterating a type of component that is part of a group with a single type view
|
||||
and adding to an entity all the components required to get it into the group
|
||||
@@ -2105,8 +2078,8 @@ mentioning.
|
||||
|
||||
When an empty type is detected, it's not instantiated by default. Therefore,
|
||||
only the entities to which it's assigned are made available. There doesn't exist
|
||||
a way to _get_ empty types from a registry. Views and groups will never return
|
||||
their instances (for example, during a call to `each`).<br/>
|
||||
a way to _get_ empty types from a registry. Views and groups never return their
|
||||
instances (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 doesn't exist any instance of the component, no matter how many entities
|
||||
@@ -2131,8 +2104,8 @@ 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
|
||||
safely do the same with components `Y` and `Z` and everything will work like a
|
||||
charm. As a trivial example, users can freely execute the rendering system and
|
||||
safely do the same with components `Y` and `Z` and everything work like just
|
||||
fine. As a trivial example, users can freely execute the rendering system and
|
||||
iterate the renderable entities while updating a physic component concurrently
|
||||
on a separate thread.
|
||||
|
||||
@@ -2153,9 +2126,9 @@ are completely responsible for synchronization whether required. On the other
|
||||
hand, they could get away with it without having to resort to particular
|
||||
expedients.
|
||||
|
||||
Finally, `EnTT` can be configured via a few compile-time definitions to make
|
||||
some of its parts implicitly thread-safe, roughly speaking only the ones that
|
||||
really make sense and can't be turned around.<br/>
|
||||
Finally, `EnTT` is configured via a few compile-time definitions to make some of
|
||||
its parts implicitly thread-safe, roughly speaking only the ones that really
|
||||
make sense and can't be turned around.<br/>
|
||||
In particular, when multiple instances of objects referencing the type index
|
||||
generator (such as the `registry` class) are used in different threads, then it
|
||||
might be useful to define `ENTT_USE_ATOMIC`.<br/>
|
||||
@@ -2169,7 +2142,7 @@ they meet at least the requirements of forward iterators.<br/>
|
||||
In other terms, they are suitable for use with the parallel algorithms of the
|
||||
standard library. If it's not clear, this is a great thing.
|
||||
|
||||
As an example, this kind of iterators can be used in combination with
|
||||
As an example, this kind of iterators are used in combination with
|
||||
`std::for_each` and `std::execution::par` to parallelize the visit and therefore
|
||||
the update of the components returned by a view or a group, as long as the
|
||||
constraints previously discussed are respected:
|
||||
@@ -2196,7 +2169,7 @@ should even benefit from it further.
|
||||
|
||||
## Const registry
|
||||
|
||||
A const registry is also fully thread safe. This means that it won't be able to
|
||||
A const registry is also fully thread safe. This means that it's not able to
|
||||
lazily initialize a missing storage when a view is generated.<br/>
|
||||
The reason for this is easy to explain. To avoid requiring types to be
|
||||
_announced_ in advance, a registry lazily creates the storage objects for the
|
||||
@@ -2220,8 +2193,8 @@ Calling the `storage` method is equivalent to _announcing_ the existence of a
|
||||
particular storage, to avoid running into problems. For those interested, there
|
||||
are also alternative approaches, such as a single threaded tick for the registry
|
||||
warm-up, but these are not always applicable.<br/>
|
||||
In this case, no placeholders will be used since all storage exist. In other
|
||||
words, views never risk becoming _invalid_.
|
||||
In this case, no placeholders are used since all storage exist. In other words,
|
||||
views never risk becoming _invalid_.
|
||||
|
||||
# Beyond this document
|
||||
|
||||
|
||||
Reference in New Issue
Block a user