/rust/registry/src/index.crates.io-1949cf8c6b5b557f/ahash-0.8.12/src/specialize.rs
Line | Count | Source |
1 | | use crate::RandomState; |
2 | | use core::hash::BuildHasher; |
3 | | use core::hash::Hash; |
4 | | use core::hash::Hasher; |
5 | | |
6 | | #[cfg(not(feature = "std"))] |
7 | | extern crate alloc; |
8 | | #[cfg(feature = "std")] |
9 | | extern crate std as alloc; |
10 | | |
11 | | #[cfg(specialize)] |
12 | | use alloc::string::String; |
13 | | #[cfg(specialize)] |
14 | | use alloc::vec::Vec; |
15 | | |
16 | | /// Provides a way to get an optimized hasher for a given data type. |
17 | | /// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash |
18 | | /// for a specific type. So this may be faster for primitive types. |
19 | | pub(crate) trait CallHasher { |
20 | | fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64; |
21 | | } |
22 | | |
23 | | #[cfg(not(specialize))] |
24 | | impl<T> CallHasher for T |
25 | | where |
26 | | T: Hash + ?Sized, |
27 | | { |
28 | | #[inline] |
29 | | fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { |
30 | | let mut hasher = random_state.build_hasher(); |
31 | | value.hash(&mut hasher); |
32 | | hasher.finish() |
33 | | } |
34 | | } |
35 | | |
36 | | #[cfg(specialize)] |
37 | | impl<T> CallHasher for T |
38 | | where |
39 | | T: Hash + ?Sized, |
40 | | { |
41 | | #[inline] |
42 | 5.13M | default fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { |
43 | 5.13M | let mut hasher = random_state.build_hasher(); |
44 | 5.13M | value.hash(&mut hasher); |
45 | 5.13M | hasher.finish() |
46 | 5.13M | } <&str as ahash::specialize::CallHasher>::get_hash::<&str> Line | Count | Source | 42 | 249k | default fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { | 43 | 249k | let mut hasher = random_state.build_hasher(); | 44 | 249k | value.hash(&mut hasher); | 45 | 249k | hasher.finish() | 46 | 249k | } |
<&alloc::string::String as ahash::specialize::CallHasher>::get_hash::<&alloc::string::String> Line | Count | Source | 42 | 4.88M | default fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { | 43 | 4.88M | let mut hasher = random_state.build_hasher(); | 44 | 4.88M | value.hash(&mut hasher); | 45 | 4.88M | hasher.finish() | 46 | 4.88M | } |
Unexecuted instantiation: <_ as ahash::specialize::CallHasher>::get_hash::<_> |
47 | | } |
48 | | |
49 | | macro_rules! call_hasher_impl_u64 { |
50 | | ($typ:ty) => { |
51 | | #[cfg(specialize)] |
52 | | impl CallHasher for $typ { |
53 | | #[inline] |
54 | 0 | fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { |
55 | 0 | random_state.hash_as_u64(value) |
56 | 0 | } Unexecuted instantiation: <u8 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <u16 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <u32 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <u64 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <i8 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <i16 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <i32 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <i64 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&u8 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&u16 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&u32 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&u64 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&i8 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&i16 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&i32 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&i64 as ahash::specialize::CallHasher>::get_hash::<_> |
57 | | } |
58 | | }; |
59 | | } |
60 | | call_hasher_impl_u64!(u8); |
61 | | call_hasher_impl_u64!(u16); |
62 | | call_hasher_impl_u64!(u32); |
63 | | call_hasher_impl_u64!(u64); |
64 | | call_hasher_impl_u64!(i8); |
65 | | call_hasher_impl_u64!(i16); |
66 | | call_hasher_impl_u64!(i32); |
67 | | call_hasher_impl_u64!(i64); |
68 | | call_hasher_impl_u64!(&u8); |
69 | | call_hasher_impl_u64!(&u16); |
70 | | call_hasher_impl_u64!(&u32); |
71 | | call_hasher_impl_u64!(&u64); |
72 | | call_hasher_impl_u64!(&i8); |
73 | | call_hasher_impl_u64!(&i16); |
74 | | call_hasher_impl_u64!(&i32); |
75 | | call_hasher_impl_u64!(&i64); |
76 | | |
77 | | macro_rules! call_hasher_impl_fixed_length{ |
78 | | ($typ:ty) => { |
79 | | #[cfg(specialize)] |
80 | | impl CallHasher for $typ { |
81 | | #[inline] |
82 | 0 | fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { |
83 | 0 | random_state.hash_as_fixed_length(value) |
84 | 0 | } Unexecuted instantiation: <u128 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <i128 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <usize as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <isize as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&u128 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&i128 as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&usize as ahash::specialize::CallHasher>::get_hash::<_> Unexecuted instantiation: <&isize as ahash::specialize::CallHasher>::get_hash::<_> |
85 | | } |
86 | | }; |
87 | | } |
88 | | |
89 | | call_hasher_impl_fixed_length!(u128); |
90 | | call_hasher_impl_fixed_length!(i128); |
91 | | call_hasher_impl_fixed_length!(usize); |
92 | | call_hasher_impl_fixed_length!(isize); |
93 | | call_hasher_impl_fixed_length!(&u128); |
94 | | call_hasher_impl_fixed_length!(&i128); |
95 | | call_hasher_impl_fixed_length!(&usize); |
96 | | call_hasher_impl_fixed_length!(&isize); |
97 | | |
98 | | #[cfg(specialize)] |
99 | | impl CallHasher for [u8] { |
100 | | #[inline] |
101 | 0 | fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { |
102 | 0 | random_state.hash_as_str(value) |
103 | 0 | } |
104 | | } |
105 | | |
106 | | #[cfg(specialize)] |
107 | | impl CallHasher for Vec<u8> { |
108 | | #[inline] |
109 | 0 | fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { |
110 | 0 | random_state.hash_as_str(value) |
111 | 0 | } |
112 | | } |
113 | | |
114 | | #[cfg(specialize)] |
115 | | impl CallHasher for str { |
116 | | #[inline] |
117 | 0 | fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { |
118 | 0 | random_state.hash_as_str(value) |
119 | 0 | } |
120 | | } |
121 | | |
122 | | #[cfg(all(specialize))] |
123 | | impl CallHasher for String { |
124 | | #[inline] |
125 | 0 | fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 { |
126 | 0 | random_state.hash_as_str(value) |
127 | 0 | } |
128 | | } |
129 | | |
130 | | #[cfg(test)] |
131 | | mod test { |
132 | | use super::*; |
133 | | use crate::*; |
134 | | |
135 | | #[test] |
136 | | #[cfg(specialize)] |
137 | | pub fn test_specialized_invoked() { |
138 | | let build_hasher = RandomState::with_seeds(1, 2, 3, 4); |
139 | | let shortened = u64::get_hash(&0, &build_hasher); |
140 | | let mut hasher = AHasher::new_with_keys(1, 2); |
141 | | 0_u64.hash(&mut hasher); |
142 | | assert_ne!(hasher.finish(), shortened); |
143 | | } |
144 | | |
145 | | /// Tests that some non-trivial transformation takes place. |
146 | | #[test] |
147 | | pub fn test_input_processed() { |
148 | | let build_hasher = RandomState::with_seeds(2, 2, 2, 2); |
149 | | assert_ne!(0, u64::get_hash(&0, &build_hasher)); |
150 | | assert_ne!(1, u64::get_hash(&0, &build_hasher)); |
151 | | assert_ne!(2, u64::get_hash(&0, &build_hasher)); |
152 | | assert_ne!(3, u64::get_hash(&0, &build_hasher)); |
153 | | assert_ne!(4, u64::get_hash(&0, &build_hasher)); |
154 | | assert_ne!(5, u64::get_hash(&0, &build_hasher)); |
155 | | |
156 | | assert_ne!(0, u64::get_hash(&1, &build_hasher)); |
157 | | assert_ne!(1, u64::get_hash(&1, &build_hasher)); |
158 | | assert_ne!(2, u64::get_hash(&1, &build_hasher)); |
159 | | assert_ne!(3, u64::get_hash(&1, &build_hasher)); |
160 | | assert_ne!(4, u64::get_hash(&1, &build_hasher)); |
161 | | assert_ne!(5, u64::get_hash(&1, &build_hasher)); |
162 | | |
163 | | let xored = u64::get_hash(&0, &build_hasher) ^ u64::get_hash(&1, &build_hasher); |
164 | | assert_ne!(0, xored); |
165 | | assert_ne!(1, xored); |
166 | | assert_ne!(2, xored); |
167 | | assert_ne!(3, xored); |
168 | | assert_ne!(4, xored); |
169 | | assert_ne!(5, xored); |
170 | | } |
171 | | |
172 | | #[test] |
173 | | pub fn test_ref_independent() { |
174 | | let build_hasher = RandomState::with_seeds(1, 2, 3, 4); |
175 | | assert_eq!(u8::get_hash(&&1, &build_hasher), u8::get_hash(&1, &build_hasher)); |
176 | | assert_eq!(u16::get_hash(&&2, &build_hasher), u16::get_hash(&2, &build_hasher)); |
177 | | assert_eq!(u32::get_hash(&&3, &build_hasher), u32::get_hash(&3, &build_hasher)); |
178 | | assert_eq!(u64::get_hash(&&4, &build_hasher), u64::get_hash(&4, &build_hasher)); |
179 | | assert_eq!(u128::get_hash(&&5, &build_hasher), u128::get_hash(&5, &build_hasher)); |
180 | | assert_eq!( |
181 | | str::get_hash(&"test", &build_hasher), |
182 | | str::get_hash("test", &build_hasher) |
183 | | ); |
184 | | assert_eq!( |
185 | | str::get_hash(&"test", &build_hasher), |
186 | | String::get_hash(&"test".to_string(), &build_hasher) |
187 | | ); |
188 | | #[cfg(specialize)] |
189 | | assert_eq!( |
190 | | str::get_hash(&"test", &build_hasher), |
191 | | <[u8]>::get_hash("test".as_bytes(), &build_hasher) |
192 | | ); |
193 | | |
194 | | let build_hasher = RandomState::with_seeds(10, 20, 30, 40); |
195 | | assert_eq!(u8::get_hash(&&&1, &build_hasher), u8::get_hash(&1, &build_hasher)); |
196 | | assert_eq!(u16::get_hash(&&&2, &build_hasher), u16::get_hash(&2, &build_hasher)); |
197 | | assert_eq!(u32::get_hash(&&&3, &build_hasher), u32::get_hash(&3, &build_hasher)); |
198 | | assert_eq!(u64::get_hash(&&&4, &build_hasher), u64::get_hash(&4, &build_hasher)); |
199 | | assert_eq!(u128::get_hash(&&&5, &build_hasher), u128::get_hash(&5, &build_hasher)); |
200 | | assert_eq!( |
201 | | str::get_hash(&&"test", &build_hasher), |
202 | | str::get_hash("test", &build_hasher) |
203 | | ); |
204 | | assert_eq!( |
205 | | str::get_hash(&&"test", &build_hasher), |
206 | | String::get_hash(&"test".to_string(), &build_hasher) |
207 | | ); |
208 | | #[cfg(specialize)] |
209 | | assert_eq!( |
210 | | str::get_hash(&&"test", &build_hasher), |
211 | | <[u8]>::get_hash(&"test".to_string().into_bytes(), &build_hasher) |
212 | | ); |
213 | | } |
214 | | } |