mod bloom;
mod count_min_sketch;
mod hyperloglog;
pub use bloom::{BloomFilter, CountingBloomFilter, ScalableBloomFilter};
pub use count_min_sketch::CountMinSketch;
pub use hyperloglog::HyperLogLog;
use std::hash::{BuildHasher, Hasher};
#[derive(Clone)]
pub(crate) struct DoubleHasher {
builder_a: std::collections::hash_map::RandomState,
builder_b: std::collections::hash_map::RandomState,
}
impl DoubleHasher {
pub(crate) fn new() -> Self {
Self {
builder_a: std::collections::hash_map::RandomState::new(),
builder_b: std::collections::hash_map::RandomState::new(),
}
}
#[cfg(test)]
pub(crate) fn deterministic() -> Self {
Self {
builder_a: std::collections::hash_map::RandomState::new(),
builder_b: std::collections::hash_map::RandomState::new(),
}
}
pub(crate) fn hash_pair(&self, key: &[u8]) -> (u64, u64) {
let mut ha = self.builder_a.build_hasher();
ha.write(key);
let h1 = ha.finish();
let mut hb = self.builder_b.build_hasher();
hb.write(key);
let h2 = hb.finish();
(h1, h2)
}
#[inline]
pub(crate) fn position(h1: u64, h2: u64, i: u32, m: usize) -> usize {
let combined = h1.wrapping_add((i as u64).wrapping_mul(h2));
(combined % (m as u64)) as usize
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_double_hasher_deterministic_positions() {
let dh = DoubleHasher::new();
let (h1, h2) = dh.hash_pair(b"test_key");
for i in 0..10u32 {
let pos = DoubleHasher::position(h1, h2, i, 1000);
assert!(pos < 1000);
}
}
#[test]
fn test_double_hasher_different_keys_different_hashes() {
let dh = DoubleHasher::new();
let (h1a, h2a) = dh.hash_pair(b"key_a");
let (h1b, h2b) = dh.hash_pair(b"key_b");
assert!(h1a != h1b || h2a != h2b);
}
}