#![deny(missing_debug_implementations)]
use std::cmp;
use std::sync::atomic::{self, AtomicU64};
const ORDERING: atomic::Ordering = atomic::Ordering::Relaxed;
fn hash(mut x: u64) -> u64 {
x = x.wrapping_mul(0x6eed0e9da4d94a4f);
let a = x >> 32;
let b = x >> 60;
x ^= a >> b;
x = x.wrapping_mul(0x6eed0e9da4d94a4f);
x ^ 0x11c92f7574d3e84f
}
#[derive(Debug)]
pub struct Filter {
bits: Vec<AtomicU64>,
hashers: usize,
}
impl Filter {
#[inline]
fn get(&self, hash: u64) -> &AtomicU64 {
&self.bits[(hash as usize / 64) % self.bits.len()]
}
pub fn new(bytes: usize, expected_elements: usize) -> Filter {
let hashers = (bytes / expected_elements)
.saturating_mul(45426)
.saturating_add(0x8000)
>> 16;
Filter::with_size_and_hashers(bytes, hashers)
}
pub fn with_size_and_hashers(bytes: usize, hashers: usize) -> Filter {
let len = (bytes.saturating_add(7)) / 8;
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
vec.push(AtomicU64::new(0));
}
Filter {
bits: vec,
hashers: cmp::max(hashers, 1),
}
}
pub fn clear(&self) {
for i in &self.bits {
i.store(0, ORDERING);
}
}
pub fn insert(&self, x: u64) {
let mut h = x;
for _ in 0..self.hashers {
h = hash(h);
self.get(h).fetch_or(1 << (h % 8), ORDERING);
}
}
pub fn maybe_contains(&self, x: u64) -> bool {
let mut h = x;
for _ in 0..self.hashers {
h = hash(h);
if self.get(h).load(ORDERING) & 1 << (h % 8) == 0 {
return false;
}
}
true
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Arc;
use std::thread;
#[test]
fn insert() {
let filter = Filter::new(400, 4);
filter.insert(3);
filter.insert(5);
filter.insert(7);
filter.insert(13);
assert!(!filter.maybe_contains(0));
assert!(!filter.maybe_contains(1));
assert!(!filter.maybe_contains(2));
assert!(filter.maybe_contains(3));
assert!(filter.maybe_contains(5));
assert!(filter.maybe_contains(7));
assert!(filter.maybe_contains(13));
for i in 14..60 {
assert!(!filter.maybe_contains(!i));
}
}
#[test]
fn clear() {
let filter = Filter::new(400, 4);
filter.insert(3);
filter.insert(5);
filter.insert(7);
filter.insert(13);
filter.clear();
assert!(!filter.maybe_contains(0));
assert!(!filter.maybe_contains(1));
assert!(!filter.maybe_contains(2));
assert!(!filter.maybe_contains(3));
assert!(!filter.maybe_contains(5));
assert!(!filter.maybe_contains(7));
assert!(!filter.maybe_contains(13));
}
#[test]
fn spam() {
let filter = Arc::new(Filter::new(2000, 100));
let mut joins = Vec::new();
for _ in 0..16 {
let filter = filter.clone();
joins.push(thread::spawn(move || {
for i in 0..100 {
filter.insert(i)
}
}));
}
for i in joins {
i.join().unwrap();
}
for i in 0..100 {
assert!(filter.maybe_contains(i));
}
for i in 100..200 {
assert!(!filter.maybe_contains(i));
}
}
}