fasthash_fork/murmur3.rs
1//! `Murmur3`, a suite of non-cryptographic hash functions that was used for hash-based lookups.
2//!
3//! by Austin Appleby (aappleby (AT) gmail)
4//!
5//! https://sites.google.com/site/murmurhash/
6//!
7//! # Note
8//!
9//! The x86 and x64 versions do _not_ produce the same results, as the
10//! algorithms are optimized for their respective platforms. You can still
11//! compile and run any of them on any platform, but your performance with the
12//! non-native version will be less than optimal.
13//!
14//! # Example
15//!
16//! ```
17//! use std::hash::{Hash, Hasher};
18//!
19//! use fasthash::{murmur3, Murmur3HasherExt};
20//!
21//! fn hash<T: Hash>(t: &T) -> u64 {
22//! let mut s: Murmur3HasherExt = Default::default();
23//! t.hash(&mut s);
24//! s.finish()
25//! }
26//!
27//! let h = murmur3::hash128(b"hello world\xff");
28//!
29//! assert_eq!(h as u64, hash(&"hello world"));
30//! ```
31//!
32#![allow(non_camel_case_types)]
33use std::os::raw::c_void;
34
35use crate::ffi;
36
37use crate::hasher::FastHash;
38
39/// `MurmurHash3` 32-bit hash functions
40///
41/// # Example
42///
43/// ```
44/// use fasthash::{murmur3::Hash32, FastHash};
45///
46/// assert_eq!(Hash32::hash(b"hello"), 613153351);
47/// assert_eq!(Hash32::hash_with_seed(b"hello", 123), 1573043710);
48/// assert_eq!(Hash32::hash(b"helloworld"), 2687965642);
49/// ```
50#[derive(Clone, Default)]
51pub struct Hash32;
52
53impl FastHash for Hash32 {
54 type Hash = u32;
55 type Seed = u32;
56
57 #[inline(always)]
58 fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u32) -> u32 {
59 unsafe {
60 let mut hash = 0_u32;
61
62 ffi::MurmurHash3_x86_32(
63 bytes.as_ref().as_ptr() as *const c_void,
64 bytes.as_ref().len() as i32,
65 seed,
66 &mut hash as *mut u32 as *mut c_void,
67 );
68
69 hash
70 }
71 }
72}
73
74trivial_hasher! {
75 /// # Example
76 ///
77 /// ```
78 /// use std::hash::Hasher;
79 ///
80 /// use fasthash::{murmur3::Hasher32, FastHasher};
81 ///
82 /// let mut h = Hasher32::new();
83 ///
84 /// h.write(b"hello");
85 /// assert_eq!(h.finish(), 613153351);
86 ///
87 /// h.write(b"world");
88 /// assert_eq!(h.finish(), 2687965642);
89 /// ```
90 Hasher32(Hash32) -> u32
91}
92
93/// `MurmurHash3` 128-bit hash functions for 32-bit processors
94///
95/// # Example
96///
97/// ```
98/// use fasthash::{murmur3::Hash128_x86, FastHash};
99///
100/// assert_eq!(
101/// Hash128_x86::hash(b"hello"),
102/// 205839232668418009241864179939306390688
103/// );
104/// assert_eq!(
105/// Hash128_x86::hash_with_seed(b"hello", 123),
106/// 39646137218600763345533167485429249129
107/// );
108/// assert_eq!(
109/// Hash128_x86::hash(b"helloworld"),
110/// 83212725615010754952022132390053357814
111/// );
112/// ```
113#[derive(Clone, Default)]
114pub struct Hash128_x86;
115
116impl FastHash for Hash128_x86 {
117 type Hash = u128;
118 type Seed = u32;
119
120 #[inline(always)]
121 fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u32) -> u128 {
122 unsafe {
123 let mut hash = 0;
124
125 ffi::MurmurHash3_x86_128(
126 bytes.as_ref().as_ptr() as *const c_void,
127 bytes.as_ref().len() as i32,
128 seed,
129 &mut hash as *mut u128 as *mut c_void,
130 );
131
132 hash
133 }
134 }
135}
136
137trivial_hasher! {
138 /// # Example
139 ///
140 /// ```
141 /// use std::hash::Hasher;
142 ///
143 /// use fasthash::{murmur3::Hasher128_x86, FastHasher, HasherExt};
144 ///
145 /// let mut h = Hasher128_x86::new();
146 ///
147 /// h.write(b"hello");
148 /// assert_eq!(h.finish_ext(), 205839232668418009241864179939306390688);
149 ///
150 /// h.write(b"world");
151 /// assert_eq!(h.finish_ext(), 83212725615010754952022132390053357814);
152 /// ```
153 Hasher128_x86(Hash128_x86) -> u128
154}
155
156/// `MurmurHash3` 128-bit hash functions for 64-bit processors
157///
158/// # Example
159///
160/// ```
161/// use fasthash::{murmur3::Hash128_x64, FastHash};
162///
163/// assert_eq!(
164/// Hash128_x64::hash(b"hello"),
165/// 121118445609844952839898260755277781762
166/// );
167/// assert_eq!(
168/// Hash128_x64::hash_with_seed(b"hello", 123),
169/// 19243349499071459060235768594146641163
170/// );
171/// assert_eq!(
172/// Hash128_x64::hash(b"helloworld"),
173/// 216280293825344914020777844322685271162
174/// );
175/// ```
176#[derive(Clone, Default)]
177pub struct Hash128_x64;
178
179impl FastHash for Hash128_x64 {
180 type Hash = u128;
181 type Seed = u32;
182
183 #[inline(always)]
184 fn hash_with_seed<T: AsRef<[u8]>>(bytes: T, seed: u32) -> u128 {
185 unsafe {
186 let mut hash = 0;
187
188 ffi::MurmurHash3_x64_128(
189 bytes.as_ref().as_ptr() as *const c_void,
190 bytes.as_ref().len() as i32,
191 seed,
192 &mut hash as *mut u128 as *mut c_void,
193 );
194
195 hash
196 }
197 }
198}
199
200trivial_hasher! {
201 /// # Example
202 ///
203 /// ```
204 /// use std::hash::Hasher;
205 ///
206 /// use fasthash::{murmur3::Hasher128_x64, FastHasher, HasherExt};
207 ///
208 /// let mut h = Hasher128_x64::new();
209 ///
210 /// h.write(b"hello");
211 /// assert_eq!(h.finish_ext(), 121118445609844952839898260755277781762);
212 ///
213 /// h.write(b"world");
214 /// assert_eq!(h.finish_ext(), 216280293825344914020777844322685271162);
215 /// ```
216 Hasher128_x64(Hash128_x64) -> u128
217}
218
219/// `MurmurHash3` 32-bit hash functions for a byte array.
220#[inline(always)]
221pub fn hash32<T: AsRef<[u8]>>(v: T) -> u32 {
222 Hash32::hash(v)
223}
224
225/// `MurmurHash3` 32-bit hash functions for a byte array.
226/// For convenience, a 32-bit seed is also hashed into the result.
227#[inline(always)]
228pub fn hash32_with_seed<T: AsRef<[u8]>>(v: T, seed: u32) -> u32 {
229 Hash32::hash_with_seed(v, seed)
230}
231
232/// `MurmurHash3` 128-bit hash functions for a byte array.
233#[inline(always)]
234pub fn hash128<T: AsRef<[u8]>>(v: T) -> u128 {
235 if cfg!(target_pointer_width = "64") {
236 Hash128_x64::hash(v)
237 } else {
238 Hash128_x86::hash(v)
239 }
240}
241
242/// `MurmurHash3` 128-bit hash functions for a byte array.
243/// For convenience, a 32-bit seed is also hashed into the result.
244#[inline(always)]
245pub fn hash128_with_seed<T: AsRef<[u8]>>(v: T, seed: u32) -> u128 {
246 if cfg!(target_pointer_width = "64") {
247 Hash128_x64::hash_with_seed(v, seed)
248 } else {
249 Hash128_x86::hash_with_seed(v, seed)
250 }
251}