Allow dense iteration for FilteredEntity(Ref|Mut) in more cases. #16396
+4
−12
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Objective
Improve the performance of some dynamic queries with
FilteredEntity(Ref|Mut)
by allowing dense iteration in more cases, and remove a call to the sort-of deprecatedAccess::component_reads_and_writes()
method.QueryBuilder
currently requires sparse iteration if any sparse set components may be read. We do need sparse iteration if sparse set components are used in the filters, butFilteredEntityRef
can still perform dense iteration when reading optional components or when reading all components.Note that the optional case is different from
Option
, which performs sparse iteration when the inner query is sparse so that it can cache whether the inner query matches for an entire archetype.Solution
Change
FilteredEntity(Ref|Mut)
to haveIS_DENSE = true
. It used to require sparse iteration in order to filter theAccess
for each archetype, but #15207 changed it to copy the entire access.Change
QueryBuilder::is_dense()
to checkD::IS_DENSE && F::IS_DENSE
instead of looking at the component reads and writes.QueryBuilder::is_dense()
still checks the filters, sobuilder.data::<&Sparse>()
will still cause sparse iteration, butbuilder.data::<Option<&Sparse>>()
no longer will.I believe this is sound, even in the presence of query transmutes. The only
WorldQuery
implementations that rely on a sparse query being sparse for soundness are&
,&mut
,Ref
, andMut
, but they can only be transmuted to if the component is in therequired
set. If a dynamic query has the component in therequired
set, then it appears in the filters and the query will use sparse iteration.Note that
Option
andHas
will misbehave and reportNone
andfalse
for all entities if they do a dense query while wrapping a sparse component, but they won't cause UB. And it's already possible to hit that case by transmuting fromQuery<EntityMut>
toQuery<Option<&Sparse>>
.