@@ -128,7 +128,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
128
128
/// # Safety
129
129
/// - all `rows` must be in `[0, table.entity_count)`.
130
130
/// - `table` must match D and F
131
- /// - Both `D::IS_DENSE` and `F::IS_DENSE ` must be true.
131
+ /// - The query iteration must be dense (i.e. `self.query_state.is_dense ` must be true) .
132
132
#[ inline]
133
133
pub ( super ) unsafe fn fold_over_table_range < B , Func > (
134
134
& mut self ,
@@ -183,7 +183,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
183
183
/// # Safety
184
184
/// - all `indices` must be in `[0, archetype.len())`.
185
185
/// - `archetype` must match D and F
186
- /// - Either `D::IS_DENSE` or `F::IS_DENSE ` must be false.
186
+ /// - The query iteration must not be dense (i.e. `self.query_state.is_dense ` must be false) .
187
187
#[ inline]
188
188
pub ( super ) unsafe fn fold_over_archetype_range < B , Func > (
189
189
& mut self ,
@@ -252,7 +252,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
252
252
/// - all `indices` must be in `[0, archetype.len())`.
253
253
/// - `archetype` must match D and F
254
254
/// - `archetype` must have the same length with it's table.
255
- /// - Either `D::IS_DENSE` or `F::IS_DENSE ` must be false.
255
+ /// - The query iteration must not be dense (i.e. `self.query_state.is_dense ` must be false) .
256
256
#[ inline]
257
257
pub ( super ) unsafe fn fold_over_dense_archetype_range < B , Func > (
258
258
& mut self ,
@@ -1031,40 +1031,47 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Iterator for QueryIter<'w, 's, D, F>
1031
1031
let Some ( item) = self . next ( ) else { break } ;
1032
1032
accum = func ( accum, item) ;
1033
1033
}
1034
- for id in self . cursor . storage_id_iter . clone ( ) {
1035
- if D :: IS_DENSE && F :: IS_DENSE {
1034
+
1035
+ if self . cursor . is_dense {
1036
+ for id in self . cursor . storage_id_iter . clone ( ) {
1037
+ // SAFETY: `self.cursor.is_dense` is true, so storage ids are guaranteed to be table ids.
1038
+ let table_id = unsafe { id. table_id } ;
1036
1039
// SAFETY: Matched table IDs are guaranteed to still exist.
1037
- let table = unsafe { self . tables . get ( id. table_id ) . debug_checked_unwrap ( ) } ;
1040
+ let table = unsafe { self . tables . get ( table_id) . debug_checked_unwrap ( ) } ;
1041
+
1038
1042
accum =
1039
1043
// SAFETY:
1040
1044
// - The fetched table matches both D and F
1041
1045
// - The provided range is equivalent to [0, table.entity_count)
1042
- // - The if block ensures that D::IS_DENSE and F::IS_DENSE are both true
1046
+ // - The if block ensures that the query iteration is dense
1043
1047
unsafe { self . fold_over_table_range ( accum, & mut func, table, 0 ..table. entity_count ( ) ) } ;
1044
- } else {
1045
- let archetype =
1046
- // SAFETY: Matched archetype IDs are guaranteed to still exist.
1047
- unsafe { self . archetypes . get ( id. archetype_id ) . debug_checked_unwrap ( ) } ;
1048
+ }
1049
+ } else {
1050
+ for id in self . cursor . storage_id_iter . clone ( ) {
1051
+ // SAFETY: `self.cursor.is_dense` is false, so storage ids are guaranteed to be archetype ids.
1052
+ let archetype_id = unsafe { id. archetype_id } ;
1053
+ // SAFETY: Matched archetype IDs are guaranteed to still exist.
1054
+ let archetype = unsafe { self . archetypes . get ( archetype_id) . debug_checked_unwrap ( ) } ;
1048
1055
// SAFETY: Matched table IDs are guaranteed to still exist.
1049
1056
let table = unsafe { self . tables . get ( archetype. table_id ( ) ) . debug_checked_unwrap ( ) } ;
1050
1057
1051
1058
// When an archetype and its table have equal entity counts, dense iteration can be safely used.
1052
1059
// this leverages cache locality to optimize performance.
1053
1060
if table. entity_count ( ) == archetype. len ( ) {
1054
1061
accum =
1055
- // SAFETY:
1056
- // - The fetched archetype matches both D and F
1057
- // - The provided archetype and its' table have the same length.
1058
- // - The provided range is equivalent to [0, archetype.len)
1059
- // - The if block ensures that ether D::IS_DENSE or F::IS_DENSE are false
1060
- unsafe { self . fold_over_dense_archetype_range ( accum, & mut func, archetype, 0 ..archetype. len ( ) ) } ;
1062
+ // SAFETY:
1063
+ // - The fetched archetype matches both D and F
1064
+ // - The provided archetype and its' table have the same length.
1065
+ // - The provided range is equivalent to [0, archetype.len)
1066
+ // - The if block ensures that the query iteration is not dense.
1067
+ unsafe { self . fold_over_dense_archetype_range ( accum, & mut func, archetype, 0 ..archetype. len ( ) ) } ;
1061
1068
} else {
1062
1069
accum =
1063
- // SAFETY:
1064
- // - The fetched archetype matches both D and F
1065
- // - The provided range is equivalent to [0, archetype.len)
1066
- // - The if block ensures that ether D::IS_DENSE or F::IS_DENSE are false
1067
- unsafe { self . fold_over_archetype_range ( accum, & mut func, archetype, 0 ..archetype. len ( ) ) } ;
1070
+ // SAFETY:
1071
+ // - The fetched archetype matches both D and F
1072
+ // - The provided range is equivalent to [0, archetype.len)
1073
+ // - The if block ensures that the query iteration is not dense.
1074
+ unsafe { self . fold_over_archetype_range ( accum, & mut func, archetype, 0 ..archetype. len ( ) ) } ;
1068
1075
}
1069
1076
}
1070
1077
}
@@ -1675,6 +1682,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter, const K: usize> Debug
1675
1682
}
1676
1683
1677
1684
struct QueryIterationCursor < ' w , ' s , D : QueryData , F : QueryFilter > {
1685
+ // whether the query iteration is dense or not. Mirrors QueryState's `is_dense` field.
1686
+ is_dense : bool ,
1678
1687
storage_id_iter : std:: slice:: Iter < ' s , StorageId > ,
1679
1688
table_entities : & ' w [ Entity ] ,
1680
1689
archetype_entities : & ' w [ ArchetypeEntity ] ,
@@ -1689,6 +1698,7 @@ struct QueryIterationCursor<'w, 's, D: QueryData, F: QueryFilter> {
1689
1698
impl < D : QueryData , F : QueryFilter > Clone for QueryIterationCursor < ' _ , ' _ , D , F > {
1690
1699
fn clone ( & self ) -> Self {
1691
1700
Self {
1701
+ is_dense : self . is_dense ,
1692
1702
storage_id_iter : self . storage_id_iter . clone ( ) ,
1693
1703
table_entities : self . table_entities ,
1694
1704
archetype_entities : self . archetype_entities ,
@@ -1701,8 +1711,6 @@ impl<D: QueryData, F: QueryFilter> Clone for QueryIterationCursor<'_, '_, D, F>
1701
1711
}
1702
1712
1703
1713
impl < ' w , ' s , D : QueryData , F : QueryFilter > QueryIterationCursor < ' w , ' s , D , F > {
1704
- const IS_DENSE : bool = D :: IS_DENSE && F :: IS_DENSE ;
1705
-
1706
1714
unsafe fn init_empty (
1707
1715
world : UnsafeWorldCell < ' w > ,
1708
1716
query_state : & ' s QueryState < D , F > ,
@@ -1732,13 +1740,15 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
1732
1740
table_entities : & [ ] ,
1733
1741
archetype_entities : & [ ] ,
1734
1742
storage_id_iter : query_state. matched_storage_ids . iter ( ) ,
1743
+ is_dense : query_state. is_dense ,
1735
1744
current_len : 0 ,
1736
1745
current_row : 0 ,
1737
1746
}
1738
1747
}
1739
1748
1740
1749
fn reborrow ( & mut self ) -> QueryIterationCursor < ' _ , ' s , D , F > {
1741
1750
QueryIterationCursor {
1751
+ is_dense : self . is_dense ,
1742
1752
fetch : D :: shrink_fetch ( self . fetch . clone ( ) ) ,
1743
1753
filter : F :: shrink_fetch ( self . filter . clone ( ) ) ,
1744
1754
table_entities : self . table_entities ,
@@ -1754,7 +1764,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
1754
1764
unsafe fn peek_last ( & mut self ) -> Option < D :: Item < ' w > > {
1755
1765
if self . current_row > 0 {
1756
1766
let index = self . current_row - 1 ;
1757
- if Self :: IS_DENSE {
1767
+ if self . is_dense {
1758
1768
let entity = self . table_entities . get_unchecked ( index) ;
1759
1769
Some ( D :: fetch (
1760
1770
& mut self . fetch ,
@@ -1780,7 +1790,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
1780
1790
/// will be **the exact count of remaining values**.
1781
1791
fn max_remaining ( & self , tables : & ' w Tables , archetypes : & ' w Archetypes ) -> usize {
1782
1792
let ids = self . storage_id_iter . clone ( ) ;
1783
- let remaining_matched: usize = if Self :: IS_DENSE {
1793
+ let remaining_matched: usize = if self . is_dense {
1784
1794
// SAFETY: The if check ensures that storage_id_iter stores TableIds
1785
1795
unsafe { ids. map ( |id| tables[ id. table_id ] . entity_count ( ) ) . sum ( ) }
1786
1796
} else {
@@ -1803,7 +1813,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
1803
1813
archetypes : & ' w Archetypes ,
1804
1814
query_state : & ' s QueryState < D , F > ,
1805
1815
) -> Option < D :: Item < ' w > > {
1806
- if Self :: IS_DENSE {
1816
+ if self . is_dense {
1807
1817
loop {
1808
1818
// we are on the beginning of the query, or finished processing a table, so skip to the next
1809
1819
if self . current_row == self . current_len {
0 commit comments