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