metrohash/
metrohash128.rs1use crate::utils::*;
2use std::hash::Hasher;
3use std::mem::MaybeUninit;
4use std::num::Wrapping;
5
6const K0: Wrapping<u64> = Wrapping(0xC83A91E1);
7const K1: Wrapping<u64> = Wrapping(0x8648DBDB);
8const K2: Wrapping<u64> = Wrapping(0x7BDEC03B);
9const K3: Wrapping<u64> = Wrapping(0x2F5870A5);
10
11pub struct MetroHash128 {
12 v: [Wrapping<u64>; 4],
13 b: [MaybeUninit<u64>; 4],
14 bytes: usize,
15}
16
17impl Default for MetroHash128 {
18 #[inline]
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl MetroHash128 {
25 #[inline]
26 pub fn new() -> MetroHash128 {
27 Self::with_seed(0)
28 }
29
30 #[inline]
31 pub fn with_seed(seed: u64) -> MetroHash128 {
32 let seed = Wrapping(seed);
33 MetroHash128 {
34 b: [MaybeUninit::uninit(); 4],
35 v: [
36 (seed - K0) * K3,
37 (seed + K1) * K2,
38 (seed + K0) * K2,
39 (seed - K1) * K3,
40 ],
41 bytes: 0,
42 }
43 }
44
45 #[inline]
46 pub fn finish128(&self) -> (u64, u64) {
47 unsafe {
48 let mut v = self.v;
50
51 if self.bytes >= 32 {
53 v[2] ^= rotate_right(((v[0] + v[3]) * K0) + v[1], 21) * K1;
54 v[3] ^= rotate_right(((v[1] + v[2]) * K1) + v[0], 21) * K0;
55 v[0] = v[0] ^ (rotate_right(((v[0] + v[2]) * K0) + v[3], 21) * K1);
56 v[1] = v[1] ^ (rotate_right(((v[1] + v[3]) * K1) + v[2], 21) * K0);
57 }
58
59 let mut ptr = self.b.as_ptr().cast::<u8>();
61 let end = ptr.add(self.bytes % 32);
62
63 if end.offset_from(ptr) >= 16 {
64 v[0] += read_u64(ptr) * K2;
65 ptr = ptr.add(8);
66 v[0] = rotate_right(v[0], 33) * K3;
67 v[1] += read_u64(ptr) * K2;
68 ptr = ptr.add(8);
69 v[1] = rotate_right(v[1], 33) * K3;
70 v[0] = v[0] ^ (rotate_right((v[0] * K2) + v[1], 45) * K1);
71 v[1] = v[1] ^ (rotate_right((v[1] * K3) + v[0], 45) * K0);
72 }
73
74 if end.offset_from(ptr) >= 8 {
75 v[0] += read_u64(ptr) * K2;
76 ptr = ptr.add(8);
77 v[0] = rotate_right(v[0], 33) * K3;
78 v[0] = v[0] ^ (rotate_right((v[0] * K2) + v[1], 27) * K1);
79 }
80
81 if end.offset_from(ptr) >= 4 {
82 v[1] += read_u32(ptr) * K2;
83 ptr = ptr.add(4);
84 v[1] = rotate_right(v[1], 33) * K3;
85 v[1] = v[1] ^ (rotate_right((v[1] * K3) + v[0], 46) * K0);
86 }
87
88 if end.offset_from(ptr) >= 2 {
89 v[0] += read_u16(ptr) * K2;
90 ptr = ptr.add(2);
91 v[0] = rotate_right(v[0], 33) * K3;
92 v[0] = v[0] ^ (rotate_right((v[0] * K2) + v[1], 22) * K1);
93 }
94
95 if end.offset_from(ptr) >= 1 {
96 v[1] += read_u8(ptr) * K2;
97 v[1] = rotate_right(v[1], 33) * K3;
98 v[1] = v[1] ^ (rotate_right((v[1] * K3) + v[0], 58) * K0);
99 }
100
101 v[0] = v[0] + (rotate_right((v[0] * K0) + v[1], 13));
102 v[1] = v[1] + (rotate_right((v[1] * K1) + v[0], 37));
103 v[0] = v[0] + (rotate_right((v[0] * K2) + v[1], 13));
104 v[1] = v[1] + (rotate_right((v[1] * K3) + v[0], 37));
105
106 (v[0].0, v[1].0)
107 }
108 }
109}
110
111impl Hasher for MetroHash128 {
112 #[inline]
113 fn write(&mut self, bytes: &[u8]) {
114 unsafe {
115 let mut ptr = bytes.as_ptr();
116 let end = ptr.add(bytes.len());
117 if self.bytes % 32 != 0 {
119 let mut fill = 32 - (self.bytes % 32);
120 if fill > bytes.len() {
121 fill = bytes.len();
122 }
123
124 copy_32(
125 ptr,
126 self.b[0].as_mut_ptr().cast::<u8>().add(self.bytes % 32),
127 fill,
128 );
129
130 ptr = ptr.add(fill);
131 self.bytes += fill;
132
133 if self.bytes % 32 != 0 {
135 return;
136 }
137
138 self.v[0] += read_u64(&self.b[0] as *const _) * K0;
140 self.v[0] = rotate_right(self.v[0], 29) + self.v[2];
141 self.v[1] += read_u64(&self.b[1] as *const _) * K1;
142 self.v[1] = rotate_right(self.v[1], 29) + self.v[3];
143 self.v[2] += read_u64(&self.b[2] as *const _) * K2;
144 self.v[2] = rotate_right(self.v[2], 29) + self.v[0];
145 self.v[3] += read_u64(&self.b[3] as *const _) * K3;
146 self.v[3] = rotate_right(self.v[3], 29) + self.v[1];
147 }
148
149 self.bytes += end.offset_from(ptr) as usize;
151 while end.offset_from(ptr) >= 32 {
152 self.v[0] += read_u64_unaligned(ptr) * K0;
155 ptr = ptr.add(8);
156 self.v[0] = rotate_right(self.v[0], 29) + self.v[2];
157 self.v[1] += read_u64_unaligned(ptr) * K1;
158 ptr = ptr.add(8);
159 self.v[1] = rotate_right(self.v[1], 29) + self.v[3];
160 self.v[2] += read_u64_unaligned(ptr) * K2;
161 ptr = ptr.add(8);
162 self.v[2] = rotate_right(self.v[2], 29) + self.v[0];
163 self.v[3] += read_u64_unaligned(ptr) * K3;
164 ptr = ptr.add(8);
165 self.v[3] = rotate_right(self.v[3], 29) + self.v[1];
166 }
167
168 if ptr < end {
170 copy_32(
171 ptr,
172 self.b.as_mut_ptr().cast::<u8>(),
173 end.offset_from(ptr) as usize,
174 );
175 }
176 }
177 }
178
179 #[inline]
180 fn finish(&self) -> u64 {
181 self.finish128().0
182 }
183}