const MURMUR3_SEED: u32 = 0;
pub use table::{IdentityHasher, PreHashedMap};
mod table {
use std::hash::{BuildHasher, Hasher};
#[derive(Clone, Copy, Default)]
pub struct IdentityHasher(u64);
pub type PreHashedMap<K, V> = std::collections::HashMap<K, V, IdentityHasher>;
impl BuildHasher for IdentityHasher {
type Hasher = Self;
fn build_hasher(&self) -> Self::Hasher {
*self
}
}
impl Hasher for IdentityHasher {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
let mut int = [0u8; 4];
int.copy_from_slice(bytes);
let int = u32::from_le_bytes(int) as u64;
self.0 = int | (int << 31);
}
}
}
#[macro_export]
macro_rules! label_hash {
($text:literal) => {{
const HASH: $crate::Label = $crate::Label::Hash($crate::hash::murmur3_str($text));
HASH
}};
($text:expr) => {{
let text: &dyn ::std::borrow::Borrow<str> = &$text;
$crate::Label::Hash($crate::hash::murmur3_str(text.borrow()))
}};
}
pub const fn murmur3(data: &[u8]) -> u32 {
murmur3_with_seed(data, MURMUR3_SEED)
}
pub const fn murmur3_with_seed(data: &[u8], seed: u32) -> u32 {
let slice_size: usize = data.len();
let mut hash = seed;
let mut i = 0;
let iterator = slice_size / 4;
while i < iterator {
assert!(data.len() > i * 4 + 3);
let data = [
data[i * 4],
data[i * 4 + 1],
data[i * 4 + 2],
data[i * 4 + 3],
];
hash ^= murmur3_scramble(data);
hash = (hash.wrapping_shl(13)) | (hash.wrapping_shr(19));
hash = hash.wrapping_mul(5).wrapping_add(0xe6546b64);
i += 1;
}
match slice_size % 4 {
0 => (),
1 => {
let data = [data[i * 4], 0, 0, 0];
let k = murmur3_scramble(data);
hash ^= k;
}
2 => {
let data = [data[i * 4], data[i * 4 + 1], 0, 0];
let k = murmur3_scramble(data);
hash ^= k;
}
3 => {
let data = [data[i * 4], data[i * 4 + 1], data[i * 4 + 2], 0];
let k = murmur3_scramble(data);
hash ^= k;
}
_ => unreachable!(),
}
hash ^= slice_size as u32;
hash = hash ^ (hash.wrapping_shr(16));
hash = hash.wrapping_mul(0x85ebca6b);
hash = hash ^ (hash.wrapping_shr(13));
hash = hash.wrapping_mul(0xc2b2ae35);
hash = hash ^ (hash.wrapping_shr(16));
hash
}
#[inline]
pub const fn murmur3_str(src: &str) -> u32 {
murmur3(src.as_bytes())
}
#[inline]
const fn murmur3_scramble(data: [u8; 4]) -> u32 {
let r1 = 15;
let c1: u32 = 0xcc9e2d51;
let c2: u32 = 0x1b873593;
let mut k = u32::from_le_bytes(data);
k = k.wrapping_mul(c1);
k = k.rotate_left(r1);
k = k.wrapping_mul(c2);
k
}
#[cfg(test)]
mod tests {
use super::murmur3_str;
#[test]
fn test_murmur3() {
assert_eq!(murmur3_str("abc"), 0xB3DD93FA);
assert_eq!(murmur3_str("FLD_EnemyData"), 0x2521C473);
assert_eq!(murmur3_str("EVT_listEv"), 0x23EE284B);
}
}