use std::collections::HashSet;
use crate::error::Error;
use crate::error::ErrorKind;
use crate::hash::check_seed_hash;
use crate::thetacommon::EntrySketch;
use crate::thetacommon::KeySketch;
use crate::thetacommon::SketchEntry;
use crate::thetacommon::SketchScalars;
use crate::thetacommon::constants::MAX_THETA;
use crate::thetacommon::hash_table::CompactSketchParts;
pub fn compute<A, B>(
seed_hash: u16,
a: A,
b: B,
ordered: bool,
) -> Result<CompactSketchParts<A::Entry>, Error>
where
A: EntrySketch,
B: KeySketch,
{
let SketchScalars {
seed_hash: a_seed_hash,
theta: a_theta,
empty: a_empty,
ordered: a_ordered,
..
} = a.scalars();
if a_empty {
return Ok(parts_from_sketch(a, ordered));
}
check_seed_hash(seed_hash, a_seed_hash, "A", ErrorKind::InvalidArgument)?;
let SketchScalars {
seed_hash: b_seed_hash,
theta: b_theta,
empty: b_empty,
ordered: b_ordered,
num_retained: b_num_retained,
} = b.scalars();
if b_empty {
return Ok(parts_from_sketch(a, ordered));
}
check_seed_hash(seed_hash, b_seed_hash, "B", ErrorKind::InvalidArgument)?;
let theta = a_theta.min(b_theta);
let mut is_empty = false;
let entries: Vec<A::Entry> = if b_num_retained == 0 {
a.entries().filter(|entry| entry.hash() < theta).collect()
} else if a_ordered && b_ordered {
let mut b_hashes = b.hashes().peekable();
let mut entries = vec![];
for entry in a.entries() {
let hash = entry.hash();
if hash >= theta {
break;
}
while let Some(&b_hash) = b_hashes.peek() {
if b_hash < hash {
b_hashes.next();
} else {
break;
}
}
if b_hashes.peek() != Some(&hash) {
entries.push(entry);
}
}
entries
} else {
let mut b_keys: HashSet<u64> = HashSet::with_capacity(b_num_retained);
for hash in b.hashes() {
if hash < theta {
b_keys.insert(hash);
} else if b_ordered {
break;
}
}
let mut entries = vec![];
for entry in a.entries() {
let hash = entry.hash();
if hash < theta {
if !b_keys.contains(&hash) {
entries.push(entry);
}
} else if a_ordered {
break;
}
}
entries
};
if entries.is_empty() && theta == MAX_THETA {
is_empty = true;
}
let out_ordered = ordered || a_ordered;
let mut entries = entries;
if ordered && !a_ordered && entries.len() > 1 {
entries.sort_unstable_by_key(SketchEntry::hash);
}
Ok(CompactSketchParts {
entries,
theta,
seed_hash,
ordered: out_ordered,
empty: is_empty,
})
}
fn parts_from_sketch<S>(sketch: S, ordered: bool) -> CompactSketchParts<S::Entry>
where
S: EntrySketch,
{
let SketchScalars {
seed_hash,
theta,
empty,
ordered: input_ordered,
..
} = sketch.scalars();
let mut entries: Vec<S::Entry> = sketch.entries().collect();
let out_ordered = ordered || input_ordered;
if ordered && !input_ordered && entries.len() > 1 {
entries.sort_unstable_by_key(SketchEntry::hash);
}
CompactSketchParts {
entries,
theta,
seed_hash,
ordered: out_ordered,
empty,
}
}