Skip to main content

bevy_ecs/storage/table/
mod.rs

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