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}