use super::counting::CountingBloomFilter;
pub struct ScalableBloomFilter {
layers: Vec<CountingBloomFilter>,
layer_capacities: Vec<usize>,
layer_counts: Vec<usize>,
growth_factor: usize,
}
impl ScalableBloomFilter {
pub fn new(initial_capacity: usize) -> Self {
Self::with_growth(initial_capacity, 2)
}
pub fn with_growth(initial_capacity: usize, growth_factor: usize) -> Self {
let cap = initial_capacity.max(1);
let g = growth_factor.max(2);
Self {
layers: vec![CountingBloomFilter::new(cap)],
layer_capacities: vec![cap],
layer_counts: vec![0],
growth_factor: g,
}
}
pub fn add(&mut self, key: &str) {
let last_idx = self.layers.len() - 1;
if self.layer_counts[last_idx] >= self.layer_capacities[last_idx] {
self.add_layer();
}
let idx = self.layers.len() - 1;
self.layers[idx].add(key);
self.layer_counts[idx] += 1;
}
pub fn might_contain(&self, key: &str) -> bool {
self.layers.iter().any(|l| l.might_contain(key))
}
pub fn layer_count(&self) -> usize {
self.layers.len()
}
pub fn total_count(&self) -> usize {
self.layer_counts.iter().sum()
}
pub fn clear(&mut self) {
self.layers.truncate(1);
self.layers[0].clear();
self.layer_capacities.truncate(1);
self.layer_counts.truncate(1);
self.layer_counts[0] = 0;
}
fn add_layer(&mut self) {
let last = self.layer_capacities.len() - 1;
let new_cap = self.layer_capacities[last] * self.growth_factor;
self.layers.push(CountingBloomFilter::new(new_cap));
self.layer_capacities.push(new_cap);
self.layer_counts.push(0);
}
}
#[cfg(test)]
#[path = "scalable_tests.rs"]
mod tests;