Thanks to visit codestin.com
Credit goes to docs.rs

bevy_ecs/storage/table/
mod.rs

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