use core::fmt::*;
use std::{
mem::{replace, take, transmute},
ptr::null_mut,
};
use pi_arr::{Arr, Location, BUCKETS};
use crate::{
archetype::{ComponentInfo, Row},
dirty::ComponentDirty,
};
pub struct Column {
blob: Blob,
pub(crate) added: ComponentDirty, pub(crate) changed: ComponentDirty, }
impl Column {
#[inline(always)]
pub fn new(info: ComponentInfo) -> Self {
Self {
blob: Blob::new(info),
added: Default::default(),
changed: Default::default(),
}
}
#[inline(always)]
pub fn info(&self) -> &ComponentInfo {
&self.blob.info
}
#[inline(always)]
pub fn get<T>(&self, row: Row) -> &T {
unsafe { transmute(self.blob.get(row)) }
}
#[inline(always)]
pub fn get_mut<T>(&self, row: Row) -> &mut T {
unsafe {
let ptr: *mut T = transmute(self.blob.get(row));
transmute(ptr)
}
}
#[inline(always)]
pub(crate) fn write<T>(&self, row: Row, val: T) {
unsafe {
let ptr: *mut T = transmute(self.blob.load(row));
ptr.write(val)
};
}
#[inline(always)]
pub fn get_row(&self, row: Row) -> *mut u8 {
unsafe { self.blob.get(row) }
}
#[inline(always)]
pub fn write_row(&self, row: Row, data: *mut u8) {
unsafe {
let dst = self.blob.load(row);
data.copy_to_nonoverlapping(dst, self.info().mem_size)
}
}
#[inline(always)]
pub(crate) fn drop_row(&self, row: Row) {
if let Some(f) = self.info().drop_fn {
f(unsafe { self.blob.get(row) })
}
}
#[inline(always)]
pub fn needs_drop(&self) -> bool {
self.info().drop_fn.is_some()
}
#[inline(always)]
pub fn drop_row_unchecked(&self, row: Row) {
self.info().drop_fn.unwrap()(unsafe { transmute(self.blob.get(row)) })
}
pub fn reserve(&mut self, len: usize, additional: usize) {
self.blob.reserve(len, additional);
self.added.reserve(additional);
}
pub(crate) fn collect(&mut self, entity_len: usize, action: &Vec<(Row, Row)>) {
for (src, dst) in action.iter() {
unsafe {
let src_data: *mut u8 = transmute(self.blob.get(*src));
let dst_data: *mut u8 = transmute(self.blob.get(*dst));
src_data.copy_to_nonoverlapping(dst_data, self.info().mem_size);
}
}
self.blob.reserve(entity_len, 0);
}
pub(crate) fn collect_dirty(&mut self) -> bool {
self.added.collect() && self.changed.collect()
}
}
impl Debug for Column {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("Column")
.field("info", &self.info())
.field("added", &self.added)
.field("changed", &self.changed)
.finish()
}
}
struct Blob {
vec: Vec<u8>,
arr: Arr<u8>,
info: ComponentInfo,
vec_capacity: usize,
}
impl Blob {
#[inline(always)]
pub fn new(info: ComponentInfo) -> Self {
Self {
vec: Vec::new(),
arr: Arr::new(),
info,
vec_capacity: 0,
}
}
#[inline(always)]
pub unsafe fn get(&self, row: Row) -> *mut u8 {
let row = row as usize;
if row < self.vec_capacity {
return transmute(self.vec.get(row * self.info.mem_size).unwrap());
}
let mut loc = Location::of(row - self.vec_capacity);
loc.entry *= self.info.mem_size;
transmute(self.arr.get(&loc).unwrap())
}
#[inline(always)]
pub unsafe fn load(&self, row: Row) -> *mut u8 {
let row = row as usize;
if row < self.vec_capacity {
return transmute(self.vec.get(row * self.info.mem_size).unwrap());
}
let mut loc = Location::of(row - self.vec_capacity);
loc.entry *= self.info.mem_size;
loc.len *= self.info.mem_size;
transmute(self.arr.load_alloc(&loc))
}
#[inline(always)]
fn vec_reserve(&mut self, additional: usize) {
self.vec.reserve(additional * self.info.mem_size);
unsafe { self.vec.set_len(self.vec.capacity()) };
self.vec_capacity = self.vec.capacity() / self.info.mem_size;
}
#[inline(always)]
pub fn reserve(&mut self, len: usize, additional: usize) {
if len <= self.vec_capacity {
return self.vec_reserve(additional);
}
let loc = Location::of(len - self.vec_capacity);
let mut raw_len = Location::index(loc.bucket as u32 + 1, 0) * self.info.mem_size;
let mut arr = self.replace(self.arr.replace());
if self.vec.capacity() == 0 {
raw_len = raw_len.saturating_sub(arr[0].len());
let _ = replace(&mut self.vec, take(&mut arr[0]));
}
self.vec.reserve(raw_len + additional * self.info.mem_size);
for mut v in arr.into_iter() {
raw_len = raw_len.saturating_sub(v.len());
self.vec.append(&mut v);
if raw_len == 0 {
break;
}
}
unsafe { self.vec.set_len(self.vec.capacity()) };
self.vec_capacity = self.vec.capacity() / self.info.mem_size;
}
fn replace(&self, arr: [*mut u8; BUCKETS]) -> [Vec<u8>; BUCKETS] {
let mut buckets = [0; BUCKETS].map(|_| Vec::new());
for (i, ptr) in arr.iter().enumerate() {
if *ptr != null_mut() {
let len = Location::bucket_len(i) * self.info.mem_size;
buckets[i] = unsafe { Vec::from_raw_parts(*ptr, len, len) };
}
}
buckets
}
}