Skip to main content

bevy_ecs/storage/table/
mod.rs

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