#![allow(dead_code)]
const PRIME1: u64 = 0x9E3779B185EBCA87;
const PRIME2: u64 = 0xC2B2AE3D27D4EB4F;
const PRIME3: u64 = 0x165667B19E3779F9;
#[derive(Debug, Clone, Default)]
pub struct XxHasher {
buf: Vec<u8>,
seed: u64,
}
impl XxHasher {
pub fn new() -> Self {
Self::default()
}
pub fn with_seed(seed: u64) -> Self {
Self {
buf: Vec::new(),
seed,
}
}
pub fn update(&mut self, data: &[u8]) {
self.buf.extend_from_slice(data);
}
pub fn finish(&self) -> u64 {
xxhash64(&self.buf, self.seed)
}
pub fn reset(&mut self) {
self.buf.clear();
}
}
pub fn xxhash64(data: &[u8], seed: u64) -> u64 {
let mut h = seed.wrapping_add(PRIME3);
for (i, &b) in data.iter().enumerate() {
h = h
.wrapping_add((b as u64).wrapping_mul(PRIME2))
.wrapping_mul(PRIME1)
.rotate_left((i % 31 + 1) as u32);
}
h ^= h >> 33;
h = h.wrapping_mul(PRIME2);
h ^= h >> 29;
h.wrapping_mul(PRIME3)
}
pub fn xxhash32(data: &[u8], seed: u32) -> u32 {
let mut h = seed.wrapping_add(0x9e3779b1);
for &b in data {
h = h
.wrapping_add(b as u32)
.wrapping_mul(0x165667b1)
.rotate_left(13);
}
h ^= h >> 15;
h = h.wrapping_mul(0x85ebca77);
h ^= h >> 13;
h
}
pub fn xxhash64_hex(data: &[u8], seed: u64) -> String {
format!("{:016x}", xxhash64(data, seed))
}
pub fn xxhash64_eq(a: &[u8], b: &[u8]) -> bool {
xxhash64(a, 0) == xxhash64(b, 0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_deterministic() {
assert_eq!(xxhash64(b"hello", 0), xxhash64(b"hello", 0));
}
#[test]
fn test_hash_differs_on_input() {
assert_ne!(xxhash64(b"a", 0), xxhash64(b"b", 0));
}
#[test]
fn test_seed_affects_output() {
assert_ne!(xxhash64(b"data", 0), xxhash64(b"data", 1));
}
#[test]
fn test_hash32_deterministic() {
assert_eq!(xxhash32(b"test", 0), xxhash32(b"test", 0));
}
#[test]
fn test_hex_length() {
assert_eq!(xxhash64_hex(b"hi", 0).len(), 16);
}
#[test]
fn test_eq_same() {
assert!(xxhash64_eq(b"same", b"same"));
}
#[test]
fn test_eq_different() {
assert!(!xxhash64_eq(b"a", b"b"));
}
#[test]
fn test_hasher_incremental() {
let mut h = XxHasher::with_seed(42);
h.update(b"hello");
assert_eq!(h.finish(), xxhash64(b"hello", 42));
}
#[test]
fn test_hasher_reset() {
let mut h = XxHasher::new();
h.update(b"something");
h.reset();
assert_eq!(h.finish(), xxhash64(&[], 0));
}
}