use super::*;
use crate::{
change_detection::MaybeLocation,
storage::{blob_array::BlobArray, thin_array_ptr::ThinArrayPtr},
};
use core::{mem::needs_drop, panic::Location};
#[derive(Debug)]
pub struct Column {
pub(super) data: BlobArray,
pub(super) added_ticks: ThinArrayPtr<UnsafeCell<Tick>>,
pub(super) changed_ticks: ThinArrayPtr<UnsafeCell<Tick>>,
pub(super) changed_by: MaybeLocation<ThinArrayPtr<UnsafeCell<&'static Location<'static>>>>,
}
impl Column {
pub fn with_capacity(component_info: &ComponentInfo, capacity: usize) -> Self {
Self {
data: unsafe {
BlobArray::with_capacity(component_info.layout(), component_info.drop(), capacity)
},
added_ticks: ThinArrayPtr::with_capacity(capacity),
changed_ticks: ThinArrayPtr::with_capacity(capacity),
changed_by: MaybeLocation::new_with(|| ThinArrayPtr::with_capacity(capacity)),
}
}
pub(crate) unsafe fn swap_remove_and_drop_unchecked_nonoverlapping(
&mut self,
last_element_index: usize,
row: TableRow,
) {
self.data
.swap_remove_and_drop_unchecked_nonoverlapping(row.index(), last_element_index);
self.added_ticks
.swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
self.changed_ticks
.swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
self.changed_by.as_mut().map(|changed_by| {
changed_by.swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
});
}
pub(crate) unsafe fn swap_remove_and_drop_unchecked(
&mut self,
last_element_index: usize,
row: TableRow,
) {
self.data
.swap_remove_and_drop_unchecked(row.index(), last_element_index);
self.added_ticks
.swap_remove_unchecked(row.index(), last_element_index);
self.changed_ticks
.swap_remove_unchecked(row.index(), last_element_index);
self.changed_by.as_mut().map(|changed_by| {
changed_by.swap_remove_unchecked(row.index(), last_element_index);
});
}
pub(crate) unsafe fn swap_remove_and_forget_unchecked_nonoverlapping(
&mut self,
last_element_index: usize,
row: TableRow,
) -> OwningPtr<'_> {
let data = self
.data
.swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
self.added_ticks
.swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
self.changed_ticks
.swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
self.changed_by.as_mut().map(|changed_by| {
changed_by.swap_remove_unchecked_nonoverlapping(row.index(), last_element_index);
});
data
}
pub(crate) unsafe fn swap_remove_and_forget_unchecked(
&mut self,
last_element_index: usize,
row: TableRow,
) -> OwningPtr<'_> {
let data = self
.data
.swap_remove_unchecked(row.index(), last_element_index);
self.added_ticks
.swap_remove_unchecked(row.index(), last_element_index);
self.changed_ticks
.swap_remove_unchecked(row.index(), last_element_index);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.swap_remove_unchecked(row.index(), last_element_index));
data
}
pub(crate) unsafe fn realloc(
&mut self,
current_capacity: NonZeroUsize,
new_capacity: NonZeroUsize,
) {
self.data.realloc(current_capacity, new_capacity);
self.added_ticks.realloc(current_capacity, new_capacity);
self.changed_ticks.realloc(current_capacity, new_capacity);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.realloc(current_capacity, new_capacity));
}
pub(crate) fn alloc(&mut self, new_capacity: NonZeroUsize) {
self.data.alloc(new_capacity);
self.added_ticks.alloc(new_capacity);
self.changed_ticks.alloc(new_capacity);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.alloc(new_capacity));
}
#[inline]
pub(crate) unsafe fn initialize(
&mut self,
row: TableRow,
data: OwningPtr<'_>,
tick: Tick,
caller: MaybeLocation,
) {
self.data.initialize_unchecked(row.index(), data);
*self.added_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
*self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = tick;
self.changed_by
.as_mut()
.map(|changed_by| changed_by.get_unchecked_mut(row.index()).get_mut())
.assign(caller);
}
#[inline]
pub(crate) unsafe fn replace(
&mut self,
row: TableRow,
data: OwningPtr<'_>,
change_tick: Tick,
caller: MaybeLocation,
) {
self.data.replace_unchecked(row.index(), data);
*self.changed_ticks.get_unchecked_mut(row.index()).get_mut() = change_tick;
self.changed_by
.as_mut()
.map(|changed_by| changed_by.get_unchecked_mut(row.index()).get_mut())
.assign(caller);
}
#[inline]
pub(crate) unsafe fn initialize_from_unchecked(
&mut self,
other: &mut Column,
other_last_element_index: usize,
src_row: TableRow,
dst_row: TableRow,
) {
debug_assert!(self.data.layout() == other.data.layout());
let src_val = other
.data
.swap_remove_unchecked(src_row.index(), other_last_element_index);
self.data.initialize_unchecked(dst_row.index(), src_val);
let added_tick = other
.added_ticks
.swap_remove_unchecked(src_row.index(), other_last_element_index);
self.added_ticks
.initialize_unchecked(dst_row.index(), added_tick);
let changed_tick = other
.changed_ticks
.swap_remove_unchecked(src_row.index(), other_last_element_index);
self.changed_ticks
.initialize_unchecked(dst_row.index(), changed_tick);
self.changed_by.as_mut().zip(other.changed_by.as_mut()).map(
|(self_changed_by, other_changed_by)| {
let changed_by = other_changed_by
.swap_remove_unchecked(src_row.index(), other_last_element_index);
self_changed_by.initialize_unchecked(dst_row.index(), changed_by);
},
);
}
#[inline]
pub(crate) unsafe fn check_change_ticks(&mut self, len: usize, check: CheckChangeTicks) {
for i in 0..len {
unsafe { self.added_ticks.get_unchecked_mut(i) }
.get_mut()
.check_tick(check);
unsafe { self.changed_ticks.get_unchecked_mut(i) }
.get_mut()
.check_tick(check);
}
}
pub(crate) unsafe fn clear(&mut self, len: usize) {
self.added_ticks.clear_elements(len);
self.changed_ticks.clear_elements(len);
self.data.clear(len);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.clear_elements(len));
}
pub(crate) unsafe fn drop(&mut self, cap: usize, len: usize) {
self.added_ticks.drop(cap, len);
self.changed_ticks.drop(cap, len);
self.data.drop(cap, len);
self.changed_by
.as_mut()
.map(|changed_by| changed_by.drop(cap, len));
}
pub(crate) unsafe fn drop_last_component(&mut self, last_element_index: usize) {
const {
assert!(!needs_drop::<UnsafeCell<Tick>>());
assert!(!needs_drop::<UnsafeCell<&'static Location<'static>>>());
}
self.data.drop_last_element(last_element_index);
}
pub unsafe fn get_data_slice<T>(&self, len: usize) -> &[UnsafeCell<T>] {
unsafe { self.data.get_sub_slice(len) }
}
pub unsafe fn get_added_ticks_slice(&self, len: usize) -> &[UnsafeCell<Tick>] {
unsafe { self.added_ticks.as_slice(len) }
}
pub unsafe fn get_changed_ticks_slice(&self, len: usize) -> &[UnsafeCell<Tick>] {
unsafe { self.changed_ticks.as_slice(len) }
}
pub unsafe fn get_changed_by_slice(
&self,
len: usize,
) -> MaybeLocation<&[UnsafeCell<&'static Location<'static>>]> {
self.changed_by
.as_ref()
.map(|changed_by| changed_by.as_slice(len))
}
#[inline]
pub unsafe fn get_data_unchecked(&self, row: TableRow) -> Ptr<'_> {
self.data.get_unchecked(row.index())
}
#[inline]
pub unsafe fn get_changed_by_unchecked(
&self,
row: TableRow,
) -> MaybeLocation<&UnsafeCell<&'static Location<'static>>> {
self.changed_by
.as_ref()
.map(|changed_by| changed_by.get_unchecked(row.index()))
}
#[inline]
pub unsafe fn get_added_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
unsafe { self.added_ticks.get_unchecked(row.index()) }
}
#[inline]
pub unsafe fn get_changed_tick_unchecked(&self, row: TableRow) -> &UnsafeCell<Tick> {
unsafe { self.changed_ticks.get_unchecked(row.index()) }
}
#[inline]
pub unsafe fn get_ticks_unchecked(&self, row: TableRow) -> ComponentTicks {
ComponentTicks {
added: self.added_ticks.get_unchecked(row.index()).read(),
changed: self.changed_ticks.get_unchecked(row.index()).read(),
}
}
#[inline]
pub fn get_drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {
self.data.get_drop()
}
}