use core::fmt::*;
use std::mem::replace;
use std::mem::size_of;
use fixedbitset::FixedBitSet;
use pi_append_vec::AppendVec;
use pi_null::Null;
use pi_share::Share;
use crate::archetype::ArchetypeIndex;
use crate::archetype::Row;
use crate::column::Column;
use crate::world::{ComponentIndex, Entity, Tick, World};
pub struct Table {
entities: AppendVec<Entity>, pub(crate) index: ArchetypeIndex,
sorted_columns: Vec<Share<Column>>, per_entity_mem_size: usize, bit_set: FixedBitSet, pub(crate) removes: AppendVec<Row>, }
impl Table {
pub fn new(sorted_columns: Vec<Share<Column>>) -> Self {
let len = sorted_columns.len();
let max = if len > 0 {
unsafe { sorted_columns.get_unchecked(len - 1).info().index.index() + 1 }
} else {
0
};
let mut per_entity_mem_size = size_of::<Entity>();
let mut bit_set = FixedBitSet::with_capacity(max);
for c in sorted_columns.iter() {
per_entity_mem_size += c.info().mem_size as usize;
unsafe { bit_set.set_unchecked(c.info().index.index(), true) };
}
Self {
entities: AppendVec::default(),
index: ArchetypeIndex::null(),
sorted_columns,
per_entity_mem_size,
bit_set,
removes: AppendVec::default(),
}
}
#[inline(always)]
pub fn len(&self) -> Row {
Row(self.entities.len() as u32)
}
pub fn mem_size(&self) -> usize {
let c = self.entities.capacity() * self.per_entity_mem_size;
c + self.sorted_columns.capacity() * size_of::<Share<Column>>()
+ self.removes.capacity() * size_of::<Row>() + size_of::<Self>()
}
#[inline(always)]
pub fn get_unchecked(&self, row: Row) -> Entity {
*self.entities.load(row.index()).unwrap()
}
#[inline(always)]
pub fn set(&self, row: Row, e: Entity) {
let a = self.entities.load(row.index()).unwrap();
*a = e;
}
#[inline(always)]
pub fn get_columns(&self) -> &Vec<Share<Column>> {
&self.sorted_columns
}
pub fn init_blobs(&self) {
for c in self.sorted_columns.iter() {
c.init_blob(self.index);
}
}
#[inline(always)]
pub fn contains(&self, index: ComponentIndex) -> bool {
self.bit_set.contains(index.index())
}
pub(crate) fn get_column_unchecked(&self, index: usize) -> &Share<Column> {
unsafe { self.sorted_columns.get_unchecked(index) }
}
pub fn reserve(&mut self, additional: usize) {
let len = self.entities.len();
self.entities.settle(additional);
let vec = vec![];
self.settle_columns(len, additional, &vec);
}
pub(crate) fn settle_columns(&mut self, len: usize, additional: usize, vec: &Vec<(Row, Row)>) {
for c in self.sorted_columns.iter_mut() {
let c = unsafe { Share::get_mut_unchecked(c) };
c.settle_by_index(self.index, len, additional, vec);
}
}
#[inline(always)]
pub fn alloc(&self) -> (&mut Entity, usize) {
self.entities.alloc()
}
pub(crate) fn destroy(&self, row: Row) -> Entity {
let e = self.entities.load(row.index()).unwrap();
if e.is_null() {
return *e;
}
for c in self.sorted_columns.iter() {
let c = c.blob_ref_unchecked(self.index);
c.drop_row(row, *e);
}
self.removes.insert(row);
replace(e, Entity::null())
}
pub(crate) fn mark_remove(&self, row: Row) -> Entity {
let e = self.entities.load(row.index()).unwrap();
if e.is_null() {
return *e;
}
self.removes.insert(row);
replace(e, Entity::null())
}
pub(crate) fn init_row(&self, world: &mut World, row: Row, e: Entity, tick: Tick) {
for column in &self.sorted_columns {
let c = column.blob_ref_unchecked(self.index);
let dst_data: *mut u8 = c.load(row, e);
column.info().set_fn.unwrap()(world, dst_data);
c.added_tick(e, row, tick)
}
}
pub(crate) fn removes_action(
removes: &AppendVec<Row>,
remove_len: usize,
entity_len: usize,
action: &mut Vec<(Row, Row)>,
set: &mut FixedBitSet,
) -> usize {
action.clear();
if remove_len >= entity_len {
return 0;
}
if remove_len == 1 {
let remove_row = unsafe { removes.get_unchecked(0) };
if remove_row.index() + 1 < entity_len {
action.push((Row(entity_len as u32 - 1), *remove_row));
}
return entity_len - 1;
}
let r = remove_len as f64;
if r * r.log2() < (entity_len - remove_len) as f64 {
for row in removes.iter() {
action.push((*row, *row));
}
action.sort_unstable();
let mut start = 0;
let mut end = action.len();
let mut index = entity_len;
while start < end {
index -= 1;
let remove_row = unsafe { action.get_unchecked(end - 1) };
if remove_row.0.index() == index {
end -= 1;
continue;
}
let r = unsafe { action.get_unchecked_mut(start) };
r.0 = Row(index as u32);
start += 1;
}
action.truncate(end);
return index;
}
set.clear();
set.grow(entity_len);
for row in removes.iter() {
set.set(row.index(), true);
}
let ones = set.ones();
let mut end = entity_len;
for row in ones {
loop {
if row >= end {
return end;
}
end -= 1;
if !set.contains(end) {
action.push((Row(end as u32), Row(row as u32)));
break;
}
}
}
end
}
pub(crate) fn settle(
&mut self,
world: &World,
action: &mut Vec<(Row, Row)>,
set: &mut FixedBitSet,
) -> bool {
let remove_len = self.removes.len();
if remove_len == 0 {
let entity_len = self.entities.len();
if entity_len > self.entities.vec_capacity() {
action.clear();
self.settle_columns(entity_len, 0, &action);
}
return true;
}
let new_entity_len =
Self::removes_action(&self.removes, remove_len, self.entities.len(), action, set);
self.removes.clear(0);
self.settle_columns(new_entity_len, 0, &action);
for (src, dst) in action.iter() {
let e =
unsafe { replace(self.entities.get_unchecked_mut(src.index()), Entity::null()) };
*unsafe { self.entities.get_unchecked_mut(dst.index()) } = e;
world.replace_row(e, *dst);
}
unsafe {
self.entities.set_len(new_entity_len);
};
self.entities.settle(0);
true
}
}
impl Drop for Table {
fn drop(&mut self) {
let len = self.len().index();
if len == 0 {
return;
}
for c in self.sorted_columns.iter_mut() {
if c.info().drop_fn.is_none() {
continue;
}
let c = c.blob_ref(self.index).unwrap();
for (row, e) in self.entities.iter().enumerate() {
if !e.is_null() {
c.drop_row_unchecked(Row(row as u32), *e);
}
}
}
}
}
impl Debug for Table {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.debug_struct("Table")
.field("entitys", &self.entities)
.field("sorted_columns", &self.sorted_columns)
.field("removes", &self.removes)
.finish()
}
}