const BITS_PER_KEY: usize = 10;
const SALT: [u32; 8] = [
0x47b6137b, 0x44974d91, 0x8824ad5b, 0xa2b7289d, 0x705495c7, 0x2df1424b, 0x9efc4947, 0x5c6bfb31,
];
pub(crate) struct BloomFilter {
words: Vec<u32>,
block_mask: usize,
added: usize,
}
impl BloomFilter {
pub(crate) fn new(expected_n: usize) -> Self {
let blocks = (expected_n.max(1) * BITS_PER_KEY).div_ceil(256).next_power_of_two();
BloomFilter {
words: vec![0; blocks * 8],
block_mask: blocks - 1,
added: 0,
}
}
#[inline(always)]
fn block(&self, key: u64) -> usize {
((key >> 32) as usize & self.block_mask) * 8
}
#[inline]
pub(crate) fn add(&mut self, key: u64) {
self.added += 1;
let at = self.block(key);
let h = key as u32;
for (word, salt) in self.words[at..at + 8].iter_mut().zip(SALT) {
*word |= 1 << (h.wrapping_mul(salt) >> 27);
}
}
pub(crate) fn stale(&self, live: usize) -> bool {
self.added * BITS_PER_KEY > self.words.len() * 32 && self.added >= 2 * live
}
#[inline]
pub(crate) fn may_contain(&self, key: u64) -> bool {
let at = self.block(key);
let h = key as u32;
let mut missing = 0u32;
for (word, salt) in self.words[at..at + 8].iter().zip(SALT) {
missing |= !word & (1 << (h.wrapping_mul(salt) >> 27));
}
missing == 0
}
}
#[cfg(test)]
#[path = "tests/bloom.rs"]
mod tests;