use bevy_platform::hash::FixedHasher;
use core::hash::{BuildHasher, Hash};
#[derive(Clone, Copy, Debug)]
pub struct BloomFilter<const N: usize, const K: usize = 2> {
bits: [u64; N],
}
impl<const N: usize, const K: usize> Default for BloomFilter<N, K> {
fn default() -> Self {
Self::new()
}
}
impl<const N: usize, const K: usize> BloomFilter<N, K> {
pub const fn new() -> Self {
assert!(N > 0, "size must be at least 1");
Self { bits: [0; N] }
}
pub fn insert(&mut self, item: &impl Hash) {
let (h1, h2) = self.hash(item);
let m = (N * 64) as u64;
for i in 0..K {
let idx = (h1.wrapping_add((i as u64).wrapping_mul(h2))) % m;
self.bits[idx as usize / 64] |= 1 << (idx % 64);
}
}
pub fn contains(&self, item: &impl Hash) -> bool {
let (h1, h2) = self.hash(item);
let m = (N * 64) as u64;
for i in 0..K {
let idx = (h1.wrapping_add((i as u64).wrapping_mul(h2))) % m;
if self.bits[idx as usize / 64] & (1 << (idx % 64)) == 0 {
return false;
}
}
true
}
pub fn check_insert(&mut self, item: &impl Hash) -> bool {
let res = self.contains(item);
if !res {
self.insert(item);
}
res
}
fn hash(&self, item: &impl Hash) -> (u64, u64) {
let hash = FixedHasher.hash_one(item);
(hash as u32 as u64, hash >> 32)
}
}