瀏覽代碼

doc: rearrange a few things

Michele Caini 2 年之前
父節點
當前提交
f1914fd946
共有 1 個文件被更改,包括 252 次插入252 次删除
  1. 252 252
      docs/md/entity.md

+ 252 - 252
docs/md/entity.md

@@ -12,7 +12,6 @@
   * [Pay per use](#pay-per-use)
   * [All or nothing](#all-or-nothing)
 * [Vademecum](#vademecum)
-* [Storage](#storage)
 * [The Registry, the Entity and the Component](#the-registry-the-entity-and-the-component)
   * [Observe changes](#observe-changes)
     * [Listeners disconnection](#listeners-disconnection)
@@ -29,18 +28,20 @@
     * [Organizer](#organizer)
   * [Context variables](#context-variables)
     * [Aliased properties](#aliased-properties)
-  * [Component traits](#component-traits)
-  * [Pointer stability](#pointer-stability)
-    * [In-place delete](#in-place-delete)
-    * [Hierarchies and the like](#hierarchies-and-the-like)
-  * [Meet the runtime](#meet-the-runtime)
-    * [A base class to rule them all](#a-base-class-to-rule-them-all)
-    * [Beam me up, registry](#beam-me-up-registry)
   * [Snapshot: complete vs continuous](#snapshot-complete-vs-continuous)
     * [Snapshot loader](#snapshot-loader)
     * [Continuous loader](#continuous-loader)
     * [Archives](#archives)
     * [One example to rule them all](#one-example-to-rule-them-all)
+* [Storage](#storage)
+  * [Component traits](#component-traits)
+  * [Empty type optimization](#empty-type-optimization)
+  * [Pointer stability](#pointer-stability)
+    * [In-place delete](#in-place-delete)
+    * [Hierarchies and the like](#hierarchies-and-the-like)
+* [Meet the runtime](#meet-the-runtime)
+  * [A base class to rule them all](#a-base-class-to-rule-them-all)
+  * [Beam me up, registry](#beam-me-up-registry)
 * [Views and Groups](#views-and-groups)
   * [Views](#views)
     * [View pack](#view-pack)
@@ -54,7 +55,6 @@
   * [Give me everything](#give-me-everything)
   * [What is allowed and what is not](#what-is-allowed-and-what-is-not)
     * [More performance, more constraints](#more-performance-more-constraints)
-* [Empty type optimization](#empty-type-optimization)
 * [Multithreading](#multithreading)
   * [Iterators](#iterators)
   * [Const registry](#const-registry)
@@ -142,20 +142,9 @@ of the `EnTT` library.<br/>
 This module is likely larger than what is described below. For more details,
 please refer to the inline documentation.
 
-# Storage
-
-Pools of components are a sort of _specialized version_ of a sparse set. Each
-pool contains all the instances of a single component type and all the entities
-to which it's assigned.<br/>
-Sparse arrays are _paged_ to avoid wasting memory. Packed arrays of components
-are also paged to have pointer stability upon additions. Packed arrays of
-entities are not instead.<br/>
-All pools rearranges their items in order to keep the internal arrays tightly
-packed and maximize performance, unless pointer stability is enabled.
-
 # The Registry, the Entity and the Component
 
-A registry stores and manages entities (or better, identifiers) and pools.<br/>
+A registry stores and manages entities (or _identifiers_) and components.<br/>
 The class template `basic_registry` lets users decide what the preferred type to
 represent an entity is. Because `std::uint32_t` is large enough for almost any
 case, there also exists the enum class `entt::entity` that _wraps_ it and the
@@ -965,9 +954,223 @@ const my_type &var = registry.ctx().get<const my_type>();
 Aliased properties are erased as it happens with any other variable. Similarly,
 it's also possible to assign them a _name_.
 
+## Snapshot: complete vs continuous
+
+This module comes with bare minimum support to serialization.<br/>
+It doesn't convert components to bytes directly, there wasn't the need of
+another tool for serialization out there. Instead, it accepts an opaque object
+with a suitable interface (namely an _archive_) to serialize its internal data
+structures and restore them later. The way types and instances are converted to
+a bunch of bytes is completely in charge to the archive and thus to final users.
+
+The goal of the serialization part is to allow users to make both a dump of the
+entire registry or a narrower snapshot, that is to select only the components in
+which they are interested.<br/>
+Intuitively, the use cases are different. As an example, the first approach is
+suitable for local save/restore functionalities while the latter is suitable for
+creating client-server applications and for transferring somehow parts of the
+representation side to side.
+
+To take a snapshot of a registry, use the `snapshot` class:
+
+```cpp
+output_archive output;
+
+entt::snapshot{registry}
+    .entities(output)
+    .component<a_component, another_component>(output);
+```
+
+It isn't necessary to invoke all functions each and every time. What functions
+to use in which case mostly depends on the goal.
+
+The `entities` member function makes the snapshot serialize all entities (both
+those still alive and those released) along with their versions.<br/>
+On the other hand, the `component` member function template is meant to store
+aside components.<br/>
+There exists also another version of the `component` member function that
+accepts a range of entities to serialize. This version is a bit slower than the
+other one, mainly because it iterates the range of entities more than once for
+internal purposes. However, it can be used to filter out those entities that
+shouldn't be serialized for some reasons:
+
+```cpp
+const auto view = registry.view<serialize>();
+output_archive output;
+
+entt::snapshot{registry}.component<a_component, another_component>(output, view.begin(), view.end());
+```
+
+Note that `component` stores items along with entities. It means that it works
+properly without a call to the `entities` member function.
+
+Once a snapshot is created, there exist mainly two _ways_ to load it: as a whole
+and in a kind of _continuous mode_.<br/>
+The following sections describe both loaders and archives in details.
+
+### Snapshot loader
+
+A snapshot loader requires that the destination registry be empty. It loads all
+the data at once while keeping intact the identifiers that the entities
+originally had:
+
+```cpp
+input_archive input;
+
+entt::snapshot_loader{registry}
+    .entities(input)
+    .component<a_component, another_component>(input)
+    .orphans();
+```
+
+It isn't necessary to invoke all functions each and every time. What functions
+to use in which case mostly depends on the goal.<br/>
+For obvious reasons, what is important is that the data are restored in exactly
+the same order in which they were serialized.
+
+The `entities` member function restores the sets of entities and the versions
+that they originally had at the source.<br/>
+The `component` member function restores all and only the components specified
+and assigns them to the right entities. The template parameter list must be the
+same used during the serialization.<br/>
+The `orphans` member function releases the entities that have no components, if
+any.
+
+### Continuous loader
+
+A continuous loader is designed to load data from a source registry to a
+(possibly) non-empty destination. The loader accommodates in a registry more
+than one snapshot in a sort of _continuous loading_ that updates the destination
+one step at a time.<br/>
+Identifiers that entities originally had are not transferred to the target.
+Instead, the loader maps remote identifiers to local ones while restoring a
+snapshot. Because of that, this kind of loader offers a way to update
+automatically identifiers that are part of components (as an example, as data
+members or gathered in a container).<br/>
+Another difference with the snapshot loader is that the continuous loader has an
+internal state that must persist over time. Therefore, there is no reason to
+limit its lifetime to that of a temporary object:
+
+```cpp
+entt::continuous_loader loader{registry};
+input_archive input;
+
+loader.entities(input)
+    .component<a_component, another_component, dirty_component>(input, &dirty_component::parent, &dirty_component::child)
+    .orphans()
+    .shrink();
+```
+
+It isn't necessary to invoke all functions each and every time. What functions
+to use in which case mostly depends on the goal.<br/>
+For obvious reasons, what is important is that the data are restored in exactly
+the same order in which they were serialized.
+
+The `entities` member function restores groups of entities and maps each entity
+to a local counterpart when required. For each remote entity identifier not yet
+registered by the loader, a local identifier is created so as to keep the local
+entity in sync with the remote one.<br/>
+The `component` member function restores all and only the components specified
+and assigns them to the right entities. In case the component contains entities
+itself (either as data members of type `entt::entity` or in a container), the
+loader can update them automatically. To do that, it's enough to specify the
+data members to update as shown in the example.<br/>
+The `orphans` member function releases the entities that have no components
+after a restore.<br/>
+Finally, `shrink` helps to purge local entities that no longer have a remote
+conterpart. Users should invoke this member function after restoring each
+snapshot, unless they know exactly what they are doing.
+
+### Archives
+
+Archives must publicly expose a predefined set of member functions. The API is
+straightforward and consists only of a group of function call operators that
+are invoked by the snapshot class and the loaders.
+
+In particular:
+
+* An output archive (the one used when creating a snapshot) exposes a function
+  call operator with the following signature to store entities:
+
+  ```cpp
+  void operator()(entt::entity);
+  ```
+
+  Where `entt::entity` is the type of the entities used by the registry.<br/>
+  Note that all member functions of the snapshot class also make an initial call
+  to store aside the _size_ of the set they are going to store. In this case,
+  the expected function type for the function call operator is:
+
+  ```cpp
+  void operator()(std::underlying_type_t<entt::entity>);
+  ```
+
+  In addition, an archive accepts a pair of entity and component for each type
+  to serialize. Therefore, given a type `T`, the archive offers a function call
+  operator with the following signature:
+
+  ```cpp
+  void operator()(entt::entity, const T &);
+  ```
+
+  The output archive can freely decide how to serialize the data. The registry
+  isn't affected at all by the decision.
+
+* An input archive (the one used when restoring a snapshot) exposes a function
+  call operator with the following signature to load entities:
+
+  ```cpp
+  void operator()(entt::entity &);
+  ```
+
+  Where `entt::entity` is the type of the entities used by the registry. Each
+  time the function is invoked, the archive reads the next element from the
+  underlying storage and copies it in the given variable.<br/>
+  All member functions of a loader class also make an initial call to read the
+  _size_ of the set they are going to load. In this case, the expected function
+  type for the function call operator is:
+
+  ```cpp
+  void operator()(std::underlying_type_t<entt::entity> &);
+  ```
+
+  In addition, the archive accepts a pair of references to an entity and its
+  component for each type to restore. Therefore, given a type `T`, the archive
+  contains a function call operator with the following signature:
+
+  ```cpp
+  void operator()(entt::entity &, T &);
+  ```
+
+  Every time this operator is invoked, the archive reads the next elements from
+  the underlying storage and copies them in the given variables.
+
+### One example to rule them all
+
+`EnTT` comes with some examples (actually some tests) that show how to integrate
+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 **isn't** production-ready and it isn't 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.
+
+# Storage
+
+Pools of components are _specialized versions_ of the sparse set class. Each
+pool contains all the instances of a single component type and all the entities
+to which it's assigned.<br/>
+Sparse arrays are _paged_ to avoid wasting memory. Packed arrays of components
+are also paged to have pointer stability upon additions. Packed arrays of
+entities are not instead.<br/>
+All pools rearranges their items in order to keep the internal arrays tightly
+packed and maximize performance, unless pointer stability is enabled.
+
 ## Component traits
 
-In `EnTT`, almost everything is customizable. Components are no exception.<br/>
+In `EnTT`, almost everything is customizable. Pools are no exception.<br/>
 In this case, the _standardized_ way to access all component properties is the
 `component_traits` class.
 
@@ -997,6 +1200,30 @@ The `component_traits` class template takes care of _extracting_ the properties
 from the supplied type.<br/>
 Plus, it's _sfinae-friendly_ and also supports feature-based specializations.
 
+## Empty type optimization
+
+An empty type `T` is such that `std::is_empty_v<T>` returns true. They also are
+the same types for which _empty base optimization_ (EBO) is possible.<br/>
+`EnTT` handles these types in a special way, optimizing both in terms of
+performance and memory usage. However, this also has consequences that are worth
+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 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 doesn't exist any instance of the component, no matter how many entities
+it is assigned to.
+
+More in general, none of the feature offered by the library is affected, but for
+the ones that require to return actual instances.<br/>
+This optimization is disabled by defining the `ENTT_NO_ETO` macro. In this case,
+empty types are treated like all other types. Setting a page size at component
+level via the `component_traits` class template is another way to disable this
+optimization selectively rather than globally.
+
 ## Pointer stability
 
 The ability to achieve pointer stability for one, several or all components is a
@@ -1071,7 +1298,7 @@ time and therefore fallback into adjacent positions, thus favoring locality even
 on random accesses. Locality that isn't sacrificed over time given the stability
 of storage positions, with undoubted performance advantages.
 
-## Meet the runtime
+# 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
@@ -1079,7 +1306,7 @@ techniques).<br/>
 To fill the gap, the library also provides a bunch of utilities and feature that
 are very useful to handle types and pools at runtime.
 
-### A base class to rule them all
+## A base class to rule them all
 
 Storage classes are fully self-contained types. They are _extended_ via mixins
 to add more functionalities (generic or type specific). In addition, they offer
@@ -1146,7 +1373,7 @@ This is particularly useful to clone entities in an opaque way. In addition, the
 decoupling of features allows for filtering or use of different copying policies
 depending on the type.
 
-### Beam me up, registry
+## Beam me up, registry
 
 `EnTT` allows the user to assign a _name_ (or rather, a numeric identifier) to a
 type and then create multiple pools of the same type:
@@ -1196,209 +1423,6 @@ The possibility of direct use of storage combined with the freedom of being able
 to create and use more than one of the same type opens the door to the use of
 `EnTT` _at runtime_, which was previously quite limited.
 
-## Snapshot: complete vs continuous
-
-This module comes with bare minimum support to serialization.<br/>
-It doesn't convert components to bytes directly, there wasn't the need of
-another tool for serialization out there. Instead, it accepts an opaque object
-with a suitable interface (namely an _archive_) to serialize its internal data
-structures and restore them later. The way types and instances are converted to
-a bunch of bytes is completely in charge to the archive and thus to final users.
-
-The goal of the serialization part is to allow users to make both a dump of the
-entire registry or a narrower snapshot, that is to select only the components in
-which they are interested.<br/>
-Intuitively, the use cases are different. As an example, the first approach is
-suitable for local save/restore functionalities while the latter is suitable for
-creating client-server applications and for transferring somehow parts of the
-representation side to side.
-
-To take a snapshot of a registry, use the `snapshot` class:
-
-```cpp
-output_archive output;
-
-entt::snapshot{registry}
-    .entities(output)
-    .component<a_component, another_component>(output);
-```
-
-It isn't necessary to invoke all functions each and every time. What functions
-to use in which case mostly depends on the goal.
-
-The `entities` member function makes the snapshot serialize all entities (both
-those still alive and those released) along with their versions.<br/>
-On the other hand, the `component` member function template is meant to store
-aside components.<br/>
-There exists also another version of the `component` member function that
-accepts a range of entities to serialize. This version is a bit slower than the
-other one, mainly because it iterates the range of entities more than once for
-internal purposes. However, it can be used to filter out those entities that
-shouldn't be serialized for some reasons:
-
-```cpp
-const auto view = registry.view<serialize>();
-output_archive output;
-
-entt::snapshot{registry}.component<a_component, another_component>(output, view.begin(), view.end());
-```
-
-Note that `component` stores items along with entities. It means that it works
-properly without a call to the `entities` member function.
-
-Once a snapshot is created, there exist mainly two _ways_ to load it: as a whole
-and in a kind of _continuous mode_.<br/>
-The following sections describe both loaders and archives in details.
-
-### Snapshot loader
-
-A snapshot loader requires that the destination registry be empty. It loads all
-the data at once while keeping intact the identifiers that the entities
-originally had:
-
-```cpp
-input_archive input;
-
-entt::snapshot_loader{registry}
-    .entities(input)
-    .component<a_component, another_component>(input)
-    .orphans();
-```
-
-It isn't necessary to invoke all functions each and every time. What functions
-to use in which case mostly depends on the goal.<br/>
-For obvious reasons, what is important is that the data are restored in exactly
-the same order in which they were serialized.
-
-The `entities` member function restores the sets of entities and the versions
-that they originally had at the source.<br/>
-The `component` member function restores all and only the components specified
-and assigns them to the right entities. The template parameter list must be the
-same used during the serialization.<br/>
-The `orphans` member function releases the entities that have no components, if
-any.
-
-### Continuous loader
-
-A continuous loader is designed to load data from a source registry to a
-(possibly) non-empty destination. The loader accommodates in a registry more
-than one snapshot in a sort of _continuous loading_ that updates the destination
-one step at a time.<br/>
-Identifiers that entities originally had are not transferred to the target.
-Instead, the loader maps remote identifiers to local ones while restoring a
-snapshot. Because of that, this kind of loader offers a way to update
-automatically identifiers that are part of components (as an example, as data
-members or gathered in a container).<br/>
-Another difference with the snapshot loader is that the continuous loader has an
-internal state that must persist over time. Therefore, there is no reason to
-limit its lifetime to that of a temporary object:
-
-```cpp
-entt::continuous_loader loader{registry};
-input_archive input;
-
-loader.entities(input)
-    .component<a_component, another_component, dirty_component>(input, &dirty_component::parent, &dirty_component::child)
-    .orphans()
-    .shrink();
-```
-
-It isn't necessary to invoke all functions each and every time. What functions
-to use in which case mostly depends on the goal.<br/>
-For obvious reasons, what is important is that the data are restored in exactly
-the same order in which they were serialized.
-
-The `entities` member function restores groups of entities and maps each entity
-to a local counterpart when required. For each remote entity identifier not yet
-registered by the loader, a local identifier is created so as to keep the local
-entity in sync with the remote one.<br/>
-The `component` member function restores all and only the components specified
-and assigns them to the right entities. In case the component contains entities
-itself (either as data members of type `entt::entity` or in a container), the
-loader can update them automatically. To do that, it's enough to specify the
-data members to update as shown in the example.<br/>
-The `orphans` member function releases the entities that have no components
-after a restore.<br/>
-Finally, `shrink` helps to purge local entities that no longer have a remote
-conterpart. Users should invoke this member function after restoring each
-snapshot, unless they know exactly what they are doing.
-
-### Archives
-
-Archives must publicly expose a predefined set of member functions. The API is
-straightforward and consists only of a group of function call operators that
-are invoked by the snapshot class and the loaders.
-
-In particular:
-
-* An output archive (the one used when creating a snapshot) exposes a function
-  call operator with the following signature to store entities:
-
-  ```cpp
-  void operator()(entt::entity);
-  ```
-
-  Where `entt::entity` is the type of the entities used by the registry.<br/>
-  Note that all member functions of the snapshot class also make an initial call
-  to store aside the _size_ of the set they are going to store. In this case,
-  the expected function type for the function call operator is:
-
-  ```cpp
-  void operator()(std::underlying_type_t<entt::entity>);
-  ```
-
-  In addition, an archive accepts a pair of entity and component for each type
-  to serialize. Therefore, given a type `T`, the archive offers a function call
-  operator with the following signature:
-
-  ```cpp
-  void operator()(entt::entity, const T &);
-  ```
-
-  The output archive can freely decide how to serialize the data. The registry
-  isn't affected at all by the decision.
-
-* An input archive (the one used when restoring a snapshot) exposes a function
-  call operator with the following signature to load entities:
-
-  ```cpp
-  void operator()(entt::entity &);
-  ```
-
-  Where `entt::entity` is the type of the entities used by the registry. Each
-  time the function is invoked, the archive reads the next element from the
-  underlying storage and copies it in the given variable.<br/>
-  All member functions of a loader class also make an initial call to read the
-  _size_ of the set they are going to load. In this case, the expected function
-  type for the function call operator is:
-
-  ```cpp
-  void operator()(std::underlying_type_t<entt::entity> &);
-  ```
-
-  In addition, the archive accepts a pair of references to an entity and its
-  component for each type to restore. Therefore, given a type `T`, the archive
-  contains a function call operator with the following signature:
-
-  ```cpp
-  void operator()(entt::entity &, T &);
-  ```
-
-  Every time this operator is invoked, the archive reads the next elements from
-  the underlying storage and copies them in the given variables.
-
-### One example to rule them all
-
-`EnTT` comes with some examples (actually some tests) that show how to integrate
-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 **isn't** production-ready and it isn't 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.
-
 # Views and Groups
 
 Views are a non-intrusive tool for working with entities and components without
@@ -1975,30 +1999,6 @@ data internally to maximize performance. Because of that, full consistency for
 owned components is guaranteed only when they are iterated as part of their
 groups or as free types with multi type views and groups in general.
 
-# Empty type optimization
-
-An empty type `T` is such that `std::is_empty_v<T>` returns true. They also are
-the same types for which _empty base optimization_ (EBO) is possible.<br/>
-`EnTT` handles these types in a special way, optimizing both in terms of
-performance and memory usage. However, this also has consequences that are worth
-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 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
-it is assigned to.
-
-More in general, none of the feature offered by the library is affected, but for
-the ones that require to return actual instances.<br/>
-This optimization is disabled by defining the `ENTT_NO_ETO` macro. In this case,
-empty types are treated like all other types. Setting a page size at component
-level via the `component_traits` class template is another way to disable this
-optimization selectively rather than globally.
-
 # Multithreading
 
 In general, the entire registry isn't thread safe as it is. Thread safety isn't