#![doc = include_str!("../README.md")]
use {std::hash, xxhash_rust::xxh3::Xxh3Builder};
pub trait HashIterHasher<T> {
fn hash_iter<K: hash::Hash + ?Sized>(&self, key: &K, count: usize) -> impl Iterator<Item = T>;
}
pub trait BuildHashIterHasher<T> {
type Hasher: HashIterHasher<T>;
fn build_hash_iter_hasher(&self) -> Self::Hasher;
}
#[derive(Clone, Copy)]
pub struct DoubleHashBuilder<T> {
seed1: T,
seed2: T,
n: T,
}
#[derive(Clone, Copy)]
pub struct DoubleHashHasher<T, H1, H2> {
hash_builder1: H1,
hash_builder2: H2,
n: T,
}
#[derive(Debug, Clone, Copy)]
pub struct Hashes<T> {
hash1: T,
hash2: T,
n: T,
k: T,
cnt: T,
}
macro_rules! impl_hash_iter_for_type {
($num_type:ty, $type_name:expr) => {
impl DoubleHashBuilder<$num_type> {
pub fn new() -> Self {
let seed1 = (12345_u64 as $num_type).wrapping_add(0);
let seed2 = (67890_u64 as $num_type).wrapping_add(0);
let n = <$num_type>::MAX;
Self { seed1, seed2, n }
}
pub fn with_seed1(self, seed1: $num_type) -> Self {
Self { seed1, ..self }
}
pub fn with_seed2(self, seed2: $num_type) -> Self {
Self { seed2, ..self }
}
pub fn with_n(self, n: $num_type) -> Self {
Self { n, ..self }
}
}
impl Default for DoubleHashBuilder<$num_type> {
fn default() -> Self {
Self::new()
}
}
impl BuildHashIterHasher<$num_type> for DoubleHashBuilder<$num_type> {
type Hasher = DoubleHashHasher<$num_type, Xxh3Builder, Xxh3Builder>;
fn build_hash_iter_hasher(&self) -> Self::Hasher {
DoubleHashHasher::<$num_type, _, _>::with_hash_builders(
Xxh3Builder::new().with_seed(self.seed1 as u64),
Xxh3Builder::new().with_seed(self.seed2 as u64),
self.n,
)
}
}
impl<H1, H2> DoubleHashHasher<$num_type, H1, H2> {
pub fn with_hash_builders(hash_builder1: H1, hash_builder2: H2, n: $num_type) -> Self {
Self {
hash_builder1,
hash_builder2,
n,
}
}
}
impl<H1, H2> HashIterHasher<$num_type> for DoubleHashHasher<$num_type, H1, H2>
where
H1: hash::BuildHasher,
H2: hash::BuildHasher,
{
fn hash_iter<K: hash::Hash + ?Sized>(
&self,
key: &K,
count: usize,
) -> impl Iterator<Item = $num_type> {
let hash1 = self.hash_builder1.hash_one(key);
let hash2 = self.hash_builder2.hash_one(key);
let x = hash1 as $num_type;
let y = hash2 as $num_type;
let count_t = count as $num_type;
Hashes::<$num_type>::new(x, y, self.n, count_t)
}
}
impl Hashes<$num_type> {
pub fn new(hash1: $num_type, hash2: $num_type, n: $num_type, k: $num_type) -> Self {
Self {
hash1,
hash2,
n,
k,
cnt: 0,
}
}
}
impl Iterator for Hashes<$num_type> {
type Item = $num_type;
fn next(&mut self) -> Option<Self::Item> {
if self.cnt == self.k {
return None;
}
let add_mod = |a: $num_type, b: $num_type, n: $num_type| -> $num_type {
debug_assert!(a < n && b < n, "operands must be reduced mod n");
if a >= n - b {
a - (n - b)
} else {
a + b
}
};
if self.cnt == 0 {
self.cnt = self.cnt + 1;
self.hash1 = self.hash1 % self.n;
self.hash2 = self.hash2 % self.n;
return Some(self.hash1);
}
self.hash1 = add_mod(self.hash1, self.hash2, self.n);
self.hash2 = add_mod(self.hash2, self.cnt, self.n);
self.cnt = self.cnt + 1;
Some(self.hash1)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = (self.k - self.cnt) as usize;
(remaining, Some(remaining))
}
}
impl ExactSizeIterator for Hashes<$num_type> {}
};
}
impl DoubleHashHasher<u64, Xxh3Builder, Xxh3Builder> {
pub fn new() -> Self {
DoubleHashBuilder::<u64>::new().build_hash_iter_hasher()
}
}
impl_hash_iter_for_type!(u32, "u32");
impl_hash_iter_for_type!(u64, "u64");
impl_hash_iter_for_type!(u128, "u128");
#[cfg(test)]
mod tests {
use {super::*, std::hash::BuildHasher};
fn hasn_fn(i: u64, hash1: u64, hash2: u64, n: u64) -> u64 {
let x = hash1.wrapping_rem(n);
let y = hash2.wrapping_rem(n);
x.wrapping_add(y.wrapping_mul(i))
.wrapping_add((i.pow(3) - i) / 6)
.wrapping_rem(n)
}
#[test]
fn default_build_hash_iter() {
let key = "mykey";
let n = 1e9 as u64;
let k = 100;
let builder = DoubleHashBuilder::<u64>::new()
.with_n(n)
.with_seed1(1)
.with_seed2(2);
let hash_builder = Xxh3Builder::new();
let hash1 = hash_builder.with_seed(1).hash_one(key);
let hash2 = hash_builder.with_seed(2).hash_one(key);
let hasher = builder.build_hash_iter_hasher();
for (i, hash) in hasher.hash_iter(&key, k).enumerate() {
assert_eq!(hash, hasn_fn(i as u64, hash1, hash2, n));
}
}
#[test]
fn hashes_next() {
let hash_builder = Xxh3Builder::new();
let hash1 = hash_builder.with_seed(1).hash_one("mykey");
let hash2 = hash_builder.with_seed(2).hash_one("mykey");
let n = 1e9 as u64;
let k = 100;
let mut iter = Hashes::<u64>::new(hash1, hash2, n, k);
for i in 0..k {
assert_eq!(iter.next(), Some(hasn_fn(i as u64, hash1, hash2, n)));
}
}
}