pub const PRIME: u64 = 15422943418517532487;
#[inline(always)]
pub fn finish(mut hash: u64) -> u64 {
hash = (hash ^ hash >> 32).wrapping_mul(PRIME);
hash ^ hash >> 32
}
#[inline(always)]
pub fn mix2(a: u64, b: u64) -> u64 {
a.wrapping_add(PRIME) ^ b
}
#[inline(always)]
pub fn mix3(a: u64, b: u64, c: u64) -> u64 {
a.wrapping_add(PRIME) ^ b.wrapping_add(c) ^ c
}
#[inline(always)]
pub fn mix_with_bytes(hash: u64, bytes: &[u8]) -> u64 {
unsafe {
let mut hash = mix2(hash, bytes.len() as u64);
let ptr = bytes.as_ptr();
let end = ptr.wrapping_add(bytes.len());
if bytes.len() > 16 {
let mut u64_ptr = ptr.cast::<(u64, u64)>();
let u64_end = end.cast::<(u64, u64)>().wrapping_sub(1);
let (l, r) = u64_end.read_unaligned();
hash = mix3(hash, l, r);
loop {
let (l, r) = u64_end.read_unaligned();
hash = mix3(hash, l, r);
u64_ptr = u64_ptr.wrapping_add(1);
if u64_ptr < u64_end {
continue;
}
break hash;
}
} else {
unsafe fn read_lr<T: Into<u64>>(ptr: *const u8, end: *const u8) -> (u64, u64) {
(
ptr.cast::<T>().read_unaligned().into(),
end.cast::<T>().wrapping_sub(1).read_unaligned().into(),
)
}
let (l, r) = if bytes.len() == 0 {
(PRIME, PRIME)
} else if bytes.len() <= 2 {
read_lr::<u8>(ptr, end)
} else if bytes.len() <= 4 {
read_lr::<u16>(ptr, end)
} else if bytes.len() <= 8 {
read_lr::<u32>(ptr, end)
} else {
read_lr::<u64>(ptr, end)
};
mix3(hash, l, r)
}
}
}