1 # Crash Course: entity-component system
8 * [Introduction](#introduction)
9 * [Design decisions](#design-decisions)
10 * [A bitset-free entity-component system](#a-bitset-free-entity-component-system)
11 * [Pay per use](#pay-per-use)
12 * [All or nothing](#all-or-nothing)
13 * [Stateless systems](#stateless-systems)
14 * [Vademecum](#vademecum)
15 * [The Registry, the Entity and the Component](#the-registry-the-entity-and-the-component)
16 * [Observe changes](#observe-changes)
17 * [They call me Reactive System](#they-call-me-reactive-system)
18 * [Runtime components](#runtime-components)
19 * [A journey through a plugin](#a-journey-through-a-plugin)
20 * [Sorting: is it possible?](#sorting-is-it-possible)
22 * [Null entity](#null-entity)
23 * [Stomp and spawn](#stomp-and-spawn)
24 * [Dependencies](#dependencies)
27 * [Context variables](#context-variables)
28 * [Snapshot: complete vs continuous](#snapshot-complete-vs-continuous)
29 * [Snapshot loader](#snapshot-loader)
30 * [Continuous loader](#continuous-loader)
31 * [Archives](#archives)
32 * [One example to rule them all](#one-example-to-rule-them-all)
33 * [Views and Groups](#views-and-groups)
35 * [Runtime views](#runtime-views)
37 * [Full-owning groups](#full-owning-groups)
38 * [Partial-owning groups](#partial-owning-groups)
39 * [Non-owning groups](#non-owning-groups)
40 * [Nested groups](#nested-groups)
41 * [Types: const, non-const and all in between](#types-const-non-const-and-all-in-between)
42 * [Give me everything](#give-me-everything)
43 * [What is allowed and what is not](#what-is-allowed-and-what-is-not)
44 * [More performance, more constraints](#more-performance-more-constraints)
45 * [Empty type optimization](#empty-type-optimization)
46 * [Multithreading](#multithreading)
47 * [Iterators](#iterators)
48 * [Beyond this document](#beyond-this-document)
50 @endcond TURN_OFF_DOXYGEN
55 `EnTT` is a header-only, tiny and easy to use entity-component system (and much
56 more) written in modern C++.<br/>
57 The entity-component-system (also known as _ECS_) is an architectural pattern
58 used mostly in game development.
62 ## A bitset-free entity-component system
64 `EnTT` offers a _bitset-free_ entity-component system that doesn't require users
65 to specify the set of components neither at compile-time nor at runtime before
66 being able to use the library itself.<br/>
67 This is why users can instantiate the core class simply like:
70 entt::registry registry;
73 In place of its more annoying and error-prone counterpart:
76 entt::registry<comp_0, comp_1, ..., comp_n> registry;
79 Furthermore, there is no need to indicate to the library in any way that a type
80 of component exists and will be used sooner or later. When the time comes, users
81 can just use it and that's all.
85 `EnTT` is entirely designed around the principle that users have to pay only for
88 When it comes to using an entity-component system, the tradeoff is usually
89 between performance and memory usage. The faster it is, the more memory it uses.
90 Even worse, some approaches tend to heavily affect other functionalities like
91 the construction and destruction of components to favor iterations, even when it
92 isn't strictly required. In fact, slightly worse performance along non-critical
93 paths are the right price to pay to reduce memory usage and have overall better
94 perfomance sometimes and I've always wondered why this kind of tools do not
95 leave me the choice.<br/>
96 `EnTT` follows a completely different approach. It gets the best out from the
97 basic data structures and gives users the possibility to pay more for higher
98 performance where needed.<br/>
99 The disadvantage of this approach is that users need to know the systems they
100 are working on and the tools they are using. Otherwise, the risk to ruin the
101 performance along critical paths is high.
103 So far, this choice has proven to be a good one and I really hope it can be for
104 many others besides me.
108 `EnTT` is such that at every moment a pair `(T *, size)` is available to
109 directly access all the instances of a given component type `T`.<br/>
110 This was a guideline and a design decision that influenced many choices, for
111 better and for worse. I cannot say whether it will be useful or not to the
112 reader, but it's worth to mention it, because it's one of the corner stones of
115 Many of the tools described below, from the registry to the views and up to the
116 groups give the possibility to get this information and have been designed
117 around this need, which was and remains one of my main requirements during the
119 The rest is experimentation and the desire to invent something new, hoping to
124 `EnTT` is designed so that it can work with _stateless systems_. In other words,
125 all systems can be free functions and there is no need to define them as classes
126 (although nothing prevents users from doing so).<br/>
127 This is possible because the main class with which the users will work provides
128 all what is needed to act as the sole _source of truth_ of an application.
130 To be honest, this point became part of the design principles at a later date,
131 but has also become one of the cornerstones of the library to date, as stateless
132 systems are widely used and appreciated in general.
136 The registry to store, the views and the groups to iterate. That's all.
138 An entity (the _E_ of an _ECS_) is an opaque identifier that users should just
139 use as-is and store around if needed. Do not try to inspect an entity
140 identifier, its format can change in future and a registry offers all the
141 functionalities to query them out-of-the-box. The underlying type of an entity
142 (either `std::uint16_t`, `std::uint32_t` or `std::uint64_t`) can be specified
143 when defining a registry. In fact, an `entt::registry` is nothing more than an
144 alias for `entt::basic_registry<entt::entity>` and `entt::entity` is a distinct
145 type that implements the concept of _entity identifier_.<br/>
146 Components (the _C_ of an _ECS_) should be plain old data structures or more
147 complex and movable data structures with a proper constructor. Actually, the
148 sole requirement of a component type is that it must be both move constructible
149 and move assignable. They are list initialized by using the parameters provided
150 to construct the component itself. No need to register components or their types
151 neither with the registry nor with the entity-component system at all.<br/>
152 Systems (the _S_ of an _ECS_) are just plain functions, functors, lambdas or
153 whatever users want. They can accept a registry, a view or a group of any type
154 and use them the way they prefer. No need to register systems or their types
155 neither with the registry nor with the entity-component system at all.
157 The following sections will explain in short how to use the entity-component
158 system, the core part of the whole library.<br/>
159 In fact, the project is composed of many other classes in addition to those
160 describe below. For more details, please refer to the inline documentation.
162 # The Registry, the Entity and the Component
164 A registry can store and manage entities, as well as create views and groups to
165 iterate the underlying data structures.<br/>
166 The class template `basic_registry` lets users decide what's the preferred type
167 to represent an entity. Because `std::uint32_t` is large enough for almost all
168 the cases, there exists also the type `entt::entity` for it, as well as the
169 alias `entt::registry` for `entt::basic_registry<entt::entity>`.
171 Entities are represented by _entity identifiers_. An entity identifier is an
172 opaque type that users should not inspect or modify in any way. It carries
173 information about the entity itself and its version.<br/>
174 User defined identifiers can be introduced by means of the `ENTT_OPAQUE_TYPE`
177 A registry is used both to construct and to destroy entities:
180 // constructs a naked entity with no components and returns its identifier
181 auto entity = registry.create();
183 // destroys an entity and all its components
184 registry.destroy(entity);
187 There exists also an overload of the `create` and `destroy` member functions
188 that accepts two iterators, that is a range to assign or to destroy. It can be
189 used to create or destroy multiple entities at once:
192 // destroys all the entities in a range
193 auto view = registry.view<a_component, another_component>();
194 registry.destroy(view.begin(), view.end());
197 In both cases, the `create` member function accepts also a list of default
198 constructible component types to assign to the entities before to return. It's a
199 faster alternative to the creation and subsequent assignment of components in
202 When an entity is destroyed, the registry can freely reuse it internally with a
203 slightly different identifier. In particular, the version of an entity is
204 increased each and every time it's discarded.<br/>
205 In case entity identifiers are stored around, the registry offers all the
206 functionalities required to test them and to get out of them the information
210 // returns true if the entity is still valid, false otherwise
211 bool b = registry.valid(entity);
213 // gets the version contained in the entity identifier
214 auto version = registry.version(entity);
216 // gets the actual version for the given entity
217 auto curr = registry.current(entity);
220 Components can be assigned to or removed from entities at any time with a few
221 calls to member functions of the registry. As for the entities, the registry
222 offers also a set of functionalities users can use to work with the components.
224 The `assign` member function template creates, initializes and assigns to an
225 entity the given component. It accepts a variable number of arguments to
226 construct the component itself if present:
229 registry.assign<position>(entity, 0., 0.);
233 auto &velocity = registry.assign<velocity>(entity);
238 If an entity already has the given component, the `replace` member function
239 template can be used to replace it:
242 registry.replace<position>(entity, 0., 0.);
246 auto &velocity = registry.replace<velocity>(entity);
251 In case users want to assign a component to an entity, but it's unknown whether
252 the entity already has it or not, `assign_or_replace` does the work in a single
253 call (there is a performance penalty to pay for this mainly due to the fact that
254 it has to check if the entity already has the given component or not):
257 registry.assign_or_replace<position>(entity, 0., 0.);
261 auto &velocity = registry.assign_or_replace<velocity>(entity);
266 Note that `assign_or_replace` is a slightly faster alternative for the following
267 `if/else` statement and nothing more:
270 if(registry.has<comp>(entity)) {
271 registry.replace<comp>(entity, arg1, argN);
273 registry.assign<comp>(entity, arg1, argN);
277 As already shown, if in doubt about whether or not an entity has one or more
278 components, the `has` member function template may be useful:
281 bool b = registry.has<position, velocity>(entity);
284 On the other side, if the goal is to delete a single component, the `remove`
285 member function template is the way to go when it's certain that the entity owns
286 a copy of the component:
289 registry.remove<position>(entity);
292 Otherwise consider to use the `reset` member function. It behaves similarly to
293 `remove` but with a strictly defined behavior (and a performance penalty is the
294 price to pay for this). In particular it removes the component if and only if it
295 exists, otherwise it returns safely to the caller:
298 registry.reset<position>(entity);
301 There exist also two other _versions_ of the `reset` member function:
303 * If no entity is passed to it, `reset` will remove the given component from
304 each entity that has it:
307 registry.reset<position>();
310 * If neither the entity nor the component are specified, all the entities still
311 in use and their components are destroyed:
317 Finally, references to components can be retrieved simply by doing this:
320 const auto &cregistry = registry;
322 // const and non-const reference
323 const auto &crenderable = cregistry.get<renderable>(entity);
324 auto &renderable = registry.get<renderable>(entity);
326 // const and non-const references
327 const auto &[cpos, cvel] = cregistry.get<position, velocity>(entity);
328 auto &[pos, vel] = registry.get<position, velocity>(entity);
331 The `get` member function template gives direct access to the component of an
332 entity stored in the underlying data structures of the registry. There exists
333 also an alternative member function named `try_get` that returns a pointer to
334 the component owned by an entity if any, a null pointer otherwise.
338 Because of how the registry works internally, it stores a bunch of signal
339 handlers for each pool in order to notify some of its data structures on the
340 construction and destruction of components or when an instance of a component is
341 explicitly replaced by the user.<br/>
342 These signal handlers are also exposed and made available to users. These are
343 the basic bricks to build fancy things like dependencies and reactive systems.
345 To get a sink to be used to connect and disconnect listeners so as to be
346 notified on the creation of a component, use the `on_construct` member function:
349 // connects a free function
350 registry.on_construct<position>().connect<&my_free_function>();
352 // connects a member function
353 registry.on_construct<position>().connect<&my_class::member>(instance);
355 // disconnects a free function
356 registry.on_construct<position>().disconnect<&my_free_function>();
358 // disconnects a member function
359 registry.on_construct<position>().disconnect<&my_class::member>(instance);
362 To be notified when components are destroyed, use the `on_destroy` member
363 function instead. Finally, the `on_replace` member function will return a sink
364 to which to connect listeners to observe changes on components.
366 The function type of a listener for the construction signal should be equivalent
370 void(entt::entity, entt::registry &, Component &);
373 Where `Component` is intuitively the type of component of interest. In other
374 words, a listener is provided with the registry that triggered the notification
375 and the entity affected by the change, in addition to the newly created
377 The sink returned by the `on_replace` member function accepts listeners the
378 signature of which is the same of that of the construction signal. The one of
379 the destruction signal is also similar, except for the `Component` parameter:
382 void(entt::entity, entt::registry &);
385 This is mainly due to performance reasons. While the component is made available
386 after the construction, it is not when destroyed. Because of that, there are no
387 reasons to get it from the underlying storage unless the user requires so. In
388 this case, the registry is made available for the purpose.
392 * Listeners for the construction signal are invoked **after** components have
393 been assigned to entities.
395 * Listeners designed to observe changes are invoked **before** components have
396 been replaced and therefore before newly created instances have been assigned
399 * Listeners for the destruction signal are invoked **before** components have
400 been removed from entities.
402 * The order of invocation of the listeners isn't guaranteed in any case.
404 There are also some limitations on what a listener can and cannot do. In
407 * Connecting and disconnecting other functions from within the body of a
408 listener should be avoided. It can lead to undefined behavior in some cases.
410 * Assigning and removing components from within the body of a listener that
411 observes the destruction of instances of a given type should be avoided. It
412 can lead to undefined behavior in some cases. This type of listeners is
413 intended to provide users with an easy way to perform cleanup and nothing
416 To a certain extent, these limitations don't apply. However, it's risky to try
417 to force them and users should respect the limitations unless they know exactly
418 what they are doing. Subtle bugs are the price to pay in case of errors
421 In general, events and therefore listeners must not be used as replacements for
422 systems. They should not contain much logic and interactions with a registry
423 should be kept to a minimum, if possible. Note also that the greater the number
424 of listeners, the greater the performance hit when components are created or
427 Please, refer to the documentation of the signal class to know all the features
429 There are many useful but less known functionalities that aren't described here,
430 such as the connection objects or the possibility to attach listeners with a
431 list of parameters that is shorter than that of the signal itself.
433 ### They call me Reactive System
435 As mentioned above, signals are the basic tools to construct reactive systems,
436 even if they are not enough on their own.<br/>
437 `EnTT` tries to take another step in that direction with the `observer` class
440 In order to explain what reactive systems are, this is a slightly revised quote
441 from the documentation of the library that first introduced this tool,
442 [Entitas](https://github.com/sschmid/Entitas-CSharp):
444 >Imagine you have 100 fighting units on the battlefield but only 10 of them
445 >changed their positions. Instead of using a normal system and updating all 100
446 >entities depending on the position, you can use a reactive system which will
447 >only update the 10 changed units. So efficient.
449 In `EnTT`, this means to iterating over a reduced set of entities and components
450 with respect to what would otherwise be returned from a view or a group.<br/>
451 On these words, however, the similarities with the proposal of `Entitas` also
452 end. The rules of language and the design of the library obviously impose and
453 allow different things.
455 An `observer` is initialized with an instance of a registry and a set of rules
456 that describe what are the entities to intercept. As an example:
459 entt::observer observer{registry, entt::collector.replace<sprite>()};
462 The class is default constructible if required and it can be reconfigured at any
463 time by means of the `connect` member function. Moreover, instances can be
464 disconnected from the underlying registries through the `disconnect` member
466 The `observer` offers also some member functions to query its internal state and
467 to know if it's empty or how many entities it contains. Moreover, it can return
468 a raw pointer to the list of entities it contains.
470 However, the most important features of this class are that:
472 * It's iterable and therefore users can easily walk through the list of entities
473 by means of a range-for loop or the `each` member function.
475 * It's clearable and therefore users can consume the entities and literally
476 reset the observer after each iteration.
478 These aspects make the observer an incredibly powerful tool to know at any time
479 what are the entities that matched the given rules since the last time one
483 for(const auto entity: observer) {
490 Note that the snippet above is equivalent to the following:
493 observer.each([](const auto entity) {
498 At least as long as the `observer` isn't const. This means that the non-const
499 overload of `each` does also reset the underlying data structure before to
500 return to the caller, while the const overload does not for obvious reasons.
502 The `collector` is an utility aimed to generate a list of `matcher`s (the actual
503 rules) to use with an `observer` instead.<br/>
504 There are two types of `matcher`s:
506 * Observing matcher: an observer will return at least all the living entities
507 for which one or more of the given components have been explicitly replaced
508 and not yet destroyed.
511 entt::collector.replace<sprite>();
514 * Grouping matcher: an observer will return at least all the living entities
515 that would have entered the given group if it existed and that would have
519 entt::collector.group<position, velocity>(entt::exclude<destroyed>);
522 A grouping matcher supports also exclusion lists as well as single components.
524 Roughly speaking, an observing matcher intercepts the entities for which the
525 given components are replaced (as in `registry::replace`) while a grouping
526 matcher tracks the entities that have assigned the given components since the
527 last time one asked.<br/>
528 Note that, for a grouping matcher, if an entity already has all the components
529 except one and the missing type is assigned to it, it is intercepted.
531 In addition, a matcher can be filtered with a `where` clause:
534 entt::collector.replace<sprite>().where<position>(entt::exclude<velocity>);
537 This clause introduces a way to intercept entities if and only if they are
538 already part of a hypothetical group. If they are not, they aren't returned by
539 the observer, no matter if they matched the given rule.<br/>
540 In the example above, whenever the component `sprite` of an entity is replaced,
541 the observer probes the entity itself to verify that it has at least `position`
542 and has not `velocity` before to store it aside. If one of the two conditions of
543 the filter isn't respected, the entity is discared, no matter what.
545 A `where` clause accepts a theoretically unlimited number of types as well as
546 multiple elements in the exclusion list. Moreover, every matcher can have it's
547 own clause and multiple clauses for the same matcher are combined in a single
550 ## Runtime components
552 Defining components at runtime is useful to support plugin systems and mods in
553 general. However, it seems impossible with a tool designed around a bunch of
554 templates. Indeed it's not that difficult.<br/>
555 Of course, some features cannot be easily exported into a runtime
556 environment. As an example, sorting a group of components defined at runtime
557 isn't for free if compared to most of the other operations. However, the basic
558 functionalities of an entity-component system such as `EnTT` fit the problem
559 perfectly and can also be used to manage runtime components if required.<br/>
560 All that is necessary to do it is to know the identifiers of the components. An
561 identifier is nothing more than a number or similar that can be used at runtime
562 to work with the type system.
564 In `EnTT`, identifiers are easily accessible:
567 entt::registry registry;
569 // component identifier
570 auto type = registry.type<position>();
573 Once the identifiers are made available, almost everything becomes pretty
576 ### A journey through a plugin
578 `EnTT` comes with an example (actually a test) that shows how to integrate
579 compile-time and runtime components in a stack based JavaScript environment. It
580 uses [`Duktape`](https://github.com/svaarala/duktape) under the hood, mainly
581 because I wanted to learn how it works at the time I was writing the code.
583 The code is not production-ready and overall performance can be highly improved.
584 However, I sacrificed optimizations in favor of a more readable piece of code. I
585 hope I succeeded.<br/>
586 Note also that this isn't neither the only nor (probably) the best way to do it.
587 In fact, the right way depends on the scripting language and the problem one is
588 facing in general.<br/>
589 That being said, feel free to use it at your own risk.
591 The basic idea is that of creating a compile-time component aimed to map all the
592 runtime components assigned to an entity.<br/>
593 Identifiers come in use to address the right function from a map when invoked
594 from the runtime environment and to filter entities when iterating.<br/>
595 With a bit of gymnastic, one can narrow views and improve the performance to
596 some extent but it was not the goal of the example.
598 ## Sorting: is it possible?
600 It goes without saying that sorting entities and components is possible with
602 In fact, there are two functions that respond to slightly different needs:
604 * Components can be sorted either directly:
607 registry.sort<renderable>([](const auto &lhs, const auto &rhs) {
608 return lhs.z < rhs.z;
613 Or by accessing their entities:
616 registry.sort<renderable>([](const entt::entity lhs, const entt::entity rhs) {
617 return entt::registry::entity(lhs) < entt::registry::entity(rhs);
621 There exists also the possibility to use a custom sort function object, as
622 long as it adheres to the requirements described in the inline
624 This is possible mainly because users can get much more with a custom sort
625 function object if the usage pattern is known. As an example, in case of an
626 almost sorted pool, quick sort could be much, much slower than insertion sort.
628 * Components can be sorted according to the order imposed by another component:
631 registry.sort<movement, physics>();
634 In this case, instances of `movement` are arranged in memory so that cache
635 misses are minimized when the two components are iterated together.
637 As a side note, when groups are involved, the sorting functions are applied
638 separately to the elements that are part of the group and to those that are not,
639 effectively generating two partitions, both of which can be ordered
640 independently of each other.
644 The so called _helpers_ are small classes and functions mainly designed to offer
645 built-in support for the most basic functionalities.<br/>
646 The list of helpers will grow longer as time passes and new ideas come out.
650 In `EnTT`, there exists a sort of _null entity_ made available to users that is
651 accessible via the `entt::null` variable.<br/>
652 The library guarantees that the following expression always returns false:
655 registry.valid(entt::null);
658 In other terms, a registry will reject the null entity in all cases because it
659 isn't considered valid. It means that the null entity cannot own components for
660 obvious reasons.<br/>
661 The type of the null entity is internal and should not be used for any purpose
662 other than defining the null entity itself. However, there exist implicit
663 conversions from the null entity to identifiers of any allowed type:
666 entt::entity null = entt::null;
669 Similarly, the null entity can be compared to any other identifier:
672 const auto entity = registry.create();
673 const bool null = (entity == entt::null);
678 The use of multiple registries is quite common. Examples of use are the
679 separation of the UI from the simulation or the loading of different scenes in
680 the background, possibly on a separate thread, without having to keep track of
681 which entity belongs to which scene.<br/>
682 In fact, with `EnTT` this is even a recommended practice, as the registry is
683 nothing more than a container and different optimizations and strategies can be
684 applied to different containers.
686 Once there are multiple registries available, however, one or more methods are
687 needed to transfer information from one container to another and this results in
688 the `stomp` member function and a couple of overloads of the `create` member
689 function for the `registry` class .<br/>
690 The `stomp` function allows to take one entity from a registry and use it to
691 _stomp_ one or more entities in another registry (or even the same, actually
692 making local copies). On the other hand, the overloads of the `create` member
693 function can be used to spawn new entities from a prototype.
695 These features open definitely the doors to a lot of interesting features like
696 migrating entities between registries, prototypes, shadow registry, prefabs,
697 shared components without an explicit owner and copy-on-write policies among the
702 The `registry` class is designed to create short circuits between its functions
703 within certain limits. This allows to easily define dependencies between
704 different operations.<br/>
705 For example, the following adds (or replaces) the component `a_type` whenever
706 `my_type` is assigned to an entity:
709 registry.on_construct<my_type>().connect<&entt::registry::assign_or_replace<a_type>>(registry);
712 Similarly, the code shown below removes `a_type` from an entity whenever
713 `my_type` is assigned to it:
716 registry.on_construct<my_type>().connect<&entt::registry::reset<a_type>>(registry);
719 A dependency can also be easily broken as follows:
722 registry.on_construct<my_type>().disconnect<&entt::registry::assign_or_replace<a_type>>(registry);
725 There are many other types of dependencies besides those shown above. In
726 general, all functions that accept an entity as the first argument are good
727 candidates for this purpose.
731 There's nothing magical about the way tags can be assigned to entities while
732 avoiding a performance hit at runtime. Nonetheless, the syntax can be annoying
733 and that's why a more user-friendly shortcut is provided to do it.<br/>
734 This shortcut is the alias template `entt::tag`.
736 If used in combination with hashed strings, it helps to use tags where types
737 would be required otherwise. As an example:
740 registry.assign<entt::tag<"enemy"_hs>>(entity);
745 The `actor` class is designed for those who don't feel immediately comfortable
746 working with components or for those who are migrating a project and want to
747 approach it one step at a time.
749 This class acts as a thin wrapper for an entity and for all its components. It's
750 constructed with a registry to be used behind the scenes and is in charge of the
751 destruction of the entity when it goes out of the scope.<br/>
752 An actor offers all the functionalities required to work with components, such
753 as the `assign` and` remove` member functions, but also `has`,` get`, `try_get`
756 My advice isn't to use the `actor` class to hide entities and components behind
757 a more object-oriented interface. Instead, users should rely on it only where
758 strictly necessary. In all other cases, it's highly advisable to become familiar
759 with the model of `EnTT` and work directly with the registry, the views and the
760 groups, rather than with a tool that could introduce a performance degradation.
762 ### Context variables
764 It is often convenient to assign context variables to a registry, so as to make
765 it the only _source of truth_ of an application.<br/>
766 This is possible by means of a member function named `set` to use to create a
767 context variable from a given type. Later on, either `ctx` or `try_ctx` can be
768 used to retrieve the newly created instance and `unset` is there to literally
774 // creates a new context variable initialized with the given values
775 registry.set<my_type>(42, 'c');
777 // gets the context variable
778 const auto &var = registry.ctx<my_type>();
780 // if in doubts, probe the registry to avoid assertions in case of errors
781 if(auto *ptr = registry.try_ctx<my_type>(); ptr) {
782 // uses the context variable associated with the registry, if any
785 // unsets the context variable
786 registry.unset<my_type>();
789 The type of a context variable must be such that it's default constructible and
790 can be moved. The `set` member function either creates a new instance of the
791 context variable or overwrites an already existing one if any. The `try_ctx`
792 member function returns a pointer to the context variable if it exists,
793 otherwise it returns a null pointer. This fits well with the `if` statement with
796 ## Snapshot: complete vs continuous
798 The `registry` class offers basic support to serialization.<br/>
799 It doesn't convert components to bytes directly, there wasn't the need of
800 another tool for serialization out there. Instead, it accepts an opaque object
801 with a suitable interface (namely an _archive_) to serialize its internal data
802 structures and restore them later. The way types and instances are converted to
803 a bunch of bytes is completely in charge to the archive and thus to final users.
805 The goal of the serialization part is to allow users to make both a dump of the
806 entire registry or a narrower snapshot, that is to select only the components in
807 which they are interested.<br/>
808 Intuitively, the use cases are different. As an example, the first approach is
809 suitable for local save/restore functionalities while the latter is suitable for
810 creating client-server applications and for transferring somehow parts of the
811 representation side to side.
813 To take a snapshot of the registry, use the `snapshot` member function. It
814 returns a temporary object properly initialized to _save_ the whole registry or
820 output_archive output;
825 .component<a_component, another_component>(output);
828 It isn't necessary to invoke all these functions each and every time. What
829 functions to use in which case mostly depends on the goal and there is not a
830 golden rule to do that.
832 The `entities` member function asks the registry to serialize all the entities
833 that are still in use along with their versions. On the other side, the
834 `destroyed` member function tells to the registry to serialize the entities that
835 have been destroyed and are no longer in use.<br/>
836 These two functions can be used to save and restore the whole set of entities
837 with the versions they had during serialization.
839 The `component` member function is a function template the aim of which is to
840 store aside components. The presence of a template parameter list is a
841 consequence of a couple of design choices from the past and in the present:
843 * First of all, there is no reason to force a user to serialize all the
844 components at once and most of the times it isn't desiderable. As an example,
845 in case the stuff for the HUD in a game is put into the registry for some
846 reasons, its components can be freely discarded during a serialization step
847 because probably the software already knows how to reconstruct the HUD
848 correctly from scratch.
850 * Furthermore, the registry makes heavy use of _type-erasure_ techniques
851 internally and doesn't know at any time what component types it contains.
852 Therefore being explicit at the call point is mandatory.
854 There exists also another version of the `component` member function that
855 accepts a range of entities to serialize. This version is a bit slower than the
856 other one, mainly because it iterates the range of entities more than once for
857 internal purposes. However, it can be used to filter out those entities that
858 shouldn't be serialized for some reasons.<br/>
862 const auto view = registry.view<serialize>();
863 output_archive output;
865 registry.snapshot().component<a_component, another_component>(output, view.cbegin(), view.cend());
868 Note that `component` stores items along with entities. It means that it works
869 properly without a call to the `entities` member function.
871 Once a snapshot is created, there exist mainly two _ways_ to load it: as a whole
872 and in a kind of _continuous mode_.<br/>
873 The following sections describe both loaders and archives in details.
877 A snapshot loader requires that the destination registry be empty and loads all
878 the data at once while keeping intact the identifiers that the entities
880 To do that, the registry offers a member function named `loader` that returns a
881 temporary object properly initialized to _restore_ a snapshot.
891 .component<a_component, another_component>(input)
895 It isn't necessary to invoke all these functions each and every time. What
896 functions to use in which case mostly depends on the goal and there is not a
897 golden rule to do that. For obvious reasons, what is important is that the data
898 are restored in exactly the same order in which they were serialized.
900 The `entities` and `destroyed` member functions restore the sets of entities and
901 the versions that the entities originally had at the source.
903 The `component` member function restores all and only the components specified
904 and assigns them to the right entities. Note that the template parameter list
905 must be exactly the same used during the serialization.
907 The `orphans` member function literally destroys those entities that have no
908 components attached. It's usually useless if the snapshot is a full dump of the
909 source. However, in case all the entities are serialized but only few components
910 are saved, it could happen that some of the entities have no components once
911 restored. The best users can do to deal with them is to destroy those entities
912 and thus update their versions.
914 ### Continuous loader
916 A continuous loader is designed to load data from a source registry to a
917 (possibly) non-empty destination. The loader can accommodate in a registry more
918 than one snapshot in a sort of _continuous loading_ that updates the
919 destination one step at a time.<br/>
920 Identifiers that entities originally had are not transferred to the target.
921 Instead, the loader maps remote identifiers to local ones while restoring a
922 snapshot. Because of that, this kind of loader offers a way to update
923 automatically identifiers that are part of components (as an example, as data
924 members or gathered in a container).<br/>
925 Another difference with the snapshot loader is that the continuous loader does
926 not need to work with the private data structures of a registry. Furthermore, it
927 has an internal state that must persist over time. Therefore, there is no reason
928 to create it by means of a registry, or to limit its lifetime to that of a
934 entt::continuous_loader<entt::entity> loader{registry};
937 loader.entities(input)
939 .component<a_component, another_component, dirty_component>(input, &dirty_component::parent, &dirty_component::child)
944 It isn't necessary to invoke all these functions each and every time. What
945 functions to use in which case mostly depends on the goal and there is not a
946 golden rule to do that. For obvious reasons, what is important is that the data
947 are restored in exactly the same order in which they were serialized.
949 The `entities` and `destroyed` member functions restore groups of entities and
950 map each entity to a local counterpart when required. In other terms, for each
951 remote entity identifier not yet registered by the loader, the latter creates a
952 local identifier so that it can keep the local entity in sync with the remote
955 The `component` member function restores all and only the components specified
956 and assigns them to the right entities.<br/>
957 In case the component contains entities itself (either as data members of type
958 `entt::entity` or as containers of entities), the loader can update them
959 automatically. To do that, it's enough to specify the data members to update as
960 shown in the example.
962 The `orphans` member function literally destroys those entities that have no
963 components after a restore. It has exactly the same purpose described in the
964 previous section and works the same way.
966 Finally, `shrink` helps to purge local entities that no longer have a remote
967 conterpart. Users should invoke this member function after restoring each
968 snapshot, unless they know exactly what they are doing.
972 Archives must publicly expose a predefined set of member functions. The API is
973 straightforward and consists only of a group of function call operators that
974 are invoked by the snapshot class and the loaders.
978 * An output archive, the one used when creating a snapshot, must expose a
979 function call operator with the following signature to store entities:
982 void operator()(entt::entity);
985 Where `entt::entity` is the type of the entities used by the registry. Note
986 that all the member functions of the snapshot class make also an initial call
987 to this endpoint to save the _size_ of the set they are going to store.<br/>
988 In addition, an archive must accept a pair of entity and component for each
989 type to be serialized. Therefore, given a type `T`, the archive must contain a
990 function call operator with the following signature:
993 void operator()(entt::entity, const T &);
996 The output archive can freely decide how to serialize the data. The register
997 is not affected at all by the decision.
999 * An input archive, the one used when restoring a snapshot, must expose a
1000 function call operator with the following signature to load entities:
1003 void operator()(entt::entity &);
1006 Where `entt::entity` is the type of the entities used by the registry. Each
1007 time the function is invoked, the archive must read the next element from the
1008 underlying storage and copy it in the given variable. Note that all the member
1009 functions of a loader class make also an initial call to this endpoint to read
1010 the _size_ of the set they are going to load.<br/>
1011 In addition, the archive must accept a pair of entity and component for each
1012 type to be restored. Therefore, given a type `T`, the archive must contain a
1013 function call operator with the following signature:
1016 void operator()(entt::entity &, T &);
1019 Every time such an operator is invoked, the archive must read the next
1020 elements from the underlying storage and copy them in the given variables.
1022 ### One example to rule them all
1024 `EnTT` comes with some examples (actually some tests) that show how to integrate
1025 a well known library for serialization as an archive. It uses
1026 [`Cereal C++`](https://uscilab.github.io/cereal/) under the hood, mainly
1027 because I wanted to learn how it works at the time I was writing the code.
1029 The code is not production-ready and it isn't neither the only nor (probably)
1030 the best way to do it. However, feel free to use it at your own risk.
1032 The basic idea is to store everything in a group of queues in memory, then bring
1033 everything back to the registry with different loaders.
1037 First of all, it is worth answering an obvious question: why views and
1039 Briefly, they are a good tool to enforce single responsibility. A system that
1040 has access to a registry can create and destroy entities, as well as assign and
1041 remove components. On the other side, a system that has access to a view or a
1042 group can only iterate entities and their components, then read or update the
1043 data members of the latter.<br/>
1044 It is a subtle difference that can help designing a better software sometimes.
1046 More in details, views are a non-intrusive tool to access entities and
1047 components without affecting other functionalities or increasing the memory
1048 consumption. On the other side, groups are an intrusive tool that allows to
1049 reach higher performance along critical paths but has also a price to pay for
1052 There are mainly two kinds of views: _compile-time_ (also known as `view`) and
1053 runtime (also known as `runtime_view`).<br/>
1054 The former require that users indicate at compile-time what are the components
1055 involved and can make several optimizations because of that. The latter can be
1056 constructed at runtime instead and are a bit slower to iterate entities and
1058 In both cases, creating and destroying a view isn't expensive at all because
1059 views don't have any type of initialization. Moreover, views don't affect any
1060 other functionality of the registry and keep memory usage at a minimum.
1062 Groups come in three different flavors: _full-owning groups_, _partial-owning
1063 groups_ and _non-owning groups_. The main difference between them is in terms of
1065 Groups can literally _own_ one or more component types. It means that they will
1066 be allowed to rearrange pools so as to speed up iterations. Roughly speaking:
1067 the more components a group owns, the faster it is to iterate them. On the other
1068 side, a given component can belong to multiple groups only if they are _nested_,
1069 so users have to define groups carefully to get the best out of them.
1071 Continue reading for more details or refer to the inline documentation.
1075 A view behaves differently if it's constructed for a single component or if it
1076 has been created to iterate multiple components. Even the API is slightly
1077 different in the two cases.
1079 Single component views are specialized in order to give a boost in terms of
1080 performance in all the situations. This kind of views can access the underlying
1081 data structures directly and avoid superfluous checks. There is nothing as fast
1082 as a single component view. In fact, they walk through a packed array of
1083 components and return them one at a time.<br/>
1084 Single component views offer a bunch of functionalities to get the number of
1085 entities they are going to return and a raw access to the entity list as well as
1086 to the component list. It's also possible to ask a view if it contains a
1088 Refer to the inline documentation for all the details.
1090 Multi component views iterate entities that have at least all the given
1091 components in their bags. During construction, these views look at the number of
1092 entities available for each component and pick up a reference to the smallest
1093 set of candidates in order to speed up iterations.<br/>
1094 They offer fewer functionalities than their companion views for single
1095 component. In particular, a multi component view exposes utility functions to
1096 get the estimated number of entities it is going to return and to know whether
1097 it's empty or not. It's also possible to ask a view if it contains a given
1099 Refer to the inline documentation for all the details.
1101 There is no need to store views around for they are extremely cheap to
1102 construct, even though they can be copied without problems and reused freely.
1103 Views also return newly created and correctly initialized iterators whenever
1104 `begin` or `end` are invoked.
1106 Views share the way they are created by means of a registry:
1109 // single component view
1110 auto single = registry.view<position>();
1112 // multi component view
1113 auto multi = registry.view<position, velocity>();
1116 Filtering entities by components is also supported:
1119 auto view = registry.view<position, velocity>(entt::exclude<renderable>);
1122 To iterate a view, either use it in a range-for loop:
1125 auto view = registry.view<position, velocity>();
1127 for(auto entity: view) {
1128 // a component at a time ...
1129 auto &position = view.get<position>(entity);
1130 auto &velocity = view.get<velocity>(entity);
1132 // ... or multiple components at once
1133 auto &[pos, vel] = view.get<position, velocity>(entity);
1139 Or rely on the `each` member function to iterate entities and get all their
1143 registry.view<position, velocity>().each([](auto entity, auto &pos, auto &vel) {
1148 The `each` member function is highly optimized. Unless users want to iterate
1149 only entities or get only some of the components, this should be the preferred
1150 approach. Note that the entity can also be excluded from the parameter list if
1151 not required, but this won't improve performance for multi component views.<br/>
1152 There exists also an alternative version of `each` named `less` that works
1153 exactly as its counterpart but for the fact that it doesn't return empty
1154 components to the caller.
1156 As a side note, in the case of single component views, `get` accepts but doesn't
1157 strictly require a template parameter, since the type is implicitly defined:
1160 auto view = registry.view<const renderable>();
1162 for(auto entity: view) {
1163 const auto &renderable = view.get(entity);
1168 **Note**: prefer the `get` member function of a view instead of the `get` member
1169 function template of a registry during iterations, if possible. However, keep in
1170 mind that it works only with the components of the view itself.
1174 Runtime views iterate entities that have at least all the given components in
1175 their bags. During construction, these views look at the number of entities
1176 available for each component and pick up a reference to the smallest
1177 set of candidates in order to speed up iterations.<br/>
1178 They offer more or less the same functionalities of a multi component view.
1179 However, they don't expose a `get` member function and users should refer to the
1180 registry that generated the view to access components. In particular, a runtime
1181 view exposes utility functions to get the estimated number of entities it is
1182 going to return and to know whether it's empty or not. It's also possible to ask
1183 a runtime view if it contains a given entity.<br/>
1184 Refer to the inline documentation for all the details.
1186 Runtime view are extremely cheap to construct and should not be stored around in
1187 any case. They should be used immediately after creation and then they should be
1188 thrown away. The reasons for this go far beyond the scope of this document.<br/>
1189 To iterate a runtime view, either use it in a range-for loop:
1192 entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
1193 auto view = registry.runtime_view(std::cbegin(types), std::cend(types));
1195 for(auto entity: view) {
1196 // a component at a time ...
1197 auto &position = registry.get<position>(entity);
1198 auto &velocity = registry.get<velocity>(entity);
1200 // ... or multiple components at once
1201 auto &[pos, vel] = registry.get<position, velocity>(entity);
1207 Or rely on the `each` member function to iterate entities:
1210 entt::component types[] = { registry.type<position>(), registry.type<velocity>() };
1212 registry.runtime_view(std::cbegin(types), std::cend(types)).each([](auto entity) {
1217 Performance are exactly the same in both cases.
1219 **Note**: runtime views are meant for all those cases where users don't know at
1220 compile-time what components to use to iterate entities. This is particularly
1221 well suited to plugin systems and mods in general. Where possible, don't use
1222 runtime views, as their performance are slightly inferior to those of the other
1227 Groups are meant to iterate multiple components at once and offer a (much)
1228 faster alternative to views. Roughly speaking, they just play in another league
1229 when compared to views.<br/>
1230 Groups overcome the performance of the other tools available but require to get
1231 the ownership of components and this sets some constraints on pools. On the
1232 other side, groups aren't an automatism that increases memory consumption,
1233 affects functionalities and tries to optimize iterations for all the possible
1234 combinations of components. Users can decide when to pay for groups and to what
1236 The most interesting aspect of groups is that they fit _usage patterns_. Other
1237 solutions around usually try to optimize everything, because it is known that
1238 somewhere within the _everything_ there are also our usage patterns. However
1239 this has a cost that isn't negligible, both in terms of performance and memory
1240 usage. Ironically, users pay the price also for things they don't want and this
1241 isn't something I like much. Even worse, one cannot easily disable such a
1242 behavior. Groups work differently instead and are designed to optimize only the
1243 real use cases when users find they need to.<br/>
1244 Another nice-to-have feature of groups is that they have no impact on memory
1245 consumption, put aside full non-owning groups that are pretty rare and should be
1246 avoided as long as possible.
1248 All groups affect to an extent the creation and destruction of their components.
1249 This is due to the fact that they must _observe_ changes in the pools of
1250 interest and arrange data _correctly_ when needed for the types they own.<br/>
1251 That being said, the way groups operate is beyond the scope of this document.
1252 However, it's unlikely that users will be able to appreciate the impact of
1253 groups on other functionalities of the registry.
1255 Groups offer a bunch of functionalities to get the number of entities they are
1256 going to return and a raw access to the entity list as well as to the component
1257 list for owned components. It's also possible to ask a group if it contains a
1259 Refer to the inline documentation for all the details.
1261 There is no need to store groups around for they are extremely cheap to
1262 construct, even though they can be copied without problems and reused freely.
1263 A group performs an initialization step the very first time it's requested and
1264 this could be quite costly. To avoid it, consider creating the group when no
1265 components have been assigned yet. If the registry is empty, preparation is
1266 extremely fast. Groups also return newly created and correctly initialized
1267 iterators whenever `begin` or `end` are invoked.
1269 To iterate groups, either use them in a range-for loop:
1272 auto group = registry.group<position>(entt::get<velocity>);
1274 for(auto entity: group) {
1275 // a component at a time ...
1276 auto &position = group.get<position>(entity);
1277 auto &velocity = group.get<velocity>(entity);
1279 // ... or multiple components at once
1280 auto &[pos, vel] = group.get<position, velocity>(entity);
1286 Or rely on the `each` member function to iterate entities and get all their
1290 registry.group<position>(entt::get<velocity>).each([](auto entity, auto &pos, auto &vel) {
1295 The `each` member function is highly optimized. Unless users want to iterate
1296 only entities, this should be the preferred approach. Note that the entity can
1297 also be excluded from the parameter list if not required and it can improve even
1298 further the performance during iterations.
1300 **Note**: prefer the `get` member function of a group instead of the `get`
1301 member function template of a registry during iterations, if possible. However,
1302 keep in mind that it works only with the components of the group itself.
1304 Let's go a bit deeper into the different types of groups made available by this
1305 library to know how they are constructed and what are the differences between
1308 ### Full-owning groups
1310 A full-owning group is the fastest tool an user can expect to use to iterate
1311 multiple components at once. It iterates all the components directly, no
1312 indirection required. This type of groups performs more or less as if users are
1313 accessing sequentially a bunch of packed arrays of components all sorted
1316 A full-owning group is created as:
1319 auto group = registry.group<position, velocity>();
1322 Filtering entities by components is also supported:
1325 auto group = registry.group<position, velocity>(entt::exclude<renderable>);
1328 Once created, the group gets the ownership of all the components specified in
1329 the template parameter list and arranges their pools so as to iterate all of
1330 them as fast as possible.
1332 Sorting owned components is no longer allowed once the group has been created.
1333 However, full-owning groups can be sorted by means of their `sort` member
1334 functions, if required. Sorting a full-owning group affects all the instances of
1335 the same group (it means that users don't have to call `sort` on each instance
1336 to sort all of them because they share the underlying data structure).
1338 ### Partial-owning groups
1340 A partial-owning group works similarly to a full-owning group for the components
1341 it owns, but relies on indirection to get components owned by other groups. This
1342 isn't as fast as a full-owning group, but it's already much faster than views
1343 when there are only one or two free components to retrieve (the most common
1344 cases likely). In the worst case, it's not slower than views anyway.
1346 A partial-owning group is created as:
1349 auto group = registry.group<position>(entt::get<velocity>);
1352 Filtering entities by components is also supported:
1355 auto group = registry.group<position>(entt::get<velocity>, entt::exclude<renderable>);
1358 Once created, the group gets the ownership of all the components specified in
1359 the template parameter list and arranges their pools so as to iterate all of
1360 them as fast as possible. The ownership of the types provided via `entt::get`
1361 doesn't pass to the group instead.
1363 Sorting owned components is no longer allowed once the group has been created.
1364 However, partial-owning groups can be sorted by means of their `sort` member
1365 functions, if required. Sorting a partial-owning group affects all the instances
1366 of the same group (it means that users don't have to call `sort` on each
1367 instance to sort all of them because they share the underlying data
1370 ### Non-owning groups
1372 Non-owning groups are usually fast enough, for sure faster than views and well
1373 suited for most of the cases. However, they require custom data structures to
1374 work properly and they increase memory consumption. As a rule of thumb, users
1375 should avoid using non-owning groups, if possible.
1377 A non-owning group is created as:
1380 auto group = registry.group<>(entt::get<position, velocity>);
1383 Filtering entities by components is also supported:
1386 auto group = registry.group<>(entt::get<position, velocity>, entt::exclude<renderable>);
1389 The group doesn't receive the ownership of any type of component in this
1390 case. This type of groups is therefore the least performing in general, but also
1391 the only one that can be used in any situation to improve a performance where
1394 Non-owning groups can be sorted by means of their `sort` member functions, if
1395 required. Sorting a non-owning group affects all the instance of the same group
1396 (it means that users don't have to call `sort` on each instance to sort all of
1397 them because they share the set of entities).
1401 A type of component cannot be owned by two or more conflicting groups such as:
1403 * `registry.group<transform, sprite>()`.
1404 * `registry.group<transform, rotation>()`.
1406 However, the same type can be owned by groups belonging to the same _family_,
1407 also called _nested groups_, such as:
1409 * `registry.group<sprite, transform>()`.
1410 * `registry.group<sprite, transform, rotation>()`.
1412 Fortunately, these are also very common cases if not the most common ones.<br/>
1413 This allows users to have the highest possible performance on a greater number
1414 of component combinations.
1416 Two nested groups are such that they own at least one type of component and the
1417 list of component types involved by one of them is contained entirely in that of
1418 the other. More specifically, this applies independently to all component lists
1419 used to define a group.<br/>
1420 Therefore, the rules for defining whether two or more groups are nested can be
1423 * One of the groups involves one or more additional component types with respect
1424 to the other, whether they are owned, observed or excluded.
1426 * The list of component types owned by the most restrictive group is the same or
1427 contains entirely that of the others. This also applies to the list of
1428 observed and excluded components.
1430 It means that more nested groups _extend_ the their parents by adding more
1431 conditions in the form of new components.
1433 As mentioned, the components don't necessarily have to be all _owned_ so that
1434 two groups can be considered nested. In other words, the following definitions
1437 * `registry.group<sprite>(entt::get<renderable>)`.
1438 * `registry.group<sprite, transform>(entt::get<renderable>)`.
1439 * `registry.group<sprite, transform>(entt::get<renderable, rotation>)`.
1441 Exclusion lists also play their part in this respect. When it comes to defining
1442 nested groups, an excluded type of component `T` is treated as being an observed
1443 type `not_T`. Therefore, these two definitions:
1445 * `registry.group<sprite, transform>()`.
1446 * `registry.group<sprite, transform>(entt::exclude<rotation>)`.
1448 Are treated as if users were defining the following groups:
1450 * `group<sprite, transform>()`.
1451 * `group<sprite, transform>(entt::get<not_rotation>)`.
1453 Where `not_rotation` is an empty tag present only when `rotation` is not.
1455 Because of this, to define a new group that is more restrictive than an existing
1456 one, it's enough to take the list of component types of the latter and extend it
1457 by adding new component types either owned, observed or excluded, without any
1458 precautions depending on the case.<br/>
1459 The opposite is also true. To define a _larger_ group, it will be enough to take
1460 an existing one and remove _constraints_ from it, in whatever form they are
1462 Note that the greater the number of component types involved by a group, the
1463 more restrictive it is.
1465 Despite the extreme flexibility of nested groups, which allow to independently
1466 use component types either owned, observed or excluded, the real strength of
1467 this tool lies in the possibility of defining a greater number of groups that
1468 **own** the same components, thus offering the best performance in more
1470 In fact, given a list of component types involved by a group, the greater the
1471 number of those owned, the greater the performance of the group itself.
1473 As a side note, it's no longer possible to sort all groups when defining nested
1474 ones. This is because the most restrictive groups share the elements with the
1475 less restrictive ones and ordering the latter would invalidate the former.<br/>
1476 However, given a family of nested groups, it's still possible to sort the most
1477 restrictive of them. To prevent users from having to remember which of their
1478 groups is the most restrictive, they offer the `sortable` member function to
1479 know if their items can be sorted or not.
1481 ## Types: const, non-const and all in between
1483 The `registry` class offers two overloads when it comes to constructing views
1484 and groups: a const version and a non-const one. The former accepts both const
1485 and non-const types as template parameters, the latter accepts only const types
1487 It means that views and groups can be constructed also from a const registry and
1488 they propagate the constness of the registry to the types involved. As an
1492 entt::view<const position, const velocity> view = std::as_const(registry).view<const position, const velocity>();
1495 Consider the following definition for a non-const view instead:
1498 entt::view<position, const velocity> view = registry.view<position, const velocity>();
1501 In the example above, `view` can be used to access either read-only or writable
1502 `position` components while `velocity` components are read-only in all
1504 In other terms, these statements are all valid:
1507 position &pos = view.get<position>(entity);
1508 const position &cpos = view.get<const position>(entity);
1509 const velocity &cpos = view.get<const velocity>(entity);
1510 std::tuple<position &, const velocity &> tup = view.get<position, const velocity>(entity);
1511 std::tuple<const position &, const velocity &> ctup = view.get<const position, const velocity>(entity);
1514 It's not possible to get non-const references to `velocity` components from the
1515 same view instead and these will result in compilation errors:
1518 velocity &cpos = view.get<velocity>(entity);
1519 std::tuple<position &, velocity &> tup = view.get<position, velocity>(entity);
1520 std::tuple<const position &, velocity &> ctup = view.get<const position, velocity>(entity);
1523 Similarly, the `each` member functions will propagate constness to the type of
1524 the components returned during iterations:
1527 view.each([](auto entity, position &pos, const velocity &vel) {
1532 Obviously, a caller can still refer to the `position` components through a const
1533 reference because of the rules of the language that fortunately already allow
1536 The same concepts apply to groups as well.
1538 ## Give me everything
1540 Views and groups are narrow windows on the entire list of entities. They work by
1541 filtering entities according to their components.<br/>
1542 In some cases there may be the need to iterate all the entities still in use
1543 regardless of their components. The registry offers a specific member function
1547 registry.each([](auto entity) {
1552 It returns to the caller all the entities that are still in use by means of the
1553 given function.<br/>
1554 As a rule of thumb, consider using a view or a group if the goal is to iterate
1555 entities that have a determinate set of components. These tools are usually much
1556 faster than combining this function with a bunch of custom tests.<br/>
1557 In all the other cases, this is the way to go.
1559 There exists also another member function to use to retrieve orphans. An orphan
1560 is an entity that is still in use and has no assigned components.<br/>
1561 The signature of the function is the same of `each`:
1564 registry.orphans([](auto entity) {
1569 To test the _orphanity_ of a single entity, use the member function `orphan`
1570 instead. It accepts a valid entity identifer as an argument and returns true in
1571 case the entity is an orphan, false otherwise.
1573 In general, all these functions can result in poor performance.<br/>
1574 `each` is fairly slow because of some checks it performs on each and every
1575 entity. For similar reasons, `orphans` can be even slower. Both functions should
1576 not be used frequently to avoid the risk of a performance hit.
1578 ## What is allowed and what is not
1580 Most of the _ECS_ available out there don't allow to create and destroy entities
1581 and components during iterations.<br/>
1582 `EnTT` partially solves the problem with a few limitations:
1584 * Creating entities and components is allowed during iterations in almost all
1587 * Deleting the current entity or removing its components is allowed during
1588 iterations. For all the other entities, destroying them or removing their
1589 components isn't allowed and can result in undefined behavior.
1591 In these cases, iterators aren't invalidated. To be clear, it doesn't mean that
1592 also references will continue to be valid.<br/>
1593 Consider the following example:
1596 registry.view<position>([&](const auto entity, auto &pos) {
1597 registry.assign<position>(registry.create(), 0., 0.);
1598 pos.x = 0.; // warning: dangling pointer
1602 The `each` member function won't break (because iterators aren't invalidated)
1603 but there are no guarantees on references. Use a common range-for loop and get
1604 components directly from the view or move the creation of components at the end
1605 of the function to avoid dangling pointers.
1607 Iterators are invalidated instead and the behavior is undefined if an entity is
1608 modified or destroyed and it's not the one currently returned by the iterator
1609 nor a newly created one.<br/>
1610 To work around it, possible approaches are:
1612 * Store aside the entities and the components to be removed and perform the
1613 operations at the end of the iteration.
1615 * Mark entities and components with a proper tag component that indicates they
1616 must be purged, then perform a second iteration to clean them up one by one.
1618 A notable side effect of this feature is that the number of required allocations
1619 is further reduced in most of the cases.
1621 ### More performance, more constraints
1623 Groups are a (much) faster alternative to views. However, the higher the
1624 performance, the greater the constraints on what is allowed and what is
1626 In particular, groups add in some rare cases a limitation on the creation of
1627 components during iterations. It happens in quite particular cases. Given the
1628 nature and the scope of the groups, it isn't something in which it will happen
1629 to come across probably, but it's good to know it anyway.
1631 First of all, it must be said that creating components while iterating a group
1632 isn't a problem at all and can be done freely as it happens with the views. The
1633 same applies to the destruction of components and entities, for which the rules
1634 mentioned above apply.
1636 The additional limitation pops out instead when a given component that is owned
1637 by a group is iterated outside of it. In this case, adding components that are
1638 part of the group itself may invalidate the iterators. There are no further
1639 limitations to the destruction of components and entities.<br/>
1640 Fortunately, this isn't always true. In fact, it almost never is and this
1641 happens only under certain conditions. In particular:
1643 * Iterating a type of component that is part of a group with a single component
1644 view and adding to an entity all the components required to get it into the
1645 group may invalidate the iterators.
1647 * Iterating a type of component that is part of a group with a multi component
1648 view and adding to an entity all the components required to get it into the
1649 group can invalidate the iterators, unless users specify another type of
1650 component to use to induce the order of iteration of the view (in this case,
1651 the former is treated as a free type and isn't affected by the limitation).
1653 In other words, the limitation doesn't exist as long as a type is treated as a
1654 free type (as an example with multi component views and partial- or non-owning
1655 groups) or iterated with its own group, but it can occur if the type is used as
1656 a main type to rule on an iteration.<br/>
1657 This happens because groups own the pools of their components and organize the
1658 data internally to maximize performance. Because of that, full consistency for
1659 owned components is guaranteed only when they are iterated as part of their
1660 groups or as free types with multi component views and groups in general.
1662 # Empty type optimization
1664 An empty type `T` is such that `std::is_empty_v<T>` returns true. They are also
1665 the same types for which _empty base optimization_ (EBO) is possibile.<br/>
1666 `EnTT` handles these types in a special way, optimizing both in terms of
1667 performance and memory usage. However, this also has consequences that are worth
1670 When an empty type is detected, it's not instantiated in any case. Therefore,
1671 only the entities to which it's assigned are made available. All the iterators
1672 as well as the `get` member functions of the registry, the views and the groups
1673 will return temporary objects. Similarly, some functions such as `try_get` or
1674 the raw access to the list of components aren't available for this kind of
1676 On the other hand, iterations are faster because only the entities to which the
1677 type is assigned are considered. Moreover, less memory is used, since there
1678 doesn't exist any instance of the component, no matter how many entities it is
1681 For similar reasons, wherever a function type of a listener accepts a component,
1682 it cannot be caught by a non-const reference. Capture it by copy or by const
1685 More in general, none of the features offered by the library is affected, but
1686 for the ones that require to return actual instances.<br/>
1687 This optimization can be disabled by defining the `ENTT_DISABLE_ETO` macro. In
1688 this case, the empty types will be treated like all other types, no matter what.
1692 In general, the entire registry isn't thread safe as it is. Thread safety isn't
1693 something that users should want out of the box for several reasons. Just to
1694 mention one of them: performance.<br/>
1695 Views, groups and consequently the approach adopted by `EnTT` are the great
1696 exception to the rule. It's true that views, groups and iterators in general
1697 aren't thread safe by themselves. Because of this users shouldn't try to iterate
1698 a set of components and modify the same set concurrently. However:
1700 * As long as a thread iterates the entities that have the component `X` or
1701 assign and removes that component from a set of entities, another thread can
1702 safely do the same with components `Y` and `Z` and everything will work like a
1703 charm. As a trivial example, users can freely execute the rendering system and
1704 iterate the renderable entities while updating a physic component concurrently
1705 on a separate thread.
1707 * Similarly, a single set of components can be iterated by multiple threads as
1708 long as the components are neither assigned nor removed in the meantime. In
1709 other words, a hypothetical movement system can start multiple threads, each
1710 of which will access the components that carry information about velocity and
1711 position for its entities.
1713 This kind of entity-component systems can be used in single threaded
1714 applications as well as along with async stuff or multiple threads. Moreover,
1715 typical thread based models for _ECS_ don't require a fully thread safe registry
1716 to work. Actually, users can reach the goal with the registry as it is while
1717 working with most of the common models.
1719 Because of the few reasons mentioned above and many others not mentioned, users
1720 are completely responsible for synchronization whether required. On the other
1721 hand, they could get away with it without having to resort to particular
1726 A special mention is needed for the iterators returned by the views and the
1727 groups. Most of the time they meet the requirements of random access iterators,
1728 in all cases they meet at least the requirements of forward iterators.<br/>
1729 In other terms, they are suitable for use with the parallel algorithms of the
1730 standard library. If it's not clear, this is a great thing.
1732 As an example, this kind of iterators can be used in combination with
1733 `std::for_each` and `std::execution::par` to parallelize the visit and therefore
1734 the update of the components returned by a view or a group, as long as the
1735 constraints previously discussed are respected:
1738 auto view = registry.view<position, const velocity>();
1740 std::for_each(std::execution::par_unseq, view.begin(), view.end(), [&view](auto entity) {
1745 This can increase the throughput considerably, even without resorting to who
1746 knows what artifacts that are difficult to maintain over time.
1748 Unfortunately, because of the limitations of the current revision of the
1749 standard, the parallel `std::for_each` accepts only forward iterators. This
1750 means that the iterators provided by the library cannot return proxy objects as
1751 references and **must** return actual reference types instead.<br/>
1752 This may change in the future and the iterators will almost certainly return
1753 both the entities and a list of references to their components sooner or later.
1754 Multi-pass guarantee won't break in any case and the performance should even
1755 benefit from it further.
1757 # Beyond this document
1759 There are many other features and functions not listed in this document.<br/>
1760 `EnTT` and in particular its ECS part is in continuous development and some
1761 things could be forgotten, others could have been omitted on purpose to reduce
1762 the size of this file. Unfortunately, some parts may even be outdated and still
1765 For further information, it's recommended to refer to the documentation included
1766 in the code itself or join the official channels to ask a question.