Skip to content

Commit e42492e

Browse files
james7132Brian Merchant64kramsystem
authored andcommitted
Clean up Fetch code (bevyengine#4800)
# Objective Clean up code surrounding fetch by pulling out the common parts into the iteration code. ## Solution Merge `Fetch::table_fetch` and `Fetch::archetype_fetch` into a single API: `Fetch::fetch(&mut self, entity: &Entity, table_row: &usize)`. This provides everything any fetch requires to internally decide which storage to read from and get the underlying data. All of these functions are marked as `#[inline(always)]` and the arguments are passed as references to attempt to optimize out the argument that isn't being used. External to `Fetch`, Query iteration has been changed to keep track of the table row and entity outside of fetch, which moves a lot of the expensive bookkeeping `Fetch` structs had previously done internally into the outer loop. ~~TODO: Benchmark, docs~~ Done. --- ## Changelog Changed: `Fetch::table_fetch` and `Fetch::archetype_fetch` have been merged into a single `Fetch::fetch` function. ## Migration Guide TODO Co-authored-by: Brian Merchant <[email protected]> Co-authored-by: Saverio Miroddi <[email protected]>
1 parent ec9ec87 commit e42492e

File tree

9 files changed

+426
-527
lines changed

9 files changed

+426
-527
lines changed

crates/bevy_ecs/macros/src/fetch.rs

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -261,9 +261,9 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
261261
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
262262
_state: &Self::State,
263263
_archetype: &'__w #path::archetype::Archetype,
264-
_tables: &'__w #path::storage::Tables
264+
_table: &'__w #path::storage::Table
265265
) {
266-
#(<#field_types>::set_archetype(&mut _fetch.#field_idents, &_state.#field_idents, _archetype, _tables);)*
266+
#(<#field_types>::set_archetype(&mut _fetch.#field_idents, &_state.#field_idents, _archetype, _table);)*
267267
}
268268

269269
/// SAFETY: we call `set_table` for each member that implements `Fetch`
@@ -276,40 +276,27 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
276276
#(<#field_types>::set_table(&mut _fetch.#field_idents, &_state.#field_idents, _table);)*
277277
}
278278

279-
/// SAFETY: we call `table_fetch` for each member that implements `Fetch`.
280-
#[inline]
281-
unsafe fn table_fetch<'__w>(
279+
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
280+
#[inline(always)]
281+
unsafe fn fetch<'__w>(
282282
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
283+
_entity: Entity,
283284
_table_row: usize
284285
) -> <Self as #path::query::WorldQueryGats<'__w>>::Item {
285286
Self::Item {
286-
#(#field_idents: <#field_types>::table_fetch(&mut _fetch.#field_idents, _table_row),)*
287+
#(#field_idents: <#field_types>::fetch(&mut _fetch.#field_idents, _entity, _table_row),)*
287288
#(#ignored_field_idents: Default::default(),)*
288289
}
289290
}
290291

291-
/// SAFETY: we call `archetype_fetch` for each member that implements `Fetch`.
292-
#[inline]
293-
unsafe fn archetype_fetch<'__w>(
294-
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
295-
_archetype_index: usize
296-
) -> <Self as #path::query::WorldQueryGats<'__w>>::Item {
297-
Self::Item {
298-
#(#field_idents: <#field_types>::archetype_fetch(&mut _fetch.#field_idents, _archetype_index),)*
299-
#(#ignored_field_idents: Default::default(),)*
300-
}
301-
}
302-
303-
#[allow(unused_variables)]
304-
#[inline]
305-
unsafe fn table_filter_fetch<'__w>(_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch, _table_row: usize) -> bool {
306-
true #(&& <#field_types>::table_filter_fetch(&mut _fetch.#field_idents, _table_row))*
307-
}
308-
309292
#[allow(unused_variables)]
310-
#[inline]
311-
unsafe fn archetype_filter_fetch<'__w>(_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch, _archetype_index: usize) -> bool {
312-
true #(&& <#field_types>::archetype_filter_fetch(&mut _fetch.#field_idents, _archetype_index))*
293+
#[inline(always)]
294+
unsafe fn filter_fetch<'__w>(
295+
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
296+
_entity: Entity,
297+
_table_row: usize
298+
) -> bool {
299+
true #(&& <#field_types>::filter_fetch(&mut _fetch.#field_idents, _entity, _table_row))*
313300
}
314301

315302
fn update_component_access(state: &Self::State, _access: &mut #path::query::FilteredAccess<#path::component::ComponentId>) {

crates/bevy_ecs/src/archetype.rs

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,19 @@ impl Edges {
121121
}
122122
}
123123

