Skip to content

Commit f7e60ca

Browse files
Avoid needless allocation in get_multiple_mut
1 parent 2cc1c4d commit f7e60ca

File tree

1 file changed

+39
-17
lines changed

1 file changed

+39
-17
lines changed

crates/bevy_ecs/src/system/query.rs

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -873,24 +873,15 @@ where
873873
lower_bound
874874
};
875875

876-
let mut entities_seen = HashSet::with_capacity(best_bound * std::mem::size_of::<Entity>());
876+
let entities_seen = HashSet::with_capacity(best_bound * std::mem::size_of::<Entity>());
877877

878-
// We must collect the results before converting back into an iterator
879-
// in order to ensure that we don't have any dangling references to entities_seen that need to be evaluated later
880-
let results: Vec<Result<<Q::Fetch as Fetch>::Item, QueryEntityError>> = entities_iter
881-
.map(|entity| {
882-
if entities_seen.contains(&entity) {
883-
Err(QueryEntityError::AliasedMutability)
884-
} else {
885-
entities_seen.insert(entity);
886-
887-
// SAFE: entities are checked for uniqueness using a HashSet
888-
unsafe { self.get_unchecked(entity) }
889-
}
890-
})
891-
.collect();
892-
893-
results.into_iter()
878+
// This is an iterator adaptor struct
879+
// used to capture the value of `entities_seen` into the iterator returned
880+
GetMultipleMut {
881+
seen: entities_seen,
882+
query: self,
883+
iter: entities_iter,
884+
}
894885
}
895886

896887
/// Returns the query result for the given [`Entity`].
@@ -1216,6 +1207,37 @@ where
12161207
}
12171208
}
12181209

1210+
/// Iterator adaptor struct used for [`Query::get_multiple_mut`]('Query::get_multiple_mut`)
1211+
/// See https://stackoverflow.com/a/49813195 for more exposition
1212+
struct GetMultipleMut<'w, 's, 'q, Q: WorldQuery, F: WorldQuery, I>
1213+
where
1214+
F::Fetch: FilterFetch,
1215+
{
1216+
seen: HashSet<Entity>,
1217+
query: &'q Query<'w, 's, Q, F>,
1218+
iter: I,
1219+
}
1220+
1221+
impl<'w, 's, 'q: 's, Q: WorldQuery, F: WorldQuery, I: Iterator<Item = Entity>> Iterator
1222+
for GetMultipleMut<'w, 's, 'q, Q, F, I>
1223+
where
1224+
F::Fetch: FilterFetch,
1225+
{
1226+
type Item = Result<<Q::Fetch as Fetch<'w, 's>>::Item, QueryEntityError>;
1227+
1228+
fn next(&mut self) -> Option<Self::Item> {
1229+
Some({
1230+
let entity = self.iter.next()?;
1231+
if self.seen.insert(entity) {
1232+
// SAFE: entities are checked for uniqueness using a HashSet
1233+
unsafe { Query::<'w, 's, Q, F>::get_unchecked(self.query, entity) }
1234+
} else {
1235+
Err(QueryEntityError::AliasedMutability)
1236+
}
1237+
})
1238+
}
1239+
}
1240+
12191241
/// An error that occurs when retrieving a specific [`Entity`]'s component from a [`Query`]
12201242
#[derive(Error, Debug)]
12211243
pub enum QueryComponentError {

0 commit comments

Comments
 (0)