From 40711df67a5e6a7766a6c3c59bcaf8783f826b7c Mon Sep 17 00:00:00 2001 From: Frizi Date: Wed, 9 Jun 2021 18:34:32 +0200 Subject: [PATCH] use associated const for is_dense --- crates/bevy_ecs/macros/src/component.rs | 5 ++- crates/bevy_ecs/macros/src/lib.rs | 23 ++++++-------- crates/bevy_ecs/src/bundle.rs | 29 +++++++++++------ crates/bevy_ecs/src/query/fetch.rs | 34 ++++++-------------- crates/bevy_ecs/src/query/filter.rs | 41 ++++++++++++------------- crates/bevy_ecs/src/query/iter.rs | 8 ++--- crates/bevy_ecs/src/query/state.rs | 9 ++---- crates/bevy_ecs/src/system/commands.rs | 2 +- crates/bevy_sprite/src/lib.rs | 7 ++--- 9 files changed, 72 insertions(+), 86 deletions(-) diff --git a/crates/bevy_ecs/macros/src/component.rs b/crates/bevy_ecs/macros/src/component.rs index e69c31f43a333..ea34ebdacf3ae 100644 --- a/crates/bevy_ecs/macros/src/component.rs +++ b/crates/bevy_ecs/macros/src/component.rs @@ -40,7 +40,10 @@ fn parse_storage_attribute(attr: &Attribute) -> Result { match ident.to_string().as_str() { "table" => Ok(StorageTy::Table), "sparse" => Ok(StorageTy::Sparse), - _ => Err(Error::new(ident.span(), "Invalid storage type, expected 'table' or 'sparse'.")), + _ => Err(Error::new( + ident.span(), + "Invalid storage type, expected 'table' or 'sparse'.", + )), } } diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index a2efa81d2aee3..6a87c9179bed8 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -115,8 +115,7 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream { let mut field_type_infos = Vec::new(); let mut field_get_components = Vec::new(); let mut field_from_components = Vec::new(); - let mut is_dense_const_exprs = Vec::new(); - let mut is_dense_fn_exprs = Vec::new(); + let mut is_dense_exprs = Vec::new(); for ((field_type, is_bundle), field) in field_type.iter().zip(is_bundle.iter()).zip(field.iter()) { @@ -130,8 +129,8 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream { field_from_components.push(quote! { #field: <#field_type as #ecs_path::bundle::Bundle>::from_components(&mut func), }); - is_dense_fn_exprs.push(quote! { - <#field_type as #ecs_path::bundle::Bundle>::is_dense() + is_dense_exprs.push(quote! { + <#field_type as #ecs_path::bundle::Bundle>::IS_DENSE }); } else { field_type_infos.push(quote! { @@ -144,9 +143,11 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream { field_from_components.push(quote! { #field: func().cast::<#field_type>().read(), }); - is_dense_const_exprs.push(quote! { - <<#field_type as #ecs_path::component::Component>::Storage as #ecs_path::component::ComponentStorage>::STORAGE_TYPE - == #ecs_path::component::StorageType::Table + is_dense_exprs.push(quote! { + match <<#field_type as #ecs_path::component::Component>::Storage as #ecs_path::component::ComponentStorage>::STORAGE_TYPE { + #ecs_path::component::StorageType::Table => true, + #ecs_path::component::StorageType::SparseSet => false, + } }); } } @@ -158,18 +159,14 @@ pub fn derive_bundle(input: TokenStream) -> TokenStream { TokenStream::from(quote! { /// SAFE: TypeInfo is returned in field-definition-order. [from_components] and [get_components] use field-definition-order unsafe impl #impl_generics #ecs_path::bundle::Bundle for #struct_name#ty_generics #where_clause { + const IS_DENSE: bool = true #(&& #is_dense_exprs)*; + fn type_info() -> Vec<#ecs_path::component::TypeInfo> { let mut type_info = Vec::with_capacity(#field_len); #(#field_type_infos)* type_info } - #[inline(always)] - fn is_dense() -> bool { - // insert const expressions in front to avoid evaluating non-const functions if possible - true #(&& (#is_dense_const_exprs))* #(&& #is_dense_fn_exprs)* - } - #[allow(unused_variables, unused_mut, non_snake_case)] unsafe fn from_components(mut func: impl FnMut() -> *mut u8) -> Self { Self { diff --git a/crates/bevy_ecs/src/bundle.rs b/crates/bevy_ecs/src/bundle.rs index 9b2791b42ea7e..d68533618ecf2 100644 --- a/crates/bevy_ecs/src/bundle.rs +++ b/crates/bevy_ecs/src/bundle.rs @@ -23,19 +23,26 @@ use std::{any::TypeId, collections::HashMap}; /// /// You can nest bundles like so: /// ``` -/// # use bevy_ecs::bundle::Bundle; +/// # use bevy_ecs::{component::Component, bundle::Bundle}; +/// +/// #[derive(Component)] +/// struct X(i32); +/// #[derive(Component)] +/// struct Y(u64); +/// #[derive(Component)] +/// struct Z(String); /// /// #[derive(Bundle)] /// struct A { -/// x: i32, -/// y: u64, +/// x: X, +/// y: Y, /// } /// /// #[derive(Bundle)] /// struct B { /// #[bundle] /// a: A, -/// z: String, +/// z: Z, /// } /// ``` /// @@ -45,6 +52,8 @@ use std::{any::TypeId, collections::HashMap}; /// [Bundle::from_components] must call `func` exactly once for each [TypeInfo] returned by /// [Bundle::type_info] pub unsafe trait Bundle: Send + Sync + 'static { + const IS_DENSE: bool; + /// Gets this [Bundle]'s components type info, in the order of this bundle's Components fn type_info() -> Vec; @@ -62,8 +71,6 @@ pub unsafe trait Bundle: Send + Sync + 'static { /// "mem::forget" the bundle fields, so callers are responsible for dropping the fields if /// that is desirable. fn get_components(self, func: impl FnMut(*mut u8)); - - fn is_dense() -> bool; } macro_rules! tuple_impl { @@ -74,10 +81,12 @@ macro_rules! tuple_impl { vec![$(TypeInfo::of::<$name>()),*] } - #[inline(always)] - fn is_dense() -> bool { - true $(&& $name::Storage::STORAGE_TYPE == StorageType::Table)* - } + const IS_DENSE: bool = true $(&& + match $name::Storage::STORAGE_TYPE { + StorageType::Table => true, + StorageType::SparseSet => false, + } + )*; #[allow(unused_variables, unused_mut)] unsafe fn from_components(mut func: impl FnMut() -> *mut u8) -> Self { diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index b4a197126c4be..1d1d5595a7566 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -67,7 +67,7 @@ pub trait Fetch<'w>: Sized { /// for "dense" queries. If this returns true, [`Fetch::set_table`] and [`Fetch::table_fetch`] /// will be called for iterators. If this returns false, [`Fetch::set_archetype`] and /// [`Fetch::archetype_fetch`] will be called for iterators. - fn is_dense(&self) -> bool; + const IS_DENSE: bool; /// Adjusts internal state to account for the next [`Archetype`]. This will always be called on /// archetypes that match this [`Fetch`]. @@ -177,10 +177,7 @@ impl<'w> Fetch<'w> for EntityFetch { type Item = Entity; type State = EntityState; - #[inline] - fn is_dense(&self) -> bool { - true - } + const IS_DENSE: bool = true; unsafe fn init( _world: &World, @@ -296,13 +293,12 @@ impl<'w, T: Component> Fetch<'w> for ReadFetch { type Item = &'w T; type State = ReadState; - #[inline] - fn is_dense(&self) -> bool { + const IS_DENSE: bool = { match T::Storage::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } - } + }; unsafe fn init( world: &World, @@ -454,13 +450,12 @@ impl<'w, T: Component> Fetch<'w> for WriteFetch { type Item = Mut<'w, T>; type State = WriteState; - #[inline] - fn is_dense(&self) -> bool { + const IS_DENSE: bool = { match T::Storage::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } - } + }; unsafe fn init( world: &World, @@ -613,10 +608,7 @@ impl<'w, T: Fetch<'w>> Fetch<'w> for OptionFetch { type Item = Option; type State = OptionState; - #[inline] - fn is_dense(&self) -> bool { - self.fetch.is_dense() - } + const IS_DENSE: bool = T::IS_DENSE; unsafe fn init( world: &World, @@ -803,13 +795,12 @@ impl<'w, T: Component> Fetch<'w> for ChangeTrackersFetch { type Item = ChangeTrackers; type State = ChangeTrackersState; - #[inline] - fn is_dense(&self) -> bool { + const IS_DENSE: bool = { match T::Storage::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } - } + }; unsafe fn init( world: &World, @@ -910,12 +901,7 @@ macro_rules! impl_tuple_fetch { ($($name::init(_world, $name, _last_change_tick, _change_tick),)*) } - - #[inline] - fn is_dense(&self) -> bool { - let ($($name,)*) = self; - true $(&& $name.is_dense())* - } + const IS_DENSE: bool = true $(&& $name::IS_DENSE)*; #[inline] unsafe fn set_archetype(&mut self, _state: &Self::State, _archetype: &Archetype, _tables: &Tables) { diff --git a/crates/bevy_ecs/src/query/filter.rs b/crates/bevy_ecs/src/query/filter.rs index b3b27736f8266..0fc067c656447 100644 --- a/crates/bevy_ecs/src/query/filter.rs +++ b/crates/bevy_ecs/src/query/filter.rs @@ -133,10 +133,12 @@ impl<'a, T: Component> Fetch<'a> for WithFetch { } } - #[inline] - fn is_dense(&self) -> bool { - T::Storage::STORAGE_TYPE == StorageType::Table - } + const IS_DENSE: bool = { + match T::Storage::STORAGE_TYPE { + StorageType::Table => true, + StorageType::SparseSet => false, + } + }; #[inline] unsafe fn set_table(&mut self, _state: &Self::State, _table: &Table) {} @@ -250,10 +252,12 @@ impl<'a, T: Component> Fetch<'a> for WithoutFetch { } } - #[inline] - fn is_dense(&self) -> bool { - T::Storage::STORAGE_TYPE == StorageType::Table - } + const IS_DENSE: bool = { + match T::Storage::STORAGE_TYPE { + StorageType::Table => true, + StorageType::SparseSet => false, + } + }; #[inline] unsafe fn set_table(&mut self, _state: &Self::State, _table: &Table) {} @@ -343,10 +347,7 @@ impl<'a, T: Bundle> Fetch<'a> for WithBundleFetch { } } - #[inline] - fn is_dense(&self) -> bool { - T::is_dense() - } + const IS_DENSE: bool = T::IS_DENSE; #[inline] unsafe fn set_table(&mut self, _state: &Self::State, _table: &Table) {} @@ -449,11 +450,7 @@ macro_rules! impl_query_filter_tuple { },)*)) } - #[inline] - fn is_dense(&self) -> bool { - let ($($filter,)*) = &self.0; - true $(&& $filter.fetch.is_dense())* - } + const IS_DENSE: bool = true $(&& $filter::IS_DENSE)*; #[inline] unsafe fn set_table(&mut self, state: &Self::State, table: &Table) { @@ -627,10 +624,12 @@ macro_rules! impl_tick_filter { value } - #[inline] - fn is_dense(&self) -> bool { - T::Storage::STORAGE_TYPE == StorageType::Table - } + const IS_DENSE: bool = { + match T::Storage::STORAGE_TYPE { + StorageType::Table => true, + StorageType::SparseSet => false, + } + }; unsafe fn set_table(&mut self, state: &Self::State, table: &Table) { self.table_ticks = table diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index 87641d7a7da75..2513d0d0db6bb 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -74,7 +74,7 @@ where // NOTE: this mimics the behavior of `QueryIter::next()`, except that it // never gets a `Self::Item`. unsafe { - if self.fetch.is_dense() && self.filter.is_dense() { + if Q::Fetch::IS_DENSE && F::Fetch::IS_DENSE { loop { if self.current_index == self.current_len { let table_id = match self.table_id_iter.next() { @@ -137,7 +137,7 @@ where #[inline(always)] fn next(&mut self) -> Option { unsafe { - if self.fetch.is_dense() && self.filter.is_dense() { + if Q::Fetch::IS_DENSE && F::Fetch::IS_DENSE { loop { if self.current_index == self.current_len { let table_id = self.table_id_iter.next()?; @@ -477,7 +477,7 @@ where #[inline] unsafe fn peek_last<'w>(&mut self) -> Option<>::Item> { if self.current_index > 0 { - if self.fetch.is_dense() && self.filter.is_dense() { + if Q::Fetch::IS_DENSE && F::Fetch::IS_DENSE { Some(self.fetch.table_fetch(self.current_index - 1)) } else { Some(self.fetch.archetype_fetch(self.current_index - 1)) @@ -497,7 +497,7 @@ where archetypes: &'w Archetypes, query_state: &'s QueryState, ) -> Option<>::Item> { - if self.fetch.is_dense() && self.filter.is_dense() { + if Q::Fetch::IS_DENSE && F::Fetch::IS_DENSE { loop { if self.current_index == self.current_len { let table_id = self.table_id_iter.next()?; diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index 05c009c6e82db..663a63647afbe 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -406,7 +406,7 @@ where ::init(world, &self.fetch_state, last_change_tick, change_tick); let mut filter = ::init(world, &self.filter_state, last_change_tick, change_tick); - if fetch.is_dense() && filter.is_dense() { + if Q::Fetch::IS_DENSE && F::Fetch::IS_DENSE { let tables = &world.storages().tables; for table_id in self.matched_table_ids.iter() { let table = &tables[*table_id]; @@ -457,12 +457,7 @@ where // NOTE: If you are changing query iteration code, remember to update the following places, where relevant: // QueryIter, QueryIterationCursor, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual task_pool.scope(|scope| { - let fetch = - ::init(world, &self.fetch_state, last_change_tick, change_tick); - let filter = - ::init(world, &self.filter_state, last_change_tick, change_tick); - - if fetch.is_dense() && filter.is_dense() { + if Q::Fetch::IS_DENSE && F::Fetch::IS_DENSE { let tables = &world.storages().tables; for table_id in self.matched_table_ids.iter() { let table = &tables[*table_id]; diff --git a/crates/bevy_ecs/src/system/commands.rs b/crates/bevy_ecs/src/system/commands.rs index a933840cec54a..c98a4ba3c5ec8 100644 --- a/crates/bevy_ecs/src/system/commands.rs +++ b/crates/bevy_ecs/src/system/commands.rs @@ -445,7 +445,7 @@ impl Command for RemoveResource { mod tests { use crate::{ self as bevy_ecs, - component::{Component, ComponentDescriptor, StorageType}, + component::Component, system::{CommandQueue, Commands}, world::World, }; diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index 6ed73ef261409..4076cac02dc52 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -28,14 +28,10 @@ pub use texture_atlas_builder::*; use bevy_app::prelude::*; use bevy_asset::{AddAsset, Assets, Handle, HandleUntyped}; -use bevy_ecs::{ - component::{ComponentDescriptor, StorageType}, - system::IntoSystem, -}; +use bevy_ecs::system::IntoSystem; use bevy_math::Vec2; use bevy_reflect::TypeUuid; use bevy_render::{ - draw::OutsideFrustum, mesh::{shape, Mesh}, pipeline::PipelineDescriptor, render_graph::RenderGraph, @@ -96,6 +92,7 @@ impl Plugin for SpritePlugin { frustum_culling::atlas_frustum_culling_system.system(), ); } + let world = app.world_mut(); let world_cell = world.cell(); let mut render_graph = world_cell.get_resource_mut::().unwrap(); let mut pipelines = world_cell