1#![allow(unreachable_code)]
2use std::ops::Shl;
3use crate::{
4 match_fallthrough,
5 match_fallthrough_reverse_branches,
6 match_fallthrough_make_loops,
7 match_fallthrough_make_match
8};
9
10
11#[inline]
12pub fn hash(data: &[u8]) -> u128 {
13 murmur3_x64_128(data, 0)
14}
15
16macro_rules! test_println {
18 ($($arg:tt)*) => {
19 if cfg!(test) {
20 println!($($arg)*)
21 }
22 }
23}
24
25
26#[inline]
27pub fn murmur3_x64_128(data: &[u8], seed: u64) -> u128 {
28 const C1: u64 = 0x87c3_7b91_1142_53d5;
29 const C2: u64 = 0x4cf5_ad43_2745_937f;
30 const C3: u64 = 0x52dc_e729;
31 const C4: u64 = 0x3849_5ab5;
32 const R1: u32 = 27;
33 const R2: u32 = 31;
34 const R3: u32 = 33;
35 const M: u64 = 5;
36 const BLOCK_SIZE: usize = 16;
37 const HALF_BLOCK_SIZE: usize = BLOCK_SIZE / 2;
38 let len = data.len();
39 let full_block_len = data.len() / BLOCK_SIZE * BLOCK_SIZE;
40
41 let mut h1: u64 = seed;
42 let mut h2: u64 = seed;
43
44 for slice in data[..full_block_len].chunks(BLOCK_SIZE) {
45 let k1 = u64::from_le_bytes(unsafe {*(
46 slice.as_ptr() as *const [u8; HALF_BLOCK_SIZE]
47 )});
48 let k2 = u64::from_le_bytes(unsafe {*(
49 slice.as_ptr().offset(HALF_BLOCK_SIZE as isize) as *const [u8; HALF_BLOCK_SIZE]
50 )});
51 h1 ^= k1.wrapping_mul(C1).rotate_left(R2).wrapping_mul(C2);
52 h1 = h1
53 .rotate_left(R1)
54 .wrapping_add(h2)
55 .wrapping_mul(M)
56 .wrapping_add(C3);
57 h2 ^= k2.wrapping_mul(C2).rotate_left(R3).wrapping_mul(C1);
58 h2 = h2
59 .rotate_left(R2)
60 .wrapping_add(h1)
61 .wrapping_mul(M)
62 .wrapping_add(C4);
63 }
64
65 let buf = &data[full_block_len..];
66 let trailing_len = buf.len();
67 let mut k1 = 0;
68 let mut k2 = 0;
69 match_fallthrough!(trailing_len, {
71 15 => k2 ^= (buf[14] as u64).shl(48),
72 14 => k2 ^= (buf[13] as u64).shl(40),
73 13 => k2 ^= (buf[12] as u64).shl(32),
74 12 => k2 ^= (buf[11] as u64).shl(24),
75 11 => k2 ^= (buf[10] as u64).shl(16),
76 10 => k2 ^= (buf[9] as u64).shl(8),
77 9 => {
78 k2 ^= buf[8] as u64;
79 k2 = k2.wrapping_mul(C2)
80 .rotate_left(33)
81 .wrapping_mul(C1);
82 h2 ^= k2;
83 },
84 8 => k1 ^= (buf[7] as u64).shl(56),
85 7 => k1 ^= (buf[6] as u64).shl(48),
86 6 => k1 ^= (buf[5] as u64).shl(40),
87 5 => k1 ^= (buf[4] as u64).shl(32),
88 4 => k1 ^= (buf[3] as u64).shl(24),
89 3 => k1 ^= (buf[2] as u64).shl(16),
90 2 => k1 ^= (buf[1] as u64).shl(8),
91 1 => k1 ^= buf[0] as u64,
92 0 => {
93 k1 = k1.wrapping_mul(C1)
94 .rotate_left(R2)
95 .wrapping_mul(C2);
96 h1 ^= k1;
97 break;
98 },
99 _ => unreachable!()
100 });
101
102 h1 ^= len as u64;
103 h2 ^= len as u64;
104 h1 = h1.wrapping_add(h2);
105 h2 = h2.wrapping_add(h1);
106 h1 = fmix64(h1);
107 h2 = fmix64(h2);
108 h1 = h1.wrapping_add(h2);
109 h2 = h2.wrapping_add(h1);
110 u128::from_ne_bytes(unsafe {*([h1, h2].as_ptr() as *const [u8; 16])})
111}
112
113
114trait XorShift {
115 fn xor_shr(&self, shift: u32) -> Self;
116}
117
118
119impl XorShift for u64 {
120 fn xor_shr(&self, shift: u32) -> Self {
121 self ^ (self >> shift)
122 }
123}
124
125
126fn fmix64(k: u64) -> u64 {
127 const C1: u64 = 0xff51_afd7_ed55_8ccd;
128 const C2: u64 = 0xc4ce_b9fe_1a85_ec53;
129 const R: u32 = 33;
130 k
131 .xor_shr(R)
132 .wrapping_mul(C1)
133 .xor_shr(R)
134 .wrapping_mul(C2)
135 .xor_shr(R)
136}