use std::hash::Hash;
use std::num::NonZeroU64;
use crate::thetacommon::SketchEntry;
use crate::thetacommon::hash_table::SketchHashTable;
use crate::thetacommon::intersection::IntersectionMergePolicy;
use crate::thetacommon::union::UnionMergePolicy;
use crate::tuple::SummaryCombinePolicy;
#[derive(Debug, Clone)]
pub struct TupleEntry<S> {
hash: NonZeroU64,
summary: S,
}
impl<S> TupleEntry<S> {
pub(super) fn new(hash: u64, summary: S) -> Self {
let hash = NonZeroU64::new(hash).expect("hash must be non-zero");
Self { hash, summary }
}
pub fn hash(&self) -> u64 {
self.hash.get()
}
pub fn summary(&self) -> &S {
&self.summary
}
}
pub type TupleHashTable<S> = SketchHashTable<TupleEntry<S>>;
impl<S> SketchEntry for TupleEntry<S> {
fn hash(&self) -> u64 {
self.hash.get()
}
}
impl<S> TupleHashTable<S> {
pub fn try_insert<T, F>(&mut self, key: T, f: F) -> bool
where
T: Hash,
F: FnOnce(Option<&mut S>) -> Option<S>,
{
let hash = self.hash(key);
self.try_insert_hash(hash, f)
}
pub fn try_insert_hash<F>(&mut self, hash: u64, f: F) -> bool
where
F: FnOnce(Option<&mut S>) -> Option<S>,
{
self.upsert_entry(hash, |existing| match existing {
Some(entry) => {
f(Some(&mut entry.summary));
None
}
None => f(None).map(|summary| TupleEntry::new(hash, summary)),
})
}
pub fn iter(&self) -> impl Iterator<Item = &TupleEntry<S>> + '_ {
self.iter_entries()
}
}
impl<P: SummaryCombinePolicy> UnionMergePolicy<TupleEntry<P::Summary>> for P {
fn merge(&self, existing: &mut TupleEntry<P::Summary>, incoming: TupleEntry<P::Summary>) {
self.combine(&mut existing.summary, &incoming.summary);
}
}
impl<P: SummaryCombinePolicy> IntersectionMergePolicy<TupleEntry<P::Summary>> for P {
fn merge(&self, existing: &mut TupleEntry<P::Summary>, incoming: TupleEntry<P::Summary>) {
self.combine(&mut existing.summary, &incoming.summary);
}
}