124-
struct TableInfo {
125-
id: TableId,
126-
entity_rows: Vec<usize>,
124+
pub struct ArchetypeEntity {
125+
pub(crate) entity: Entity,
126+
pub(crate) table_row: usize,
127+
}
128+
129+
impl ArchetypeEntity {
130+
pub fn entity(&self) -> Entity {
131+
self.entity
132+
}
133+
134+
pub fn table_row(&self) -> usize {
135+
self.table_row
136+
}
127137
}
128138

129139
pub(crate) struct ArchetypeSwapRemoveResult {
@@ -138,9 +148,9 @@ pub(crate) struct ArchetypeComponentInfo {
138148

139149
pub struct Archetype {
140150
id: ArchetypeId,
141-
entities: Vec<Entity>,
151+
table_id: TableId,
142152
edges: Edges,
143-
table_info: TableInfo,
153+
entities: Vec<ArchetypeEntity>,
144154
table_components: Box<[ComponentId]>,
145155
sparse_set_components: Box<[ComponentId]>,
146156
components: SparseSet<ComponentId, ArchetypeComponentInfo>,
@@ -183,14 +193,11 @@ impl Archetype {
183193
}
184194
Self {
185195
id,
186-
table_info: TableInfo {
187-
id: table_id,
188-
entity_rows: Default::default(),
189-
},
196+
table_id,
197+
entities: Vec::new(),
190198
components,
191199
table_components,
192200
sparse_set_components,
193-
entities: Default::default(),
194201
edges: Default::default(),
195202
}
196203
}
@@ -202,19 +209,14 @@ impl Archetype {
202209

203210
#[inline]
204211
pub fn table_id(&self) -> TableId {
205-
self.table_info.id
212+
self.table_id
206213
}
207214

208215
#[inline]
209-
pub fn entities(&self) -> &[Entity] {
216+
pub fn entities(&self) -> &[ArchetypeEntity] {
210217
&self.entities
211218
}
212219

213-
#[inline]
214-
pub fn entity_table_rows(&self) -> &[usize] {
215-
&self.table_info.entity_rows
216-
}
217-
218220
#[inline]
219221
pub fn table_components(&self) -> &[ComponentId] {
220222
&self.table_components
@@ -242,20 +244,19 @@ impl Archetype {
242244

243245
#[inline]
244246
pub fn entity_table_row(&self, index: usize) -> usize {
245-
self.table_info.entity_rows[index]
247+
self.entities[index].table_row
246248
}
247249

248250
#[inline]
249251
pub(crate) fn set_entity_table_row(&mut self, index: usize, table_row: usize) {
250-
self.table_info.entity_rows[index] = table_row;
252+
self.entities[index].table_row = table_row;
251253
}
252254

253255
/// # Safety
254256
/// valid component values must be immediately written to the relevant storages
255257
/// `table_row` must be valid
256258
pub(crate) unsafe fn allocate(&mut self, entity: Entity, table_row: usize) -> EntityLocation {
257-
self.entities.push(entity);
258-
self.table_info.entity_rows.push(table_row);
259+
self.entities.push(ArchetypeEntity { entity, table_row });
259260

260261
EntityLocation {
261262
archetype_id: self.id,
@@ -265,21 +266,20 @@ impl Archetype {
265266

266267
pub(crate) fn reserve(&mut self, additional: usize) {
267268
self.entities.reserve(additional);
268-
self.table_info.entity_rows.reserve(additional);
269269
}
270270

271271
/// Removes the entity at `index` by swapping it out. Returns the table row the entity is stored
272272
/// in.
273273
pub(crate) fn swap_remove(&mut self, index: usize) -> ArchetypeSwapRemoveResult {
274274
let is_last = index == self.entities.len() - 1;
275-
self.entities.swap_remove(index);
275+
let entity = self.entities.swap_remove(index);
276276
ArchetypeSwapRemoveResult {
277277
swapped_entity: if is_last {
278278
None
279279
} else {
280-
Some(self.entities[index])
280+
Some(self.entities[index].entity)
281281
},
282-
table_row: self.table_info.entity_rows.swap_remove(index),
282+
table_row: entity.table_row,
283283
}
284284
}
285285

@@ -317,7 +317,6 @@ impl Archetype {
317317

318318
pub(crate) fn clear_entities(&mut self) {
319319
self.entities.clear();
320-
self.table_info.entity_rows.clear();
321320
}
322321
}
323322

crates/bevy_ecs/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,8 @@ mod tests {
540540
let f = world
541541
.spawn((TableStored("def"), A(456), SparseStored(1)))
542542
.id();
543-
// // this should be skipped
544-
// SparseStored(1).spawn("abc");
543+
// this should be skipped
544+
// world.spawn(SparseStored(1));
545545
let ents = world
546546
.query::<(Entity, Option<&SparseStored>, &A)>()
547547
.iter(&world)

0 commit comments

Comments
 (0)