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