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