const DEPTH: usize = 4;
const FNV_OFFSET: u64 = 0xcbf29ce484222325;
const FNV_PRIME: u64 = 0x100000001b3;
fn fnv1a_64(data: &[u8], init: u64) -> u64 {
let mut h = init;
for &b in data {
h ^= b as u64;
h = h.wrapping_mul(FNV_PRIME);
}
h
}
pub(crate) fn double_hash(data: &[u8]) -> (u64, u64) {
let h_a = fnv1a_64(data, FNV_OFFSET);
let h_b = fnv1a_64(data, FNV_OFFSET ^ 0x6c62272e07bb0142);
(h_a, h_b)
}
fn row_col(h_a: u64, h_b: u64, row: usize, w: usize) -> usize {
h_a.wrapping_add((row as u64).wrapping_mul(h_b)) as usize % w
}
fn nibble_get(counters: &[u8], row: usize, col: usize, half_w: usize) -> u8 {
let byte_idx = row * half_w + col / 2;
let byte = counters[byte_idx];
if col.is_multiple_of(2) {
byte & 0x0F
} else {
(byte >> 4) & 0x0F
}
}
fn nibble_set(counters: &mut [u8], row: usize, col: usize, half_w: usize, val: u8) {
let byte_idx = row * half_w + col / 2;
if col.is_multiple_of(2) {
counters[byte_idx] = (counters[byte_idx] & 0xF0) | (val & 0x0F);
} else {
counters[byte_idx] = (counters[byte_idx] & 0x0F) | ((val & 0x0F) << 4);
}
}
pub struct CountMinSketch {
counters: Vec<u8>,
w: usize,
half_w: usize,
additions: u64,
sample_size: u64,
}
impl CountMinSketch {
#[must_use]
pub fn new(capacity: usize) -> Self {
let w = capacity.next_power_of_two().max(1);
let half_w = w / 2;
let size = DEPTH * half_w;
CountMinSketch {
counters: vec![0u8; size.max(1)],
w,
half_w: half_w.max(1),
additions: 0,
sample_size: (capacity as u64) * 10,
}
}
pub fn increment(&mut self, key_bytes: &[u8]) {
let (h_a, h_b) = double_hash(key_bytes);
for row in 0..DEPTH {
let col = row_col(h_a, h_b, row, self.w);
let cur = nibble_get(&self.counters, row, col, self.half_w);
if cur < 15 {
nibble_set(&mut self.counters, row, col, self.half_w, cur + 1);
}
}
self.additions += 1;
if self.additions >= self.sample_size {
self.age();
}
}
#[must_use]
pub fn estimate(&self, key_bytes: &[u8]) -> u64 {
let (h_a, h_b) = double_hash(key_bytes);
let mut min_val = u64::MAX;
for row in 0..DEPTH {
let col = row_col(h_a, h_b, row, self.w);
let val = nibble_get(&self.counters, row, col, self.half_w) as u64;
if val < min_val {
min_val = val;
}
}
min_val
}
pub fn age(&mut self) {
for byte in self.counters.iter_mut() {
let upper_nibble = ((*byte >> 4) >> 1) << 4;
let lower_nibble = (*byte & 0x0F) >> 1;
*byte = upper_nibble | lower_nibble;
}
self.additions = 0;
}
pub fn clear(&mut self) {
for b in self.counters.iter_mut() {
*b = 0;
}
self.additions = 0;
}
}
pub struct Doorkeeper {
bits: Vec<u64>,
num_bits: usize,
}
impl Doorkeeper {
#[must_use]
pub fn new(capacity: usize) -> Self {
let num_bits = (capacity * 8).next_power_of_two().max(64);
let num_words = num_bits / 64;
Doorkeeper {
bits: vec![0u64; num_words],
num_bits,
}
}
pub fn put(&mut self, key_bytes: &[u8]) -> bool {
let (h_a, h_b) = double_hash(key_bytes);
let mut all_set = true;
for row in 0..DEPTH {
let pos = row_col(h_a, h_b, row, self.num_bits);
let word = pos / 64;
let bit = pos % 64;
if self.bits[word] & (1u64 << bit) == 0 {
all_set = false;
self.bits[word] |= 1u64 << bit;
}
}
all_set
}
pub fn clear(&mut self) {
for w in self.bits.iter_mut() {
*w = 0;
}
}
}