honeycomb_core/attributes/
collections.rsuse super::{AttributeBind, AttributeStorage, AttributeUpdate, UnknownAttributeStorage};
use crate::{
cmap::{CMapError, CMapResult},
prelude::DartIdType,
};
use num_traits::ToPrimitive;
use stm::{atomically, StmResult, TVar, Transaction};
#[derive(Debug)]
pub struct AttrSparseVec<T: AttributeBind + AttributeUpdate> {
data: Vec<TVar<Option<T>>>,
}
#[doc(hidden)]
impl<A: AttributeBind + AttributeUpdate> AttrSparseVec<A> {
fn write_core(
&self,
trans: &mut Transaction,
id: &A::IdentifierType,
val: A,
) -> StmResult<Option<A>> {
self.data[id.to_usize().unwrap()].replace(trans, Some(val))
}
fn read_core(&self, trans: &mut Transaction, id: &A::IdentifierType) -> StmResult<Option<A>> {
self.data[id.to_usize().unwrap()].read(trans)
}
fn remove_core(&self, trans: &mut Transaction, id: &A::IdentifierType) -> StmResult<Option<A>> {
self.data[id.to_usize().unwrap()].replace(trans, None)
}
}
unsafe impl<A: AttributeBind + AttributeUpdate> Send for AttrSparseVec<A> {}
unsafe impl<A: AttributeBind + AttributeUpdate> Sync for AttrSparseVec<A> {}
impl<A: AttributeBind + AttributeUpdate> UnknownAttributeStorage for AttrSparseVec<A> {
fn new(length: usize) -> Self
where
Self: Sized,
{
Self {
data: (0..length).map(|_| TVar::new(None)).collect(),
}
}
fn extend(&mut self, length: usize) {
self.data.extend((0..length).map(|_| TVar::new(None)));
}
fn n_attributes(&self) -> usize {
self.data
.iter()
.filter(|v| v.read_atomic().is_some())
.count()
}
fn merge(
&self,
trans: &mut Transaction,
out: DartIdType,
lhs_inp: DartIdType,
rhs_inp: DartIdType,
) -> StmResult<()> {
let new_v = match (
self.data[lhs_inp as usize].read(trans)?,
self.data[rhs_inp as usize].read(trans)?,
) {
(Some(v1), Some(v2)) => Some(AttributeUpdate::merge(v1, v2)),
(Some(v), None) | (None, Some(v)) => Some(AttributeUpdate::merge_incomplete(v)),
(None, None) => AttributeUpdate::merge_from_none(),
};
if new_v.is_none() {
eprintln!("W: cannot merge two null attribute value");
eprintln!(" setting new target value to `None`");
}
self.data[rhs_inp as usize].write(trans, None)?;
self.data[lhs_inp as usize].write(trans, None)?;
self.data[out as usize].write(trans, new_v)?;
Ok(())
}
fn try_merge(
&self,
trans: &mut Transaction,
out: DartIdType,
lhs_inp: DartIdType,
rhs_inp: DartIdType,
) -> CMapResult<()> {
let new_v = match (
self.data[lhs_inp as usize].read(trans)?,
self.data[rhs_inp as usize].read(trans)?,
) {
(Some(v1), Some(v2)) => Some(AttributeUpdate::merge(v1, v2)),
(Some(_), None) | (None, Some(_)) => {
return Err(CMapError::FailedAttributeMerge(
"missing one value for merge",
))
}
(None, None) => {
return Err(CMapError::FailedAttributeMerge(
"missing both values for merge",
))
}
};
if new_v.is_none() {
eprintln!("W: cannot merge two null attribute value");
eprintln!(" setting new target value to `None`");
}
self.data[rhs_inp as usize].write(trans, None)?;
self.data[lhs_inp as usize].write(trans, None)?;
self.data[out as usize].write(trans, new_v)?;
Ok(())
}
fn split(
&self,
trans: &mut Transaction,
lhs_out: DartIdType,
rhs_out: DartIdType,
inp: DartIdType,
) -> StmResult<()> {
if let Some(val) = self.data[inp as usize].read(trans)? {
let (lhs_val, rhs_val) = AttributeUpdate::split(val);
self.data[inp as usize].write(trans, None)?;
self.data[lhs_out as usize].write(trans, Some(lhs_val))?;
self.data[rhs_out as usize].write(trans, Some(rhs_val))?;
} else {
eprintln!("W: cannot split attribute value (not found in storage)");
eprintln!(" setting both new values to `None`");
self.data[lhs_out as usize].write(trans, None)?;
self.data[rhs_out as usize].write(trans, None)?;
}
Ok(())
}
fn try_split(
&self,
trans: &mut Transaction,
lhs_out: DartIdType,
rhs_out: DartIdType,
inp: DartIdType,
) -> CMapResult<()> {
if let Some(val) = self.data[inp as usize].read(trans)? {
let (lhs_val, rhs_val) = AttributeUpdate::split(val);
self.data[inp as usize].write(trans, None)?;
self.data[lhs_out as usize].write(trans, Some(lhs_val))?;
self.data[rhs_out as usize].write(trans, Some(rhs_val))?;
} else {
return Err(CMapError::FailedAttributeSplit("no value to split from"));
}
Ok(())
}
}
impl<A: AttributeBind + AttributeUpdate> AttributeStorage<A> for AttrSparseVec<A> {
fn force_write(&self, id: <A as AttributeBind>::IdentifierType, val: A) -> Option<A> {
atomically(|trans| self.write_core(trans, &id, val))
}
fn write(
&self,
trans: &mut Transaction,
id: <A as AttributeBind>::IdentifierType,
val: A,
) -> StmResult<Option<A>> {
self.write_core(trans, &id, val)
}
fn force_read(&self, id: <A as AttributeBind>::IdentifierType) -> Option<A> {
atomically(|trans| self.read_core(trans, &id))
}
fn read(
&self,
trans: &mut Transaction,
id: <A as AttributeBind>::IdentifierType,
) -> StmResult<Option<A>> {
self.read_core(trans, &id)
}
fn force_remove(&self, id: <A as AttributeBind>::IdentifierType) -> Option<A> {
atomically(|trans| self.remove_core(trans, &id))
}
fn remove(
&self,
trans: &mut Transaction,
id: <A as AttributeBind>::IdentifierType,
) -> StmResult<Option<A>> {
self.remove_core(trans, &id)
}
}
#[cfg(feature = "utils")]
impl<T: AttributeBind + AttributeUpdate> AttrSparseVec<T> {
#[must_use = "returned value is not used, consider removing this method call"]
pub fn allocated_size(&self) -> usize {
self.data.capacity() * std::mem::size_of::<Option<T>>()
}
#[must_use = "returned value is not used, consider removing this method call"]
pub fn effective_size(&self) -> usize {
self.data.len() * std::mem::size_of::<Option<T>>()
}
#[must_use = "returned value is not used, consider removing this method call"]
pub fn used_size(&self) -> usize {
self.n_attributes() * size_of::<TVar<Option<T>>>()
}
}