mod sharded;
mod striped;
pub use sharded::ShardedBloomFilter;
pub use striped::StripedBloomFilter;
pub mod prelude {
pub use super::{ShardedBloomFilter, StripedBloomFilter};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::SharedBloomFilter;
#[test]
fn test_sharded_insert() {
let filter = ShardedBloomFilter::<i32>::new(10_000, 0.01);
for i in 0..100 {
filter.insert(&i);
}
for i in 0..100 {
assert!(filter.contains(&i), "Missing item {}", i);
}
}
#[test]
fn test_striped_insert() {
let filter = StripedBloomFilter::<i32>::new(10_000, 0.01).unwrap();
for i in 0..100 {
filter.insert(&i);
}
for i in 0..100 {
assert!(filter.contains(&i), "Missing item {}", i);
}
}
#[test]
fn test_sharded_clear() {
let filter = ShardedBloomFilter::<i32>::new(10_000, 0.01);
filter.insert(&1);
filter.insert(&2);
assert!(!filter.is_empty());
filter.clear();
assert!(filter.is_empty());
assert!(!filter.contains(&1));
}
#[test]
fn test_striped_clear() {
let filter = StripedBloomFilter::<i32>::new(10_000, 0.01).unwrap();
filter.insert(&1);
filter.insert(&2);
assert!(!filter.is_empty());
filter.clear();
assert!(filter.is_empty());
assert!(!filter.contains(&1));
}
#[test]
fn test_sharded_concurrent() {
use std::sync::Arc;
use std::thread;
let filter = Arc::new(ShardedBloomFilter::<i32>::new(10_000, 0.01));
let handles: Vec<_> = (0..4)
.map(|tid| {
let f = Arc::clone(&filter);
thread::spawn(move || {
for i in 0..100 {
f.insert(&(tid * 100 + i));
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
for tid in 0..4 {
for i in 0..100 {
assert!(
filter.contains(&(tid * 100 + i)),
"Missing item {}",
tid * 100 + i
);
}
}
}
#[test]
fn test_striped_concurrent() {
use std::sync::Arc;
use std::thread;
let filter = Arc::new(StripedBloomFilter::<i32>::new(10_000, 0.01).unwrap());
let handles: Vec<_> = (0..4)
.map(|tid| {
let f = Arc::clone(&filter);
thread::spawn(move || {
for i in 0..100 {
f.insert(&(tid * 100 + i));
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
for tid in 0..4 {
for i in 0..100 {
assert!(
filter.contains(&(tid * 100 + i)),
"Missing item {}",
tid * 100 + i
);
}
}
}
#[test]
fn test_sharded_fp_rate() {
let filter = ShardedBloomFilter::<i32>::new(1_000, 0.01);
for i in 0..500 {
filter.insert(&i);
}
let fp_rate = filter.false_positive_rate();
assert!(
fp_rate < 0.05,
"False positive rate {} exceeds threshold",
fp_rate
);
}
#[test]
fn test_striped_fp_rate() {
let filter = StripedBloomFilter::<i32>::new(1_000, 0.01).unwrap();
for i in 0..500 {
filter.insert(&i);
}
let fp_rate = filter.false_positive_rate();
assert!(
fp_rate < 0.05,
"False positive rate {} exceeds threshold",
fp_rate
);
}
#[test]
fn test_sharded_estimate_count() {
let filter = ShardedBloomFilter::<i32>::new(10_000, 0.01);
for i in 0..1000 {
filter.insert(&i);
}
let estimated = filter.estimate_count();
let error_pct = ((estimated as i64 - 1000).abs() as f64 / 1000.0) * 100.0;
assert!(
error_pct < 20.0,
"Estimation error {:.1}% exceeds threshold",
error_pct
);
}
#[test]
fn test_striped_estimate_count() {
let filter = StripedBloomFilter::<i32>::new(10_000, 0.01).unwrap();
for i in 0..1000 {
filter.insert(&i);
}
let estimated = filter.estimate_count();
let error_pct = ((estimated as i64 - 1000).abs() as f64 / 1000.0) * 100.0;
assert!(
error_pct < 20.0,
"Estimation error {:.1}% exceeds threshold",
error_pct
);
}
}