Skip to content

Commit

Permalink
Make sure that the hash of referenced specialize types is the same (#213
Browse files Browse the repository at this point in the history
)

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.
  • Loading branch information
eaufavor committed Mar 1, 2024
1 parent 3ac041a commit e7481cd
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 39 deletions.
19 changes: 19 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
75 changes: 36 additions & 39 deletions src/specialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<H: Hash + ?Sized, B: BuildHasher>(value: &H, build_hasher: &B) -> u64 {
build_hasher.hash_as_fixed_length(value)
}
}

#[cfg(feature = "specialize")]
impl CallHasher for i128 {
#[inline]
fn get_hash<H: Hash + ?Sized, B: BuildHasher>(value: &H, build_hasher: &B) -> u64 {
build_hasher.hash_as_fixed_length(value)
}
}

#[cfg(feature = "specialize")]
impl CallHasher for usize {
#[inline]
fn get_hash<H: Hash + ?Sized, B: BuildHasher>(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<H: Hash + ?Sized, B: BuildHasher>(value: &H, build_hasher: &B) -> u64 {
build_hasher.hash_as_fixed_length(value)
}
}
};
}

#[cfg(feature = "specialize")]
impl CallHasher for isize {
#[inline]
fn get_hash<H: Hash + ?Sized, B: BuildHasher>(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] {
Expand Down

0 comments on commit e7481cd

Please sign in to comment.