Skip to content

Commit c83a184

Browse files
committed
Dedupe move logic in remove_bundle and remove_bundle_intersection (bevyengine#2521)
This logic was in both `remove_bundle` and ` remove_bundle_intersection` but only differed by whether we call `.._forget_missing_..` or `.._drop_missing_..`
1 parent d3ae816 commit c83a184

File tree

1 file changed

+60
-46
lines changed

1 file changed

+60
-46
lines changed

crates/bevy_ecs/src/world/entity_ref.rs

Lines changed: 60 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,42 @@ impl<'w> EntityMut<'w> {
340340
})
341341
};
342342

343+
unsafe {
344+
Self::move_entity_from_remove::<false>(
345+
entity,
346+
&mut self.location,
347+
old_location.archetype_id,
348+
old_location,
349+
entities,
350+
archetypes,
351+
storages,
352+
new_archetype_id,
353+
);
354+
}
355+
356+
Some(result)
357+
}
358+
359+
/// Safety: `new_archetype_id` must have the same or a subset of the components
360+
/// in `old_archetype_id`. Probably more safety stuff too, audit a call to
361+
/// this fn as if the code here was written inline
362+
///
363+
/// when DROP is true removed components will be dropped otherwise they will be forgotten
364+
///
365+
// We use a const generic here so that we are less reliant on
366+
// inlining for rustc to optimize out the `match DROP`
367+
#[allow(clippy::too_many_arguments)]
368+
unsafe fn move_entity_from_remove<const DROP: bool>(
369+
entity: Entity,
370+
self_location: &mut EntityLocation,
371+
old_archetype_id: ArchetypeId,
372+
old_location: EntityLocation,
373+
entities: &mut Entities,
374+
archetypes: &mut Archetypes,
375+
storages: &mut Storages,
376+
new_archetype_id: ArchetypeId,
377+
) {
378+
let old_archetype = &mut archetypes[old_archetype_id];
343379
let remove_result = old_archetype.swap_remove(old_location.index);
344380
if let Some(swapped_entity) = remove_result.swapped_entity {
345381
entities.meta[swapped_entity.id as usize].location = old_location;
@@ -349,34 +385,34 @@ impl<'w> EntityMut<'w> {
349385
let new_archetype = &mut archetypes[new_archetype_id];
350386

351387
let new_location = if old_table_id == new_archetype.table_id() {
352-
unsafe { new_archetype.allocate(entity, old_table_row) }
388+
new_archetype.allocate(entity, old_table_row)
353389
} else {
354390
let (old_table, new_table) = storages
355391
.tables
356392
.get_2_mut(old_table_id, new_archetype.table_id());
357393

358-
// SAFE: table_row exists. All "missing" components have been extracted into the bundle
359-
// above and the caller takes ownership
360-
let move_result =
361-
unsafe { old_table.move_to_and_forget_missing_unchecked(old_table_row, new_table) };
394+
// SAFE: old_table_row exists
395+
let move_result = if DROP {
396+
old_table.move_to_and_drop_missing_unchecked(old_table_row, new_table)
397+
} else {
398+
old_table.move_to_and_forget_missing_unchecked(old_table_row, new_table)
399+
};
362400

363-
// SAFE: new_table_row is a valid position in new_archetype's table
364-
let new_location = unsafe { new_archetype.allocate(entity, move_result.new_row) };
401+
// SAFE: move_result.new_row is a valid position in new_archetype's table
402+
let new_location = new_archetype.allocate(entity, move_result.new_row);
365403

366404
// if an entity was moved into this entity's table spot, update its table row
367405
if let Some(swapped_entity) = move_result.swapped_entity {
368406
let swapped_location = entities.get(swapped_entity).unwrap();
369-
let archetype = &mut archetypes[swapped_location.archetype_id];
370-
archetype.set_entity_table_row(swapped_location.index, old_table_row);
407+
archetypes[swapped_location.archetype_id]
408+
.set_entity_table_row(swapped_location.index, old_table_row);
371409
}
372410

373411
new_location
374412
};
375413

376-
self.location = new_location;
377-
entities.meta[self.entity.id as usize].location = new_location;
378-
379-
Some(result)
414+
*self_location = new_location;
415+
entities.meta[entity.id as usize].location = new_location;
380416
}
381417

382418
/// Remove any components in the bundle that the entity has.
@@ -425,40 +461,18 @@ impl<'w> EntityMut<'w> {
425461
}
426462
}
427463

428-
let remove_result = old_archetype.swap_remove(old_location.index);
429-
if let Some(swapped_entity) = remove_result.swapped_entity {
430-
entities.meta[swapped_entity.id as usize].location = old_location;
464+
unsafe {
465+
Self::move_entity_from_remove::<true>(
466+
entity,
467+
&mut self.location,
468+
old_location.archetype_id,
469+
old_location,
470+
entities,
471+
archetypes,
472+
storages,
473+
new_archetype_id,
474+
)
431475
}
432-
let old_table_row = remove_result.table_row;
433-
let old_table_id = old_archetype.table_id();
434-
let new_archetype = &mut archetypes[new_archetype_id];
435-
436-
let new_location = if old_table_id == new_archetype.table_id() {
437-
unsafe { new_archetype.allocate(entity, old_table_row) }
438-
} else {
439-
let (old_table, new_table) = storages
440-
.tables
441-
.get_2_mut(old_table_id, new_archetype.table_id());
442-
443-
// SAFE: table_row exists
444-
let move_result =
445-
unsafe { old_table.move_to_and_drop_missing_unchecked(old_table_row, new_table) };
446-
447-
// SAFE: new_table_row is a valid position in new_archetype's table
448-
let new_location = unsafe { new_archetype.allocate(entity, move_result.new_row) };
449-
450-
// if an entity was moved into this entity's table spot, update its table row
451-
if let Some(swapped_entity) = move_result.swapped_entity {
452-
let swapped_location = entities.get(swapped_entity).unwrap();
453-
archetypes[swapped_location.archetype_id]
454-
.set_entity_table_row(swapped_location.index, old_table_row);
455-
}
456-
457-
new_location
458-
};
459-
460-
self.location = new_location;
461-
entities.meta[self.entity.id as usize].location = new_location;
462476
}
463477

464478
pub fn insert<T: Component>(&mut self, value: T) -> &mut Self {

0 commit comments

Comments
 (0)