use core::fmt::*;
use std::{
cell::SyncUnsafeCell,
mem::transmute,
ops::{Deref, DerefMut, Range},
sync::atomic::AtomicUsize,
};
use pi_append_vec::SafeVec;
use pi_arr::Arr;
use pi_null::Null;
use pi_share::Share;
use crate::{
archetype::{Archetype, ArchetypeIndex, ComponentInfo, Row, ShareArchetype},
event::ComponentEventVec,
world::{Entity, Tick},
};
#[cfg(debug_assertions)]
pub static COMPONENT_INDEX: AtomicUsize = AtomicUsize::new(usize::MAX);
#[cfg(debug_assertions)]
pub static ARCHETYPE_INDEX: AtomicUsize = AtomicUsize::new(usize::MAX);
pub struct Column {
pub(crate) info: ColumnInfo,
pub(crate) arr: Arr<BlobTicks>,
pub(crate) last_len: SyncUnsafeCell<usize>,
}
impl Column {
pub fn memsize(&self) -> usize {
let mut result = 0;
let end = self.arr.capacity(0);
for idx in 0..end {
if let Some(item) = self.arr.get(idx) {
result += item.memsize();
}
}
result += self.info.memsize();
result
}
#[inline(always)]
pub fn new(info: ComponentInfo) -> Self {
Self {
info: ColumnInfo {
changed: None,
added: None,
removed: None,
info,
},
arr: Arr::default(),
last_len: SyncUnsafeCell::new(0usize.into()),
}
}
#[inline(always)]
pub fn info(&self) -> &ComponentInfo {
&self.info
}
#[inline(always)]
pub fn info_mut(&mut self) -> &mut ComponentInfo {
&mut self.info.info
}
pub fn init_blob(&self, index: ArchetypeIndex) {
*unsafe { &mut *self.last_len.get() } = index.index() + 1;
unsafe { self.arr.load_alloc(index.index()).blob.set_vec_capacity(0) };
}
pub fn contains(&self, index: ArchetypeIndex) -> bool {
match self.arr.load(index.index()) {
Some(b) => !b.blob.vec_capacity().is_null(),
None => false,
}
}
#[inline(always)]
pub fn blob_ref_unchecked(&self, index: ArchetypeIndex) -> BlobRef<'_> {
#[cfg(debug_assertions)]
let debug_a_index = ARCHETYPE_INDEX.load(std::sync::atomic::Ordering::Relaxed);
#[cfg(debug_assertions)]
let debug_c_index = COMPONENT_INDEX.load(std::sync::atomic::Ordering::Relaxed);
#[cfg(debug_assertions)]
if (!debug_a_index.is_null() || !debug_c_index.is_null())
&& (debug_a_index.is_null() || index.index() == debug_a_index)
&& (debug_c_index.is_null() || self.info.index.index() == debug_c_index)
{
println!(
"blob_ref_unchecked, {} {:p}",
self.arr.vec_capacity(),
unsafe { self.arr.load_unchecked(index.index()) }
);
}
BlobRef::new(
unsafe { self.arr.load_unchecked(index.index()) },
&self.info,
#[cfg(debug_assertions)]
index,
)
}
#[inline(always)]
pub fn blob_ref(&self, index: ArchetypeIndex) -> Option<BlobRef<'_>> {
#[cfg(debug_assertions)]
let debug_a_index = ARCHETYPE_INDEX.load(std::sync::atomic::Ordering::Relaxed);
#[cfg(debug_assertions)]
let debug_c_index = COMPONENT_INDEX.load(std::sync::atomic::Ordering::Relaxed);
#[cfg(debug_assertions)]
if (!debug_a_index.is_null() || !debug_c_index.is_null())
&& (debug_a_index.is_null() || index.index() == debug_a_index)
&& (debug_c_index.is_null() || self.info.index.index() == debug_c_index)
{
println!("blob_ref, {} {:p}", self.arr.vec_capacity(), unsafe {
self.arr.load_unchecked(index.index())
});
}
let blob = match self.arr.load(index.index()) {
Some(b) => b,
_ => return None,
};
if blob.blob.vec_capacity().is_null() {
return None;
}
Some(BlobRef::new(
blob,
&self.info,
#[cfg(debug_assertions)]
index,
))
}
pub(crate) fn update<F>(&self, archetypes: &SafeVec<ShareArchetype>, set_fn: F)
where
F: Fn(&BlobRef, Row, &Archetype),
{
let mut size = 0;
for ar in archetypes.iter() {
if let Some(blob) = self.arr.load(ar.index.index()) {
if blob.blob.vec_capacity().is_null() {
continue;
}
let r = BlobRef::new(
blob,
&self.info,
#[cfg(debug_assertions)]
ar.index,
);
for row in 0..ar.len().index() {
set_fn(&r, row.into(), &ar)
}
size += blob.memsize();
}
}
}
pub(crate) fn settle(&mut self) {
let len = *self.last_len.get_mut();
if len > self.arr.vec_capacity() {
self.arr.settle(len, 0, 1);
}
}
pub(crate) fn settle_by_index(
&mut self,
index: ArchetypeIndex,
len: usize,
additional: usize,
action: &Vec<(Row, Row)>,
) {
if self.info.size() == 0 {
return;
}
let blob = unsafe { self.arr.get_unchecked_mut(index.index()) };
#[cfg(debug_assertions)]
let debug_index = ARCHETYPE_INDEX.load(std::sync::atomic::Ordering::Relaxed);
#[cfg(debug_assertions)]
if (debug_index.is_null() || index.index() == debug_index)
&& self.info.index.index() == COMPONENT_INDEX.load(std::sync::atomic::Ordering::Relaxed)
{
println!(
"Column settle_by_index:===={:?} {:p}",
(index, blob.blob.vec_capacity(), action),
blob
);
}
let r = BlobRef::new(
blob,
&self.info,
#[cfg(debug_assertions)]
index,
);
if self.info.is_tick() {
for (src, dst) in action.iter() {
unsafe {
let src_data: *mut u8 = r.get_blob(*src);
let dst_data: *mut u8 = r.load_blob(*dst);
src_data.copy_to_nonoverlapping(dst_data, self.info.size());
let tick = r.get_tick_unchecked(*src);
r.set_tick_unchecked(*dst, tick);
}
}
blob.blob.settle(len, additional, self.info.size());
blob.ticks.settle(len, additional, 1);
return;
}
for (src, dst) in action.iter() {
unsafe {
let src_data: *mut u8 = r.get_blob(*src);
let dst_data: *mut u8 = r.load_blob(*dst);
src_data.copy_to_nonoverlapping(dst_data, self.info.size());
}
}
blob.blob.settle(len, additional, self.info.size());
}
}
impl Debug for Column {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("Column")
.field("info", &self.info.info)
.field("last_index", &self.last_len.get())
.finish()
}
}
pub(crate) struct ColumnInfo {
pub(crate) changed: Option<Share<ComponentEventVec>>,
pub(crate) added: Option<Share<ComponentEventVec>>,
pub(crate) removed: Option<Share<ComponentEventVec>>,
pub(crate) info: ComponentInfo,
}
impl Deref for ColumnInfo {
type Target = ComponentInfo;
fn deref(&self) -> &Self::Target {
&self.info
}
}
impl ColumnInfo {
pub fn memsize(&self) -> usize {
let mut result = 0;
if let Some(item) = &self.changed {
result += item.capacity();
}
if let Some(item) = &self.added {
result += item.capacity();
}
if let Some(item) = &self.removed {
result += item.capacity();
}
result += self.info.size();
result
}
}
struct Blob(Arr<u8>);
impl Default for Blob {
fn default() -> Self {
let mut arr = Arr::default();
unsafe { arr.set_vec_capacity(usize::null()) };
Self(arr)
}
}
impl Drop for Blob {
fn drop(&mut self) {
if self.vec_capacity().is_null() {
unsafe { self.set_vec_capacity(0) };
}
}
}
impl Deref for Blob {
type Target = Arr<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Blob {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Blob {
pub fn memsize(&self) -> usize {
let val = self.0.vec_capacity();
if val.is_null() {
24
} else {
val + 24
}
}
}
#[derive(Default)]
pub(crate) struct BlobTicks {
blob: Blob,
pub(crate) ticks: Arr<Tick>,
}
impl BlobTicks {
pub fn memsize(&self) -> usize {
self.blob.memsize() + self.ticks.vec_capacity() * 4
}
}
#[derive(Clone)]
pub struct BlobRef<'a> {
pub(crate) blob: &'a BlobTicks,
pub(crate) info: &'a ColumnInfo,
#[cfg(debug_assertions)]
index: ArchetypeIndex,
}
impl<'a> BlobRef<'a> {
#[inline(always)]
pub(crate) fn new(
blob: &'a mut BlobTicks,
info: &'a ColumnInfo,
#[cfg(debug_assertions)] index: ArchetypeIndex,
) -> Self {
Self {
blob,
info,
#[cfg(debug_assertions)]
index,
}
}
#[inline(always)]
pub fn get_tick_unchecked(&self, row: Row) -> Tick {
self.blob
.ticks
.get(row.index())
.map_or(Tick::default(), |t| *t)
}
#[inline]
pub fn added_tick(&self, e: Entity, row: Row, tick: Tick) {
if !self.info.is_tick() {
return;
}
*self.blob.ticks.load_alloc(row.index()) = tick;
if let Some(vec) = &self.info.added {
vec.record(e);
}
}
#[inline]
pub fn changed_tick(&self, e: Entity, row: Row, tick: Tick) {
if !self.info.is_tick() {
return;
}
let old = self.blob.ticks.load_alloc(row.index());
if *old >= tick {
return;
}
*old = tick;
if let Some(vec) = &self.info.changed {
vec.record(e);
}
}
#[inline]
pub fn set_tick_unchecked(&self, row: Row, tick: Tick) {
*self.blob.ticks.load_alloc(row.index()) = tick;
}
fn trace(&self, row: Row, e: Entity, path: &str, src_data: *mut u8) {
#[cfg(debug_assertions)]
let debug_a_index = ARCHETYPE_INDEX.load(std::sync::atomic::Ordering::Relaxed);
#[cfg(debug_assertions)]
let debug_c_index = COMPONENT_INDEX.load(std::sync::atomic::Ordering::Relaxed);
#[cfg(debug_assertions)]
if (!debug_a_index.is_null() || !debug_c_index.is_null())
&& (debug_a_index.is_null() || self.index.index() == debug_a_index)
&& (debug_c_index.is_null() || self.info.index.index() == debug_c_index)
{
let ptr: *mut u8 = self
.blob
.blob
.load_alloc_multiple(row.index(), self.info.size());
let slice: &[u8] =
unsafe { transmute(std::ptr::slice_from_raw_parts(src_data, self.info.size())) };
println!(
"Column {:?}:===={:?} blob_ptr:{:p}, dst:{:p}, src:{:p}, src_data:{:?}",
path,
(row, e, self.index, self.blob.blob.vec_capacity()),
self.blob,
ptr,
src_data,
slice,
);
}
}
#[inline(always)]
pub fn get<T>(&self, row: Row, e: Entity) -> &'a T {
unsafe { transmute(self.get_blob(row)) }
}
#[inline(always)]
pub fn get_mut<T>(&self, row: Row, e: Entity) -> &'a mut T {
unsafe { transmute(self.load_blob(row)) }
}
#[inline(always)]
pub(crate) fn write<T>(&self, row: Row, e: Entity, val: T) {
self.trace(row, e, "write", unsafe { transmute(&val) });
unsafe {
let ptr: *mut T = transmute(self.load_blob(row));
ptr.write(val)
};
}
#[inline(always)]
pub fn load(&self, row: Row, e: Entity) -> *mut u8 {
self.trace(row, e, "load", std::ptr::null_mut());
self.load_blob(row)
}
#[inline(always)]
pub fn get_row(&self, row: Row, e: Entity) -> *mut u8 {
assert!(!row.is_null());
self.trace(row, e, "get_row", std::ptr::null_mut());
self.get_blob(row)
}
#[inline(always)]
pub fn write_row(&self, row: Row, e: Entity, data: *mut u8) {
self.trace(row, e, "write_row", data);
unsafe {
let dst = self.load_blob(row);
data.copy_to_nonoverlapping(dst, self.info.size());
}
}
#[inline(always)]
pub(crate) fn drop_row(&self, row: Row, e: Entity) {
assert!(!row.is_null());
self.trace(row, e, "drop_row", std::ptr::null_mut());
if let Some(f) = self.info.drop_fn {
f(self.get_blob(row))
}
}
#[inline(always)]
pub fn drop_row_unchecked(&self, row: Row, e: Entity) {
assert!(!row.is_null());
self.trace(row, e, "drop_row_unchecked", std::ptr::null_mut());
self.info.drop_fn.unwrap()(self.get_blob(row))
}
#[inline(always)]
pub fn get_blob(&self, row: Row) -> *mut u8 {
assert!(!row.is_null());
unsafe { transmute(self.blob.blob.get_multiple(row.index(), self.info.size())) }
}
#[inline(always)]
pub fn load_blob(&self, row: Row) -> *mut u8 {
assert!(!row.is_null());
unsafe {
transmute(
self.blob
.blob
.load_alloc_multiple(row.index(), self.info.size()),
)
}
}
#[inline(always)]
pub fn needs_drop(&self) -> bool {
self.info.drop_fn.is_some()
}
}
impl<'a> Debug for BlobRef<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("Column")
.field("info", &self.info.info)
.finish()
}
}