1 #[cfg(feature = "specialize")] 2 use crate::HasherExt; 3 use core::hash::Hash; 4 use core::hash::Hasher; 5 6 /// Provides a way to get an optimized hasher for a given data type. 7 /// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash 8 /// for a specific type. So this may be faster for primitive types. It does however consume the hasher in the process. 9 /// #Example 10 /// ``` 11 /// use std::hash::BuildHasher; 12 /// use ahash::RandomState; 13 /// use ahash::CallHasher; 14 /// 15 /// let hash_builder = RandomState::new(); 16 /// //... 17 /// let value = 17; 18 /// let hash = value.get_hash(hash_builder.build_hasher()); 19 /// ``` 20 pub trait CallHasher: Hash { get_hash<H: Hasher>(&self, hasher: H) -> u6421 fn get_hash<H: Hasher>(&self, hasher: H) -> u64; 22 } 23 24 #[cfg(not(feature = "specialize"))] 25 impl<T> CallHasher for T 26 where 27 T: Hash, 28 { 29 #[inline] get_hash<H: Hasher>(&self, mut hasher: H) -> u6430 fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 { 31 self.hash(&mut hasher); 32 hasher.finish() 33 } 34 } 35 36 #[cfg(feature = "specialize")] 37 impl<T> CallHasher for T 38 where 39 T: Hash, 40 { 41 #[inline] get_hash<H: Hasher>(&self, mut hasher: H) -> u6442 default fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 { 43 self.hash(&mut hasher); 44 hasher.finish() 45 } 46 } 47 48 macro_rules! call_hasher_impl { 49 ($typ:ty) => { 50 #[cfg(feature = "specialize")] 51 impl CallHasher for $typ { 52 #[inline] 53 fn get_hash<H: Hasher>(&self, hasher: H) -> u64 { 54 hasher.hash_u64(*self as u64) 55 } 56 } 57 }; 58 } 59 call_hasher_impl!(u8); 60 call_hasher_impl!(u16); 61 call_hasher_impl!(u32); 62 call_hasher_impl!(u64); 63 call_hasher_impl!(i8); 64 call_hasher_impl!(i16); 65 call_hasher_impl!(i32); 66 call_hasher_impl!(i64); 67 68 #[cfg(feature = "specialize")] 69 impl CallHasher for u128 { 70 #[inline] get_hash<H: Hasher>(&self, mut hasher: H) -> u6471 fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 { 72 hasher.write_u128(*self); 73 hasher.short_finish() 74 } 75 } 76 77 #[cfg(feature = "specialize")] 78 impl CallHasher for i128 { 79 #[inline] get_hash<H: Hasher>(&self, mut hasher: H) -> u6480 fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 { 81 hasher.write_u128(*self as u128); 82 hasher.short_finish() 83 } 84 } 85 86 #[cfg(feature = "specialize")] 87 impl CallHasher for [u8] { 88 #[inline] get_hash<H: Hasher>(&self, mut hasher: H) -> u6489 fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 { 90 hasher.write(self); 91 hasher.finish() 92 } 93 } 94 95 #[cfg(all(feature = "specialize", feature = "std"))] 96 impl CallHasher for Vec<u8> { 97 #[inline] get_hash<H: Hasher>(&self, mut hasher: H) -> u6498 fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 { 99 hasher.write(self); 100 hasher.finish() 101 } 102 } 103 104 #[cfg(feature = "specialize")] 105 impl CallHasher for str { 106 #[inline] get_hash<H: Hasher>(&self, mut hasher: H) -> u64107 fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 { 108 hasher.write(self.as_bytes()); 109 hasher.finish() 110 } 111 } 112 113 #[cfg(all(feature = "specialize", feature = "std"))] 114 impl CallHasher for String { 115 #[inline] get_hash<H: Hasher>(&self, mut hasher: H) -> u64116 fn get_hash<H: Hasher>(&self, mut hasher: H) -> u64 { 117 hasher.write(self.as_bytes()); 118 hasher.finish() 119 } 120 } 121 122 #[cfg(test)] 123 mod test { 124 use super::*; 125 use crate::*; 126 127 #[test] 128 #[cfg(feature = "specialize")] test_specialized_invoked()129 pub fn test_specialized_invoked() { 130 let shortened = 0_u64.get_hash(AHasher::new_with_keys(1, 2)); 131 let mut hasher = AHasher::new_with_keys(1, 2); 132 0_u64.hash(&mut hasher); 133 assert_ne!(hasher.finish(), shortened); 134 } 135 136 /// Tests that some non-trivial transformation takes place. 137 #[test] test_input_processed()138 pub fn test_input_processed() { 139 let hasher = || AHasher::new_with_keys(3, 2); 140 assert_ne!(0, 0_u64.get_hash(hasher())); 141 assert_ne!(1, 0_u64.get_hash(hasher())); 142 assert_ne!(2, 0_u64.get_hash(hasher())); 143 assert_ne!(3, 0_u64.get_hash(hasher())); 144 assert_ne!(4, 0_u64.get_hash(hasher())); 145 assert_ne!(5, 0_u64.get_hash(hasher())); 146 147 assert_ne!(0, 1_u64.get_hash(hasher())); 148 assert_ne!(1, 1_u64.get_hash(hasher())); 149 assert_ne!(2, 1_u64.get_hash(hasher())); 150 assert_ne!(3, 1_u64.get_hash(hasher())); 151 assert_ne!(4, 1_u64.get_hash(hasher())); 152 assert_ne!(5, 1_u64.get_hash(hasher())); 153 154 let xored = 0_u64.get_hash(hasher()) ^ 1_u64.get_hash(hasher()); 155 assert_ne!(0, xored); 156 assert_ne!(1, xored); 157 assert_ne!(2, xored); 158 assert_ne!(3, xored); 159 assert_ne!(4, xored); 160 assert_ne!(5, xored); 161 } 162 } 163