From 2234a81a5bbb48c0536eed7d5141e88bce71b2b3 Mon Sep 17 00:00:00 2001 From: Yuchen Wu Date: Wed, 28 Feb 2024 15:38:44 -0800 Subject: [PATCH] Make sure that the hash of referenced specialize types is the same In general users would expect the hash of &T is the same as the hash of T. This is the case in ahash unless the "specialize" feature is used. This change is a stop gap to make sure that the hash of the specialized types is the same whether reference is used or not. Note that this change still doesn't address doubly referenced types like &&u64. But hopefully it already covers most cases. --- src/lib.rs | 19 ++++++++++++ src/specialize.rs | 75 +++++++++++++++++++++++------------------------ 2 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 69fb2ca..7b88324 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -393,4 +393,23 @@ mod test { fn test_ahasher_construction() { let _ = AHasher::new_with_keys(1234, 5678); } + + #[test] + fn test_specialize_reference_hash() { + let hasher_build = RandomState::with_seeds(0, 0, 0, 0); + let h1 = hasher_build.hash_one(1u64); + let h2 = hasher_build.hash_one(&1u64); + + assert_eq!(h1, h2); + + let h1 = u64::get_hash(&1_u64, &hasher_build); + let h2 = <&u64>::get_hash(&&1_u64, &hasher_build); + + assert_eq!(h1, h2); + + let h1 = hasher_build.hash_one(1u128); + let h2 = hasher_build.hash_one(&1u128); + + assert_eq!(h1, h2); + } } diff --git a/src/specialize.rs b/src/specialize.rs index 05d335b..acdf7d1 100644 --- a/src/specialize.rs +++ b/src/specialize.rs @@ -47,7 +47,7 @@ where } } -macro_rules! call_hasher_impl { +macro_rules! call_hasher_impl_u64 { ($typ:ty) => { #[cfg(feature = "specialize")] impl CallHasher for $typ { @@ -58,46 +58,43 @@ macro_rules! call_hasher_impl { } }; } -call_hasher_impl!(u8); -call_hasher_impl!(u16); -call_hasher_impl!(u32); -call_hasher_impl!(u64); -call_hasher_impl!(i8); -call_hasher_impl!(i16); -call_hasher_impl!(i32); -call_hasher_impl!(i64); - -#[cfg(feature = "specialize")] -impl CallHasher for u128 { - #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_fixed_length(value) - } -} - -#[cfg(feature = "specialize")] -impl CallHasher for i128 { - #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_fixed_length(value) - } -} - -#[cfg(feature = "specialize")] -impl CallHasher for usize { - #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_fixed_length(value) - } +call_hasher_impl_u64!(u8); +call_hasher_impl_u64!(u16); +call_hasher_impl_u64!(u32); +call_hasher_impl_u64!(u64); +call_hasher_impl_u64!(i8); +call_hasher_impl_u64!(i16); +call_hasher_impl_u64!(i32); +call_hasher_impl_u64!(i64); +call_hasher_impl_u64!(&u8); +call_hasher_impl_u64!(&u16); +call_hasher_impl_u64!(&u32); +call_hasher_impl_u64!(&u64); +call_hasher_impl_u64!(&i8); +call_hasher_impl_u64!(&i16); +call_hasher_impl_u64!(&i32); +call_hasher_impl_u64!(&i64); + +macro_rules! call_hasher_impl_fixed_length{ + ($typ:ty) => { + #[cfg(feature = "specialize")] + impl CallHasher for $typ { + #[inline] + fn get_hash(value: &H, build_hasher: &B) -> u64 { + build_hasher.hash_as_fixed_length(value) + } + } + }; } -#[cfg(feature = "specialize")] -impl CallHasher for isize { - #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_fixed_length(value) - } -} +call_hasher_impl_fixed_length!(u128); +call_hasher_impl_fixed_length!(i128); +call_hasher_impl_fixed_length!(usize); +call_hasher_impl_fixed_length!(isize); +call_hasher_impl_fixed_length!(&u128); +call_hasher_impl_fixed_length!(&i128); +call_hasher_impl_fixed_length!(&usize); +call_hasher_impl_fixed_length!(&isize); #[cfg(feature = "specialize")] impl CallHasher for [u8] {