use core::hash::BuildHasher;
use core::hash::Hasher;
use crate::fmix32;
use crate::read_u32;
use crate::read_u64;
const C1_32: u32 = 0xcc9e_2d51;
const C2_32: u32 = 0x1b87_3593;
const C1_X64_128: u64 = 0x87c3_7b91_1142_53d5;
const C2_X64_128: u64 = 0x4cf5_ad43_2745_937f;
#[inline(always)]
fn mix_k32(value: u32) -> u32 {
value
.wrapping_mul(C1_32)
.rotate_left(15)
.wrapping_mul(C2_32)
}
#[inline(always)]
fn consume_32(hash: u32, lane: u32) -> u32 {
(hash ^ mix_k32(lane))
.rotate_left(13)
.wrapping_mul(5)
.wrapping_add(0xe654_6b64)
}
#[inline(always)]
fn finish_32(mut hash: u32, tail: &[u8], total_len: u64) -> u32 {
let mut lane = 0;
for (index, &byte) in tail.iter().enumerate() {
lane |= u32::from(byte) << (index * 8);
}
if !tail.is_empty() {
hash ^= mix_k32(lane);
}
fmix32(hash ^ total_len as u32)
}
#[must_use]
#[inline]
pub fn murmur3_x86_32(input: &[u8], seed: u32) -> u32 {
let mut hash = seed;
let mut offset = 0;
while offset + 4 <= input.len() {
hash = consume_32(hash, read_u32(input, offset));
offset += 4;
}
finish_32(hash, &input[offset..], input.len() as u64)
}
#[derive(Clone, Debug)]
pub struct Murmur3X86_32 {
seed: u32,
hash: u32,
buffer: [u8; 4],
buffered: usize,
total_len: u64,
}
impl Murmur3X86_32 {
#[must_use]
pub const fn new() -> Self {
Self::with_seed(0)
}
#[must_use]
pub const fn with_seed(seed: u32) -> Self {
Self {
seed,
hash: seed,
buffer: [0; 4],
buffered: 0,
total_len: 0,
}
}
#[inline]
pub fn update(&mut self, mut input: &[u8]) {
self.total_len = self.total_len.wrapping_add(input.len() as u64);
if self.buffered != 0 {
let copied = (4 - self.buffered).min(input.len());
self.buffer[self.buffered..self.buffered + copied].copy_from_slice(&input[..copied]);
self.buffered += copied;
input = &input[copied..];
if self.buffered < 4 {
return;
}
self.hash = consume_32(self.hash, read_u32(&self.buffer, 0));
self.buffered = 0;
}
while input.len() >= 4 {
self.hash = consume_32(self.hash, read_u32(input, 0));
input = &input[4..];
}
self.buffer[..input.len()].copy_from_slice(input);
self.buffered = input.len();
}
#[must_use]
#[inline]
pub fn digest(&self) -> u32 {
finish_32(self.hash, &self.buffer[..self.buffered], self.total_len)
}
pub fn reset(&mut self) {
*self = Self::with_seed(self.seed);
}
#[must_use]
pub const fn seed(&self) -> u32 {
self.seed
}
#[must_use]
pub const fn total_len(&self) -> u64 {
self.total_len
}
}
impl Default for Murmur3X86_32 {
fn default() -> Self {
Self::new()
}
}
impl Hasher for Murmur3X86_32 {
#[inline]
fn finish(&self) -> u64 {
u64::from(self.digest())
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
self.update(bytes);
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Murmur3X86_32Builder {
seed: u32,
}
impl Murmur3X86_32Builder {
#[must_use]
pub const fn with_seed(seed: u32) -> Self {
Self { seed }
}
}
impl BuildHasher for Murmur3X86_32Builder {
type Hasher = Murmur3X86_32;
#[inline]
fn build_hasher(&self) -> Self::Hasher {
Murmur3X86_32::with_seed(self.seed)
}
}
const C1_X86_128: u32 = 0x239b_961b;
const C2_X86_128: u32 = 0xab0e_9789;
const C3_X86_128: u32 = 0x38b3_4ae5;
const C4_X86_128: u32 = 0xa1e3_8b93;
#[inline(always)]
fn mix_x86_128(value: u32, first: u32, rotation: u32, second: u32) -> u32 {
value
.wrapping_mul(first)
.rotate_left(rotation)
.wrapping_mul(second)
}
#[inline(always)]
fn consume_x86_128(mut hash: [u32; 4], block: &[u8]) -> [u32; 4] {
hash[0] ^= mix_x86_128(read_u32(block, 0), C1_X86_128, 15, C2_X86_128);
hash[0] = hash[0]
.rotate_left(19)
.wrapping_add(hash[1])
.wrapping_mul(5)
.wrapping_add(0x561c_cd1b);
hash[1] ^= mix_x86_128(read_u32(block, 4), C2_X86_128, 16, C3_X86_128);
hash[1] = hash[1]
.rotate_left(17)
.wrapping_add(hash[2])
.wrapping_mul(5)
.wrapping_add(0x0bca_a747);
hash[2] ^= mix_x86_128(read_u32(block, 8), C3_X86_128, 17, C4_X86_128);
hash[2] = hash[2]
.rotate_left(15)
.wrapping_add(hash[3])
.wrapping_mul(5)
.wrapping_add(0x96cd_1c35);
hash[3] ^= mix_x86_128(read_u32(block, 12), C4_X86_128, 18, C1_X86_128);
hash[3] = hash[3]
.rotate_left(13)
.wrapping_add(hash[0])
.wrapping_mul(5)
.wrapping_add(0x32ac_3b17);
hash
}
#[inline(always)]
fn partial_u32(input: &[u8]) -> u32 {
let mut value = 0;
for (index, &byte) in input.iter().enumerate() {
value |= u32::from(byte) << (index * 8);
}
value
}
#[inline(always)]
fn finish_x86_128(mut hash: [u32; 4], tail: &[u8], total_len: u64) -> u128 {
if tail.len() > 12 {
hash[3] ^= mix_x86_128(partial_u32(&tail[12..]), C4_X86_128, 18, C1_X86_128);
}
if tail.len() > 8 {
hash[2] ^= mix_x86_128(
partial_u32(&tail[8..tail.len().min(12)]),
C3_X86_128,
17,
C4_X86_128,
);
}
if tail.len() > 4 {
hash[1] ^= mix_x86_128(
partial_u32(&tail[4..tail.len().min(8)]),
C2_X86_128,
16,
C3_X86_128,
);
}
if !tail.is_empty() {
hash[0] ^= mix_x86_128(
partial_u32(&tail[..tail.len().min(4)]),
C1_X86_128,
15,
C2_X86_128,
);
}
let total_len = total_len as u32;
for word in &mut hash {
*word ^= total_len;
}
hash[0] = hash[0]
.wrapping_add(hash[1])
.wrapping_add(hash[2])
.wrapping_add(hash[3]);
hash[1] = hash[1].wrapping_add(hash[0]);
hash[2] = hash[2].wrapping_add(hash[0]);
hash[3] = hash[3].wrapping_add(hash[0]);
for word in &mut hash {
*word = fmix32(*word);
}
hash[0] = hash[0]
.wrapping_add(hash[1])
.wrapping_add(hash[2])
.wrapping_add(hash[3]);
hash[1] = hash[1].wrapping_add(hash[0]);
hash[2] = hash[2].wrapping_add(hash[0]);
hash[3] = hash[3].wrapping_add(hash[0]);
(u128::from(hash[3]) << 96)
| (u128::from(hash[2]) << 64)
| (u128::from(hash[1]) << 32)
| u128::from(hash[0])
}
#[inline]
fn update_128_state<H>(
hash: &mut H,
buffer: &mut [u8; 16],
buffered: &mut usize,
total_len: &mut u64,
mut input: &[u8],
mut consume: impl FnMut(&mut H, &[u8]),
) {
*total_len = total_len.wrapping_add(input.len() as u64);
if *buffered != 0 {
let copied = (16 - *buffered).min(input.len());
buffer[*buffered..*buffered + copied].copy_from_slice(&input[..copied]);
*buffered += copied;
input = &input[copied..];
if *buffered < 16 {
return;
}
consume(hash, buffer);
*buffered = 0;
}
while input.len() >= 16 {
consume(hash, &input[..16]);
input = &input[16..];
}
buffer[..input.len()].copy_from_slice(input);
*buffered = input.len();
}
#[must_use]
#[inline]
pub fn murmur3_x86_128(input: &[u8], seed: u32) -> u128 {
let mut hash = [seed; 4];
let mut offset = 0;
while offset + 16 <= input.len() {
hash = consume_x86_128(hash, &input[offset..offset + 16]);
offset += 16;
}
finish_x86_128(hash, &input[offset..], input.len() as u64)
}
#[derive(Clone, Debug)]
pub struct Murmur3X86_128 {
seed: u32,
hash: [u32; 4],
buffer: [u8; 16],
buffered: usize,
total_len: u64,
}
impl Murmur3X86_128 {
#[must_use]
pub const fn new() -> Self {
Self::with_seed(0)
}
#[must_use]
pub const fn with_seed(seed: u32) -> Self {
Self {
seed,
hash: [seed; 4],
buffer: [0; 16],
buffered: 0,
total_len: 0,
}
}
#[inline]
pub fn update(&mut self, input: &[u8]) {
update_128_state(
&mut self.hash,
&mut self.buffer,
&mut self.buffered,
&mut self.total_len,
input,
|hash, block| *hash = consume_x86_128(*hash, block),
);
}
#[must_use]
#[inline]
pub fn digest(&self) -> u128 {
finish_x86_128(self.hash, &self.buffer[..self.buffered], self.total_len)
}
pub fn reset(&mut self) {
*self = Self::with_seed(self.seed);
}
#[must_use]
pub const fn seed(&self) -> u32 {
self.seed
}
#[must_use]
pub const fn total_len(&self) -> u64 {
self.total_len
}
}
impl Default for Murmur3X86_128 {
fn default() -> Self {
Self::new()
}
}
#[inline(always)]
fn mix_k1_x64_128(value: u64) -> u64 {
value
.wrapping_mul(C1_X64_128)
.rotate_left(31)
.wrapping_mul(C2_X64_128)
}
#[inline(always)]
fn mix_k2_x64_128(value: u64) -> u64 {
value
.wrapping_mul(C2_X64_128)
.rotate_left(33)
.wrapping_mul(C1_X64_128)
}
#[inline(always)]
fn consume_x64_128(mut hash: [u64; 2], lane1: u64, lane2: u64) -> [u64; 2] {
hash[0] ^= mix_k1_x64_128(lane1);
hash[0] = hash[0]
.rotate_left(27)
.wrapping_add(hash[1])
.wrapping_mul(5)
.wrapping_add(0x52dc_e729);
hash[1] ^= mix_k2_x64_128(lane2);
hash[1] = hash[1]
.rotate_left(31)
.wrapping_add(hash[0])
.wrapping_mul(5)
.wrapping_add(0x3849_5ab5);
hash
}
#[inline(always)]
fn fmix64(mut value: u64) -> u64 {
value ^= value >> 33;
value = value.wrapping_mul(0xff51_afd7_ed55_8ccd);
value ^= value >> 33;
value = value.wrapping_mul(0xc4ce_b9fe_1a85_ec53);
value ^ (value >> 33)
}
#[inline(always)]
fn partial_u64(input: &[u8]) -> u64 {
let mut value = 0;
for (index, &byte) in input.iter().enumerate() {
value |= u64::from(byte) << (index * 8);
}
value
}
#[inline(always)]
fn finish_x64_128(mut hash: [u64; 2], tail: &[u8], total_len: u64) -> u128 {
if tail.len() > 8 {
hash[1] ^= mix_k2_x64_128(partial_u64(&tail[8..]));
}
if !tail.is_empty() {
hash[0] ^= mix_k1_x64_128(partial_u64(&tail[..tail.len().min(8)]));
}
hash[0] ^= total_len;
hash[1] ^= total_len;
hash[0] = hash[0].wrapping_add(hash[1]);
hash[1] = hash[1].wrapping_add(hash[0]);
hash[0] = fmix64(hash[0]);
hash[1] = fmix64(hash[1]);
hash[0] = hash[0].wrapping_add(hash[1]);
hash[1] = hash[1].wrapping_add(hash[0]);
(u128::from(hash[1]) << 64) | u128::from(hash[0])
}
#[must_use]
#[inline]
pub fn murmur3_x64_128(input: &[u8], seed: u32) -> u128 {
let seed = u64::from(seed);
let mut hash = [seed, seed];
let mut offset = 0;
while offset + 16 <= input.len() {
hash = consume_x64_128(hash, read_u64(input, offset), read_u64(input, offset + 8));
offset += 16;
}
finish_x64_128(hash, &input[offset..], input.len() as u64)
}
#[derive(Clone, Debug)]
pub struct Murmur3X64_128 {
seed: u32,
hash: [u64; 2],
buffer: [u8; 16],
buffered: usize,
total_len: u64,
}
impl Murmur3X64_128 {
#[must_use]
pub const fn new() -> Self {
Self::with_seed(0)
}
#[must_use]
pub const fn with_seed(seed: u32) -> Self {
Self {
seed,
hash: [seed as u64, seed as u64],
buffer: [0; 16],
buffered: 0,
total_len: 0,
}
}
#[inline]
pub fn update(&mut self, input: &[u8]) {
update_128_state(
&mut self.hash,
&mut self.buffer,
&mut self.buffered,
&mut self.total_len,
input,
|hash, block| {
*hash = consume_x64_128(*hash, read_u64(block, 0), read_u64(block, 8));
},
);
}
#[must_use]
#[inline]
pub fn digest(&self) -> u128 {
finish_x64_128(self.hash, &self.buffer[..self.buffered], self.total_len)
}
pub fn reset(&mut self) {
*self = Self::with_seed(self.seed);
}
#[must_use]
pub const fn seed(&self) -> u32 {
self.seed
}
#[must_use]
pub const fn total_len(&self) -> u64 {
self.total_len
}
}
impl Default for Murmur3X64_128 {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_vectors_are_zero_with_zero_seed() {
assert_eq!(murmur3_x86_32(b"", 0), 0);
assert_eq!(murmur3_x86_128(b"", 0), 0);
assert_eq!(murmur3_x64_128(b"", 0), 0);
}
#[test]
fn reset_reuses_seed() {
let mut hash = Murmur3X64_128::with_seed(42);
hash.update(b"before");
hash.reset();
hash.update(b"after");
assert_eq!(hash.digest(), murmur3_x64_128(b"after", 42));
}
}