use std::cell::SyncUnsafeCell;
use std::collections::BTreeMap;
use std::ptr::NonNull;
use std::{array, slice};
use super::{Access, ChunkMut, ChunkRef, Partition, Storage};
use crate::{entity, util};
pub struct Tree<RawT: entity::Raw, C> {
data: BTreeMap<RawT, SyncUnsafeCell<C>>,
}
impl<RawT: entity::Raw, C> Default for Tree<RawT, C> {
fn default() -> Self { Self { data: BTreeMap::new() } }
}
impl<RawT: entity::Raw, C: Send + Sync + 'static> Access for Tree<RawT, C> {
type RawEntity = RawT;
type Comp = C;
fn get_mut(&mut self, id: Self::RawEntity) -> Option<&mut C> {
self.data.get_mut(&id).map(|cell| cell.get_mut())
}
fn get_many_mut<const N: usize>(
&mut self,
entities: [Self::RawEntity; N],
) -> Option<[&mut Self::Comp; N]> {
let ptrs = entities.map(|entity| {
let datum = self.data.get(&entity)?;
let ptr = datum.get();
NonNull::new(ptr)
});
if !util::is_all_distinct_quadtime(&ptrs) {
return None;
}
if ptrs.iter().any(|ptr| ptr.is_none()) {
return None;
}
Some(ptrs.map(|ptr| {
let mut ptr = ptr.expect("checked all are not none");
unsafe {
ptr.as_mut()
}
}))
}
type IterMut<'t> = impl Iterator<Item = (Self::RawEntity, &'t mut Self::Comp)> + 't;
fn iter_mut(&mut self) -> Self::IterMut<'_> {
Box::new(self.data.iter_mut().map(|(&entity, cell)| (entity, cell.get_mut())))
}
}
impl<RawT: entity::Raw, C: Send + Sync + 'static> Storage for Tree<RawT, C> {
fn get(&self, id: Self::RawEntity) -> Option<&C> {
self.data.get(&id).map(|cell| unsafe {
&*cell.get()
})
}
fn set(&mut self, id: Self::RawEntity, new: Option<C>) -> Option<C> {
match new {
Some(new) => self.data.insert(id, SyncUnsafeCell::new(new)),
None => self.data.remove(&id),
}
.map(|cell| cell.into_inner())
}
fn cardinality(&self) -> usize { self.data.len() }
type Iter<'t> = impl Iterator<Item = (Self::RawEntity, &'t Self::Comp)> + 't;
fn iter(&self) -> Self::Iter<'_> {
self.data.iter().map(|(&entity, cell)| {
(entity, unsafe {
&*cell.get()
})
})
}
type IterChunks<'t> = impl Iterator<Item = ChunkRef<'t, Self>> + 't;
fn iter_chunks(&self) -> Self::IterChunks<'_> {
self.iter().map(|(entity, item)| ChunkRef { slice: slice::from_ref(item), start: entity })
}
type IterChunksMut<'t> = impl Iterator<Item = ChunkMut<'t, Self>> + 't;
fn iter_chunks_mut(&mut self) -> Self::IterChunksMut<'_> {
self.iter_mut()
.map(|(entity, item)| ChunkMut { slice: slice::from_mut(item), start: entity })
}
type Partition<'t> = StoragePartition<'t, RawT, C>;
fn as_partition(&mut self) -> Self::Partition<'_> {
StoragePartition { data: &self.data, lower_bound: None, upper_bound: None }
}
}
pub struct StoragePartition<'t, RawT: entity::Raw, C> {
data: &'t BTreeMap<RawT, SyncUnsafeCell<C>>,
lower_bound: Option<RawT>,
upper_bound: Option<RawT>,
}
impl<'t, RawT: entity::Raw, C> StoragePartition<'t, RawT, C> {
fn assert_bounds(&self, entity: RawT) {
if let Some(bound) = self.lower_bound {
assert!(entity >= bound, "Entity {entity:?} is not in the partition {bound:?}..");
}
if let Some(bound) = self.upper_bound {
assert!(entity < bound, "Entity {entity:?} is not in the partition ..{bound:?}");
}
}
}
impl<'t, RawT: entity::Raw, C: Send + Sync + 'static> Access for StoragePartition<'t, RawT, C> {
type RawEntity = RawT;
type Comp = C;
fn get_mut(&mut self, entity: RawT) -> Option<&mut C> {
self.assert_bounds(entity);
let cell = self.data.get(&entity)?;
unsafe {
Some(&mut *cell.get())
}
}
fn get_many_mut<const N: usize>(
&mut self,
entities: [RawT; N],
) -> Option<[&mut Self::Comp; N]> {
self.by_ref().into_many_mut(entities)
}
type IterMut<'u> = impl Iterator<Item = (Self::RawEntity, &'u mut Self::Comp)> + 'u where Self: 'u;
fn iter_mut(&mut self) -> Self::IterMut<'_> { self.by_ref().into_iter_mut() }
}
impl<'t, RawT: entity::Raw, C: Send + Sync + 'static> Partition<'t>
for StoragePartition<'t, RawT, C>
{
type ByRef<'u> = StoragePartition<'u, RawT, C> where Self: 'u;
fn by_ref(&mut self) -> Self::ByRef<'_> {
StoragePartition {
data: self.data,
lower_bound: self.lower_bound,
upper_bound: self.upper_bound,
}
}
type IntoIterMut = impl Iterator<Item = (RawT, &'t mut C)>;
fn into_iter_mut(self) -> Self::IntoIterMut {
let iter = match (self.lower_bound, self.upper_bound) {
(Some(lower), Some(upper)) => Box::new(self.data.range(lower..upper))
as Box<dyn Iterator<Item = (&RawT, &SyncUnsafeCell<C>)>>,
(Some(lower), None) => Box::new(self.data.range(lower..)),
(None, Some(upper)) => Box::new(self.data.range(..upper)),
(None, None) => Box::new(self.data.iter()),
};
iter.map(|(entity, cell)| unsafe {
(*entity, &mut *cell.get())
})
}
fn into_mut(self, entity: Self::RawEntity) -> Option<&'t mut Self::Comp> {
self.assert_bounds(entity);
let cell = self.data.get(&entity)?;
unsafe {
Some(&mut *cell.get())
}
}
fn into_many_mut<const N: usize>(
self,
entities: [Self::RawEntity; N],
) -> Option<[&'t mut Self::Comp; N]> {
for entity in entities {
self.assert_bounds(entity);
}
let ptrs = entities.map(|entity| {
let datum = self.data.get(&entity)?;
let ptr = datum.get();
NonNull::new(ptr)
});
if !util::is_all_distinct_quadtime(&ptrs) {
return None;
}
array::try_from_fn(|i| {
let mut ptr = ptrs[i]?;
unsafe {
Some(ptr.as_mut())
}
})
}
fn split_out(&mut self, entity: RawT) -> Self {
self.assert_bounds(entity);
let right = Self {
data: self.data,
lower_bound: Some(entity),
upper_bound: self.upper_bound,
};
self.upper_bound = Some(entity);
right
}
}
#[cfg(test)]
super::tests::test_storage!(NON_CHUNKED Tree<std::num::NonZeroU32, i64>);