use mem_dbg::MemSize;
use crate::{hash::MulHash, util::mul_high};
pub trait Reduce: Copy + Sync + std::fmt::Debug {
fn new(d: usize) -> Self;
fn reduce(self, h: u64) -> usize;
fn reduce_with_remainder(self, _h: u64) -> (usize, u64) {
unimplemented!();
}
}
#[derive(Copy, Clone, Debug, MemSize)]
#[cfg_attr(feature = "epserde", derive(epserde::prelude::Epserde))]
#[cfg_attr(feature = "epserde", repr(C))]
#[cfg_attr(feature = "epserde", zero_copy)]
pub struct FastReduce {
d: u64,
}
impl Reduce for FastReduce {
fn new(d: usize) -> Self {
Self { d: d as u64 }
}
fn reduce(self, h: u64) -> usize {
mul_high(self.d, h) as usize
}
fn reduce_with_remainder(self, h: u64) -> (usize, u64) {
let r = self.d as u128 * h as u128;
((r >> 64) as usize, r as u64)
}
}
#[derive(Copy, Clone, Debug, MemSize)]
#[cfg_attr(feature = "epserde", derive(epserde::prelude::Epserde))]
#[cfg_attr(feature = "epserde", repr(C))]
#[cfg_attr(feature = "epserde", zero_copy)]
pub struct MulReduce {
mask: u64,
}
impl MulReduce {
pub const C: u64 = MulHash::C;
}
impl Reduce for MulReduce {
fn new(d: usize) -> Self {
assert!(d.is_power_of_two(), "{d} is not a power of 2");
Self {
mask: (d - 1) as u64,
}
}
fn reduce(self, h: u64) -> usize {
(mul_high(Self::C, h) & self.mask) as usize
}
}