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