bevy_ecs/storage/table/
mod.rs

1use crate::{
2    change_detection::MaybeLocation,
3    component::{ComponentId, ComponentInfo, ComponentTicks, Components, Tick},
4    entity::Entity,
5    query::DebugCheckedUnwrap,
6    storage::{blob_vec::BlobVec, ImmutableSparseSet, SparseSet},
7};
8use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
9use bevy_utils::HashMap;
10pub use column::*;
11#[cfg(feature = "track_change_detection")]
12use core::panic::Location;
13use core::{
14    alloc::Layout,
15    cell::UnsafeCell,
16    num::NonZeroUsize,
17    ops::{Index, IndexMut},
18};
19mod column;
20
21/// An opaque unique ID for a [`Table`] within a [`World`].
22///
23/// Can be used with [`Tables::get`] to fetch the corresponding
24/// table.
25///
26/// Each [`Archetype`] always points to a table via [`Archetype::table_id`].
27/// Multiple archetypes can point to the same table so long as the components
28/// stored in the table are identical, but do not share the same sparse set
29/// components.
30///
31/// [`World`]: crate::world::World
32/// [`Archetype`]: crate::archetype::Archetype
33/// [`Archetype::table_id`]: crate::archetype::Archetype::table_id
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35// SAFETY: Must be repr(transparent) due to the safety requirements on EntityLocation
36#[repr(transparent)]
37pub struct TableId(u32);
38
39impl TableId {
40    pub(crate) const INVALID: TableId = TableId(u32::MAX);
41
42    /// Creates a new [`TableId`].
43    ///
44    /// `index` *must* be retrieved from calling [`TableId::as_u32`] on a `TableId` you got
45    /// from a table of a given [`World`] or the created ID may be invalid.
46    ///
47    /// [`World`]: crate::world::World
48    #[inline]
49    pub const fn from_u32(index: u32) -> Self {
50        Self(index)
51    }
52
53    /// Creates a new [`TableId`].
54    ///
55    /// `index` *must* be retrieved from calling [`TableId::as_usize`] on a `TableId` you got
56    /// from a table of a given [`World`] or the created ID may be invalid.
57    ///
58    /// [`World`]: crate::world::World
59    ///
60    /// # Panics
61    ///
62    /// Will panic if the provided value does not fit within a [`u32`].
63    #[inline]
64    pub const fn from_usize(index: usize) -> Self {
65        debug_assert!(index as u32 as usize == index);
66        Self(index as u32)
67    }
68
69    /// Gets the underlying table index from the ID.
70    #[inline]
71    pub const fn as_u32(self) -> u32 {
72        self.0
73    }
74
75    /// Gets the underlying table index from the ID.
76    #[inline]
77    pub const fn as_usize(self) -> usize {
78        // usize is at least u32 in Bevy
79        self.0 as usize
80    }
81
82    /// The [`TableId`] of the [`Table`] without any components.
83    #[inline]
84    pub const fn empty() -> Self {
85        Self(0)
86    }
87}
88
89/// A opaque newtype for rows in [`Table`]s. Specifies a single row in a specific table.
90///
91/// Values of this type are retrievable from [`Archetype::entity_table_row`] and can be
92/// used alongside [`Archetype::table_id`] to fetch the exact table and row where an
93/// [`Entity`]'s
94///
95/// Values of this type are only valid so long as entities have not moved around.
96/// Adding and removing components from an entity, or despawning it will invalidate
97/// potentially any table row in the table the entity was previously stored in. Users
98/// should *always* fetch the appropriate row from the entity's [`Archetype`] before
99/// fetching the entity's components.
100///
101/// [`Archetype`]: crate::archetype::Archetype
102/// [`Archetype::entity_table_row`]: crate::archetype::Archetype::entity_table_row
103/// [`Archetype::table_id`]: crate::archetype::Archetype::table_id
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105// SAFETY: Must be repr(transparent) due to the safety requirements on EntityLocation
106#[repr(transparent)]
107pub struct TableRow(u32);
108
109impl TableRow {
110    pub(crate) const INVALID: TableRow = TableRow(u32::MAX);
111
112    /// Creates a `TableRow`.
113    #[inline]
114    pub const fn from_u32(index: u32) -> Self {
115        Self(index)
116    }
117
118    /// Creates a `TableRow` from a [`usize`] index.
119    ///
120    /// # Panics
121    ///
122    /// Will panic if the provided value does not fit within a [`u32`].
123    #[inline]
124    pub const fn from_usize(index: usize) -> Self {
125        debug_assert!(index as u32 as usize == index);
126        Self(index as u32)
127    }
128
129    /// Gets the index of the row as a [`usize`].
130    #[inline]
131    pub const fn as_usize(self) -> usize {
132        // usize is at least u32 in Bevy
133        self.0 as usize
134    }
135
136    /// Gets the index of the row as a [`usize`].
137    #[inline]
138    pub const fn as_u32(self) -> u32 {
139        self.0
140    }
141}
142
143/// A builder type for constructing [`Table`]s.
144///
145///  - Use [`with_capacity`] to initialize the builder.
146///  - Repeatedly call [`add_column`] to add columns for components.
147///  - Finalize with [`build`] to get the constructed [`Table`].
148///
149/// [`with_capacity`]: Self::with_capacity
150/// [`add_column`]: Self::add_column
151/// [`build`]: Self::build
152pub(crate) struct TableBuilder {
153    columns: SparseSet<ComponentId, ThinColumn>,
154    capacity: usize,
155}
156
157impl TableBuilder {
158    /// Start building a new [`Table`] with a specified `column_capacity` (How many components per column?) and a `capacity` (How many columns?)
159    pub fn with_capacity(capacity: usize, column_capacity: usize) -> Self {
160        Self {
161            columns: SparseSet::with_capacity(column_capacity),
162            capacity,
163        }
164    }
165
166    /// Add a new column to the [`Table`]. Specify the component which will be stored in the [`column`](ThinColumn) using its [`ComponentId`]
167    #[must_use]
168    pub fn add_column(mut self, component_info: &ComponentInfo) -> Self {
169        self.columns.insert(
170            component_info.id(),
171            ThinColumn::with_capacity(component_info, self.capacity),
172        );
173        self
174    }
175
176    /// Build the [`Table`], after this operation the caller wouldn't be able to add more columns. The [`Table`] will be ready to use.
177    #[must_use]
178    pub fn build(self) -> Table {
179        Table {
180            columns: self.columns.into_immutable(),
181            entities: Vec::with_capacity(self.capacity),
182        }
183    }
184}
185
186/// A column-oriented [structure-of-arrays] based storage for [`Component`]s of entities
187/// in a [`World`].
188///
189/// Conceptually, a `Table` can be thought of as an `HashMap<ComponentId, Column>`, where
190/// each [`ThinColumn`] is a type-erased `Vec<T: Component>`. Each row corresponds to a single entity
191/// (i.e. index 3 in Column A and index 3 in Column B point to different components on the same
192/// entity). Fetching components from a table involves fetching the associated column for a
193/// component type (via its [`ComponentId`]), then fetching the entity's row within that column.
194///
195/// [structure-of-arrays]: https://en.wikipedia.org/wiki/AoS_and_SoA#Structure_of_arrays
196/// [`Component`]: crate::component::Component
197/// [`World`]: crate::world::World
198pub struct Table {
199    columns: ImmutableSparseSet<ComponentId, ThinColumn>,
200    entities: Vec<Entity>,
201}
202
203struct AbortOnPanic;
204
205impl Drop for AbortOnPanic {
206    fn drop(&mut self) {
207        // Panicking while unwinding will force an abort.
208        panic!("Aborting due to allocator error");
209    }
210}
211
212impl Table {
213    /// Fetches a read-only slice of the entities stored within the [`Table`].
214    #[inline]
215    pub fn entities(&self) -> &[Entity] {
216        &self.entities
217    }
218
219    /// Get the capacity of this table, in entities.
220    /// Note that if an allocation is in process, this might not match the actual capacity of the columns, but it should once the allocation ends.
221    #[inline]
222    pub fn capacity(&self) -> usize {
223        self.entities.capacity()
224    }
225
226    /// Removes the entity at the given row and returns the entity swapped in to replace it (if an
227    /// entity was swapped in)
228    ///
229    /// # Safety
230    /// `row` must be in-bounds (`row.as_usize()` < `self.len()`)
231    pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) -> Option<Entity> {
232        debug_assert!(row.as_usize() < self.entity_count());
233        let last_element_index = self.entity_count() - 1;
234        if row.as_usize() != last_element_index {
235            // Instead of checking this condition on every `swap_remove` call, we
236            // check it here and use `swap_remove_nonoverlapping`.
237            for col in self.columns.values_mut() {
238                // SAFETY:
239                // - `row` < `len`
240                // - `last_element_index` = `len` - 1
241                // - `row` != `last_element_index`
242                // - the `len` is kept within `self.entities`, it will update accordingly.
243                unsafe {
244                    col.swap_remove_and_drop_unchecked_nonoverlapping(last_element_index, row);
245                };
246            }
247        } else {
248            // If `row.as_usize()` == `last_element_index` than there's no point in removing the component
249            // at `row`, but we still need to drop it.
250            for col in self.columns.values_mut() {
251                col.drop_last_component(last_element_index);
252            }
253        }
254        let is_last = row.as_usize() == last_element_index;
255        self.entities.swap_remove(row.as_usize());
256        if is_last {
257            None
258        } else {
259            Some(self.entities[row.as_usize()])
260        }
261    }
262
263    /// Moves the `row` column values to `new_table`, for the columns shared between both tables.
264    /// Returns the index of the new row in `new_table` and the entity in this table swapped in
265    /// to replace it (if an entity was swapped in). missing columns will be "forgotten". It is
266    /// the caller's responsibility to drop them.  Failure to do so may result in resources not
267    /// being released (i.e. files handles not being released, memory leaks, etc.)
268    ///
269    /// # Safety
270    /// - `row` must be in-bounds
271    pub(crate) unsafe fn move_to_and_forget_missing_unchecked(
272        &mut self,
273        row: TableRow,
274        new_table: &mut Table,
275    ) -> TableMoveResult {
276        debug_assert!(row.as_usize() < self.entity_count());
277        let last_element_index = self.entity_count() - 1;
278        let is_last = row.as_usize() == last_element_index;
279        let new_row = new_table.allocate(self.entities.swap_remove(row.as_usize()));
280        for (component_id, column) in self.columns.iter_mut() {
281            if let Some(new_column) = new_table.get_column_mut(*component_id) {
282                new_column.initialize_from_unchecked(column, last_element_index, row, new_row);
283            } else {
284                // It's the caller's responsibility to drop these cases.
285                column.swap_remove_and_forget_unchecked(last_element_index, row);
286            }
287        }
288        TableMoveResult {
289            new_row,
290            swapped_entity: if is_last {
291                None
292            } else {
293                Some(self.entities[row.as_usize()])
294            },
295        }
296    }
297
298    /// Moves the `row` column values to `new_table`, for the columns shared between both tables.
299    /// Returns the index of the new row in `new_table` and the entity in this table swapped in
300    /// to replace it (if an entity was swapped in).
301    ///
302    /// # Safety
303    /// row must be in-bounds
304    pub(crate) unsafe fn move_to_and_drop_missing_unchecked(
305        &mut self,
306        row: TableRow,
307        new_table: &mut Table,
308    ) -> TableMoveResult {
309        debug_assert!(row.as_usize() < self.entity_count());
310        let last_element_index = self.entity_count() - 1;
311        let is_last = row.as_usize() == last_element_index;
312        let new_row = new_table.allocate(self.entities.swap_remove(row.as_usize()));
313        for (component_id, column) in self.columns.iter_mut() {
314            if let Some(new_column) = new_table.get_column_mut(*component_id) {
315                new_column.initialize_from_unchecked(column, last_element_index, row, new_row);
316            } else {
317                column.swap_remove_and_drop_unchecked(last_element_index, row);
318            }
319        }
320        TableMoveResult {
321            new_row,
322            swapped_entity: if is_last {
323                None
324            } else {
325                Some(self.entities[row.as_usize()])
326            },
327        }
328    }
329
330    /// Moves the `row` column values to `new_table`, for the columns shared between both tables.
331    /// Returns the index of the new row in `new_table` and the entity in this table swapped in
332    /// to replace it (if an entity was swapped in).
333    ///
334    /// # Safety
335    /// - `row` must be in-bounds
336    /// - `new_table` must contain every component this table has
337    pub(crate) unsafe fn move_to_superset_unchecked(
338        &mut self,
339        row: TableRow,
340        new_table: &mut Table,
341    ) -> TableMoveResult {
342        debug_assert!(row.as_usize() < self.entity_count());
343        let last_element_index = self.entity_count() - 1;
344        let is_last = row.as_usize() == last_element_index;
345        let new_row = new_table.allocate(self.entities.swap_remove(row.as_usize()));
346        for (component_id, column) in self.columns.iter_mut() {
347            new_table
348                .get_column_mut(*component_id)
349                .debug_checked_unwrap()
350                .initialize_from_unchecked(column, last_element_index, row, new_row);
351        }
352        TableMoveResult {
353            new_row,
354            swapped_entity: if is_last {
355                None
356            } else {
357                Some(self.entities[row.as_usize()])
358            },
359        }
360    }
361
362    /// Get the data of the column matching `component_id` as a slice.
363    ///
364    /// # Safety
365    /// `row.as_usize()` < `self.len()`
366    /// - `T` must match the `component_id`
367    pub unsafe fn get_data_slice_for<T>(
368        &self,
369        component_id: ComponentId,
370    ) -> Option<&[UnsafeCell<T>]> {
371        self.get_column(component_id)
372            .map(|col| col.get_data_slice(self.entity_count()))
373    }
374
375    /// Get the added ticks of the column matching `component_id` as a slice.
376    pub fn get_added_ticks_slice_for(
377        &self,
378        component_id: ComponentId,
379    ) -> Option<&[UnsafeCell<Tick>]> {
380        self.get_column(component_id)
381            // SAFETY: `self.len()` is guaranteed to be the len of the ticks array
382            .map(|col| unsafe { col.get_added_ticks_slice(self.entity_count()) })
383    }
384
385    /// Get the changed ticks of the column matching `component_id` as a slice.
386    pub fn get_changed_ticks_slice_for(
387        &self,
388        component_id: ComponentId,
389    ) -> Option<&[UnsafeCell<Tick>]> {
390        self.get_column(component_id)
391            // SAFETY: `self.len()` is guaranteed to be the len of the ticks array
392            .map(|col| unsafe { col.get_changed_ticks_slice(self.entity_count()) })
393    }
394
395    /// Fetches the calling locations that last changed the each component
396    #[cfg(feature = "track_change_detection")]
397    pub fn get_changed_by_slice_for(
398        &self,
399        component_id: ComponentId,
400    ) -> Option<&[UnsafeCell<&'static Location<'static>>]> {
401        self.get_column(component_id)
402            // SAFETY: `self.len()` is guaranteed to be the len of the locations array
403            .map(|col| unsafe { col.get_changed_by_slice(self.entity_count()) })
404    }
405
406    /// Get the specific [`change tick`](Tick) of the component matching `component_id` in `row`.
407    pub fn get_changed_tick(
408        &self,
409        component_id: ComponentId,
410        row: TableRow,
411    ) -> Option<&UnsafeCell<Tick>> {
412        (row.as_usize() < self.entity_count()).then_some(
413            // SAFETY: `row.as_usize()` < `len`
414            unsafe {
415                self.get_column(component_id)?
416                    .changed_ticks
417                    .get_unchecked(row.as_usize())
418            },
419        )
420    }
421
422    /// Get the specific [`added tick`](Tick) of the component matching `component_id` in `row`.
423    pub fn get_added_tick(
424        &self,
425        component_id: ComponentId,
426        row: TableRow,
427    ) -> Option<&UnsafeCell<Tick>> {
428        (row.as_usize() < self.entity_count()).then_some(
429            // SAFETY: `row.as_usize()` < `len`
430            unsafe {
431                self.get_column(component_id)?
432                    .added_ticks
433                    .get_unchecked(row.as_usize())
434            },
435        )
436    }
437
438    /// Get the specific calling location that changed the component matching `component_id` in `row`
439    #[cfg(feature = "track_change_detection")]
440    pub fn get_changed_by(
441        &self,
442        component_id: ComponentId,
443        row: TableRow,
444    ) -> Option<&UnsafeCell<&'static Location<'static>>> {
445        (row.as_usize() < self.entity_count()).then_some(
446            // SAFETY: `row.as_usize()` < `len`
447            unsafe {
448                self.get_column(component_id)?
449                    .changed_by
450                    .get_unchecked(row.as_usize())
451            },
452        )
453    }
454
455    /// Get the [`ComponentTicks`] of the component matching `component_id` in `row`.
456    ///
457    /// # Safety
458    /// - `row.as_usize()` < `self.len()`
459    pub unsafe fn get_ticks_unchecked(
460        &self,
461        component_id: ComponentId,
462        row: TableRow,
463    ) -> Option<ComponentTicks> {
464        self.get_column(component_id).map(|col| ComponentTicks {
465            added: col.added_ticks.get_unchecked(row.as_usize()).read(),
466            changed: col.changed_ticks.get_unchecked(row.as_usize()).read(),
467        })
468    }
469
470    /// Fetches a read-only reference to the [`ThinColumn`] for a given [`Component`] within the table.
471    ///
472    /// Returns `None` if the corresponding component does not belong to the table.
473    ///
474    /// [`Component`]: crate::component::Component
475    #[inline]
476    pub fn get_column(&self, component_id: ComponentId) -> Option<&ThinColumn> {
477        self.columns.get(component_id)
478    }
479
480    /// Fetches a mutable reference to the [`ThinColumn`] for a given [`Component`] within the
481    /// table.
482    ///
483    /// Returns `None` if the corresponding component does not belong to the table.
484    ///
485    /// [`Component`]: crate::component::Component
486    #[inline]
487    pub(crate) fn get_column_mut(&mut self, component_id: ComponentId) -> Option<&mut ThinColumn> {
488        self.columns.get_mut(component_id)
489    }
490
491    /// Checks if the table contains a [`ThinColumn`] for a given [`Component`].
492    ///
493    /// Returns `true` if the column is present, `false` otherwise.
494    ///
495    /// [`Component`]: crate::component::Component
496    #[inline]
497    pub fn has_column(&self, component_id: ComponentId) -> bool {
498        self.columns.contains(component_id)
499    }
500
501    /// Reserves `additional` elements worth of capacity within the table.
502    pub(crate) fn reserve(&mut self, additional: usize) {
503        if self.capacity() - self.entity_count() < additional {
504            let column_cap = self.capacity();
505            self.entities.reserve(additional);
506
507            // use entities vector capacity as driving capacity for all related allocations
508            let new_capacity = self.entities.capacity();
509
510            if column_cap == 0 {
511                // SAFETY: the current capacity is 0
512                unsafe { self.alloc_columns(NonZeroUsize::new_unchecked(new_capacity)) };
513            } else {
514                // SAFETY:
515                // - `column_cap` is indeed the columns' capacity
516                unsafe {
517                    self.realloc_columns(
518                        NonZeroUsize::new_unchecked(column_cap),
519                        NonZeroUsize::new_unchecked(new_capacity),
520                    );
521                };
522            }
523        }
524    }
525
526    /// Allocate memory for the columns in the [`Table`]
527    ///
528    /// The current capacity of the columns should be 0, if it's not 0, then the previous data will be overwritten and leaked.
529    fn alloc_columns(&mut self, new_capacity: NonZeroUsize) {
530        // If any of these allocations trigger an unwind, the wrong capacity will be used while dropping this table - UB.
531        // To avoid this, we use `AbortOnPanic`. If the allocation triggered a panic, the `AbortOnPanic`'s Drop impl will be
532        // called, and abort the program.
533        let _guard = AbortOnPanic;
534        for col in self.columns.values_mut() {
535            col.alloc(new_capacity);
536        }
537        core::mem::forget(_guard); // The allocation was successful, so we don't drop the guard.
538    }
539
540    /// Reallocate memory for the columns in the [`Table`]
541    ///
542    /// # Safety
543    /// - `current_column_capacity` is indeed the capacity of the columns
544    unsafe fn realloc_columns(
545        &mut self,
546        current_column_capacity: NonZeroUsize,
547        new_capacity: NonZeroUsize,
548    ) {
549        // If any of these allocations trigger an unwind, the wrong capacity will be used while dropping this table - UB.
550        // To avoid this, we use `AbortOnPanic`. If the allocation triggered a panic, the `AbortOnPanic`'s Drop impl will be
551        // called, and abort the program.
552        let _guard = AbortOnPanic;
553
554        // SAFETY:
555        // - There's no overflow
556        // - `current_capacity` is indeed the capacity - safety requirement
557        // - current capacity > 0
558        for col in self.columns.values_mut() {
559            col.realloc(current_column_capacity, new_capacity);
560        }
561        core::mem::forget(_guard); // The allocation was successful, so we don't drop the guard.
562    }
563
564    /// Allocates space for a new entity
565    ///
566    /// # Safety
567    /// the allocated row must be written to immediately with valid values in each column
568    pub(crate) unsafe fn allocate(&mut self, entity: Entity) -> TableRow {
569        self.reserve(1);
570        let len = self.entity_count();
571        self.entities.push(entity);
572        for col in self.columns.values_mut() {
573            col.added_ticks
574                .initialize_unchecked(len, UnsafeCell::new(Tick::new(0)));
575            col.changed_ticks
576                .initialize_unchecked(len, UnsafeCell::new(Tick::new(0)));
577            #[cfg(feature = "track_change_detection")]
578            col.changed_by
579                .initialize_unchecked(len, UnsafeCell::new(Location::caller()));
580        }
581        TableRow::from_usize(len)
582    }
583
584    /// Gets the number of entities currently being stored in the table.
585    #[inline]
586    pub fn entity_count(&self) -> usize {
587        self.entities.len()
588    }
589
590    /// Get the drop function for some component that is stored in this table.
591    #[inline]
592    pub fn get_drop_for(&self, component_id: ComponentId) -> Option<unsafe fn(OwningPtr<'_>)> {
593        self.get_column(component_id)?.data.drop
594    }
595
596    /// Gets the number of components being stored in the table.
597    #[inline]
598    pub fn component_count(&self) -> usize {
599        self.columns.len()
600    }
601
602    /// Gets the maximum number of entities the table can currently store
603    /// without reallocating the underlying memory.
604    #[inline]
605    pub fn entity_capacity(&self) -> usize {
606        self.entities.capacity()
607    }
608
609    /// Checks if the [`Table`] is empty or not.
610    ///
611    /// Returns `true` if the table contains no entities, `false` otherwise.
612    #[inline]
613    pub fn is_empty(&self) -> bool {
614        self.entities.is_empty()
615    }
616
617    /// Call [`Tick::check_tick`] on all of the ticks in the [`Table`]
618    pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
619        let len = self.entity_count();
620        for col in self.columns.values_mut() {
621            // SAFETY: `len` is the actual length of the column
622            unsafe { col.check_change_ticks(len, change_tick) };
623        }
624    }
625
626    /// Iterates over the [`ThinColumn`]s of the [`Table`].
627    pub fn iter_columns(&self) -> impl Iterator<Item = &ThinColumn> {
628        self.columns.values()
629    }
630
631    /// Clears all of the stored components in the [`Table`].
632    pub(crate) fn clear(&mut self) {
633        let len = self.entity_count();
634        // We must clear the entities first, because in the drop function causes a panic, it will result in a double free of the columns.
635        self.entities.clear();
636        for column in self.columns.values_mut() {
637            // SAFETY: we defer `self.entities.clear()` until after clearing the columns,
638            // so `self.len()` should match the columns' len
639            unsafe { column.clear(len) };
640        }
641    }
642
643    /// Moves component data out of the [`Table`].
644    ///
645    /// This function leaves the underlying memory unchanged, but the component behind
646    /// returned pointer is semantically owned by the caller and will not be dropped in its original location.
647    /// Caller is responsible to drop component data behind returned pointer.
648    ///
649    /// # Safety
650    /// - This table must hold the component matching `component_id`
651    /// - `row` must be in bounds
652    /// - The row's inconsistent state that happens after taking the component must be resolved—either initialize a new component or remove the row.
653    pub(crate) unsafe fn take_component(
654        &mut self,
655        component_id: ComponentId,
656        row: TableRow,
657    ) -> OwningPtr<'_> {
658        self.get_column_mut(component_id)
659            .debug_checked_unwrap()
660            .data
661            .get_unchecked_mut(row.as_usize())
662            .promote()
663    }
664
665    /// Get the component at a given `row`, if the [`Table`] stores components with the given `component_id`
666    ///
667    /// # Safety
668    /// `row.as_usize()` < `self.len()`
669    pub unsafe fn get_component(
670        &self,
671        component_id: ComponentId,
672        row: TableRow,
673    ) -> Option<Ptr<'_>> {
674        self.get_column(component_id)
675            .map(|col| col.data.get_unchecked(row.as_usize()))
676    }
677}
678
679/// A collection of [`Table`] storages, indexed by [`TableId`]
680///
681/// Can be accessed via [`Storages`](crate::storage::Storages)
682pub struct Tables {
683    tables: Vec<Table>,
684    table_ids: HashMap<Box<[ComponentId]>, TableId>,
685}
686
687impl Default for Tables {
688    fn default() -> Self {
689        let empty_table = TableBuilder::with_capacity(0, 0).build();
690        Tables {
691            tables: vec![empty_table],
692            table_ids: HashMap::default(),
693        }
694    }
695}
696
697pub(crate) struct TableMoveResult {
698    pub swapped_entity: Option<Entity>,
699    pub new_row: TableRow,
700}
701
702impl Tables {
703    /// Returns the number of [`Table`]s this collection contains
704    #[inline]
705    pub fn len(&self) -> usize {
706        self.tables.len()
707    }
708
709    /// Returns true if this collection contains no [`Table`]s
710    #[inline]
711    pub fn is_empty(&self) -> bool {
712        self.tables.is_empty()
713    }
714
715    /// Fetches a [`Table`] by its [`TableId`].
716    ///
717    /// Returns `None` if `id` is invalid.
718    #[inline]
719    pub fn get(&self, id: TableId) -> Option<&Table> {
720        self.tables.get(id.as_usize())
721    }
722
723    /// Fetches mutable references to two different [`Table`]s.
724    ///
725    /// # Panics
726    ///
727    /// Panics if `a` and `b` are equal.
728    #[inline]
729    pub(crate) fn get_2_mut(&mut self, a: TableId, b: TableId) -> (&mut Table, &mut Table) {
730        if a.as_usize() > b.as_usize() {
731            let (b_slice, a_slice) = self.tables.split_at_mut(a.as_usize());
732            (&mut a_slice[0], &mut b_slice[b.as_usize()])
733        } else {
734            let (a_slice, b_slice) = self.tables.split_at_mut(b.as_usize());
735            (&mut a_slice[a.as_usize()], &mut b_slice[0])
736        }
737    }
738
739    /// Attempts to fetch a table based on the provided components,
740    /// creating and returning a new [`Table`] if one did not already exist.
741    ///
742    /// # Safety
743    /// `component_ids` must contain components that exist in `components`
744    pub(crate) unsafe fn get_id_or_insert(
745        &mut self,
746        component_ids: &[ComponentId],
747        components: &Components,
748    ) -> TableId {
749        let tables = &mut self.tables;
750        let (_key, value) = self
751            .table_ids
752            .raw_entry_mut()
753            .from_key(component_ids)
754            .or_insert_with(|| {
755                let mut table = TableBuilder::with_capacity(0, component_ids.len());
756                for component_id in component_ids {
757                    table = table.add_column(components.get_info_unchecked(*component_id));
758                }
759                tables.push(table.build());
760                (component_ids.into(), TableId::from_usize(tables.len() - 1))
761            });
762
763        *value
764    }
765
766    /// Iterates through all of the tables stored within in [`TableId`] order.
767    pub fn iter(&self) -> core::slice::Iter<'_, Table> {
768        self.tables.iter()
769    }
770
771    /// Clears all data from all [`Table`]s stored within.
772    pub(crate) fn clear(&mut self) {
773        for table in &mut self.tables {
774            table.clear();
775        }
776    }
777
778    pub(crate) fn check_change_ticks(&mut self, change_tick: Tick) {
779        for table in &mut self.tables {
780            table.check_change_ticks(change_tick);
781        }
782    }
783}
784
785impl Index<TableId> for Tables {
786    type Output = Table;
787
788    #[inline]
789    fn index(&self, index: TableId) -> &Self::Output {
790        &self.tables[index.as_usize()]
791    }
792}
793
794impl IndexMut<TableId> for Tables {
795    #[inline]
796    fn index_mut(&mut self, index: TableId) -> &mut Self::Output {
797        &mut self.tables[index.as_usize()]
798    }
799}
800
801impl Drop for Table {
802    fn drop(&mut self) {
803        let len = self.entity_count();
804        let cap = self.capacity();
805        self.entities.clear();
806        for col in self.columns.values_mut() {
807            // SAFETY: `cap` and `len` are correct
808            unsafe {
809                col.drop(cap, len);
810            }
811        }
812    }
813}
814
815#[cfg(test)]
816mod tests {
817    use crate as bevy_ecs;
818    use crate::{
819        component::{Component, Components, Tick},
820        entity::Entity,
821        ptr::OwningPtr,
822        storage::{Storages, TableBuilder, TableRow},
823    };
824    #[cfg(feature = "track_change_detection")]
825    use core::panic::Location;
826
827    #[derive(Component)]
828    struct W<T>(T);
829
830    #[test]
831    fn table() {
832        let mut components = Components::default();
833        let mut storages = Storages::default();
834        let component_id = components.register_component::<W<TableRow>>(&mut storages);
835        let columns = &[component_id];
836        let mut table = TableBuilder::with_capacity(0, columns.len())
837            .add_column(components.get_info(component_id).unwrap())
838            .build();
839        let entities = (0..200).map(Entity::from_raw).collect::<Vec<_>>();
840        for entity in &entities {
841            // SAFETY: we allocate and immediately set data afterwards
842            unsafe {
843                let row = table.allocate(*entity);
844                let value: W<TableRow> = W(row);
845                OwningPtr::make(value, |value_ptr| {
846                    table.get_column_mut(component_id).unwrap().initialize(
847                        row,
848                        value_ptr,
849                        Tick::new(0),
850                        #[cfg(feature = "track_change_detection")]
851                        Location::caller(),
852                    );
853                });
854            };
855        }
856
857        assert_eq!(table.entity_capacity(), 256);
858        assert_eq!(table.entity_count(), 200);
859    }
860}