1 #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
2 use crate::convert::Convert;
3 #[cfg(feature = "specialize")]
4 use crate::BuildHasherExt;
5
6 #[cfg(any(
7 all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
8 all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
9 ))]
10 pub use crate::aes_hash::*;
11
12 #[cfg(not(any(
13 all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
14 all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
15 )))]
16 pub use crate::fallback_hash::*;
17
18 #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
19 use const_random::const_random;
20 use core::any::{Any, TypeId};
21 use core::fmt;
22 use core::hash::BuildHasher;
23 #[cfg(feature = "specialize")]
24 use core::hash::Hash;
25 use core::hash::Hasher;
26
27 #[cfg(not(feature = "std"))]
28 extern crate alloc;
29 #[cfg(feature = "std")]
30 extern crate std as alloc;
31
32 use alloc::boxed::Box;
33 use core::sync::atomic::{AtomicUsize, Ordering};
34 #[cfg(not(all(target_arch = "arm", target_os = "none")))]
35 use once_cell::race::OnceBox;
36
37 #[cfg(any(
38 all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
39 all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
40 ))]
41 use crate::aes_hash::*;
42 #[cfg(not(any(
43 all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)),
44 all(any(target_arch = "arm", target_arch = "aarch64"), target_feature = "crypto", not(miri), feature = "stdsimd")
45 )))]
46 use crate::fallback_hash::*;
47
48 #[cfg(not(all(target_arch = "arm", target_os = "none")))]
49 static RAND_SOURCE: OnceBox<Box<dyn RandomSource + Send + Sync>> = OnceBox::new();
50
51 #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
read_urandom(dest: &mut [u8]) -> Result<(), std::io::Error>52 fn read_urandom(dest: &mut [u8]) -> Result<(), std::io::Error> {
53 use std::fs::File;
54 use std::io::Read;
55
56 let mut f = File::open("/dev/urandom")?;
57 f.read_exact(dest)
58 }
59
60 /// A supplier of Randomness used for different hashers.
61 /// See [RandomState.set_random_source].
62 pub trait RandomSource {
63
get_fixed_seeds(&self) -> &'static [[u64; 4]; 2]64 fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2];
65
gen_hasher_seed(&self) -> usize66 fn gen_hasher_seed(&self) -> usize;
67
68 }
69
70 pub(crate) const PI: [u64; 4] = [
71 0x243f_6a88_85a3_08d3,
72 0x1319_8a2e_0370_7344,
73 0xa409_3822_299f_31d0,
74 0x082e_fa98_ec4e_6c89,
75 ];
76
77 pub(crate) const PI2: [u64; 4] = [
78 0x4528_21e6_38d0_1377,
79 0xbe54_66cf_34e9_0c6c,
80 0xc0ac_29b7_c97c_50dd,
81 0x3f84_d5b5_b547_0917,
82 ];
83
84 struct DefaultRandomSource {
85 counter: AtomicUsize,
86 }
87
88 impl DefaultRandomSource {
new() -> DefaultRandomSource89 fn new() -> DefaultRandomSource {
90 DefaultRandomSource {
91 counter: AtomicUsize::new(&PI as *const _ as usize),
92 }
93 }
94
default() -> DefaultRandomSource95 const fn default() -> DefaultRandomSource {
96 DefaultRandomSource {
97 counter: AtomicUsize::new(PI[3] as usize),
98 }
99 }
100 }
101
102 impl RandomSource for DefaultRandomSource {
103
104 #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
get_fixed_seeds(&self) -> &'static [[u64; 4]; 2]105 fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] {
106 static SEEDS: OnceBox<[[u64; 4]; 2]> = OnceBox::new();
107
108 SEEDS.get_or_init(|| {
109 let mut result: [u8; 64] = [0; 64];
110 if read_urandom(&mut result).is_err() {
111 getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed.");
112 }
113 Box::new(result.convert())
114 })
115 }
116
117 #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
get_fixed_seeds(&self) -> &'static [[u64; 4]; 2]118 fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] {
119 const RAND: [[u64; 4]; 2] = [
120 [
121 const_random!(u64),
122 const_random!(u64),
123 const_random!(u64),
124 const_random!(u64),
125 ], [
126 const_random!(u64),
127 const_random!(u64),
128 const_random!(u64),
129 const_random!(u64),
130 ]
131 ];
132 &RAND
133 }
134
135 #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
get_fixed_seeds(&self) -> &'static [[u64; 4]; 2]136 fn get_fixed_seeds(&self) -> &'static [[u64; 4]; 2] {
137 &[PI, PI2]
138 }
139
140 #[cfg(not(all(target_arch = "arm", target_os = "none")))]
gen_hasher_seed(&self) -> usize141 fn gen_hasher_seed(&self) -> usize {
142 let stack = self as *const _ as usize;
143 self.counter.fetch_add(stack, Ordering::Relaxed)
144 }
145
146 #[cfg(all(target_arch = "arm", target_os = "none"))]
gen_hasher_seed(&self) -> usize147 fn gen_hasher_seed(&self) -> usize {
148 let stack = self as *const _ as usize;
149 let previous = self.counter.load(Ordering::Relaxed);
150 let new = previous.wrapping_add(stack);
151 self.counter.store(new, Ordering::Relaxed);
152 new
153 }
154 }
155
156 /// Provides a [Hasher] factory. This is typically used (e.g. by [HashMap]) to create
157 /// [AHasher]s in order to hash the keys of the map. See `build_hasher` below.
158 ///
159 /// [build_hasher]: ahash::
160 /// [Hasher]: std::hash::Hasher
161 /// [BuildHasher]: std::hash::BuildHasher
162 /// [HashMap]: std::collections::HashMap
163 #[derive(Clone)]
164 pub struct RandomState {
165 pub(crate) k0: u64,
166 pub(crate) k1: u64,
167 pub(crate) k2: u64,
168 pub(crate) k3: u64,
169 }
170
171 impl fmt::Debug for RandomState {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 f.pad("RandomState { .. }")
174 }
175 }
176
177 impl RandomState {
178
179 /// Provides an optional way to manually supply a source of randomness for Hasher keys.
180 ///
181 /// The provided [RandomSource] will be used to be used as a source of randomness by [RandomState] to generate new states.
182 /// If this method is not invoked the standard source of randomness is used as described in the Readme.
183 ///
184 /// The source of randomness can only be set once, and must be set before the first RandomState is created.
185 /// If the source has already been specified `Err` is returned with a `bool` indicating if the set failed because
186 /// method was previously invoked (true) or if the default source is already being used (false).
187 #[cfg(not(all(target_arch = "arm", target_os = "none")))]
set_random_source(source: impl RandomSource + Send + Sync + 'static) -> Result<(), bool>188 pub fn set_random_source(source: impl RandomSource + Send + Sync + 'static) -> Result<(), bool> {
189 RAND_SOURCE.set(Box::new(Box::new(source))).map_err(|s| s.as_ref().type_id() != TypeId::of::<&DefaultRandomSource>())
190 }
191
192 #[inline]
193 #[cfg(not(all(target_arch = "arm", target_os = "none")))]
get_src() -> &'static dyn RandomSource194 fn get_src() -> &'static dyn RandomSource {
195 RAND_SOURCE.get_or_init(|| Box::new(Box::new(DefaultRandomSource::new()))).as_ref()
196 }
197
198 #[inline]
199 #[cfg(all(target_arch = "arm", target_os = "none"))]
get_src() -> &'static dyn RandomSource200 fn get_src() -> &'static dyn RandomSource {
201 static RAND_SOURCE: DefaultRandomSource = DefaultRandomSource::default();
202 &RAND_SOURCE
203 }
204
205 /// Use randomly generated keys
206 #[inline]
new() -> RandomState207 pub fn new() -> RandomState {
208 let src = Self::get_src();
209 let fixed = src.get_fixed_seeds();
210 Self::from_keys(&fixed[0], &fixed[1], src.gen_hasher_seed())
211 }
212
213 /// Allows for supplying seeds, but each time it is called the resulting state will be different.
214 /// This is done using a static counter, so it can safely be used with a fixed keys.
215 #[inline]
generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState216 pub fn generate_with(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
217 let src = Self::get_src();
218 let fixed = src.get_fixed_seeds();
219 RandomState::from_keys(&fixed[0], &[k0, k1, k2, k3], src.gen_hasher_seed())
220 }
221
from_keys(a: &[u64; 4], b: &[u64; 4], c: usize) -> RandomState222 fn from_keys(a: &[u64; 4], b: &[u64; 4], c: usize) -> RandomState {
223 let &[k0, k1, k2, k3] = a;
224 let mut hasher = AHasher::from_random_state(&RandomState { k0, k1, k2, k3 });
225 hasher.write_usize(c);
226 let mix = |k: u64| {
227 let mut h = hasher.clone();
228 h.write_u64(k);
229 h.finish()
230 };
231 RandomState {
232 k0: mix(b[0]),
233 k1: mix(b[1]),
234 k2: mix(b[2]),
235 k3: mix(b[3]),
236 }
237 }
238
239 /// Internal. Used by Default.
240 #[inline]
with_fixed_keys() -> RandomState241 pub(crate) fn with_fixed_keys() -> RandomState {
242 let [k0, k1, k2, k3] = Self::get_src().get_fixed_seeds()[0];
243 RandomState { k0, k1, k2, k3 }
244 }
245
246 /// Allows for explicitly setting a seed to used.
247 ///
248 /// Note: This method does not require the provided seed to be strong.
249 #[inline]
with_seed(key: usize) -> RandomState250 pub fn with_seed(key: usize) -> RandomState {
251 let fixed = Self::get_src().get_fixed_seeds();
252 RandomState::from_keys(&fixed[0], &fixed[1], key)
253 }
254
255 /// Allows for explicitly setting the seeds to used.
256 ///
257 /// Note: This method is robust against 0s being passed for one or more of the parameters
258 /// or the same value being passed for more than one parameter.
259 #[inline]
with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState260 pub const fn with_seeds(k0: u64, k1: u64, k2: u64, k3: u64) -> RandomState {
261 RandomState { k0: k0 ^ PI2[0], k1: k1 ^ PI2[1], k2: k2 ^ PI2[2], k3: k3 ^ PI2[3] }
262 }
263 }
264
265 impl Default for RandomState {
266 #[inline]
default() -> Self267 fn default() -> Self {
268 Self::new()
269 }
270 }
271
272 impl BuildHasher for RandomState {
273 type Hasher = AHasher;
274
275 /// Constructs a new [AHasher] with keys based on this [RandomState] object.
276 /// This means that two different [RandomState]s will will generate
277 /// [AHasher]s that will return different hashcodes, but [Hasher]s created from the same [BuildHasher]
278 /// will generate the same hashes for the same input data.
279 ///
280 /// # Examples
281 ///
282 /// ```
283 /// use ahash::{AHasher, RandomState};
284 /// use std::hash::{Hasher, BuildHasher};
285 ///
286 /// let build_hasher = RandomState::new();
287 /// let mut hasher_1 = build_hasher.build_hasher();
288 /// let mut hasher_2 = build_hasher.build_hasher();
289 ///
290 /// hasher_1.write_u32(1234);
291 /// hasher_2.write_u32(1234);
292 ///
293 /// assert_eq!(hasher_1.finish(), hasher_2.finish());
294 ///
295 /// let other_build_hasher = RandomState::new();
296 /// let mut different_hasher = other_build_hasher.build_hasher();
297 /// different_hasher.write_u32(1234);
298 /// assert_ne!(different_hasher.finish(), hasher_1.finish());
299 /// ```
300 /// [Hasher]: std::hash::Hasher
301 /// [BuildHasher]: std::hash::BuildHasher
302 /// [HashMap]: std::collections::HashMap
303 #[inline]
build_hasher(&self) -> AHasher304 fn build_hasher(&self) -> AHasher {
305 AHasher::from_random_state(self)
306 }
307 }
308
309 #[cfg(feature = "specialize")]
310 impl BuildHasherExt for RandomState {
311 #[inline]
hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64312 fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
313 let mut hasher = AHasherU64 {
314 buffer: self.k0,
315 pad: self.k1,
316 };
317 value.hash(&mut hasher);
318 hasher.finish()
319 }
320
321 #[inline]
hash_as_fixed_length<T: Hash + ?Sized>(&self, value: &T) -> u64322 fn hash_as_fixed_length<T: Hash + ?Sized>(&self, value: &T) -> u64 {
323 let mut hasher = AHasherFixed(self.build_hasher());
324 value.hash(&mut hasher);
325 hasher.finish()
326 }
327
328 #[inline]
hash_as_str<T: Hash + ?Sized>(&self, value: &T) -> u64329 fn hash_as_str<T: Hash + ?Sized>(&self, value: &T) -> u64 {
330 let mut hasher = AHasherStr(self.build_hasher());
331 value.hash(&mut hasher);
332 hasher.finish()
333 }
334 }
335
336 #[cfg(test)]
337 mod test {
338 use super::*;
339
340 #[test]
test_unique()341 fn test_unique() {
342 let a = RandomState::new();
343 let b = RandomState::new();
344 assert_ne!(a.build_hasher().finish(), b.build_hasher().finish());
345 }
346
347 #[cfg(all(feature = "runtime-rng", not(all(feature = "compile-time-rng", test))))]
348 #[test]
test_not_pi()349 fn test_not_pi() {
350 assert_ne!(PI, RandomState::get_src().get_fixed_seeds()[0]);
351 }
352
353 #[cfg(all(feature = "compile-time-rng", any(not(feature = "runtime-rng"), test)))]
354 #[test]
test_not_pi_const()355 fn test_not_pi_const() {
356 assert_ne!(PI, RandomState::get_src().get_fixed_seeds()[0]);
357 }
358
359 #[cfg(all(not(feature = "runtime-rng"), not(feature = "compile-time-rng")))]
360 #[test]
test_pi()361 fn test_pi() {
362 assert_eq!(PI, RandomState::get_src().get_fixed_seeds()[0]);
363 }
364
365 #[test]
test_with_seeds_const()366 fn test_with_seeds_const() {
367 const _CONST_RANDOM_STATE: RandomState = RandomState::with_seeds(17, 19, 21, 23);
368 }
369 }
370