crate::ix!();
pub struct RollingBloomFilter {
n_entries_per_generation: i32,
n_entries_this_generation: i32,
n_generation: i32,
data: Vec<u64>,
n_tweak: u32,
n_hash_funcs: i32,
}
impl RollingBloomFilter {
pub fn new(
n_elements: u32,
fp_rate: f64) -> Self {
let mut x: Self = unsafe { std::mem::zeroed() };
let log_fp_rate: f64 = fp_rate.log10();
x.n_hash_funcs = {
let h = 0.5_f64.log10();
let r = (log_fp_rate / h).round();
let m = min(r as i32, 50);
max(1,m)
};
x.n_entries_per_generation = ((n_elements + 1) / 2).try_into().unwrap();
let n_max_elements: u32
= (x.n_entries_per_generation * 3)
.try_into()
.unwrap();
let n_filter_bits: u32 = {
let num = -1.0_f64 * (x.n_hash_funcs as f64) * (n_max_elements as f64);
let denom = {
let n = log_fp_rate;
let d = x.n_hash_funcs;
let e = (n / (d as f64)).exp();
(1.0 - e).log10()
};
(num / denom).ceil() as u32
};
x.data.clear();
let new_size: usize = (((n_filter_bits + 63) / 64) << 1).try_into().unwrap();
x.data.resize(new_size, Default::default());
x.reset();
x
}
pub fn insert_key(&mut self, key: &[u8]) {
if self.n_entries_this_generation == self.n_entries_per_generation {
self.n_entries_this_generation = 0;
self.n_generation += 1;
if self.n_generation == 4 {
self.n_generation = 1;
}
let n_generation_mask1: u64 = 0 - (self.n_generation & 1) as u64;
let n_generation_mask2: u64 = 0 - (self.n_generation >> 1) as u64;
let mut p: usize = 0;
while p < self.data.len() {
let p1: u64 = self.data[p];
let p2: u64 = self.data[p + 1];
let mask: u64 = (p1 ^ n_generation_mask1) | (p2 ^ n_generation_mask2);
self.data[p] = p1 & mask;
self.data[p + 1] = p2 & mask;
p += 2
}
}
self.n_entries_this_generation += 1;
for n in 0..self.n_hash_funcs {
let h: u32 = rolling_bloom_hash(
n.try_into().unwrap(),
self.n_tweak,
key
);
let bit: i32 = (h & 0x3F).try_into().unwrap();
let pos: usize = fast_mod(h,self.data.len()).try_into().unwrap();
self.data[pos & !1] = (self.data[pos & !1] & !((1 as u64) << bit)) | ((self.n_generation & 1) as u64) << bit;
self.data[pos | 1] = (self.data[pos | 1] & !((1 as u64) << bit)) | ((self.n_generation >> 1) as u64) << bit;
}
}
pub fn contains_key(&self, key: &[u8]) -> bool {
for n in 0..self.n_hash_funcs {
let h: u32 = rolling_bloom_hash(
n.try_into().unwrap(),
self.n_tweak,
key
);
let bit: i32 = (h & 0x3F).try_into().unwrap();
let pos: usize = {
let len = self.data.len();
fast_mod(h, len).try_into().unwrap()
};
let j = self.data[pos & !1] | self.data[pos | 1];
let js = j >> bit;
if (js & 1) == 0 {
return false;
}
}
true
}
pub fn reset(&mut self) {
self.n_tweak = get_rand(u32::MAX.into()).try_into().unwrap();
self.n_entries_this_generation = 0;
self.n_generation = 1;
self.data.iter_mut().map(|x| *x = 0);
}
}