Dedupe move logic in remove_bundle and remove_bundle_intersection (#2521)

This logic was in both `remove_bundle` and ` remove_bundle_intersection` but only differed by whether we call `.._forget_missing_..` or `.._drop_missing_..`
This commit is contained in:
Boxy 2021-07-27 05:16:47 +00:00
parent d3ae816e3e
commit c83a184e2f

View file

@ -340,6 +340,42 @@ impl<'w> EntityMut<'w> {
}) })
}; };
unsafe {
Self::move_entity_from_remove::<false>(
entity,
&mut self.location,
old_location.archetype_id,
old_location,
entities,
archetypes,
storages,
new_archetype_id,
);
}
Some(result)
}
/// Safety: `new_archetype_id` must have the same or a subset of the components
/// in `old_archetype_id`. Probably more safety stuff too, audit a call to
/// this fn as if the code here was written inline
///
/// when DROP is true removed components will be dropped otherwise they will be forgotten
///
// We use a const generic here so that we are less reliant on
// inlining for rustc to optimize out the `match DROP`
#[allow(clippy::too_many_arguments)]
unsafe fn move_entity_from_remove<const DROP: bool>(
entity: Entity,
self_location: &mut EntityLocation,
old_archetype_id: ArchetypeId,
old_location: EntityLocation,
entities: &mut Entities,
archetypes: &mut Archetypes,
storages: &mut Storages,
new_archetype_id: ArchetypeId,
) {
let old_archetype = &mut archetypes[old_archetype_id];
let remove_result = old_archetype.swap_remove(old_location.index); let remove_result = old_archetype.swap_remove(old_location.index);
if let Some(swapped_entity) = remove_result.swapped_entity { if let Some(swapped_entity) = remove_result.swapped_entity {
entities.meta[swapped_entity.id as usize].location = old_location; entities.meta[swapped_entity.id as usize].location = old_location;
@ -349,34 +385,34 @@ impl<'w> EntityMut<'w> {
let new_archetype = &mut archetypes[new_archetype_id]; let new_archetype = &mut archetypes[new_archetype_id];
let new_location = if old_table_id == new_archetype.table_id() { let new_location = if old_table_id == new_archetype.table_id() {
unsafe { new_archetype.allocate(entity, old_table_row) } new_archetype.allocate(entity, old_table_row)
} else { } else {
let (old_table, new_table) = storages let (old_table, new_table) = storages
.tables .tables
.get_2_mut(old_table_id, new_archetype.table_id()); .get_2_mut(old_table_id, new_archetype.table_id());
// SAFE: table_row exists. All "missing" components have been extracted into the bundle // SAFE: old_table_row exists
// above and the caller takes ownership let move_result = if DROP {
let move_result = old_table.move_to_and_drop_missing_unchecked(old_table_row, new_table)
unsafe { old_table.move_to_and_forget_missing_unchecked(old_table_row, new_table) }; } else {
old_table.move_to_and_forget_missing_unchecked(old_table_row, new_table)
};
// SAFE: new_table_row is a valid position in new_archetype's table // SAFE: move_result.new_row is a valid position in new_archetype's table
let new_location = unsafe { new_archetype.allocate(entity, move_result.new_row) }; let new_location = new_archetype.allocate(entity, move_result.new_row);
// if an entity was moved into this entity's table spot, update its table row // if an entity was moved into this entity's table spot, update its table row
if let Some(swapped_entity) = move_result.swapped_entity { if let Some(swapped_entity) = move_result.swapped_entity {
let swapped_location = entities.get(swapped_entity).unwrap(); let swapped_location = entities.get(swapped_entity).unwrap();
let archetype = &mut archetypes[swapped_location.archetype_id]; archetypes[swapped_location.archetype_id]
archetype.set_entity_table_row(swapped_location.index, old_table_row); .set_entity_table_row(swapped_location.index, old_table_row);
} }
new_location new_location
}; };
self.location = new_location; *self_location = new_location;
entities.meta[self.entity.id as usize].location = new_location; entities.meta[entity.id as usize].location = new_location;
Some(result)
} }
/// Remove any components in the bundle that the entity has. /// Remove any components in the bundle that the entity has.
@ -425,40 +461,18 @@ impl<'w> EntityMut<'w> {
} }
} }
let remove_result = old_archetype.swap_remove(old_location.index); unsafe {
if let Some(swapped_entity) = remove_result.swapped_entity { Self::move_entity_from_remove::<true>(
entities.meta[swapped_entity.id as usize].location = old_location; entity,
&mut self.location,
old_location.archetype_id,
old_location,
entities,
archetypes,
storages,
new_archetype_id,
)
} }
let old_table_row = remove_result.table_row;
let old_table_id = old_archetype.table_id();
let new_archetype = &mut archetypes[new_archetype_id];
let new_location = if old_table_id == new_archetype.table_id() {
unsafe { new_archetype.allocate(entity, old_table_row) }
} else {
let (old_table, new_table) = storages
.tables
.get_2_mut(old_table_id, new_archetype.table_id());
// SAFE: table_row exists
let move_result =
unsafe { old_table.move_to_and_drop_missing_unchecked(old_table_row, new_table) };
// SAFE: new_table_row is a valid position in new_archetype's table
let new_location = unsafe { new_archetype.allocate(entity, move_result.new_row) };
// if an entity was moved into this entity's table spot, update its table row
if let Some(swapped_entity) = move_result.swapped_entity {
let swapped_location = entities.get(swapped_entity).unwrap();
archetypes[swapped_location.archetype_id]
.set_entity_table_row(swapped_location.index, old_table_row);
}
new_location
};
self.location = new_location;
entities.meta[self.entity.id as usize].location = new_location;
} }
pub fn insert<T: Component>(&mut self, value: T) -> &mut Self { pub fn insert<T: Component>(&mut self, value: T) -> &mut Self {