use std::hash::Hasher as _;
use bufhash::partitioned::Hasher;
use bufhash::PartitionedHasher;
#[derive(Debug, Default)]
pub struct Murmur3 {
hash: u32,
num_bytes: usize,
}
const C1: u32 = 0xCC9E_2D51;
const C2: u32 = 0x1B87_3593;
const R1: u32 = 15;
const R2: u32 = 13;
const M: u32 = 5;
const N: u32 = 0xE654_6B64;
impl Hasher<4> for Murmur3 {
fn write(&mut self, bytes: &[u8; 4]) {
let mut k = u32::from_le_bytes(*bytes);
k = k.wrapping_mul(C1);
k = k.rotate_left(R1);
k = k.wrapping_mul(C2);
self.hash ^= k;
self.hash = self.hash.rotate_left(R2);
self.hash = self.hash.wrapping_mul(M).wrapping_add(N);
self.num_bytes += 4;
}
fn finish(&self, bytes: &[u8]) -> u64 {
let mut hash = self.hash;
let mut num_bytes = self.num_bytes;
if !bytes.is_empty() {
let mut buffer = [0u8; 4];
for (i, &byte) in bytes.iter().enumerate() {
buffer[i] = byte;
}
let mut remaining = u32::from_le_bytes(buffer);
remaining = remaining.wrapping_mul(C1);
remaining = remaining.rotate_left(R1);
remaining = remaining.wrapping_mul(C2);
hash ^= remaining;
num_bytes += bytes.len();
}
hash ^= num_bytes as u32;
hash ^= hash >> 16;
hash = hash.wrapping_mul(0x85EB_CA6B);
hash ^= hash >> 13;
hash = hash.wrapping_mul(0xC2B2_AE35);
hash ^= hash >> 16;
hash as u64
}
}
pub fn main() {
let mut hasher = PartitionedHasher::new(Murmur3::default());
hasher.write(b"Hello, world!");
let result = hasher.finish();
println!("Single-call result: 0x{:X}", &result);
assert_eq!(result, 0xC036_3E43);
let mut hasher = PartitionedHasher::new(Murmur3::default());
hasher.write(b"H");
hasher.write(b"e");
hasher.write(b"l");
hasher.write(b"l");
hasher.write(b"o");
hasher.write(b",");
hasher.write(b" ");
hasher.write(b"w");
hasher.write(b"o");
hasher.write(b"r");
hasher.write(b"l");
hasher.write(b"d");
hasher.write(b"!");
let result = hasher.finish();
println!("Multiple-call result: 0x{:X}", &result);
assert_eq!(result, 0xC036_3E43);
}