/rust/registry/src/index.crates.io-6f17d22bba15001f/ahash-0.8.12/src/lib.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! AHash is a high performance keyed hash function. |
2 | | //! |
3 | | //! It quickly provides a high quality hash where the result is not predictable without knowing the Key. |
4 | | //! AHash works with `HashMap` to hash keys, but without allowing for the possibility that an malicious user can |
5 | | //! induce a collision. |
6 | | //! |
7 | | //! # How aHash works |
8 | | //! |
9 | | //! When it is available aHash uses the hardware AES instructions to provide a keyed hash function. |
10 | | //! When it is not, aHash falls back on a slightly slower alternative algorithm. |
11 | | //! |
12 | | //! Because aHash does not have a fixed standard for its output, it is able to improve over time. |
13 | | //! But this also means that different computers or computers using different versions of ahash may observe different |
14 | | //! hash values for the same input. |
15 | | #![cfg_attr( |
16 | | all( |
17 | | feature = "std", |
18 | | any(feature = "compile-time-rng", feature = "runtime-rng", feature = "no-rng") |
19 | | ), |
20 | | doc = r##" |
21 | | # Basic Usage |
22 | | AHash provides an implementation of the [Hasher] trait. |
23 | | To construct a HashMap using aHash as its hasher do the following: |
24 | | ``` |
25 | | use ahash::{AHasher, RandomState}; |
26 | | use std::collections::HashMap; |
27 | | |
28 | | let mut map: HashMap<i32, i32, RandomState> = HashMap::default(); |
29 | | map.insert(12, 34); |
30 | | ``` |
31 | | |
32 | | ### Randomness |
33 | | |
34 | | The above requires a source of randomness to generate keys for the hashmap. By default this obtained from the OS. |
35 | | It is also possible to have randomness supplied via the `compile-time-rng` flag, or manually. |
36 | | |
37 | | ### If randomness is not available |
38 | | |
39 | | [AHasher::default()] can be used to hash using fixed keys. This works with |
40 | | [BuildHasherDefault](std::hash::BuildHasherDefault). For example: |
41 | | |
42 | | ``` |
43 | | use std::hash::BuildHasherDefault; |
44 | | use std::collections::HashMap; |
45 | | use ahash::AHasher; |
46 | | |
47 | | let mut m: HashMap<_, _, BuildHasherDefault<AHasher>> = HashMap::default(); |
48 | | # m.insert(12, 34); |
49 | | ``` |
50 | | It is also possible to instantiate [RandomState] directly: |
51 | | |
52 | | ``` |
53 | | use ahash::HashMap; |
54 | | use ahash::RandomState; |
55 | | |
56 | | let mut m = HashMap::with_hasher(RandomState::with_seed(42)); |
57 | | # m.insert(1, 2); |
58 | | ``` |
59 | | Or for uses besides a hashhmap: |
60 | | ``` |
61 | | use std::hash::BuildHasher; |
62 | | use ahash::RandomState; |
63 | | |
64 | | let hash_builder = RandomState::with_seed(42); |
65 | | let hash = hash_builder.hash_one("Some Data"); |
66 | | ``` |
67 | | There are several constructors for [RandomState] with different ways to supply seeds. |
68 | | |
69 | | # Convenience wrappers |
70 | | |
71 | | For convenience, both new-type wrappers and type aliases are provided. |
72 | | |
73 | | The new type wrappers are called called `AHashMap` and `AHashSet`. |
74 | | ``` |
75 | | use ahash::AHashMap; |
76 | | |
77 | | let mut map: AHashMap<i32, i32> = AHashMap::new(); |
78 | | map.insert(12, 34); |
79 | | ``` |
80 | | This avoids the need to type "RandomState". (For convenience `From`, `Into`, and `Deref` are provided). |
81 | | |
82 | | # Aliases |
83 | | |
84 | | For even less typing and better interop with existing libraries (such as rayon) which require a `std::collection::HashMap` , |
85 | | the type aliases [HashMap], [HashSet] are provided. |
86 | | |
87 | | ``` |
88 | | use ahash::{HashMap, HashMapExt}; |
89 | | |
90 | | let mut map: HashMap<i32, i32> = HashMap::new(); |
91 | | map.insert(12, 34); |
92 | | ``` |
93 | | Note the import of [HashMapExt]. This is needed for the constructor. |
94 | | |
95 | | "## |
96 | | )] |
97 | | #![deny(clippy::correctness, clippy::complexity, clippy::perf)] |
98 | | #![allow(clippy::pedantic, clippy::cast_lossless, clippy::unreadable_literal)] |
99 | | #![cfg_attr(all(not(test), not(feature = "std")), no_std)] |
100 | | #![cfg_attr(specialize, feature(min_specialization))] |
101 | | #![cfg_attr(feature = "nightly-arm-aes", feature(stdarch_arm_neon_intrinsics))] |
102 | | |
103 | | #[macro_use] |
104 | | mod convert; |
105 | | |
106 | | mod fallback_hash; |
107 | | |
108 | | cfg_if::cfg_if! { |
109 | | if #[cfg(any( |
110 | | all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), |
111 | | all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), |
112 | | all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), |
113 | | ))] { |
114 | | mod aes_hash; |
115 | | pub use crate::aes_hash::AHasher; |
116 | | } else { |
117 | | pub use crate::fallback_hash::AHasher; |
118 | | } |
119 | | } |
120 | | |
121 | | cfg_if::cfg_if! { |
122 | | if #[cfg(feature = "std")] { |
123 | | mod hash_map; |
124 | | mod hash_set; |
125 | | |
126 | | pub use crate::hash_map::AHashMap; |
127 | | pub use crate::hash_set::AHashSet; |
128 | | |
129 | | /// [Hasher]: std::hash::Hasher |
130 | | /// [HashMap]: std::collections::HashMap |
131 | | /// Type alias for [HashMap]<K, V, ahash::RandomState> |
132 | | pub type HashMap<K, V> = std::collections::HashMap<K, V, crate::RandomState>; |
133 | | |
134 | | /// Type alias for [HashSet]<K, ahash::RandomState> |
135 | | pub type HashSet<K> = std::collections::HashSet<K, crate::RandomState>; |
136 | | } |
137 | | } |
138 | | |
139 | | #[cfg(test)] |
140 | | mod hash_quality_test; |
141 | | |
142 | | mod operations; |
143 | | pub mod random_state; |
144 | | mod specialize; |
145 | | |
146 | | pub use crate::random_state::RandomState; |
147 | | |
148 | | use core::hash::BuildHasher; |
149 | | |
150 | | #[cfg(feature = "std")] |
151 | | /// A convenience trait that can be used together with the type aliases defined to |
152 | | /// get access to the `new()` and `with_capacity()` methods for the HashMap type alias. |
153 | | pub trait HashMapExt { |
154 | | /// Constructs a new HashMap |
155 | | fn new() -> Self; |
156 | | /// Constructs a new HashMap with a given initial capacity |
157 | | fn with_capacity(capacity: usize) -> Self; |
158 | | } |
159 | | |
160 | | #[cfg(feature = "std")] |
161 | | /// A convenience trait that can be used together with the type aliases defined to |
162 | | /// get access to the `new()` and `with_capacity()` methods for the HashSet type aliases. |
163 | | pub trait HashSetExt { |
164 | | /// Constructs a new HashSet |
165 | | fn new() -> Self; |
166 | | /// Constructs a new HashSet with a given initial capacity |
167 | | fn with_capacity(capacity: usize) -> Self; |
168 | | } |
169 | | |
170 | | #[cfg(feature = "std")] |
171 | | impl<K, V, S> HashMapExt for std::collections::HashMap<K, V, S> |
172 | | where |
173 | | S: BuildHasher + Default, |
174 | | { |
175 | 0 | fn new() -> Self { |
176 | 0 | std::collections::HashMap::with_hasher(S::default()) |
177 | 0 | } |
178 | | |
179 | 0 | fn with_capacity(capacity: usize) -> Self { |
180 | 0 | std::collections::HashMap::with_capacity_and_hasher(capacity, S::default()) |
181 | 0 | } |
182 | | } |
183 | | |
184 | | #[cfg(feature = "std")] |
185 | | impl<K, S> HashSetExt for std::collections::HashSet<K, S> |
186 | | where |
187 | | S: BuildHasher + Default, |
188 | | { |
189 | 0 | fn new() -> Self { |
190 | 0 | std::collections::HashSet::with_hasher(S::default()) |
191 | 0 | } |
192 | | |
193 | 0 | fn with_capacity(capacity: usize) -> Self { |
194 | 0 | std::collections::HashSet::with_capacity_and_hasher(capacity, S::default()) |
195 | 0 | } |
196 | | } |
197 | | |
198 | | /// Provides a default [Hasher] with fixed keys. |
199 | | /// This is typically used in conjunction with [BuildHasherDefault] to create |
200 | | /// [AHasher]s in order to hash the keys of the map. |
201 | | /// |
202 | | /// Generally it is preferable to use [RandomState] instead, so that different |
203 | | /// hashmaps will have different keys. However if fixed keys are desirable this |
204 | | /// may be used instead. |
205 | | /// |
206 | | /// # Example |
207 | | /// ``` |
208 | | /// use std::hash::BuildHasherDefault; |
209 | | /// use ahash::{AHasher, RandomState}; |
210 | | /// use std::collections::HashMap; |
211 | | /// |
212 | | /// let mut map: HashMap<i32, i32, BuildHasherDefault<AHasher>> = HashMap::default(); |
213 | | /// map.insert(12, 34); |
214 | | /// ``` |
215 | | /// |
216 | | /// [BuildHasherDefault]: std::hash::BuildHasherDefault |
217 | | /// [Hasher]: std::hash::Hasher |
218 | | /// [HashMap]: std::collections::HashMap |
219 | | impl Default for AHasher { |
220 | | /// Constructs a new [AHasher] with fixed keys. |
221 | | /// If `std` is enabled these will be generated upon first invocation. |
222 | | /// Otherwise if the `compile-time-rng`feature is enabled these will be generated at compile time. |
223 | | /// If neither of these features are available, hardcoded constants will be used. |
224 | | /// |
225 | | /// Because the values are fixed, different hashers will all hash elements the same way. |
226 | | /// This could make hash values predictable, if DOS attacks are a concern. If this behaviour is |
227 | | /// not required, it may be preferable to use [RandomState] instead. |
228 | | /// |
229 | | /// # Examples |
230 | | /// |
231 | | /// ``` |
232 | | /// use ahash::AHasher; |
233 | | /// use std::hash::Hasher; |
234 | | /// |
235 | | /// let mut hasher_1 = AHasher::default(); |
236 | | /// let mut hasher_2 = AHasher::default(); |
237 | | /// |
238 | | /// hasher_1.write_u32(1234); |
239 | | /// hasher_2.write_u32(1234); |
240 | | /// |
241 | | /// assert_eq!(hasher_1.finish(), hasher_2.finish()); |
242 | | /// ``` |
243 | | #[inline] |
244 | 0 | fn default() -> AHasher { |
245 | 0 | RandomState::with_fixed_keys().build_hasher() |
246 | 0 | } |
247 | | } |
248 | | |
249 | | // #[inline(never)] |
250 | | // #[doc(hidden)] |
251 | | // pub fn hash_test(input: &[u8]) -> u64 { |
252 | | // let a = RandomState::with_seeds(11, 22, 33, 44); |
253 | | // <[u8]>::get_hash(input, &a) |
254 | | // } |
255 | | |
256 | | #[cfg(feature = "std")] |
257 | | #[cfg(test)] |
258 | | mod test { |
259 | | use crate::convert::Convert; |
260 | | use crate::specialize::CallHasher; |
261 | | use crate::*; |
262 | | use core::hash::Hash; |
263 | | use core::hash::Hasher; |
264 | | use std::collections::HashMap; |
265 | | |
266 | | #[test] |
267 | | fn test_ahash_alias_map_construction() { |
268 | | let mut map = super::HashMap::with_capacity(1234); |
269 | | map.insert(1, "test"); |
270 | | } |
271 | | |
272 | | #[test] |
273 | | fn test_ahash_alias_set_construction() { |
274 | | let mut set = super::HashSet::with_capacity(1234); |
275 | | set.insert(1); |
276 | | } |
277 | | |
278 | | #[test] |
279 | | fn test_default_builder() { |
280 | | use core::hash::BuildHasherDefault; |
281 | | |
282 | | let mut map = HashMap::<u32, u64, BuildHasherDefault<AHasher>>::default(); |
283 | | map.insert(1, 3); |
284 | | } |
285 | | |
286 | | #[test] |
287 | | fn test_builder() { |
288 | | let mut map = HashMap::<u32, u64, RandomState>::default(); |
289 | | map.insert(1, 3); |
290 | | } |
291 | | |
292 | | #[test] |
293 | | fn test_conversion() { |
294 | | let input: &[u8] = b"dddddddd"; |
295 | | let bytes: u64 = as_array!(input, 8).convert(); |
296 | | assert_eq!(bytes, 0x6464646464646464); |
297 | | } |
298 | | |
299 | | #[test] |
300 | | fn test_non_zero() { |
301 | | let mut hasher1 = AHasher::new_with_keys(0, 0); |
302 | | let mut hasher2 = AHasher::new_with_keys(0, 0); |
303 | | "foo".hash(&mut hasher1); |
304 | | "bar".hash(&mut hasher2); |
305 | | assert_ne!(hasher1.finish(), 0); |
306 | | assert_ne!(hasher2.finish(), 0); |
307 | | assert_ne!(hasher1.finish(), hasher2.finish()); |
308 | | |
309 | | let mut hasher1 = AHasher::new_with_keys(0, 0); |
310 | | let mut hasher2 = AHasher::new_with_keys(0, 0); |
311 | | 3_u64.hash(&mut hasher1); |
312 | | 4_u64.hash(&mut hasher2); |
313 | | assert_ne!(hasher1.finish(), 0); |
314 | | assert_ne!(hasher2.finish(), 0); |
315 | | assert_ne!(hasher1.finish(), hasher2.finish()); |
316 | | } |
317 | | |
318 | | #[test] |
319 | | fn test_non_zero_specialized() { |
320 | | let hasher_build = RandomState::with_seeds(0, 0, 0, 0); |
321 | | |
322 | | let h1 = str::get_hash("foo", &hasher_build); |
323 | | let h2 = str::get_hash("bar", &hasher_build); |
324 | | assert_ne!(h1, 0); |
325 | | assert_ne!(h2, 0); |
326 | | assert_ne!(h1, h2); |
327 | | |
328 | | let h1 = u64::get_hash(&3_u64, &hasher_build); |
329 | | let h2 = u64::get_hash(&4_u64, &hasher_build); |
330 | | assert_ne!(h1, 0); |
331 | | assert_ne!(h2, 0); |
332 | | assert_ne!(h1, h2); |
333 | | } |
334 | | |
335 | | #[test] |
336 | | fn test_ahasher_construction() { |
337 | | let _ = AHasher::new_with_keys(1234, 5678); |
338 | | } |
339 | | |
340 | | #[test] |
341 | | fn test_specialize_reference_hash() { |
342 | | let hasher_build = RandomState::with_seeds(0, 0, 0, 0); |
343 | | let h1 = hasher_build.hash_one(1u64); |
344 | | let h2 = hasher_build.hash_one(&1u64); |
345 | | |
346 | | assert_eq!(h1, h2); |
347 | | |
348 | | let h1 = u64::get_hash(&1_u64, &hasher_build); |
349 | | let h2 = <&u64>::get_hash(&&1_u64, &hasher_build); |
350 | | |
351 | | assert_eq!(h1, h2); |
352 | | |
353 | | let h1 = hasher_build.hash_one(1u128); |
354 | | let h2 = hasher_build.hash_one(&1u128); |
355 | | |
356 | | assert_eq!(h1, h2); |
357 | | } |
358 | | } |