1#![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
22AHash provides an implementation of the [Hasher] trait.
23To construct a HashMap using aHash as its hasher do the following:
24```
25use ahash::{AHasher, RandomState};
26use std::collections::HashMap;
27
28let mut map: HashMap<i32, i32, RandomState> = HashMap::default();
29map.insert(12, 34);
30```
31
32### Randomness
33
34The above requires a source of randomness to generate keys for the hashmap. By default this obtained from the OS.
35It 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```
43use std::hash::BuildHasherDefault;
44use std::collections::HashMap;
45use ahash::AHasher;
46
47let mut m: HashMap<_, _, BuildHasherDefault<AHasher>> = HashMap::default();
48 # m.insert(12, 34);
49```
50It is also possible to instantiate [RandomState] directly:
51
52```
53use ahash::HashMap;
54use ahash::RandomState;
55
56let mut m = HashMap::with_hasher(RandomState::with_seed(42));
57 # m.insert(1, 2);
58```
59Or for uses besides a hashhmap:
60```
61use std::hash::BuildHasher;
62use ahash::RandomState;
63
64let hash_builder = RandomState::with_seed(42);
65let hash = hash_builder.hash_one("Some Data");
66```
67There are several constructors for [RandomState] with different ways to supply seeds.
68
69# Convenience wrappers
70
71For convenience, both new-type wrappers and type aliases are provided.
72
73The new type wrappers are called called `AHashMap` and `AHashSet`.
74```
75use ahash::AHashMap;
76
77let mut map: AHashMap<i32, i32> = AHashMap::new();
78map.insert(12, 34);
79```
80This avoids the need to type "RandomState". (For convenience `From`, `Into`, and `Deref` are provided).
81
82# Aliases
83
84For even less typing and better interop with existing libraries (such as rayon) which require a `std::collection::HashMap` ,
85the type aliases [HashMap], [HashSet] are provided.
86
87```
88use ahash::{HashMap, HashMapExt};
89
90let mut map: HashMap<i32, i32> = HashMap::new();
91map.insert(12, 34);
92```
93Note 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]
104mod convert;
105
106mod fallback_hash;
107
108cfg_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
121cfg_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 pub type HashMap<K, V> = std::collections::HashMap<K, V, crate::RandomState>;
133
134 pub type HashSet<K> = std::collections::HashSet<K, crate::RandomState>;
136 }
137}
138
139#[cfg(test)]
140mod hash_quality_test;
141
142mod operations;
143pub mod random_state;
144mod specialize;
145
146pub use crate::random_state::RandomState;
147
148use core::hash::BuildHasher;
149
150#[cfg(feature = "std")]
151pub trait HashMapExt {
154 fn new() -> Self;
156 fn with_capacity(capacity: usize) -> Self;
158}
159
160#[cfg(feature = "std")]
161pub trait HashSetExt {
164 fn new() -> Self;
166 fn with_capacity(capacity: usize) -> Self;
168}
169
170#[cfg(feature = "std")]
171impl<K, V, S> HashMapExt for std::collections::HashMap<K, V, S>
172where
173 S: BuildHasher + Default,
174{
175 fn new() -> Self {
176 std::collections::HashMap::with_hasher(S::default())
177 }
178
179 fn with_capacity(capacity: usize) -> Self {
180 std::collections::HashMap::with_capacity_and_hasher(capacity, S::default())
181 }
182}
183
184#[cfg(feature = "std")]
185impl<K, S> HashSetExt for std::collections::HashSet<K, S>
186where
187 S: BuildHasher + Default,
188{
189 fn new() -> Self {
190 std::collections::HashSet::with_hasher(S::default())
191 }
192
193 fn with_capacity(capacity: usize) -> Self {
194 std::collections::HashSet::with_capacity_and_hasher(capacity, S::default())
195 }
196}
197
198impl Default for AHasher {
220 #[inline]
244 fn default() -> AHasher {
245 RandomState::with_fixed_keys().build_hasher()
246 }
247}
248
249#[cfg(feature = "std")]
257#[cfg(test)]
258mod 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}