use crate::city64::{K1, hash64_len_0_to_16, read_le64, shift_mix};
#[inline]
fn hash_len16(lo: u64, hi: u64) -> u64 {
const K_MUL: u64 = 0x9ddfea08eb382d69u64;
let mut a = (lo ^ hi).wrapping_mul(K_MUL);
a ^= a >> 47;
let mut b = (hi ^ a).wrapping_mul(K_MUL);
b ^= b >> 47;
b = b.wrapping_mul(K_MUL);
b
}
#[inline]
fn city_murmur_with_seed_impl(bytes: &[u8], seed: u128) -> u128 {
let mut a = (seed & 0xffff_ffff_ffff_ffff) as u64;
let mut b = (seed >> 64) as u64;
let mut c;
let mut d;
let len = bytes.len();
if len <= 16 {
a = shift_mix(a.wrapping_mul(K1)).wrapping_mul(K1);
c = b.wrapping_mul(K1).wrapping_add(hash64_len_0_to_16(bytes));
d = shift_mix(a.wrapping_add(if len >= 8 { read_le64(bytes, 0) } else { c }));
} else {
c = hash_len16(read_le64(bytes, len - 8).wrapping_add(K1), a);
d = hash_len16(
b.wrapping_add(len as u64),
c.wrapping_add(read_le64(bytes, len - 16)),
);
a += d;
let iters = (bytes.len() - 1) / 16;
let sliced = &bytes[..iters * 16];
for chunk in sliced.chunks_exact(32) {
a ^= shift_mix(read_le64(chunk, 0).wrapping_mul(K1)).wrapping_mul(K1);
a = a.wrapping_mul(K1);
b ^= a;
c ^= shift_mix(read_le64(chunk, 8).wrapping_mul(K1)).wrapping_mul(K1);
c = c.wrapping_mul(K1);
d ^= c;
a ^= shift_mix(read_le64(chunk, 16).wrapping_mul(K1)).wrapping_mul(K1);
a = a.wrapping_mul(K1);
b ^= a;
c ^= shift_mix(read_le64(chunk, 24).wrapping_mul(K1)).wrapping_mul(K1);
c = c.wrapping_mul(K1);
d ^= c;
}
let rem = sliced.chunks_exact(32).remainder();
for chunk in rem.chunks_exact(16) {
a ^= shift_mix(read_le64(chunk, 0).wrapping_mul(K1)).wrapping_mul(K1);
a = a.wrapping_mul(K1);
b ^= a;
c ^= shift_mix(read_le64(chunk, 8).wrapping_mul(K1)).wrapping_mul(K1);
c = c.wrapping_mul(K1);
d ^= c;
}
}
a = hash_len16(a, c);
b = hash_len16(d, b);
((a ^ b) as u128) | (hash_len16(b, a) as u128).wrapping_shl(64)
}
pub fn city_murmur_with_seed(bytes: &[u8], seed: u128) -> u128 {
city_murmur_with_seed_impl(bytes, seed)
}
pub fn city_murmur(bytes: &[u8]) -> u128 {
city_murmur_with_seed_impl(bytes, 0)
}
#[cfg(test)]
mod tests {
use crate::murmur::city_murmur;
#[test]
fn test_city_murmur() {
assert_eq!(
city_murmur(b"123456789"),
137555568363236656549789161648540888277
);
assert_eq!(city_murmur(b"123"), 147516989038733154062198668001837519169);
assert_eq!(city_murmur(&[]), 236886107234819556091512130834823996519);
assert_eq!(city_murmur(b"1"), 232547357270412657736765068303298868200);
assert_eq!(
city_murmur(b"123456789123456"),
99170281196658490251255024019638099994
);
assert_eq!(
city_murmur(b"The quick brown fox jumps over the lazy dog"),
251933285825128086863441730578249075428
);
assert_eq!(
city_murmur(b"The current version, completed April 3, 2011, is MurmurHash3,[12][13] which yields a 32-bit or 128-bit hash value. When using 128-bits, the x86 and x64 versions do not produce the same values, as the algorithms are optimized for their respective platforms. MurmurHash3 was released alongside SMHasher, a hash function test suite."),
49367195754802758346567295079188952398
);
}
}