Remove redundant table and sparse set component IDs from Archetype (#4927)
# Objective Archetype is a deceptively large type in memory. It stores metadata about which components are in which storage in multiple locations, which is only used when creating new Archetypes while moving entities. ## Solution Remove the redundant `Box<[ComponentId]>`s and iterate over the sparse set of component metadata instead. Reduces Archetype's size by 4 usizes (32 bytes on 64-bit systems), as well as the additional allocations for holding these slices. It'd seem like there's a downside that the origin archetype has it's component metadata iterated over twice when creating a new archetype, but this change also removes the extra `Vec<ArchetypeComponentId>` allocations when creating a new archetype which may amortize out to a net gain here. This change likely negatively impacts creating new archetypes with a large number of components, but that's a cost mitigated by the fact that these archetypal relationships are cached in Edges and is incurred only once for each edge created. ## Additional Context There are several other in-flight PRs that shrink Archetype: - #4800 merges the entities and rows Vecs together (shaves off 24 bytes per archetype) - #4809 removes unique_components and moves it to it's own dedicated storage (shaves off 72 bytes per archetype) --- ## Changelog Changed: `Archetype::table_components` and `Archetype::sparse_set_components` return iterators instead of slices. `Archetype::new` requires iterators instead of parallel slices/vecs. ## Migration Guide Do I still need to do this? I really hope people were not relying on the public facing APIs changed here.
This commit is contained in:
		
							parent
							
								
									51aab032ed
								
							
						
					
					
						commit
						11c544c29a
					
				@ -182,8 +182,6 @@ pub struct Archetype {
 | 
			
		||||
    table_id: TableId,
 | 
			
		||||
    edges: Edges,
 | 
			
		||||
    entities: Vec<ArchetypeEntity>,
 | 
			
		||||
    table_components: Box<[ComponentId]>,
 | 
			
		||||
    sparse_set_components: Box<[ComponentId]>,
 | 
			
		||||
    components: SparseSet<ComponentId, ArchetypeComponentInfo>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -191,18 +189,15 @@ impl Archetype {
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        id: ArchetypeId,
 | 
			
		||||
        table_id: TableId,
 | 
			
		||||
        table_components: Box<[ComponentId]>,
 | 
			
		||||
        sparse_set_components: Box<[ComponentId]>,
 | 
			
		||||
        table_archetype_components: Vec<ArchetypeComponentId>,
 | 
			
		||||
        sparse_set_archetype_components: Vec<ArchetypeComponentId>,
 | 
			
		||||
        table_components: impl Iterator<Item = (ComponentId, ArchetypeComponentId)>,
 | 
			
		||||
        sparse_set_components: impl Iterator<Item = (ComponentId, ArchetypeComponentId)>,
 | 
			
		||||
    ) -> Self {
 | 
			
		||||
        let mut components =
 | 
			
		||||
            SparseSet::with_capacity(table_components.len() + sparse_set_components.len());
 | 
			
		||||
        for (component_id, archetype_component_id) in
 | 
			
		||||
            table_components.iter().zip(table_archetype_components)
 | 
			
		||||
        {
 | 
			
		||||
        let (min_table, _) = table_components.size_hint();
 | 
			
		||||
        let (min_sparse, _) = sparse_set_components.size_hint();
 | 
			
		||||
        let mut components = SparseSet::with_capacity(min_table + min_sparse);
 | 
			
		||||
        for (component_id, archetype_component_id) in table_components {
 | 
			
		||||
            components.insert(
 | 
			
		||||
                *component_id,
 | 
			
		||||
                component_id,
 | 
			
		||||
                ArchetypeComponentInfo {
 | 
			
		||||
                    storage_type: StorageType::Table,
 | 
			
		||||
                    archetype_component_id,
 | 
			
		||||
@ -210,12 +205,9 @@ impl Archetype {
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (component_id, archetype_component_id) in sparse_set_components
 | 
			
		||||
            .iter()
 | 
			
		||||
            .zip(sparse_set_archetype_components)
 | 
			
		||||
        {
 | 
			
		||||
        for (component_id, archetype_component_id) in sparse_set_components {
 | 
			
		||||
            components.insert(
 | 
			
		||||
                *component_id,
 | 
			
		||||
                component_id,
 | 
			
		||||
                ArchetypeComponentInfo {
 | 
			
		||||
                    storage_type: StorageType::SparseSet,
 | 
			
		||||
                    archetype_component_id,
 | 
			
		||||
@ -225,10 +217,8 @@ impl Archetype {
 | 
			
		||||
        Self {
 | 
			
		||||
            id,
 | 
			
		||||
            table_id,
 | 
			
		||||
            entities: Vec::new(),
 | 
			
		||||
            components,
 | 
			
		||||
            table_components,
 | 
			
		||||
            sparse_set_components,
 | 
			
		||||
            entities: Default::default(),
 | 
			
		||||
            edges: Default::default(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -249,13 +239,19 @@ impl Archetype {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn table_components(&self) -> &[ComponentId] {
 | 
			
		||||
        &self.table_components
 | 
			
		||||
    pub fn table_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
 | 
			
		||||
        self.components
 | 
			
		||||
            .iter()
 | 
			
		||||
            .filter(|(_, component)| component.storage_type == StorageType::Table)
 | 
			
		||||
            .map(|(id, _)| *id)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    pub fn sparse_set_components(&self) -> &[ComponentId] {
 | 
			
		||||
        &self.sparse_set_components
 | 
			
		||||
    pub fn sparse_set_components(&self) -> impl Iterator<Item = ComponentId> + '_ {
 | 
			
		||||
        self.components
 | 
			
		||||
            .iter()
 | 
			
		||||
            .filter(|(_, component)| component.storage_type == StorageType::SparseSet)
 | 
			
		||||
            .map(|(id, _)| *id)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
@ -484,38 +480,33 @@ impl Archetypes {
 | 
			
		||||
        table_components: Vec<ComponentId>,
 | 
			
		||||
        sparse_set_components: Vec<ComponentId>,
 | 
			
		||||
    ) -> ArchetypeId {
 | 
			
		||||
        let table_components = table_components.into_boxed_slice();
 | 
			
		||||
        let sparse_set_components = sparse_set_components.into_boxed_slice();
 | 
			
		||||
        let archetype_identity = ArchetypeIdentity {
 | 
			
		||||
            sparse_set_components: sparse_set_components.clone(),
 | 
			
		||||
            table_components: table_components.clone(),
 | 
			
		||||
            sparse_set_components: sparse_set_components.clone().into_boxed_slice(),
 | 
			
		||||
            table_components: table_components.clone().into_boxed_slice(),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let archetypes = &mut self.archetypes;
 | 
			
		||||
        let archetype_component_count = &mut self.archetype_component_count;
 | 
			
		||||
        let mut next_archetype_component_id = move || {
 | 
			
		||||
            let id = ArchetypeComponentId(*archetype_component_count);
 | 
			
		||||
            *archetype_component_count += 1;
 | 
			
		||||
            id
 | 
			
		||||
        };
 | 
			
		||||
        *self
 | 
			
		||||
            .archetype_ids
 | 
			
		||||
            .entry(archetype_identity)
 | 
			
		||||
            .or_insert_with(move || {
 | 
			
		||||
                let id = ArchetypeId(archetypes.len());
 | 
			
		||||
                let table_archetype_components = (0..table_components.len())
 | 
			
		||||
                    .map(|_| next_archetype_component_id())
 | 
			
		||||
                    .collect();
 | 
			
		||||
                let sparse_set_archetype_components = (0..sparse_set_components.len())
 | 
			
		||||
                    .map(|_| next_archetype_component_id())
 | 
			
		||||
                    .collect();
 | 
			
		||||
                let table_start = *archetype_component_count;
 | 
			
		||||
                *archetype_component_count += table_components.len();
 | 
			
		||||
                let table_archetype_components =
 | 
			
		||||
                    (table_start..*archetype_component_count).map(ArchetypeComponentId);
 | 
			
		||||
                let sparse_start = *archetype_component_count;
 | 
			
		||||
                *archetype_component_count += sparse_set_components.len();
 | 
			
		||||
                let sparse_set_archetype_components =
 | 
			
		||||
                    (sparse_start..*archetype_component_count).map(ArchetypeComponentId);
 | 
			
		||||
                archetypes.push(Archetype::new(
 | 
			
		||||
                    id,
 | 
			
		||||
                    table_id,
 | 
			
		||||
                    table_components,
 | 
			
		||||
                    sparse_set_components,
 | 
			
		||||
                    table_archetype_components,
 | 
			
		||||
                    sparse_set_archetype_components,
 | 
			
		||||
                    table_components.into_iter().zip(table_archetype_components),
 | 
			
		||||
                    sparse_set_components
 | 
			
		||||
                        .into_iter()
 | 
			
		||||
                        .zip(sparse_set_archetype_components),
 | 
			
		||||
                ));
 | 
			
		||||
                id
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
@ -461,7 +461,7 @@ impl BundleInfo {
 | 
			
		||||
                table_components = if new_table_components.is_empty() {
 | 
			
		||||
                    // if there are no new table components, we can keep using this table
 | 
			
		||||
                    table_id = current_archetype.table_id();
 | 
			
		||||
                    current_archetype.table_components().to_vec()
 | 
			
		||||
                    current_archetype.table_components().collect()
 | 
			
		||||
                } else {
 | 
			
		||||
                    new_table_components.extend(current_archetype.table_components());
 | 
			
		||||
                    // sort to ignore order while hashing
 | 
			
		||||
@ -477,7 +477,7 @@ impl BundleInfo {
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                sparse_set_components = if new_sparse_set_components.is_empty() {
 | 
			
		||||
                    current_archetype.sparse_set_components().to_vec()
 | 
			
		||||
                    current_archetype.sparse_set_components().collect()
 | 
			
		||||
                } else {
 | 
			
		||||
                    new_sparse_set_components.extend(current_archetype.sparse_set_components());
 | 
			
		||||
                    // sort to ignore order while hashing
 | 
			
		||||
 | 
			
		||||
@ -505,7 +505,7 @@ impl<'w> EntityMut<'w> {
 | 
			
		||||
            table_row = remove_result.table_row;
 | 
			
		||||
 | 
			
		||||
            for component_id in archetype.sparse_set_components() {
 | 
			
		||||
                let sparse_set = world.storages.sparse_sets.get_mut(*component_id).unwrap();
 | 
			
		||||
                let sparse_set = world.storages.sparse_sets.get_mut(component_id).unwrap();
 | 
			
		||||
                sparse_set.remove(self.entity);
 | 
			
		||||
            }
 | 
			
		||||
            // SAFETY: table rows stored in archetypes always exist
 | 
			
		||||
@ -843,8 +843,8 @@ unsafe fn remove_bundle_from_archetype(
 | 
			
		||||
            // components are already sorted
 | 
			
		||||
            removed_table_components.sort();
 | 
			
		||||
            removed_sparse_set_components.sort();
 | 
			
		||||
            next_table_components = current_archetype.table_components().to_vec();
 | 
			
		||||
            next_sparse_set_components = current_archetype.sparse_set_components().to_vec();
 | 
			
		||||
            next_table_components = current_archetype.table_components().collect();
 | 
			
		||||
            next_sparse_set_components = current_archetype.sparse_set_components().collect();
 | 
			
		||||
            sorted_remove(&mut next_table_components, &removed_table_components);
 | 
			
		||||
            sorted_remove(
 | 
			
		||||
                &mut next_sparse_set_components,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user