Reduced TableRow
as
Casting (#10811)
# Objective - Fixes #10806 ## Solution Replaced `new` and `index` methods for both `TableRow` and `TableId` with `from_*` and `as_*` methods. These remove the need to perform casting at call sites, reducing the total number of casts in the Bevy codebase. Within these methods, an appropriate `debug_assertion` ensures the cast will behave in an expected manner (no wrapping, etc.). I am using a `debug_assertion` instead of an `assert` to reduce any possible runtime overhead, however minimal. This choice is something I am open to changing (or leaving up to another PR) if anyone has any strong arguments for it. --- ## Changelog - `ComponentSparseSet::sparse` stores a `TableRow` instead of a `u32` (private change) - Replaced `TableRow::new` and `TableRow::index` methods with `TableRow::from_*` and `TableRow::as_*`, with `debug_assertions` protecting any internal casting. - Replaced `TableId::new` and `TableId::index` methods with `TableId::from_*` and `TableId::as_*`, with `debug_assertions` protecting any internal casting. - All `TableId` methods are now `const` ## Migration Guide - `TableRow::new` -> `TableRow::from_usize` - `TableRow::index` -> `TableRow::as_usize` - `TableId::new` -> `TableId::from_usize` - `TableId::index` -> `TableId::as_usize` --- ## Notes I have chosen to remove the `index` and `new` methods for the following chain of reasoning: - Across the codebase, `new` was called with a mixture of `u32` and `usize` values. Likewise for `index`. - Choosing `new` to either be `usize` or `u32` would break half of these call-sites, requiring `as` casting at the site. - Adding a second method `new_u32` or `new_usize` avoids the above, bu looks visually inconsistent. - Therefore, they should be replaced with `from_*` and `as_*` methods instead. Worth noting is that by updating `ComponentSparseSet`, there are now zero instances of interacting with the inner value of `TableRow` as a `u32`, it is exclusively used as a `usize` value (due to interactions with methods like `len` and slice indexing). I have left the `as_u32` and `from_u32` methods as the "proper" constructors/getters.
This commit is contained in:
parent
83ee6de1da
commit
72adf2ae2a
@ -605,7 +605,7 @@ unsafe impl<T: Component> WorldQuery for &T {
|
|||||||
StorageType::Table => fetch
|
StorageType::Table => fetch
|
||||||
.table_components
|
.table_components
|
||||||
.debug_checked_unwrap()
|
.debug_checked_unwrap()
|
||||||
.get(table_row.index())
|
.get(table_row.as_usize())
|
||||||
.deref(),
|
.deref(),
|
||||||
StorageType::SparseSet => fetch
|
StorageType::SparseSet => fetch
|
||||||
.sparse_set
|
.sparse_set
|
||||||
@ -760,10 +760,10 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
|||||||
let (table_components, added_ticks, changed_ticks) =
|
let (table_components, added_ticks, changed_ticks) =
|
||||||
fetch.table_data.debug_checked_unwrap();
|
fetch.table_data.debug_checked_unwrap();
|
||||||
Ref {
|
Ref {
|
||||||
value: table_components.get(table_row.index()).deref(),
|
value: table_components.get(table_row.as_usize()).deref(),
|
||||||
ticks: Ticks {
|
ticks: Ticks {
|
||||||
added: added_ticks.get(table_row.index()).deref(),
|
added: added_ticks.get(table_row.as_usize()).deref(),
|
||||||
changed: changed_ticks.get(table_row.index()).deref(),
|
changed: changed_ticks.get(table_row.as_usize()).deref(),
|
||||||
this_run: fetch.this_run,
|
this_run: fetch.this_run,
|
||||||
last_run: fetch.last_run,
|
last_run: fetch.last_run,
|
||||||
},
|
},
|
||||||
@ -927,10 +927,10 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
|||||||
let (table_components, added_ticks, changed_ticks) =
|
let (table_components, added_ticks, changed_ticks) =
|
||||||
fetch.table_data.debug_checked_unwrap();
|
fetch.table_data.debug_checked_unwrap();
|
||||||
Mut {
|
Mut {
|
||||||
value: table_components.get(table_row.index()).deref_mut(),
|
value: table_components.get(table_row.as_usize()).deref_mut(),
|
||||||
ticks: TicksMut {
|
ticks: TicksMut {
|
||||||
added: added_ticks.get(table_row.index()).deref_mut(),
|
added: added_ticks.get(table_row.as_usize()).deref_mut(),
|
||||||
changed: changed_ticks.get(table_row.index()).deref_mut(),
|
changed: changed_ticks.get(table_row.as_usize()).deref_mut(),
|
||||||
this_run: fetch.this_run,
|
this_run: fetch.this_run,
|
||||||
last_run: fetch.last_run,
|
last_run: fetch.last_run,
|
||||||
},
|
},
|
||||||
|
@ -626,7 +626,7 @@ unsafe impl<T: Component> WorldQuery for Added<T> {
|
|||||||
StorageType::Table => fetch
|
StorageType::Table => fetch
|
||||||
.table_ticks
|
.table_ticks
|
||||||
.debug_checked_unwrap()
|
.debug_checked_unwrap()
|
||||||
.get(table_row.index())
|
.get(table_row.as_usize())
|
||||||
.deref()
|
.deref()
|
||||||
.is_newer_than(fetch.last_run, fetch.this_run),
|
.is_newer_than(fetch.last_run, fetch.this_run),
|
||||||
StorageType::SparseSet => {
|
StorageType::SparseSet => {
|
||||||
@ -802,7 +802,7 @@ unsafe impl<T: Component> WorldQuery for Changed<T> {
|
|||||||
StorageType::Table => fetch
|
StorageType::Table => fetch
|
||||||
.table_ticks
|
.table_ticks
|
||||||
.debug_checked_unwrap()
|
.debug_checked_unwrap()
|
||||||
.get(table_row.index())
|
.get(table_row.as_usize())
|
||||||
.deref()
|
.deref()
|
||||||
.is_newer_than(fetch.last_run, fetch.this_run),
|
.is_newer_than(fetch.last_run, fetch.this_run),
|
||||||
StorageType::SparseSet => {
|
StorageType::SparseSet => {
|
||||||
|
@ -106,6 +106,11 @@ impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> QueryIter<'w, 's, Q, F> {
|
|||||||
where
|
where
|
||||||
Func: FnMut(B, Q::Item<'w>) -> B,
|
Func: FnMut(B, Q::Item<'w>) -> B,
|
||||||
{
|
{
|
||||||
|
assert!(
|
||||||
|
rows.end <= u32::MAX as usize,
|
||||||
|
"TableRow is only valid up to u32::MAX"
|
||||||
|
);
|
||||||
|
|
||||||
Q::set_table(&mut self.cursor.fetch, &self.query_state.fetch_state, table);
|
Q::set_table(&mut self.cursor.fetch, &self.query_state.fetch_state, table);
|
||||||
F::set_table(
|
F::set_table(
|
||||||
&mut self.cursor.filter,
|
&mut self.cursor.filter,
|
||||||
@ -117,7 +122,7 @@ impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> QueryIter<'w, 's, Q, F> {
|
|||||||
for row in rows {
|
for row in rows {
|
||||||
// SAFETY: Caller assures `row` in range of the current archetype.
|
// SAFETY: Caller assures `row` in range of the current archetype.
|
||||||
let entity = entities.get_unchecked(row);
|
let entity = entities.get_unchecked(row);
|
||||||
let row = TableRow::new(row);
|
let row = TableRow::from_usize(row);
|
||||||
// SAFETY: set_table was called prior.
|
// SAFETY: set_table was called prior.
|
||||||
// Caller assures `row` in range of the current archetype.
|
// Caller assures `row` in range of the current archetype.
|
||||||
if !F::filter_fetch(&mut self.cursor.filter, *entity, row) {
|
if !F::filter_fetch(&mut self.cursor.filter, *entity, row) {
|
||||||
@ -707,7 +712,11 @@ impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> QueryIterationCursor<'w, 's
|
|||||||
let index = self.current_row - 1;
|
let index = self.current_row - 1;
|
||||||
if Self::IS_DENSE {
|
if Self::IS_DENSE {
|
||||||
let entity = self.table_entities.get_unchecked(index);
|
let entity = self.table_entities.get_unchecked(index);
|
||||||
Some(Q::fetch(&mut self.fetch, *entity, TableRow::new(index)))
|
Some(Q::fetch(
|
||||||
|
&mut self.fetch,
|
||||||
|
*entity,
|
||||||
|
TableRow::from_usize(index),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
let archetype_entity = self.archetype_entities.get_unchecked(index);
|
let archetype_entity = self.archetype_entities.get_unchecked(index);
|
||||||
Some(Q::fetch(
|
Some(Q::fetch(
|
||||||
@ -768,7 +777,7 @@ impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> QueryIterationCursor<'w, 's
|
|||||||
// SAFETY: set_table was called prior.
|
// SAFETY: set_table was called prior.
|
||||||
// `current_row` is a table row in range of the current table, because if it was not, then the if above would have been executed.
|
// `current_row` is a table row in range of the current table, because if it was not, then the if above would have been executed.
|
||||||
let entity = self.table_entities.get_unchecked(self.current_row);
|
let entity = self.table_entities.get_unchecked(self.current_row);
|
||||||
let row = TableRow::new(self.current_row);
|
let row = TableRow::from_usize(self.current_row);
|
||||||
if !F::filter_fetch(&mut self.filter, *entity, row) {
|
if !F::filter_fetch(&mut self.filter, *entity, row) {
|
||||||
self.current_row += 1;
|
self.current_row += 1;
|
||||||
continue;
|
continue;
|
||||||
|
@ -267,7 +267,7 @@ impl<Q: WorldQueryData, F: WorldQueryFilter> QueryState<Q, F> {
|
|||||||
self.matched_archetypes.set(archetype_index, true);
|
self.matched_archetypes.set(archetype_index, true);
|
||||||
self.matched_archetype_ids.push(archetype.id());
|
self.matched_archetype_ids.push(archetype.id());
|
||||||
}
|
}
|
||||||
let table_index = archetype.table_id().index();
|
let table_index = archetype.table_id().as_usize();
|
||||||
if !self.matched_tables.contains(table_index) {
|
if !self.matched_tables.contains(table_index) {
|
||||||
self.matched_tables.grow(table_index + 1);
|
self.matched_tables.grow(table_index + 1);
|
||||||
self.matched_tables.set(table_index, true);
|
self.matched_tables.set(table_index, true);
|
||||||
|
@ -40,7 +40,7 @@ impl<const SEND: bool> Drop for ResourceData<SEND> {
|
|||||||
|
|
||||||
impl<const SEND: bool> ResourceData<SEND> {
|
impl<const SEND: bool> ResourceData<SEND> {
|
||||||
/// The only row in the underlying column.
|
/// The only row in the underlying column.
|
||||||
const ROW: TableRow = TableRow::new(0);
|
const ROW: TableRow = TableRow::from_u32(0);
|
||||||
|
|
||||||
/// Validates the access to `!Send` resources is only done on the thread they were created from.
|
/// Validates the access to `!Send` resources is only done on the thread they were created from.
|
||||||
///
|
///
|
||||||
|
@ -124,7 +124,7 @@ pub struct ComponentSparseSet {
|
|||||||
entities: Vec<EntityIndex>,
|
entities: Vec<EntityIndex>,
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
entities: Vec<Entity>,
|
entities: Vec<Entity>,
|
||||||
sparse: SparseArray<EntityIndex, u32>,
|
sparse: SparseArray<EntityIndex, TableRow>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComponentSparseSet {
|
impl ComponentSparseSet {
|
||||||
@ -171,13 +171,13 @@ impl ComponentSparseSet {
|
|||||||
) {
|
) {
|
||||||
if let Some(&dense_index) = self.sparse.get(entity.index()) {
|
if let Some(&dense_index) = self.sparse.get(entity.index()) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(entity, self.entities[dense_index as usize]);
|
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||||
self.dense
|
self.dense.replace(dense_index, value, change_tick);
|
||||||
.replace(TableRow::new(dense_index as usize), value, change_tick);
|
|
||||||
} else {
|
} else {
|
||||||
let dense_index = self.dense.len();
|
let dense_index = self.dense.len();
|
||||||
self.dense.push(value, ComponentTicks::new(change_tick));
|
self.dense.push(value, ComponentTicks::new(change_tick));
|
||||||
self.sparse.insert(entity.index(), dense_index as u32);
|
self.sparse
|
||||||
|
.insert(entity.index(), TableRow::from_usize(dense_index));
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(self.entities.len(), dense_index);
|
assert_eq!(self.entities.len(), dense_index);
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
@ -194,7 +194,7 @@ impl ComponentSparseSet {
|
|||||||
{
|
{
|
||||||
if let Some(&dense_index) = self.sparse.get(entity.index()) {
|
if let Some(&dense_index) = self.sparse.get(entity.index()) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(entity, self.entities[dense_index as usize]);
|
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@ -209,12 +209,11 @@ impl ComponentSparseSet {
|
|||||||
/// Returns `None` if `entity` does not have a component in the sparse set.
|
/// Returns `None` if `entity` does not have a component in the sparse set.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, entity: Entity) -> Option<Ptr<'_>> {
|
pub fn get(&self, entity: Entity) -> Option<Ptr<'_>> {
|
||||||
self.sparse.get(entity.index()).map(|dense_index| {
|
self.sparse.get(entity.index()).map(|&dense_index| {
|
||||||
let dense_index = (*dense_index) as usize;
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(entity, self.entities[dense_index]);
|
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||||
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
||||||
unsafe { self.dense.get_data_unchecked(TableRow::new(dense_index)) }
|
unsafe { self.dense.get_data_unchecked(dense_index) }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,9 +222,9 @@ impl ComponentSparseSet {
|
|||||||
/// Returns `None` if `entity` does not have a component in the sparse set.
|
/// Returns `None` if `entity` does not have a component in the sparse set.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_with_ticks(&self, entity: Entity) -> Option<(Ptr<'_>, TickCells<'_>)> {
|
pub fn get_with_ticks(&self, entity: Entity) -> Option<(Ptr<'_>, TickCells<'_>)> {
|
||||||
let dense_index = TableRow::new(*self.sparse.get(entity.index())? as usize);
|
let dense_index = *self.sparse.get(entity.index())?;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(entity, self.entities[dense_index.index()]);
|
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||||
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
||||||
unsafe {
|
unsafe {
|
||||||
Some((
|
Some((
|
||||||
@ -243,16 +242,11 @@ impl ComponentSparseSet {
|
|||||||
/// Returns `None` if `entity` does not have a component in the sparse set.
|
/// Returns `None` if `entity` does not have a component in the sparse set.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_added_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {
|
pub fn get_added_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {
|
||||||
let dense_index = *self.sparse.get(entity.index())? as usize;
|
let dense_index = *self.sparse.get(entity.index())?;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(entity, self.entities[dense_index]);
|
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||||
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
||||||
unsafe {
|
unsafe { Some(self.dense.get_added_tick_unchecked(dense_index)) }
|
||||||
Some(
|
|
||||||
self.dense
|
|
||||||
.get_added_tick_unchecked(TableRow::new(dense_index)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the "changed" tick of the entity's component value.
|
/// Returns a reference to the "changed" tick of the entity's component value.
|
||||||
@ -260,16 +254,11 @@ impl ComponentSparseSet {
|
|||||||
/// Returns `None` if `entity` does not have a component in the sparse set.
|
/// Returns `None` if `entity` does not have a component in the sparse set.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_changed_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {
|
pub fn get_changed_tick(&self, entity: Entity) -> Option<&UnsafeCell<Tick>> {
|
||||||
let dense_index = *self.sparse.get(entity.index())? as usize;
|
let dense_index = *self.sparse.get(entity.index())?;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(entity, self.entities[dense_index]);
|
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||||
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
||||||
unsafe {
|
unsafe { Some(self.dense.get_changed_tick_unchecked(dense_index)) }
|
||||||
Some(
|
|
||||||
self.dense
|
|
||||||
.get_changed_tick_unchecked(TableRow::new(dense_index)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the "added" and "changed" ticks of the entity's component value.
|
/// Returns a reference to the "added" and "changed" ticks of the entity's component value.
|
||||||
@ -277,11 +266,11 @@ impl ComponentSparseSet {
|
|||||||
/// Returns `None` if `entity` does not have a component in the sparse set.
|
/// Returns `None` if `entity` does not have a component in the sparse set.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_ticks(&self, entity: Entity) -> Option<ComponentTicks> {
|
pub fn get_ticks(&self, entity: Entity) -> Option<ComponentTicks> {
|
||||||
let dense_index = *self.sparse.get(entity.index())? as usize;
|
let dense_index = *self.sparse.get(entity.index())?;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(entity, self.entities[dense_index]);
|
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||||
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
||||||
unsafe { Some(self.dense.get_ticks_unchecked(TableRow::new(dense_index))) }
|
unsafe { Some(self.dense.get_ticks_unchecked(dense_index)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes the `entity` from this sparse set and returns a pointer to the associated value (if
|
/// Removes the `entity` from this sparse set and returns a pointer to the associated value (if
|
||||||
@ -289,23 +278,19 @@ impl ComponentSparseSet {
|
|||||||
#[must_use = "The returned pointer must be used to drop the removed component."]
|
#[must_use = "The returned pointer must be used to drop the removed component."]
|
||||||
pub(crate) fn remove_and_forget(&mut self, entity: Entity) -> Option<OwningPtr<'_>> {
|
pub(crate) fn remove_and_forget(&mut self, entity: Entity) -> Option<OwningPtr<'_>> {
|
||||||
self.sparse.remove(entity.index()).map(|dense_index| {
|
self.sparse.remove(entity.index()).map(|dense_index| {
|
||||||
let dense_index = dense_index as usize;
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(entity, self.entities[dense_index]);
|
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||||
self.entities.swap_remove(dense_index);
|
self.entities.swap_remove(dense_index.as_usize());
|
||||||
let is_last = dense_index == self.dense.len() - 1;
|
let is_last = dense_index.as_usize() == self.dense.len() - 1;
|
||||||
// SAFETY: dense_index was just removed from `sparse`, which ensures that it is valid
|
// SAFETY: dense_index was just removed from `sparse`, which ensures that it is valid
|
||||||
let (value, _) = unsafe {
|
let (value, _) = unsafe { self.dense.swap_remove_and_forget_unchecked(dense_index) };
|
||||||
self.dense
|
|
||||||
.swap_remove_and_forget_unchecked(TableRow::new(dense_index))
|
|
||||||
};
|
|
||||||
if !is_last {
|
if !is_last {
|
||||||
let swapped_entity = self.entities[dense_index];
|
let swapped_entity = self.entities[dense_index.as_usize()];
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
let index = swapped_entity;
|
let index = swapped_entity;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let index = swapped_entity.index();
|
let index = swapped_entity.index();
|
||||||
*self.sparse.get_mut(index).unwrap() = dense_index as u32;
|
*self.sparse.get_mut(index).unwrap() = dense_index;
|
||||||
}
|
}
|
||||||
value
|
value
|
||||||
})
|
})
|
||||||
@ -316,20 +301,21 @@ impl ComponentSparseSet {
|
|||||||
/// Returns `true` if `entity` had a component value in the sparse set.
|
/// Returns `true` if `entity` had a component value in the sparse set.
|
||||||
pub(crate) fn remove(&mut self, entity: Entity) -> bool {
|
pub(crate) fn remove(&mut self, entity: Entity) -> bool {
|
||||||
if let Some(dense_index) = self.sparse.remove(entity.index()) {
|
if let Some(dense_index) = self.sparse.remove(entity.index()) {
|
||||||
let dense_index = dense_index as usize;
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
assert_eq!(entity, self.entities[dense_index]);
|
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||||
self.entities.swap_remove(dense_index);
|
self.entities.swap_remove(dense_index.as_usize());
|
||||||
let is_last = dense_index == self.dense.len() - 1;
|
let is_last = dense_index.as_usize() == self.dense.len() - 1;
|
||||||
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
||||||
unsafe { self.dense.swap_remove_unchecked(TableRow::new(dense_index)) }
|
unsafe {
|
||||||
|
self.dense.swap_remove_unchecked(dense_index);
|
||||||
|
}
|
||||||
if !is_last {
|
if !is_last {
|
||||||
let swapped_entity = self.entities[dense_index];
|
let swapped_entity = self.entities[dense_index.as_usize()];
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
let index = swapped_entity;
|
let index = swapped_entity;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let index = swapped_entity.index();
|
let index = swapped_entity.index();
|
||||||
*self.sparse.get_mut(index).unwrap() = dense_index as u32;
|
*self.sparse.get_mut(index).unwrap() = dense_index;
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
@ -35,25 +35,48 @@ impl TableId {
|
|||||||
|
|
||||||
/// Creates a new [`TableId`].
|
/// Creates a new [`TableId`].
|
||||||
///
|
///
|
||||||
/// `index` *must* be retrieved from calling [`TableId::index`] on a `TableId` you got
|
/// `index` *must* be retrieved from calling [`TableId::as_u32`] on a `TableId` you got
|
||||||
/// from a table of a given [`World`] or the created ID may be invalid.
|
/// from a table of a given [`World`] or the created ID may be invalid.
|
||||||
///
|
///
|
||||||
/// [`World`]: crate::world::World
|
/// [`World`]: crate::world::World
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(index: usize) -> Self {
|
pub const fn from_u32(index: u32) -> Self {
|
||||||
TableId(index as u32)
|
Self(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new [`TableId`].
|
||||||
|
///
|
||||||
|
/// `index` *must* be retrieved from calling [`TableId::as_usize`] on a `TableId` you got
|
||||||
|
/// from a table of a given [`World`] or the created ID may be invalid.
|
||||||
|
///
|
||||||
|
/// [`World`]: crate::world::World
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Will panic if the provided value does not fit within a [`u32`].
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_usize(index: usize) -> Self {
|
||||||
|
assert!(index as u32 as usize == index);
|
||||||
|
Self(index as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the underlying table index from the ID.
|
/// Gets the underlying table index from the ID.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn index(self) -> usize {
|
pub const fn as_u32(self) -> u32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the underlying table index from the ID.
|
||||||
|
#[inline]
|
||||||
|
pub const fn as_usize(self) -> usize {
|
||||||
|
// usize is at least u32 in Bevy
|
||||||
self.0 as usize
|
self.0 as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The [`TableId`] of the [`Table`] without any components.
|
/// The [`TableId`] of the [`Table`] without any components.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn empty() -> TableId {
|
pub const fn empty() -> Self {
|
||||||
TableId(0)
|
Self(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,15 +105,33 @@ impl TableRow {
|
|||||||
|
|
||||||
/// Creates a `TableRow`.
|
/// Creates a `TableRow`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn new(index: usize) -> Self {
|
pub const fn from_u32(index: u32) -> Self {
|
||||||
|
Self(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a `TableRow` from a [`usize`] index.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Will panic if the provided value does not fit within a [`u32`].
|
||||||
|
#[inline]
|
||||||
|
pub const fn from_usize(index: usize) -> Self {
|
||||||
|
assert!(index as u32 as usize == index);
|
||||||
Self(index as u32)
|
Self(index as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the index of the row.
|
/// Gets the index of the row as a [`usize`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn index(self) -> usize {
|
pub const fn as_usize(self) -> usize {
|
||||||
|
// usize is at least u32 in Bevy
|
||||||
self.0 as usize
|
self.0 as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the index of the row as a [`usize`].
|
||||||
|
#[inline]
|
||||||
|
pub const fn as_u32(self) -> u32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type-erased contiguous container for data of a homogeneous type.
|
/// A type-erased contiguous container for data of a homogeneous type.
|
||||||
@ -139,10 +180,13 @@ impl Column {
|
|||||||
/// Assumes data has already been allocated for the given row.
|
/// Assumes data has already been allocated for the given row.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn initialize(&mut self, row: TableRow, data: OwningPtr<'_>, tick: Tick) {
|
pub(crate) unsafe fn initialize(&mut self, row: TableRow, data: OwningPtr<'_>, tick: Tick) {
|
||||||
debug_assert!(row.index() < self.len());
|
debug_assert!(row.as_usize() < self.len());
|
||||||
self.data.initialize_unchecked(row.index(), data);
|
self.data.initialize_unchecked(row.as_usize(), data);
|
||||||
*self.added_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
|
*self.added_ticks.get_unchecked_mut(row.as_usize()).get_mut() = tick;
|
||||||
*self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
|
*self
|
||||||
|
.changed_ticks
|
||||||
|
.get_unchecked_mut(row.as_usize())
|
||||||
|
.get_mut() = tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes component data to the column at given row.
|
/// Writes component data to the column at given row.
|
||||||
@ -152,9 +196,12 @@ impl Column {
|
|||||||
/// Assumes data has already been allocated for the given row.
|
/// Assumes data has already been allocated for the given row.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn replace(&mut self, row: TableRow, data: OwningPtr<'_>, change_tick: Tick) {
|
pub(crate) unsafe fn replace(&mut self, row: TableRow, data: OwningPtr<'_>, change_tick: Tick) {
|
||||||
debug_assert!(row.index() < self.len());
|
debug_assert!(row.as_usize() < self.len());
|
||||||
self.data.replace_unchecked(row.index(), data);
|
self.data.replace_unchecked(row.as_usize(), data);
|
||||||
*self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = change_tick;
|
*self
|
||||||
|
.changed_ticks
|
||||||
|
.get_unchecked_mut(row.as_usize())
|
||||||
|
.get_mut() = change_tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes component data to the column at given row.
|
/// Writes component data to the column at given row.
|
||||||
@ -165,8 +212,8 @@ impl Column {
|
|||||||
/// Assumes data has already been allocated for the given row.
|
/// Assumes data has already been allocated for the given row.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn replace_untracked(&mut self, row: TableRow, data: OwningPtr<'_>) {
|
pub(crate) unsafe fn replace_untracked(&mut self, row: TableRow, data: OwningPtr<'_>) {
|
||||||
debug_assert!(row.index() < self.len());
|
debug_assert!(row.as_usize() < self.len());
|
||||||
self.data.replace_unchecked(row.index(), data);
|
self.data.replace_unchecked(row.as_usize(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the current number of elements stored in the column.
|
/// Gets the current number of elements stored in the column.
|
||||||
@ -193,9 +240,9 @@ impl Column {
|
|||||||
///
|
///
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) {
|
pub(crate) unsafe fn swap_remove_unchecked(&mut self, row: TableRow) {
|
||||||
self.data.swap_remove_and_drop_unchecked(row.index());
|
self.data.swap_remove_and_drop_unchecked(row.as_usize());
|
||||||
self.added_ticks.swap_remove(row.index());
|
self.added_ticks.swap_remove(row.as_usize());
|
||||||
self.changed_ticks.swap_remove(row.index());
|
self.changed_ticks.swap_remove(row.as_usize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes an element from the [`Column`] and returns it and its change detection ticks.
|
/// Removes an element from the [`Column`] and returns it and its change detection ticks.
|
||||||
@ -214,11 +261,11 @@ impl Column {
|
|||||||
&mut self,
|
&mut self,
|
||||||
row: TableRow,
|
row: TableRow,
|
||||||
) -> Option<(OwningPtr<'_>, ComponentTicks)> {
|
) -> Option<(OwningPtr<'_>, ComponentTicks)> {
|
||||||
(row.index() < self.data.len()).then(|| {
|
(row.as_usize() < self.data.len()).then(|| {
|
||||||
// SAFETY: The row was length checked before this.
|
// SAFETY: The row was length checked before this.
|
||||||
let data = unsafe { self.data.swap_remove_and_forget_unchecked(row.index()) };
|
let data = unsafe { self.data.swap_remove_and_forget_unchecked(row.as_usize()) };
|
||||||
let added = self.added_ticks.swap_remove(row.index()).into_inner();
|
let added = self.added_ticks.swap_remove(row.as_usize()).into_inner();
|
||||||
let changed = self.changed_ticks.swap_remove(row.index()).into_inner();
|
let changed = self.changed_ticks.swap_remove(row.as_usize()).into_inner();
|
||||||
(data, ComponentTicks { added, changed })
|
(data, ComponentTicks { added, changed })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -241,9 +288,9 @@ impl Column {
|
|||||||
&mut self,
|
&mut self,
|
||||||
row: TableRow,
|
row: TableRow,
|
||||||
) -> (OwningPtr<'_>, ComponentTicks) {
|
) -> (OwningPtr<'_>, ComponentTicks) {
|
||||||
let data = self.data.swap_remove_and_forget_unchecked(row.index());
|
let data = self.data.swap_remove_and_forget_unchecked(row.as_usize());
|
||||||
let added = self.added_ticks.swap_remove(row.index()).into_inner();
|
let added = self.added_ticks.swap_remove(row.as_usize()).into_inner();
|
||||||
let changed = self.changed_ticks.swap_remove(row.index()).into_inner();
|
let changed = self.changed_ticks.swap_remove(row.as_usize()).into_inner();
|
||||||
(data, ComponentTicks { added, changed })
|
(data, ComponentTicks { added, changed })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,12 +313,12 @@ impl Column {
|
|||||||
dst_row: TableRow,
|
dst_row: TableRow,
|
||||||
) {
|
) {
|
||||||
debug_assert!(self.data.layout() == other.data.layout());
|
debug_assert!(self.data.layout() == other.data.layout());
|
||||||
let ptr = self.data.get_unchecked_mut(dst_row.index());
|
let ptr = self.data.get_unchecked_mut(dst_row.as_usize());
|
||||||
other.data.swap_remove_unchecked(src_row.index(), ptr);
|
other.data.swap_remove_unchecked(src_row.as_usize(), ptr);
|
||||||
*self.added_ticks.get_unchecked_mut(dst_row.index()) =
|
*self.added_ticks.get_unchecked_mut(dst_row.as_usize()) =
|
||||||
other.added_ticks.swap_remove(src_row.index());
|
other.added_ticks.swap_remove(src_row.as_usize());
|
||||||
*self.changed_ticks.get_unchecked_mut(dst_row.index()) =
|
*self.changed_ticks.get_unchecked_mut(dst_row.as_usize()) =
|
||||||
other.changed_ticks.swap_remove(src_row.index());
|
other.changed_ticks.swap_remove(src_row.as_usize());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pushes a new value onto the end of the [`Column`].
|
/// Pushes a new value onto the end of the [`Column`].
|
||||||
@ -338,15 +385,15 @@ impl Column {
|
|||||||
/// Returns `None` if `row` is out of bounds.
|
/// Returns `None` if `row` is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, row: TableRow) -> Option<(Ptr<'_>, TickCells<'_>)> {
|
pub fn get(&self, row: TableRow) -> Option<(Ptr<'_>, TickCells<'_>)> {
|
||||||
(row.index() < self.data.len())
|
(row.as_usize() < self.data.len())
|
||||||
// SAFETY: The row is length checked before fetching the pointer. This is being
|
// SAFETY: The row is length checked before fetching the pointer. This is being
|
||||||
// accessed through a read-only reference to the column.
|
// accessed through a read-only reference to the column.
|
||||||
.then(|| unsafe {
|
.then(|| unsafe {
|
||||||
(
|
(
|
||||||
self.data.get_unchecked(row.index()),
|
self.data.get_unchecked(row.as_usize()),
|
||||||
TickCells {
|
TickCells {
|
||||||
added: self.added_ticks.get_unchecked(row.index()),
|
added: self.added_ticks.get_unchecked(row.as_usize()),
|
||||||
changed: self.changed_ticks.get_unchecked(row.index()),
|
changed: self.changed_ticks.get_unchecked(row.as_usize()),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -357,9 +404,11 @@ impl Column {
|
|||||||
/// Returns `None` if `row` is out of bounds.
|
/// Returns `None` if `row` is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_data(&self, row: TableRow) -> Option<Ptr<'_>> {
|
pub fn get_data(&self, row: TableRow) -> Option<Ptr<'_>> {
|
||||||
// SAFETY: The row is length checked before fetching the pointer. This is being
|
(row.as_usize() < self.data.len()).then(|| {
|
||||||
// accessed through a read-only reference to the column.
|
// SAFETY: The row is length checked before fetching the pointer. This is being
|
||||||
(row.index() < self.data.len()).then(|| unsafe { self.data.get_unchecked(row.index()) })
|
// accessed through a read-only reference to the column.
|
||||||
|
unsafe { self.data.get_unchecked(row.as_usize()) }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches a read-only reference to the data at `row`. Unlike [`Column::get`] this does not
|
/// Fetches a read-only reference to the data at `row`. Unlike [`Column::get`] this does not
|
||||||
@ -370,8 +419,8 @@ impl Column {
|
|||||||
/// - no other mutable reference to the data of the same row can exist at the same time
|
/// - no other mutable reference to the data of the same row can exist at the same time
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_data_unchecked(&self, row: TableRow) -> Ptr<'_> {
|
pub unsafe fn get_data_unchecked(&self, row: TableRow) -> Ptr<'_> {
|
||||||
debug_assert!(row.index() < self.data.len());
|
debug_assert!(row.as_usize() < self.data.len());
|
||||||
self.data.get_unchecked(row.index())
|
self.data.get_unchecked(row.as_usize())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches a mutable reference to the data at `row`.
|
/// Fetches a mutable reference to the data at `row`.
|
||||||
@ -379,9 +428,11 @@ impl Column {
|
|||||||
/// Returns `None` if `row` is out of bounds.
|
/// Returns `None` if `row` is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_data_mut(&mut self, row: TableRow) -> Option<PtrMut<'_>> {
|
pub fn get_data_mut(&mut self, row: TableRow) -> Option<PtrMut<'_>> {
|
||||||
// SAFETY: The row is length checked before fetching the pointer. This is being
|
(row.as_usize() < self.data.len()).then(|| {
|
||||||
// accessed through an exclusive reference to the column.
|
// SAFETY: The row is length checked before fetching the pointer. This is being
|
||||||
(row.index() < self.data.len()).then(|| unsafe { self.data.get_unchecked_mut(row.index()) })
|
// accessed through an exclusive reference to the column.
|
||||||
|
unsafe { self.data.get_unchecked_mut(row.as_usize()) }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches a mutable reference to the data at `row`. Unlike [`Column::get_data_mut`] this does not
|
/// Fetches a mutable reference to the data at `row`. Unlike [`Column::get_data_mut`] this does not
|
||||||
@ -392,8 +443,8 @@ impl Column {
|
|||||||
/// - no other reference to the data of the same row can exist at the same time
|
/// - no other reference to the data of the same row can exist at the same time
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn get_data_unchecked_mut(&mut self, row: TableRow) -> PtrMut<'_> {
|
pub(crate) unsafe fn get_data_unchecked_mut(&mut self, row: TableRow) -> PtrMut<'_> {
|
||||||
debug_assert!(row.index() < self.data.len());
|
debug_assert!(row.as_usize() < self.data.len());
|
||||||
self.data.get_unchecked_mut(row.index())
|
self.data.get_unchecked_mut(row.as_usize())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches the "added" change detection tick for the value at `row`.
|
/// Fetches the "added" change detection tick for the value at `row`.
|
||||||
@ -405,7 +456,7 @@ impl Column {
|
|||||||
/// adhere to the safety invariants of [`UnsafeCell`].
|
/// adhere to the safety invariants of [`UnsafeCell`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_added_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
|
pub fn get_added_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
|
||||||
self.added_ticks.get(row.index())
|
self.added_ticks.get(row.as_usize())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches the "changed" change detection tick for the value at `row`.
|
/// Fetches the "changed" change detection tick for the value at `row`.
|
||||||
@ -417,7 +468,7 @@ impl Column {
|
|||||||
/// adhere to the safety invariants of [`UnsafeCell`].
|
/// adhere to the safety invariants of [`UnsafeCell`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_changed_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
|
pub fn get_changed_tick(&self, row: TableRow) -> Option<&UnsafeCell<Tick>> {
|
||||||
self.changed_ticks.get(row.index())
|
self.changed_ticks.get(row.as_usize())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches the change detection ticks for the value at `row`.
|
/// Fetches the change detection ticks for the value at `row`.
|
||||||
@ -425,7 +476,7 @@ impl Column {
|
|||||||
/// Returns `None` if `row` is out of bounds.
|
/// Returns `None` if `row` is out of bounds.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_ticks(&self, row: TableRow) -> Option<ComponentTicks> {
|
pub fn get_ticks(&self, row: TableRow) -> Option<ComponentTicks> {
|
||||||
if row.index() < self.data.len() {
|
if row.as_usize() < self.data.len() {
|
||||||
// SAFETY: The size of the column has already been checked.
|
// SAFETY: The size of the column has already been checked.
|
||||||
Some(unsafe { self.get_ticks_unchecked(row) })
|
Some(unsafe { self.get_ticks_unchecked(row) })
|
||||||
} else {
|
} else {
|
||||||
@ -440,8 +491,8 @@ impl Column {
|
|||||||
/// `row` must be within the range `[0, self.len())`.
|
/// `row` must be within the range `[0, self.len())`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_added_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
|
pub unsafe fn get_added_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
|
||||||
debug_assert!(row.index() < self.added_ticks.len());
|
debug_assert!(row.as_usize() < self.added_ticks.len());
|
||||||
self.added_ticks.get_unchecked(row.index())
|
self.added_ticks.get_unchecked(row.as_usize())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches the "changed" change detection tick for the value at `row`. Unlike [`Column::get_changed_tick`]
|
/// Fetches the "changed" change detection tick for the value at `row`. Unlike [`Column::get_changed_tick`]
|
||||||
@ -451,8 +502,8 @@ impl Column {
|
|||||||
/// `row` must be within the range `[0, self.len())`.
|
/// `row` must be within the range `[0, self.len())`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_changed_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
|
pub unsafe fn get_changed_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
|
||||||
debug_assert!(row.index() < self.changed_ticks.len());
|
debug_assert!(row.as_usize() < self.changed_ticks.len());
|
||||||
self.changed_ticks.get_unchecked(row.index())
|
self.changed_ticks.get_unchecked(row.as_usize())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches the change detection ticks for the value at `row`. Unlike [`Column::get_ticks`]
|
/// Fetches the change detection ticks for the value at `row`. Unlike [`Column::get_ticks`]
|
||||||
@ -462,11 +513,11 @@ impl Column {
|
|||||||
/// `row` must be within the range `[0, self.len())`.
|
/// `row` must be within the range `[0, self.len())`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_ticks_unchecked(&self, row: TableRow) -> ComponentTicks {
|
pub unsafe fn get_ticks_unchecked(&self, row: TableRow) -> ComponentTicks {
|
||||||
debug_assert!(row.index() < self.added_ticks.len());
|
debug_assert!(row.as_usize() < self.added_ticks.len());
|
||||||
debug_assert!(row.index() < self.changed_ticks.len());
|
debug_assert!(row.as_usize() < self.changed_ticks.len());
|
||||||
ComponentTicks {
|
ComponentTicks {
|
||||||
added: self.added_ticks.get_unchecked(row.index()).read(),
|
added: self.added_ticks.get_unchecked(row.as_usize()).read(),
|
||||||
changed: self.changed_ticks.get_unchecked(row.index()).read(),
|
changed: self.changed_ticks.get_unchecked(row.as_usize()).read(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -565,12 +616,12 @@ impl Table {
|
|||||||
for column in self.columns.values_mut() {
|
for column in self.columns.values_mut() {
|
||||||
column.swap_remove_unchecked(row);
|
column.swap_remove_unchecked(row);
|
||||||
}
|
}
|
||||||
let is_last = row.index() == self.entities.len() - 1;
|
let is_last = row.as_usize() == self.entities.len() - 1;
|
||||||
self.entities.swap_remove(row.index());
|
self.entities.swap_remove(row.as_usize());
|
||||||
if is_last {
|
if is_last {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.entities[row.index()])
|
Some(self.entities[row.as_usize()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,9 +638,9 @@ impl Table {
|
|||||||
row: TableRow,
|
row: TableRow,
|
||||||
new_table: &mut Table,
|
new_table: &mut Table,
|
||||||
) -> TableMoveResult {
|
) -> TableMoveResult {
|
||||||
debug_assert!(row.index() < self.entity_count());
|
debug_assert!(row.as_usize() < self.entity_count());
|
||||||
let is_last = row.index() == self.entities.len() - 1;
|
let is_last = row.as_usize() == self.entities.len() - 1;
|
||||||
let new_row = new_table.allocate(self.entities.swap_remove(row.index()));
|
let new_row = new_table.allocate(self.entities.swap_remove(row.as_usize()));
|
||||||
for (component_id, column) in self.columns.iter_mut() {
|
for (component_id, column) in self.columns.iter_mut() {
|
||||||
if let Some(new_column) = new_table.get_column_mut(*component_id) {
|
if let Some(new_column) = new_table.get_column_mut(*component_id) {
|
||||||
new_column.initialize_from_unchecked(column, row, new_row);
|
new_column.initialize_from_unchecked(column, row, new_row);
|
||||||
@ -603,7 +654,7 @@ impl Table {
|
|||||||
swapped_entity: if is_last {
|
swapped_entity: if is_last {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.entities[row.index()])
|
Some(self.entities[row.as_usize()])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -619,9 +670,9 @@ impl Table {
|
|||||||
row: TableRow,
|
row: TableRow,
|
||||||
new_table: &mut Table,
|
new_table: &mut Table,
|
||||||
) -> TableMoveResult {
|
) -> TableMoveResult {
|
||||||
debug_assert!(row.index() < self.entity_count());
|
debug_assert!(row.as_usize() < self.entity_count());
|
||||||
let is_last = row.index() == self.entities.len() - 1;
|
let is_last = row.as_usize() == self.entities.len() - 1;
|
||||||
let new_row = new_table.allocate(self.entities.swap_remove(row.index()));
|
let new_row = new_table.allocate(self.entities.swap_remove(row.as_usize()));
|
||||||
for (component_id, column) in self.columns.iter_mut() {
|
for (component_id, column) in self.columns.iter_mut() {
|
||||||
if let Some(new_column) = new_table.get_column_mut(*component_id) {
|
if let Some(new_column) = new_table.get_column_mut(*component_id) {
|
||||||
new_column.initialize_from_unchecked(column, row, new_row);
|
new_column.initialize_from_unchecked(column, row, new_row);
|
||||||
@ -634,7 +685,7 @@ impl Table {
|
|||||||
swapped_entity: if is_last {
|
swapped_entity: if is_last {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.entities[row.index()])
|
Some(self.entities[row.as_usize()])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -650,9 +701,9 @@ impl Table {
|
|||||||
row: TableRow,
|
row: TableRow,
|
||||||
new_table: &mut Table,
|
new_table: &mut Table,
|
||||||
) -> TableMoveResult {
|
) -> TableMoveResult {
|
||||||
debug_assert!(row.index() < self.entity_count());
|
debug_assert!(row.as_usize() < self.entity_count());
|
||||||
let is_last = row.index() == self.entities.len() - 1;
|
let is_last = row.as_usize() == self.entities.len() - 1;
|
||||||
let new_row = new_table.allocate(self.entities.swap_remove(row.index()));
|
let new_row = new_table.allocate(self.entities.swap_remove(row.as_usize()));
|
||||||
for (component_id, column) in self.columns.iter_mut() {
|
for (component_id, column) in self.columns.iter_mut() {
|
||||||
new_table
|
new_table
|
||||||
.get_column_mut(*component_id)
|
.get_column_mut(*component_id)
|
||||||
@ -664,7 +715,7 @@ impl Table {
|
|||||||
swapped_entity: if is_last {
|
swapped_entity: if is_last {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(self.entities[row.index()])
|
Some(self.entities[row.as_usize()])
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -728,7 +779,7 @@ impl Table {
|
|||||||
column.added_ticks.push(UnsafeCell::new(Tick::new(0)));
|
column.added_ticks.push(UnsafeCell::new(Tick::new(0)));
|
||||||
column.changed_ticks.push(UnsafeCell::new(Tick::new(0)));
|
column.changed_ticks.push(UnsafeCell::new(Tick::new(0)));
|
||||||
}
|
}
|
||||||
TableRow::new(index)
|
TableRow::from_usize(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the number of entities currently being stored in the table.
|
/// Gets the number of entities currently being stored in the table.
|
||||||
@ -819,7 +870,7 @@ impl Tables {
|
|||||||
/// Returns `None` if `id` is invalid.
|
/// Returns `None` if `id` is invalid.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get(&self, id: TableId) -> Option<&Table> {
|
pub fn get(&self, id: TableId) -> Option<&Table> {
|
||||||
self.tables.get(id.index())
|
self.tables.get(id.as_usize())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches mutable references to two different [`Table`]s.
|
/// Fetches mutable references to two different [`Table`]s.
|
||||||
@ -829,12 +880,12 @@ impl Tables {
|
|||||||
/// Panics if `a` and `b` are equal.
|
/// Panics if `a` and `b` are equal.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn get_2_mut(&mut self, a: TableId, b: TableId) -> (&mut Table, &mut Table) {
|
pub(crate) fn get_2_mut(&mut self, a: TableId, b: TableId) -> (&mut Table, &mut Table) {
|
||||||
if a.index() > b.index() {
|
if a.as_usize() > b.as_usize() {
|
||||||
let (b_slice, a_slice) = self.tables.split_at_mut(a.index());
|
let (b_slice, a_slice) = self.tables.split_at_mut(a.as_usize());
|
||||||
(&mut a_slice[0], &mut b_slice[b.index()])
|
(&mut a_slice[0], &mut b_slice[b.as_usize()])
|
||||||
} else {
|
} else {
|
||||||
let (a_slice, b_slice) = self.tables.split_at_mut(b.index());
|
let (a_slice, b_slice) = self.tables.split_at_mut(b.as_usize());
|
||||||
(&mut a_slice[a.index()], &mut b_slice[0])
|
(&mut a_slice[a.as_usize()], &mut b_slice[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,7 +910,10 @@ impl Tables {
|
|||||||
table = table.add_column(components.get_info_unchecked(*component_id));
|
table = table.add_column(components.get_info_unchecked(*component_id));
|
||||||
}
|
}
|
||||||
tables.push(table.build());
|
tables.push(table.build());
|
||||||
(component_ids.to_vec(), TableId::new(tables.len() - 1))
|
(
|
||||||
|
component_ids.to_vec(),
|
||||||
|
TableId::from_usize(tables.len() - 1),
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
*value
|
*value
|
||||||
@ -889,14 +943,14 @@ impl Index<TableId> for Tables {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: TableId) -> &Self::Output {
|
fn index(&self, index: TableId) -> &Self::Output {
|
||||||
&self.tables[index.index()]
|
&self.tables[index.as_usize()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexMut<TableId> for Tables {
|
impl IndexMut<TableId> for Tables {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: TableId) -> &mut Self::Output {
|
fn index_mut(&mut self, index: TableId) -> &mut Self::Output {
|
||||||
&mut self.tables[index.index()]
|
&mut self.tables[index.as_usize()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user