kaige_ecs/
storage.rs

1//! A "packed archetype" storage model.
2//!
3//! Any combination of types of components can be attached to each entity
4//! in a [`World`](super::world::World). Storing the (potentially unique)
5//! set of component values for each entity in a manner which is efficient
6//! to search and access is the responsibility of the ECS libary.
7//!
8//! Legion achieves this via the use of "archetypes". Archetypes are a
9//! collection of entities who all have exactly the same set of component
10//! types attached. By storing these together, we can perform filtering
11//! operations at the archetype level without needing to ever inspect each
12//! individual entity. Archetypes also allow us to store contiguous and
13//! ordered arrays of each component. For example, all `Position` components
14//! for all entities in an archetype are stored together in one array, and
15//! can be returned from queries as a slice. All component arrays for an
16//! archetype are stored in the same order and are necessarily the same
17//! length, allowing us to index them together to access the components for
18//! a single entity.
19//!
20//! Because these components are stored contiguously in memory, iterating
21//! through the components in an archetype is extremely performant as
22//! it offers perfect cache locality. By storing each component type in
23//! its own array, we only need to access the memory containing components
24//! actually reqested by the query's view (see the [`query`](crate::query)
25//! module).
26//!
27//! One of the disadvantages of archetypes is that there are discontinuities
28//! between component arrays of different archetypes. In practise this causes
29//! approximately one additional L2/3 cache miss per unique entity layout that
30//! exists among the result set of a query.
31//!
32//! Legion mitigates this by conservatively packing archetype component
33//! slices next to each other. A component slice is considered eligible
34//! for packing if its components have remained stable for some time (i.e no
35//! entities have been added or removed from the archetype recently) and
36//! an estimate of potential saved cache misses passes a "worthwhile"
37//! threshold.
38//!
39//! By default, legion will pack component slices in the order in which
40//! the archetypes were created. This matches the order in which queries will
41//! attempt to access each slice. However, most queries do not access all
42//! archetypes that contain a certain component - more likely they will skip
43//! past many archetypes due to other filters (such as only being interested
44//! in archetypes which also contain another specific component).
45//!
46//! We can provide hints to a world about how it should pack archetypes by
47//! declaring groups with the world's [options](super::world::WorldOptions)
48//! which can be provided while constructing the world. Component groups can be
49//! used to accelerate the largest and most common queries by optmizing the data
50//! layout for those queries.
51//!
52//! Each component type in a world may belong to precisely one group. A group is
53//! a set of components which are frequently queried for together. Queries which
54//! match a group will not suffer from performance loss due to archetype
55//! fragmentation.
56//!
57//! Each group implicitly also defines sub-groups, such that the group
58//! `(A, B, C, D)` also defines the groups `(A, B, C)` and `(A, B)`.
59//!
60//! Groups are defined before constructing a world and are passed in the world's
61//! options.
62//!
63//! ```
64//! # use legion::*;
65//! // our component types
66//! struct A;
67//! struct B;
68//! struct C;
69//!
70//! // create a world optimized for cases where (A, B) and/or
71//! // (A, B, C) are significant queries.
72//! let group = <(A, B, C)>::to_group();
73//! let options = WorldOptions {
74//!     groups: vec![group],
75//! };
76//! let world = World::new(options);
77//! ```
78
79pub use crate::internals::{
80    cons::{ConsAppend, ConsFlatten},
81    hash::{ComponentTypeIdHasher, U64Hasher},
82    insert::{
83        ArchetypeSource, ArchetypeWriter, ComponentSource, ComponentWriter, IntoComponentSource,
84        IntoSoa, UnknownComponentWriter,
85    },
86    storage::{
87        archetype::{Archetype, ArchetypeIndex, EntityLayout},
88        component::{Component, ComponentTypeId},
89        group::{Group, GroupDef, GroupSource},
90        index::SearchIndex,
91        packed::PackedStorage,
92        ComponentIndex, ComponentMeta, ComponentSlice, ComponentSliceMut, ComponentStorage,
93        Components, Epoch, MultiMut, PackOptions, UnknownComponentStorage, Version,
94    },
95};