Skip to content

Commit

Permalink
use associated const for is_dense
Browse files Browse the repository at this point in the history
  • Loading branch information
Frizi committed Jun 9, 2021
1 parent c529535 commit 40711df
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 86 deletions.
5 changes: 4 additions & 1 deletion crates/bevy_ecs/macros/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ fn parse_storage_attribute(attr: &Attribute) -> Result<StorageTy> {
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'.",
)),
}
}

Expand Down
23 changes: 10 additions & 13 deletions crates/bevy_ecs/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
{
Expand All @@ -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! {
Expand All @@ -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,
}
});
}
}
Expand All @@ -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 {
Expand Down
29 changes: 19 additions & 10 deletions crates/bevy_ecs/src/bundle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
/// }
/// ```
///
Expand All @@ -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<TypeInfo>;

Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
34 changes: 10 additions & 24 deletions crates/bevy_ecs/src/query/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`].
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -296,13 +293,12 @@ impl<'w, T: Component> Fetch<'w> for ReadFetch<T> {
type Item = &'w T;
type State = ReadState<T>;

#[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,
Expand Down Expand Up @@ -454,13 +450,12 @@ impl<'w, T: Component> Fetch<'w> for WriteFetch<T> {
type Item = Mut<'w, T>;
type State = WriteState<T>;

#[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,
Expand Down Expand Up @@ -613,10 +608,7 @@ impl<'w, T: Fetch<'w>> Fetch<'w> for OptionFetch<T> {
type Item = Option<T::Item>;
type State = OptionState<T::State>;

#[inline]
fn is_dense(&self) -> bool {
self.fetch.is_dense()
}
const IS_DENSE: bool = T::IS_DENSE;

unsafe fn init(
world: &World,
Expand Down Expand Up @@ -803,13 +795,12 @@ impl<'w, T: Component> Fetch<'w> for ChangeTrackersFetch<T> {
type Item = ChangeTrackers<T>;
type State = ChangeTrackersState<T>;

#[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,
Expand Down Expand Up @@ -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) {
Expand Down
41 changes: 20 additions & 21 deletions crates/bevy_ecs/src/query/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,12 @@ impl<'a, T: Component> Fetch<'a> for WithFetch<T> {
}
}

#[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) {}
Expand Down Expand Up @@ -250,10 +252,12 @@ impl<'a, T: Component> Fetch<'a> for WithoutFetch<T> {
}
}

#[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) {}
Expand Down Expand Up @@ -343,10 +347,7 @@ impl<'a, T: Bundle> Fetch<'a> for WithBundleFetch<T> {
}
}

#[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) {}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_ecs/src/query/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -137,7 +137,7 @@ where
#[inline(always)]
fn next(&mut self) -> Option<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 = self.table_id_iter.next()?;
Expand Down Expand Up @@ -477,7 +477,7 @@ where
#[inline]
unsafe fn peek_last<'w>(&mut self) -> Option<<Q::Fetch as Fetch<'w>>::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))
Expand All @@ -497,7 +497,7 @@ where
archetypes: &'w Archetypes,
query_state: &'s QueryState<Q, F>,
) -> Option<<Q::Fetch as Fetch<'w>>::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()?;
Expand Down
9 changes: 2 additions & 7 deletions crates/bevy_ecs/src/query/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ where
<Q::Fetch as Fetch>::init(world, &self.fetch_state, last_change_tick, change_tick);
let mut filter =
<F::Fetch as Fetch>::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];
Expand Down Expand Up @@ -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 =
<Q::Fetch as Fetch>::init(world, &self.fetch_state, last_change_tick, change_tick);
let filter =
<F::Fetch as Fetch>::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];
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/system/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ impl<T: Resource> Command for RemoveResource<T> {
mod tests {
use crate::{
self as bevy_ecs,
component::{Component, ComponentDescriptor, StorageType},
component::Component,
system::{CommandQueue, Commands},
world::World,
};
Expand Down
7 changes: 2 additions & 5 deletions crates/bevy_sprite/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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::<RenderGraph>().unwrap();
let mut pipelines = world_cell
Expand Down

0 comments on commit 40711df

Please sign in to comment.