Path: blob/main/crates/bevy_ecs/src/storage/sparse_set.rs
9358 views
use crate::{1change_detection::{CheckChangeTicks, ComponentTickCells, ComponentTicks, MaybeLocation, Tick},2component::{ComponentId, ComponentInfo},3entity::{Entity, EntityIndex},4query::DebugCheckedUnwrap,5storage::{AbortOnPanic, Column, TableRow, VecExtensions},6};7use alloc::{boxed::Box, vec::Vec};8use bevy_ptr::{OwningPtr, Ptr};9use core::{cell::UnsafeCell, hash::Hash, marker::PhantomData, num::NonZero, panic::Location};10use nonmax::{NonMaxU32, NonMaxUsize};1112#[derive(Debug)]13pub(crate) struct SparseArray<I, V = I> {14values: Vec<Option<V>>,15marker: PhantomData<I>,16}1718/// A space-optimized version of [`SparseArray`] that cannot be changed19/// after construction.20#[derive(Debug)]21pub(crate) struct ImmutableSparseArray<I, V = I> {22values: Box<[Option<V>]>,23marker: PhantomData<I>,24}2526impl<I: SparseSetIndex, V> Default for SparseArray<I, V> {27fn default() -> Self {28Self::new()29}30}3132impl<I, V> SparseArray<I, V> {33#[inline]34pub const fn new() -> Self {35Self {36values: Vec::new(),37marker: PhantomData,38}39}40}4142macro_rules! impl_sparse_array {43($ty:ident) => {44impl<I: SparseSetIndex, V> $ty<I, V> {45/// Returns `true` if the collection contains a value for the specified `index`.46#[inline]47pub fn contains(&self, index: I) -> bool {48let index = index.sparse_set_index();49self.values.get(index).is_some_and(Option::is_some)50}5152/// Returns a reference to the value at `index`.53///54/// Returns `None` if `index` does not have a value or if `index` is out of bounds.55#[inline]56pub fn get(&self, index: I) -> Option<&V> {57let index = index.sparse_set_index();58self.values.get(index).and_then(Option::as_ref)59}60}61};62}6364impl_sparse_array!(SparseArray);65impl_sparse_array!(ImmutableSparseArray);6667impl<I: SparseSetIndex, V> SparseArray<I, V> {68/// Inserts `value` at `index` in the array.69///70/// # Panics71/// - Panics if the insertion forces a reallocation, and any of the new capacity overflows `isize::MAX` bytes.72/// - Panics if the insertion forces a reallocation, and any of the new the reallocations causes an out-of-memory error.73///74/// If `index` is out-of-bounds, this will enlarge the buffer to accommodate it.75#[inline]76pub fn insert(&mut self, index: I, value: V) {77let index = index.sparse_set_index();78if index >= self.values.len() {79self.values.resize_with(index + 1, || None);80}81self.values[index] = Some(value);82}8384/// Returns a mutable reference to the value at `index`.85///86/// Returns `None` if `index` does not have a value or if `index` is out of bounds.87#[inline]88pub fn get_mut(&mut self, index: I) -> Option<&mut V> {89let index = index.sparse_set_index();90self.values.get_mut(index).and_then(Option::as_mut)91}9293/// Removes and returns the value stored at `index`.94///95/// Returns `None` if `index` did not have a value or if `index` is out of bounds.96#[inline]97pub fn remove(&mut self, index: I) -> Option<V> {98let index = index.sparse_set_index();99self.values.get_mut(index).and_then(Option::take)100}101102/// Removes all of the values stored within.103pub fn clear(&mut self) {104self.values.clear();105}106107/// Converts the [`SparseArray`] into an immutable variant.108pub(crate) fn into_immutable(self) -> ImmutableSparseArray<I, V> {109ImmutableSparseArray {110values: self.values.into_boxed_slice(),111marker: PhantomData,112}113}114}115116/// A sparse data structure of [`Component`](crate::component::Component)s.117///118/// Designed for relatively fast insertions and deletions.119#[derive(Debug)]120pub struct ComponentSparseSet {121/// Capacity and length match those of `entities`.122dense: Column,123// Internally this only relies on the Entity index to keep track of where the component data is124// stored for entities that are alive. The generation is not required, but is stored125// in debug builds to validate that access is correct.126#[cfg(not(debug_assertions))]127entities: Vec<EntityIndex>,128#[cfg(debug_assertions)]129entities: Vec<Entity>,130sparse: SparseArray<EntityIndex, TableRow>,131}132133impl ComponentSparseSet {134/// Creates a new [`ComponentSparseSet`] with a given component type layout and135/// initial `capacity`.136pub(crate) fn new(component_info: &ComponentInfo, capacity: usize) -> Self {137let entities = Vec::with_capacity(capacity);138Self {139dense: Column::with_capacity(component_info, entities.capacity()),140entities,141sparse: Default::default(),142}143}144145/// Removes all of the values stored within.146pub(crate) fn clear(&mut self) {147// SAFETY: This is using the size of the ComponentSparseSet.148unsafe { self.dense.clear(self.len()) };149self.entities.clear();150self.sparse.clear();151}152153/// Returns the number of component values in the sparse set.154#[inline]155pub fn len(&self) -> usize {156self.entities.len()157}158159/// Returns `true` if the sparse set contains no component values.160#[inline]161pub fn is_empty(&self) -> bool {162self.entities.is_empty()163}164165/// Inserts the `entity` key and component `value` pair into this sparse166/// set.167///168/// # Aborts169/// - Aborts the process if the insertion forces a reallocation, and any of the new capacity overflows `isize::MAX` bytes.170/// - Aborts the process if the insertion forces a reallocation, and any of the new the reallocations causes an out-of-memory error.171///172/// # Safety173/// The `value` pointer must point to a valid address that matches the [`Layout`](std::alloc::Layout)174/// inside the [`ComponentInfo`] given when constructing this sparse set.175pub(crate) unsafe fn insert(176&mut self,177entity: Entity,178value: OwningPtr<'_>,179change_tick: Tick,180caller: MaybeLocation,181) {182if let Some(&dense_index) = self.sparse.get(entity.index()) {183#[cfg(debug_assertions)]184assert_eq!(entity, self.entities[dense_index.index()]);185self.dense.replace(dense_index, value, change_tick, caller);186} else {187let dense_index = self.entities.len();188let capacity = self.entities.capacity();189190#[cfg(not(debug_assertions))]191self.entities.push(entity.index());192#[cfg(debug_assertions)]193self.entities.push(entity);194195// If any of the following operations panic due to an allocation error, the state196// of the `ComponentSparseSet` will be left in an invalid state and potentially cause UB.197// We create an AbortOnPanic guard to force panics to terminate the process if this occurs.198let _guard = AbortOnPanic;199if capacity != self.entities.capacity() {200// SAFETY: An entity was just pushed onto `entities`, its capacity cannot be zero.201let new_capacity = unsafe { NonZero::new_unchecked(self.entities.capacity()) };202if let Some(capacity) = NonZero::new(capacity) {203// SAFETY: This is using the capacity of the previous allocation.204unsafe { self.dense.realloc(capacity, new_capacity) };205} else {206self.dense.alloc(new_capacity);207}208}209210// SAFETY: This entity index does not exist here yet, so there are no duplicates,211// and the entity index is `NonMaxU32` so the length must not be max either.212let table_row = unsafe { TableRow::new(NonMaxU32::new_unchecked(dense_index as u32)) };213self.dense.initialize(table_row, value, change_tick, caller);214self.sparse.insert(entity.index(), table_row);215216core::mem::forget(_guard);217}218}219220/// Returns `true` if the sparse set has a component value for the provided `entity`.221#[inline]222pub fn contains(&self, entity: Entity) -> bool {223#[cfg(debug_assertions)]224{225if let Some(&dense_index) = self.sparse.get(entity.index()) {226#[cfg(debug_assertions)]227assert_eq!(entity, self.entities[dense_index.index()]);228true229} else {230false231}232}233#[cfg(not(debug_assertions))]234self.sparse.contains(entity.index())235}236237/// Returns a reference to the entity's component value.238///239/// Returns `None` if `entity` does not have a component in the sparse set.240#[inline]241pub fn get(&self, entity: Entity) -> Option<Ptr<'_>> {242self.sparse.get(entity.index()).map(|&dense_index| {243#[cfg(debug_assertions)]244assert_eq!(entity, self.entities[dense_index.index()]);245// SAFETY: if the sparse index points to something in the dense vec, it exists246unsafe { self.dense.get_data_unchecked(dense_index) }247})248}249250/// Returns references to the entity's component value and its added and changed ticks.251///252/// Returns `None` if `entity` does not have a component in the sparse set.253#[inline]254pub fn get_with_ticks(&self, entity: Entity) -> Option<(Ptr<'_>, ComponentTickCells<'_>)> {255let dense_index = *self.sparse.get(entity.index())?;256#[cfg(debug_assertions)]257assert_eq!(entity, self.entities[dense_index.index()]);258// SAFETY: if the sparse index points to something in the dense vec, it exists259unsafe {260Some((261self.dense.get_data_unchecked(dense_index),262ComponentTickCells {263added: self.dense.get_added_tick_unchecked(dense_index),264changed: self.dense.get_changed_tick_unchecked(dense_index),265changed_by: self.dense.get_changed_by_unchecked(dense_index),266},267))268}269}270271/// Returns a reference to the "added" tick of the entity's component value.272///273/// Returns `None` if `entity` does not have a component in the sparse set.274#[inline]275pub fn get_added_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {276let dense_index = *self.sparse.get(entity.index())?;277#[cfg(debug_assertions)]278assert_eq!(entity, self.entities[dense_index.index()]);279// SAFETY: if the sparse index points to something in the dense vec, it exists280unsafe { Some(self.dense.get_added_tick_unchecked(dense_index)) }281}282283/// Returns a reference to the "changed" tick of the entity's component value.284///285/// Returns `None` if `entity` does not have a component in the sparse set.286#[inline]287pub fn get_changed_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {288let dense_index = *self.sparse.get(entity.index())?;289#[cfg(debug_assertions)]290assert_eq!(entity, self.entities[dense_index.index()]);291// SAFETY: if the sparse index points to something in the dense vec, it exists292unsafe { Some(self.dense.get_changed_tick_unchecked(dense_index)) }293}294295/// Returns a reference to the "added" and "changed" ticks of the entity's component value.296///297/// Returns `None` if `entity` does not have a component in the sparse set.298#[inline]299pub fn get_ticks(&self, entity: Entity) -> Option<ComponentTicks> {300let dense_index = *self.sparse.get(entity.index())?;301#[cfg(debug_assertions)]302assert_eq!(entity, self.entities[dense_index.index()]);303// SAFETY: if the sparse index points to something in the dense vec, it exists304unsafe { Some(self.dense.get_ticks_unchecked(dense_index)) }305}306307/// Returns a reference to the calling location that last changed the entity's component value.308///309/// Returns `None` if `entity` does not have a component in the sparse set.310#[inline]311pub fn get_changed_by(312&self,313entity: Entity,314) -> MaybeLocation<Option<&UnsafeCell<&'static Location<'static>>>> {315MaybeLocation::new_with_flattened(|| {316let dense_index = *self.sparse.get(entity.index())?;317#[cfg(debug_assertions)]318assert_eq!(entity, self.entities[dense_index.index()]);319// SAFETY: if the sparse index points to something in the dense vec, it exists320unsafe { Some(self.dense.get_changed_by_unchecked(dense_index)) }321})322}323324/// Returns the drop function for the component type stored in the sparse set,325/// or `None` if it doesn't need to be dropped.326#[inline]327pub fn get_drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {328self.dense.get_drop()329}330331/// Removes the `entity` from this sparse set and returns a pointer to the associated value (if332/// it exists).333#[must_use = "The returned pointer must be used to drop the removed component."]334pub(crate) fn remove_and_forget(&mut self, entity: Entity) -> Option<OwningPtr<'_>> {335self.sparse.remove(entity.index()).map(|dense_index| {336#[cfg(debug_assertions)]337assert_eq!(entity, self.entities[dense_index.index()]);338let last = self.entities.len() - 1;339if dense_index.index() >= last {340#[cfg(debug_assertions)]341assert_eq!(dense_index.index(), last);342// SAFETY: This is strictly decreasing the length, so it cannot outgrow343// it also cannot underflow as an item was just removed from the sparse array.344unsafe { self.entities.set_len(last) };345// SAFETY: `last` is guaranteed to be the last element in `dense` as the length is synced with346// the `entities` store.347unsafe {348self.dense349.get_data_unchecked(dense_index)350.assert_unique()351.promote()352}353} else {354// SAFETY: The above check ensures that `dense_index` and the last element are not355// overlapping, and thus also within bounds.356unsafe {357self.entities358.swap_remove_nonoverlapping_unchecked(dense_index.index());359};360// SAFETY: The above check ensures that `dense_index` is in bounds.361let swapped_entity = unsafe { self.entities.get_unchecked(dense_index.index()) };362#[cfg(not(debug_assertions))]363let index = *swapped_entity;364#[cfg(debug_assertions)]365let index = swapped_entity.index();366// SAFETY: The swapped entity was just fetched from the entity Vec, it must have already367// been inserted and in bounds.368unsafe {369*self.sparse.get_mut(index).debug_checked_unwrap() = dense_index;370}371// SAFETY: The above check ensures that `dense_index` and the last element are not372// overlapping, and thus also within bounds.373unsafe {374self.dense375.swap_remove_and_forget_unchecked_nonoverlapping(last, dense_index)376}377}378})379}380381/// Removes (and drops) the entity's component value from the sparse set.382///383/// Returns `true` if `entity` had a component value in the sparse set.384pub(crate) fn remove(&mut self, entity: Entity) -> bool {385self.sparse386.remove(entity.index())387.map(|dense_index| {388#[cfg(debug_assertions)]389assert_eq!(entity, self.entities[dense_index.index()]);390let last = self.entities.len() - 1;391if dense_index.index() >= last {392#[cfg(debug_assertions)]393assert_eq!(dense_index.index(), last);394// SAFETY: This is strictly decreasing the length, so it cannot outgrow395// it also cannot underflow as an item was just removed from the sparse array.396unsafe { self.entities.set_len(last) };397// SAFETY: `last` is guaranteed to be the last element in `dense` as the length is synced with398// the `entities` store.399unsafe { self.dense.drop_last_component(last) };400} else {401// SAFETY: The above check ensures that `dense_index` and the last element are not402// overlapping, and thus also within bounds.403unsafe {404self.entities405.swap_remove_nonoverlapping_unchecked(dense_index.index());406};407let swapped_entity =408// SAFETY: The above check ensures that `dense_index` is in bounds.409unsafe { self.entities.get_unchecked(dense_index.index()) };410#[cfg(not(debug_assertions))]411let index = *swapped_entity;412#[cfg(debug_assertions)]413let index = swapped_entity.index();414// SAFETY: The swapped entity was just fetched from the entity Vec, it must have already415// been inserted and in bounds.416unsafe {417*self.sparse.get_mut(index).debug_checked_unwrap() = dense_index;418}419// SAFETY: The above check ensures that `dense_index` and the last element are not420// overlapping, and thus also within bounds.421unsafe {422self.dense423.swap_remove_and_drop_unchecked_nonoverlapping(last, dense_index);424}425}426})427.is_some()428}429430pub(crate) fn check_change_ticks(&mut self, check: CheckChangeTicks) {431// SAFETY: This is using the valid size of the column.432unsafe { self.dense.check_change_ticks(self.len(), check) };433}434}435436impl Drop for ComponentSparseSet {437fn drop(&mut self) {438let len = self.entities.len();439self.entities.clear();440// SAFETY: `cap` and `len` are correct. `dense` is never accessed again after this call.441unsafe {442self.dense.drop(self.entities.capacity(), len);443}444}445}446447/// A data structure that blends dense and sparse storage448///449/// `I` is the type of the indices, while `V` is the type of data stored in the dense storage.450#[derive(Debug)]451pub struct SparseSet<I, V: 'static> {452dense: Vec<V>,453indices: Vec<I>,454sparse: SparseArray<I, NonMaxUsize>,455}456457/// A space-optimized version of [`SparseSet`] that cannot be changed458/// after construction.459#[derive(Debug)]460pub(crate) struct ImmutableSparseSet<I, V: 'static> {461dense: Box<[V]>,462indices: Box<[I]>,463sparse: ImmutableSparseArray<I, NonMaxUsize>,464}465466macro_rules! impl_sparse_set {467($ty:ident) => {468impl<I: SparseSetIndex, V> $ty<I, V> {469/// Returns the number of elements in the sparse set.470#[inline]471pub fn len(&self) -> usize {472self.dense.len()473}474475/// Returns `true` if the sparse set contains a value for `index`.476#[inline]477pub fn contains(&self, index: I) -> bool {478self.sparse.contains(index)479}480481/// Returns a reference to the value for `index`.482///483/// Returns `None` if `index` does not have a value in the sparse set.484pub fn get(&self, index: I) -> Option<&V> {485self.sparse.get(index).map(|dense_index| {486// SAFETY: if the sparse index points to something in the dense vec, it exists487unsafe { self.dense.get_unchecked(dense_index.get()) }488})489}490491/// Returns a mutable reference to the value for `index`.492///493/// Returns `None` if `index` does not have a value in the sparse set.494pub fn get_mut(&mut self, index: I) -> Option<&mut V> {495let dense = &mut self.dense;496self.sparse.get(index).map(move |dense_index| {497// SAFETY: if the sparse index points to something in the dense vec, it exists498unsafe { dense.get_unchecked_mut(dense_index.get()) }499})500}501502/// Returns an iterator visiting all keys (indices) in arbitrary order.503pub fn indices(&self) -> &[I] {504&self.indices505}506507/// Returns an iterator visiting all values in arbitrary order.508pub fn values(&self) -> impl Iterator<Item = &V> {509self.dense.iter()510}511512/// Returns an iterator visiting all values mutably in arbitrary order.513pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> {514self.dense.iter_mut()515}516517/// Returns an iterator visiting all key-value pairs in arbitrary order, with references to the values.518pub fn iter(&self) -> impl Iterator<Item = (&I, &V)> {519self.indices.iter().zip(self.dense.iter())520}521522/// Returns an iterator visiting all key-value pairs in arbitrary order, with mutable references to the values.523pub fn iter_mut(&mut self) -> impl Iterator<Item = (&I, &mut V)> {524self.indices.iter().zip(self.dense.iter_mut())525}526}527};528}529530impl_sparse_set!(SparseSet);531impl_sparse_set!(ImmutableSparseSet);532533impl<I: SparseSetIndex, V> Default for SparseSet<I, V> {534fn default() -> Self {535Self::new()536}537}538539impl<I, V> SparseSet<I, V> {540/// Creates a new [`SparseSet`].541pub const fn new() -> Self {542Self {543dense: Vec::new(),544indices: Vec::new(),545sparse: SparseArray::new(),546}547}548}549550impl<I: SparseSetIndex, V> SparseSet<I, V> {551/// Creates a new [`SparseSet`] with a specified initial capacity.552///553/// # Panics554/// - Panics if the new capacity of the allocation overflows `isize::MAX` bytes.555/// - Panics if the new allocation causes an out-of-memory error.556pub fn with_capacity(capacity: usize) -> Self {557Self {558dense: Vec::with_capacity(capacity),559indices: Vec::with_capacity(capacity),560sparse: Default::default(),561}562}563564/// Returns the total number of elements the [`SparseSet`] can hold without needing to reallocate.565#[inline]566pub fn capacity(&self) -> usize {567self.dense.capacity()568}569570/// Inserts `value` at `index`.571///572/// If a value was already present at `index`, it will be overwritten.573///574/// # Panics575/// - Panics if the insertion forces an reallocation and the new capacity overflows `isize::MAX` bytes.576/// - Panics if the insertion forces an reallocation and causes an out-of-memory error.577pub fn insert(&mut self, index: I, value: V) {578if let Some(dense_index) = self.sparse.get(index.clone()).cloned() {579// SAFETY: dense indices stored in self.sparse always exist580unsafe {581*self.dense.get_unchecked_mut(dense_index.get()) = value;582}583} else {584self.sparse585.insert(index.clone(), NonMaxUsize::new(self.dense.len()).unwrap());586self.indices.push(index);587self.dense.push(value);588}589}590591/// Returns a reference to the value for `index`, inserting one computed from `func`592/// if not already present.593///594/// # Panics595/// - Panics if the insertion forces an reallocation and the new capacity overflows `isize::MAX` bytes.596/// - Panics if the insertion forces an reallocation and causes an out-of-memory error.597pub fn get_or_insert_with(&mut self, index: I, func: impl FnOnce() -> V) -> &mut V {598if let Some(dense_index) = self.sparse.get(index.clone()).cloned() {599// SAFETY: dense indices stored in self.sparse always exist600unsafe { self.dense.get_unchecked_mut(dense_index.get()) }601} else {602let value = func();603let dense_index = self.dense.len();604self.sparse605.insert(index.clone(), NonMaxUsize::new(dense_index).unwrap());606self.indices.push(index);607self.dense.push(value);608// SAFETY: dense index was just populated above609unsafe { self.dense.get_unchecked_mut(dense_index) }610}611}612613/// Returns `true` if the sparse set contains no elements.614#[inline]615pub fn is_empty(&self) -> bool {616self.dense.len() == 0617}618619/// Removes and returns the value for `index`.620///621/// Returns `None` if `index` does not have a value in the sparse set.622pub fn remove(&mut self, index: I) -> Option<V> {623self.sparse.remove(index).map(|dense_index| {624let index = dense_index.get();625let is_last = index == self.dense.len() - 1;626let value = self.dense.swap_remove(index);627self.indices.swap_remove(index);628if !is_last {629let swapped_index = self.indices[index].clone();630*self.sparse.get_mut(swapped_index).unwrap() = dense_index;631}632value633})634}635636/// Clears all of the elements from the sparse set.637///638/// # Panics639/// - Panics if any of the keys or values implements [`Drop`] and any of those panic.640pub fn clear(&mut self) {641self.dense.clear();642self.indices.clear();643self.sparse.clear();644}645646/// Converts the sparse set into its immutable variant.647pub(crate) fn into_immutable(self) -> ImmutableSparseSet<I, V> {648ImmutableSparseSet {649dense: self.dense.into_boxed_slice(),650indices: self.indices.into_boxed_slice(),651sparse: self.sparse.into_immutable(),652}653}654}655656/// Represents something that can be stored in a [`SparseSet`] as an integer.657///658/// Ideally, the `usize` values should be very small (ie: incremented starting from659/// zero), as the number of bits needed to represent a `SparseSetIndex` in a `FixedBitSet`660/// is proportional to the **value** of those `usize`.661pub trait SparseSetIndex: Clone + PartialEq + Eq + Hash {662/// Gets the sparse set index corresponding to this instance.663fn sparse_set_index(&self) -> usize;664/// Creates a new instance of this type with the specified index.665fn get_sparse_set_index(value: usize) -> Self;666}667668macro_rules! impl_sparse_set_index {669($($ty:ty),+) => {670$(impl SparseSetIndex for $ty {671#[inline]672fn sparse_set_index(&self) -> usize {673*self as usize674}675676#[inline]677fn get_sparse_set_index(value: usize) -> Self {678value as $ty679}680})*681};682}683684impl_sparse_set_index!(u8, u16, u32, u64, usize);685686/// A collection of [`ComponentSparseSet`] storages, indexed by [`ComponentId`]687///688/// Can be accessed via [`Storages`](crate::storage::Storages)689#[derive(Default)]690pub struct SparseSets {691sets: SparseSet<ComponentId, ComponentSparseSet>,692}693694impl SparseSets {695/// Returns the number of [`ComponentSparseSet`]s this collection contains.696#[inline]697pub fn len(&self) -> usize {698self.sets.len()699}700701/// Returns true if this collection contains no [`ComponentSparseSet`]s.702#[inline]703pub fn is_empty(&self) -> bool {704self.sets.is_empty()705}706707/// An Iterator visiting all ([`ComponentId`], [`ComponentSparseSet`]) pairs.708/// NOTE: Order is not guaranteed.709pub fn iter(&self) -> impl Iterator<Item = (ComponentId, &ComponentSparseSet)> {710self.sets.iter().map(|(id, data)| (*id, data))711}712713/// Gets a reference to the [`ComponentSparseSet`] of a [`ComponentId`]. This may be `None` if the component has never been spawned.714#[inline]715pub fn get(&self, component_id: ComponentId) -> Option<&ComponentSparseSet> {716self.sets.get(component_id)717}718719/// Gets a mutable reference of [`ComponentSparseSet`] of a [`ComponentInfo`].720/// Create a new [`ComponentSparseSet`] if not exists.721///722/// # Panics723/// - Panics if the insertion forces an reallocation and the new capacity overflows `isize::MAX` bytes.724/// - Panics if the insertion forces an reallocation and causes an out-of-memory error.725pub(crate) fn get_or_insert(726&mut self,727component_info: &ComponentInfo,728) -> &mut ComponentSparseSet {729if !self.sets.contains(component_info.id()) {730self.sets.insert(731component_info.id(),732ComponentSparseSet::new(component_info, 64),733);734}735736self.sets.get_mut(component_info.id()).unwrap()737}738739/// Gets a mutable reference to the [`ComponentSparseSet`] of a [`ComponentId`]. This may be `None` if the component has never been spawned.740pub(crate) fn get_mut(&mut self, component_id: ComponentId) -> Option<&mut ComponentSparseSet> {741self.sets.get_mut(component_id)742}743744/// Clear entities stored in each [`ComponentSparseSet`]745///746/// # Panics747/// - Panics if any of the components stored within implement [`Drop`] and any of them panic.748pub(crate) fn clear_entities(&mut self) {749for set in self.sets.values_mut() {750set.clear();751}752}753754pub(crate) fn check_change_ticks(&mut self, check: CheckChangeTicks) {755for set in self.sets.values_mut() {756set.check_change_ticks(check);757}758}759}760761#[cfg(test)]762mod tests {763use super::SparseSets;764use crate::{765component::{Component, ComponentDescriptor, ComponentId, ComponentInfo},766entity::{Entity, EntityIndex},767storage::SparseSet,768};769use alloc::{vec, vec::Vec};770771#[derive(Debug, Eq, PartialEq)]772struct Foo(usize);773774#[test]775fn sparse_set() {776let mut set = SparseSet::<Entity, Foo>::default();777let e0 = Entity::from_index(EntityIndex::from_raw_u32(0).unwrap());778let e1 = Entity::from_index(EntityIndex::from_raw_u32(1).unwrap());779let e2 = Entity::from_index(EntityIndex::from_raw_u32(2).unwrap());780let e3 = Entity::from_index(EntityIndex::from_raw_u32(3).unwrap());781let e4 = Entity::from_index(EntityIndex::from_raw_u32(4).unwrap());782783set.insert(e1, Foo(1));784set.insert(e2, Foo(2));785set.insert(e3, Foo(3));786787assert_eq!(set.get(e0), None);788assert_eq!(set.get(e1), Some(&Foo(1)));789assert_eq!(set.get(e2), Some(&Foo(2)));790assert_eq!(set.get(e3), Some(&Foo(3)));791assert_eq!(set.get(e4), None);792793{794let iter_results = set.values().collect::<Vec<_>>();795assert_eq!(iter_results, vec![&Foo(1), &Foo(2), &Foo(3)]);796}797798assert_eq!(set.remove(e2), Some(Foo(2)));799assert_eq!(set.remove(e2), None);800801assert_eq!(set.get(e0), None);802assert_eq!(set.get(e1), Some(&Foo(1)));803assert_eq!(set.get(e2), None);804assert_eq!(set.get(e3), Some(&Foo(3)));805assert_eq!(set.get(e4), None);806807assert_eq!(set.remove(e1), Some(Foo(1)));808809assert_eq!(set.get(e0), None);810assert_eq!(set.get(e1), None);811assert_eq!(set.get(e2), None);812assert_eq!(set.get(e3), Some(&Foo(3)));813assert_eq!(set.get(e4), None);814815set.insert(e1, Foo(10));816817assert_eq!(set.get(e1), Some(&Foo(10)));818819*set.get_mut(e1).unwrap() = Foo(11);820assert_eq!(set.get(e1), Some(&Foo(11)));821}822823#[test]824fn sparse_sets() {825let mut sets = SparseSets::default();826827#[derive(Component, Default, Debug)]828struct TestComponent1;829830#[derive(Component, Default, Debug)]831struct TestComponent2;832833assert_eq!(sets.len(), 0);834assert!(sets.is_empty());835836register_component::<TestComponent1>(&mut sets, 1);837assert_eq!(sets.len(), 1);838839register_component::<TestComponent2>(&mut sets, 2);840assert_eq!(sets.len(), 2);841842// check its shape by iter843let mut collected_sets = sets844.iter()845.map(|(id, set)| (id, set.len()))846.collect::<Vec<_>>();847collected_sets.sort();848assert_eq!(849collected_sets,850vec![(ComponentId::new(1), 0), (ComponentId::new(2), 0),]851);852853fn register_component<T: Component>(sets: &mut SparseSets, id: usize) {854let descriptor = ComponentDescriptor::new::<T>();855let id = ComponentId::new(id);856let info = ComponentInfo::new(id, descriptor);857sets.get_or_insert(&info);858}859}860}861862863