use crate::error::SketchError;
use crate::hll::normal_representation::NormalRepresentation;
use crate::hll::sparse_representation::SparseRepresentation;
use crate::hll::state::State;
pub const SPARSE_PRECISION_DISABLED: i32 = 0;
pub trait RepresentationOps: std::fmt::Debug {
fn add_hash(self, hash: u64) -> Result<RepresentationUnion, SketchError>;
fn add_sparse_value(
self,
encoding: &crate::hll::encoding::Sparse,
sparse_value: u32,
) -> Result<RepresentationUnion, SketchError>;
fn add_sparse_values<I: IntoIterator<Item = u32>>(
self,
encoding: &crate::hll::encoding::Sparse,
sparse_values: Option<I>,
) -> Result<RepresentationUnion, SketchError>;
fn estimate(&self) -> Result<i64, SketchError>;
fn merge_from_normal(
self,
other: NormalRepresentation,
) -> Result<RepresentationUnion, SketchError>;
fn merge_from_sparse(
self,
other: SparseRepresentation,
) -> Result<RepresentationUnion, SketchError>;
fn compact(self) -> Result<RepresentationUnion, SketchError>;
fn state_mut(&mut self) -> &mut State;
fn state(&self) -> &State;
}
#[derive(Debug, Clone)]
pub enum RepresentationUnion {
Normal(NormalRepresentation),
Sparse(SparseRepresentation),
Invalid,
}
impl RepresentationUnion {
pub fn state(&self) -> &State {
match self {
RepresentationUnion::Normal(n) => n.state(),
RepresentationUnion::Sparse(s) => s.state(),
RepresentationUnion::Invalid => {
panic!("Invalid representation");
}
}
}
pub fn state_mut(&mut self) -> &mut State {
match self {
RepresentationUnion::Normal(n) => n.state_mut(),
RepresentationUnion::Sparse(s) => s.state_mut(),
RepresentationUnion::Invalid => panic!("Invalid representation"),
}
}
}
#[derive(Debug, Clone)]
pub struct Representation {
repr: RepresentationUnion,
}
impl Representation {
pub fn from_state(state: State) -> Result<Self, SketchError> {
if state.sparse_data.is_some() && state.sparse_precision == SPARSE_PRECISION_DISABLED {
return Err(SketchError::InvalidState(
"Must have a sparse precision when sparse data is set".to_string(),
));
}
if state.data.is_some() || state.sparse_precision == SPARSE_PRECISION_DISABLED {
Ok(Self {
repr: RepresentationUnion::Normal(NormalRepresentation::new(state)?),
})
} else {
Ok(Self {
repr: RepresentationUnion::Sparse(SparseRepresentation::new(state)?),
})
}
}
pub fn add_hash(&mut self, hash: u64) -> Result<(), SketchError> {
self.repr = match std::mem::replace(&mut self.repr, RepresentationUnion::Invalid) {
RepresentationUnion::Normal(n) => n.add_hash(hash)?,
RepresentationUnion::Sparse(s) => s.add_hash(hash)?,
RepresentationUnion::Invalid => {
return Err(SketchError::InvalidState(
"Representation is invalid".to_string(),
))
}
};
Ok(())
}
pub fn estimate(&self) -> Result<i64, SketchError> {
match &self.repr {
RepresentationUnion::Normal(n) => n.estimate(),
RepresentationUnion::Sparse(s) => s.estimate(),
RepresentationUnion::Invalid => Err(SketchError::InvalidState(
"Representation is invalid".to_string(),
)),
}
}
pub fn compact(&mut self) -> Result<(), SketchError> {
self.repr = match std::mem::replace(&mut self.repr, RepresentationUnion::Invalid) {
RepresentationUnion::Normal(n) => n.compact()?,
RepresentationUnion::Sparse(s) => s.compact()?,
RepresentationUnion::Invalid => {
return Err(SketchError::InvalidState(
"Representation is invalid".to_string(),
))
}
};
Ok(())
}
pub fn state(&self) -> &State {
self.repr.state()
}
pub fn state_mut(&mut self) -> &mut State {
self.repr.state_mut()
}
pub fn merge(&mut self, other: Representation) -> Result<(), SketchError> {
self.repr = match (self.repr.clone(), other.repr) {
(RepresentationUnion::Normal(n1), RepresentationUnion::Normal(n2)) => {
n1.merge_from_normal(n2)?
}
(RepresentationUnion::Sparse(s1), RepresentationUnion::Sparse(s2)) => {
s1.merge_from_sparse(s2)?
}
(RepresentationUnion::Normal(n), RepresentationUnion::Sparse(s)) => {
n.merge_from_sparse(s)?
}
(RepresentationUnion::Sparse(s), RepresentationUnion::Normal(n)) => {
s.merge_from_normal(n)?
}
_ => {
return Err(SketchError::InvalidState(
"Representation is invalid".to_string(),
))
}
};
Ok(())
}
}
#[cfg(test)]
impl Representation {
pub fn is_normal(&self) -> bool {
matches!(self.repr, RepresentationUnion::Normal(_))
}
pub fn is_sparse(&self) -> bool {
matches!(self.repr, RepresentationUnion::Sparse(_))
}
}