use std::hash::Hasher;
const K: u32 = 0x9e37_79b9;
const MIX: u32 = 0x7feb_352d;
#[derive(Clone, Copy, Default)]
pub struct WordHasher {
hash: u32,
}
impl WordHasher {
#[inline]
fn add(&mut self, word: u32) {
self.hash = self.hash.wrapping_add(word).wrapping_mul(K);
}
}
impl Hasher for WordHasher {
#[inline]
fn write(&mut self, bytes: &[u8]) {
let (words, tail) = bytes.as_chunks::<4>();
for word in words {
self.add(u32::from_le_bytes(*word));
}
if !tail.is_empty() {
let mut word = [0; 4];
word[..tail.len()].copy_from_slice(tail);
self.add(u32::from_le_bytes(word));
}
}
#[inline]
fn write_u8(&mut self, value: u8) {
self.add(u32::from(value));
}
#[inline]
fn write_u16(&mut self, value: u16) {
self.add(u32::from(value));
}
#[inline]
fn write_u32(&mut self, value: u32) {
self.add(value);
}
#[inline]
fn write_u64(&mut self, value: u64) {
self.add(value as u32);
self.add((value >> 32) as u32);
}
#[inline]
fn write_u128(&mut self, value: u128) {
self.write_u64(value as u64);
self.write_u64((value >> 64) as u64);
}
#[inline]
fn write_usize(&mut self, value: usize) {
if usize::BITS == u32::BITS {
self.add(value as u32);
} else {
self.write_u64(value as u64);
}
}
#[inline]
fn finish(&self) -> u64 {
let mut hash = self.hash;
hash ^= hash >> 16;
hash = hash.wrapping_mul(MIX);
hash ^= hash >> 15;
u64::from(hash)
}
}
#[cfg(test)]
#[path = "tests/word_hash_tests.rs"]
mod tests;