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