From 373c7fe14950fb232defdd05ca02a34afc862ac8 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sat, 10 Feb 2024 21:53:54 -0800 Subject: [PATCH 01/19] Bump version to 0.8.8 (#205) Signed-off-by: Tom Kaitchuck --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2d65614..32b7f0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ahash" -version = "0.8.7" +version = "0.8.8" authors = ["Tom Kaitchuck "] license = "MIT OR Apache-2.0" description = "A non-cryptographic hash function using AES-NI for high performance" From 5aeb6729d1edcb3aa8c8f397f8563ad294dc3d64 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sat, 10 Feb 2024 22:11:14 -0800 Subject: [PATCH 02/19] Make unit test endian independent (#206) Signed-off-by: Tom Kaitchuck --- src/operations.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/operations.rs b/src/operations.rs index a420587..98d8075 100644 --- a/src/operations.rs +++ b/src/operations.rs @@ -364,9 +364,11 @@ mod test { #[test] fn test_add_length() { - let mut enc = (u64::MAX as u128) << 64 | 50; + let enc : [u64; 2] = [50, u64::MAX]; + let mut enc : u128 = enc.convert(); add_in_length(&mut enc, u64::MAX); - assert_eq!(enc >> 64, u64::MAX as u128); - assert_eq!(enc as u64, 49); + let enc : [u64; 2] = enc.convert(); + assert_eq!(enc[1], u64::MAX); + assert_eq!(enc[0], 49); } } From 9f052f84857a98c40deb63624bae526ec265cd92 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Mon, 19 Feb 2024 17:24:35 -0800 Subject: [PATCH 03/19] Issue #207: Rollback MSRV bump (#208) Signed-off-by: Tom Kaitchuck --- Cargo.toml | 2 +- src/lib.rs | 2 +- src/operations.rs | 5 +++-- src/random_state.rs | 2 +- tests/bench.rs | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 32b7f0f..01faf1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ edition = "2018" readme = "README.md" build = "./build.rs" exclude = ["/smhasher", "/benchmark_tools"] -rust-version = "1.72.0" +rust-version = "1.60.0" [lib] name = "ahash" diff --git a/src/lib.rs b/src/lib.rs index 500f430..653c3bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,7 +108,7 @@ mod fallback_hash; cfg_if::cfg_if! { if #[cfg(any( all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), ))] { mod aes_hash; diff --git a/src/operations.rs b/src/operations.rs index 98d8075..5ec0337 100644 --- a/src/operations.rs +++ b/src/operations.rs @@ -1,4 +1,5 @@ use crate::convert::*; +#[allow(unused)] use zerocopy::transmute; ///This constant comes from Kunth's prng (Empirically it works better than those from splitmix32). @@ -111,7 +112,7 @@ pub(crate) fn aesenc(value: u128, xor: u128) -> u128 { } #[cfg(any( - all(target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), ))] #[allow(unused)] @@ -141,7 +142,7 @@ pub(crate) fn aesdec(value: u128, xor: u128) -> u128 { } #[cfg(any( - all(target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), ))] #[allow(unused)] diff --git a/src/random_state.rs b/src/random_state.rs index 3db8396..3ee629f 100644 --- a/src/random_state.rs +++ b/src/random_state.rs @@ -2,7 +2,7 @@ use core::hash::Hash; cfg_if::cfg_if! { if #[cfg(any( all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), ))] { use crate::aes_hash::*; diff --git a/tests/bench.rs b/tests/bench.rs index e038ba4..59287ab 100644 --- a/tests/bench.rs +++ b/tests/bench.rs @@ -14,7 +14,7 @@ const AHASH_IMPL: &str = if cfg!(any( target_feature = "aes", not(miri), ), - all(target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), all( feature = "nightly-arm-aes", target_arch = "arm", From 3ac041a80c454e02e6720758d678166015c4882e Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Tue, 27 Feb 2024 10:32:01 -0800 Subject: [PATCH 04/19] Issue 210: Strengthen fastpath for u64 hashes (#211) * Strengthen fastpath for u64 hashes --------- Signed-off-by: Tom Kaitchuck --- Cargo.toml | 3 ++- src/aes_hash.rs | 1 + src/fallback_hash.rs | 2 +- src/lib.rs | 1 - src/operations.rs | 1 - tests/map_tests.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 01faf1e..d80856b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,8 +97,9 @@ fnv = "1.0.5" fxhash = "0.2.1" hex = "0.4.2" rand = "0.8.5" +pcg-mwc = "0.2.1" serde_json = "1.0.59" -hashbrown = "0.12.3" +hashbrown = "0.14.3" [package.metadata.docs.rs] rustc-args = ["-C", "target-feature=+aes"] diff --git a/src/aes_hash.rs b/src/aes_hash.rs index 0b9a1d4..7ad9af7 100644 --- a/src/aes_hash.rs +++ b/src/aes_hash.rs @@ -252,6 +252,7 @@ impl Hasher for AHasherU64 { #[inline] fn write_u64(&mut self, i: u64) { self.buffer = folded_multiply(i ^ self.buffer, MULTIPLE); + self.pad = self.pad.wrapping_add(i); } #[inline] diff --git a/src/fallback_hash.rs b/src/fallback_hash.rs index f78074d..eb55479 100644 --- a/src/fallback_hash.rs +++ b/src/fallback_hash.rs @@ -237,6 +237,7 @@ impl Hasher for AHasherU64 { #[inline] fn write_u64(&mut self, i: u64) { self.buffer = folded_multiply(i ^ self.buffer, MULTIPLE); + self.pad = self.pad.wrapping_add(i); } #[inline] @@ -341,7 +342,6 @@ impl Hasher for AHasherStr { #[cfg(test)] mod tests { - use crate::convert::Convert; use crate::fallback_hash::*; #[test] diff --git a/src/lib.rs b/src/lib.rs index 653c3bc..69fb2ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -319,7 +319,6 @@ mod test { use crate::specialize::CallHasher; use crate::*; use std::collections::HashMap; - use std::hash::Hash; #[test] fn test_ahash_alias_map_construction() { diff --git a/src/operations.rs b/src/operations.rs index 5ec0337..4509c52 100644 --- a/src/operations.rs +++ b/src/operations.rs @@ -184,7 +184,6 @@ pub(crate) fn add_in_length(enc: &mut u128, len: u64) { #[cfg(test)] mod test { use super::*; - use crate::convert::Convert; // This is code to search for the shuffle constant // diff --git a/tests/map_tests.rs b/tests/map_tests.rs index bdf37d8..7849f4a 100644 --- a/tests/map_tests.rs +++ b/tests/map_tests.rs @@ -225,6 +225,56 @@ fn test_key_ref() { assert!(m.contains(&b"hello"[..])); } +#[cfg(feature = "std")] +#[test] +fn test_byte_dist() { + use rand::{SeedableRng, Rng, RngCore}; + use pcg_mwc::Mwc256XXA64; + + let mut r = Mwc256XXA64::seed_from_u64(0xe786_c22b_119c_1479); + let mut lowest = 2.541; + let mut highest = 2.541; + for _round in 0..100 { + let mut table: [bool; 256 * 8] = [false; 256 * 8]; + let hasher = RandomState::with_seeds(r.gen(), r.gen(), r.gen(), r.gen()); + for i in 0..128 { + let mut keys: [u8; 8] = hasher.hash_one(i as u64).to_ne_bytes(); + //let mut keys = r.next_u64().to_ne_bytes(); //This is a control to test assert sensitivity. + for idx in 0..8 { + while table[idx * 256 + keys[idx] as usize] { + keys[idx] = keys[idx].wrapping_add(1); + } + table[idx * 256 + keys[idx] as usize] = true; + } + } + + for idx in 0..8 { + let mut len = 0; + let mut total_len = 0; + let mut num_seq = 0; + for i in 0..256 { + if table[idx * 256 + i] { + len += 1; + } else if len != 0 { + num_seq += 1; + total_len += len; + len = 0; + } + } + let mean = total_len as f32 / num_seq as f32; + println!("Mean sequence length = {}", mean); + if mean > highest { + highest = mean; + } + if mean < lowest { + lowest = mean; + } + } + } + assert!(lowest > 1.9, "Lowest = {}", lowest); + assert!(highest < 3.9, "Highest = {}", highest); +} + fn ahash_vec(b: &Vec) -> u64 { let mut total: u64 = 0; From e7481cd4a356ba2ee36110e5c7d768c391f99dee Mon Sep 17 00:00:00 2001 From: Yuchen Wu Date: Thu, 29 Feb 2024 23:37:54 -0800 Subject: [PATCH 05/19] Make sure that the hash of referenced specialize types is the same (#213) 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] { From 7778357cf9a684b06aaada11788ac1cd796dc5b8 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 3 Mar 2024 09:23:31 -0800 Subject: [PATCH 06/19] Issue 210: Fast path hardening take 2 (#215) * Reverts the basic fast path for u64 to be two folded multiplies. Signed-off-by: Tom Kaitchuck --- Cargo.toml | 3 ++- compare/Cargo.toml | 3 +++ compare/src/main.rs | 32 ++++++++++++++++++++++++++++++++ src/aes_hash.rs | 4 +--- src/fallback_hash.rs | 11 +++++------ src/hash_quality_test.rs | 18 ++++++++++-------- src/random_state.rs | 4 ++-- tests/bench.rs | 2 +- tests/map_tests.rs | 2 +- 9 files changed, 57 insertions(+), 22 deletions(-) create mode 100644 compare/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index d80856b..8fa6bcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ahash" -version = "0.8.8" +version = "0.8.10" authors = ["Tom Kaitchuck "] license = "MIT OR Apache-2.0" description = "A non-cryptographic hash function using AES-NI for high performance" @@ -100,6 +100,7 @@ rand = "0.8.5" pcg-mwc = "0.2.1" serde_json = "1.0.59" hashbrown = "0.14.3" +smallvec = "1.13.1" [package.metadata.docs.rs] rustc-args = ["-C", "target-feature=+aes"] diff --git a/compare/Cargo.toml b/compare/Cargo.toml index 88bdf19..e638ae6 100644 --- a/compare/Cargo.toml +++ b/compare/Cargo.toml @@ -29,6 +29,9 @@ codegen-units = 1 [dependencies] ahash = { path = "../", default-features = false } +pcg-mwc = "0.2.1" +rand = "0.8.5" +rand_core = "0.6.4" [dev-dependencies] criterion = "0.3.3" diff --git a/compare/src/main.rs b/compare/src/main.rs new file mode 100644 index 0000000..b2a0b98 --- /dev/null +++ b/compare/src/main.rs @@ -0,0 +1,32 @@ +use std::io::Error; +use std::fs::File; +use std::io::Write; +use pcg_mwc::Mwc256XXA64; +use ahash::RandomState; +use std::io::BufWriter; +use std::path::Path; +use rand_core::SeedableRng; +use rand::Rng; +use std::time::Instant; + + +fn main() -> Result<(), Error> { + let mut r = Mwc256XXA64::seed_from_u64(0xe786_c22b_119c_1479); + + let path = Path::new("hash_output"); + + let mut file = BufWriter::new(File::create(path)?); + let hasher = RandomState::with_seeds(r.gen(), r.gen(), r.gen(), r.gen()); + let start = Instant::now(); + let mut sum: u64 = 0; + for i in 0..i32::MAX { + let value = hasher.hash_one(i as u64); + sum = sum.wrapping_add(value); + let value: [u8; 8] = value.to_ne_bytes(); + file.write_all(&value)?; + } + let elapsed = start.elapsed(); + println!("Sum {} Elapsed time: {}", sum, elapsed.as_millis()); + file.flush()?; + Ok(()) +} \ No newline at end of file diff --git a/src/aes_hash.rs b/src/aes_hash.rs index 7ad9af7..daf3ae4 100644 --- a/src/aes_hash.rs +++ b/src/aes_hash.rs @@ -225,8 +225,7 @@ pub(crate) struct AHasherU64 { impl Hasher for AHasherU64 { #[inline] fn finish(&self) -> u64 { - let rot = (self.pad & 63) as u32; - self.buffer.rotate_left(rot) + folded_multiply(self.buffer, self.pad) } #[inline] @@ -252,7 +251,6 @@ impl Hasher for AHasherU64 { #[inline] fn write_u64(&mut self, i: u64) { self.buffer = folded_multiply(i ^ self.buffer, MULTIPLE); - self.pad = self.pad.wrapping_add(i); } #[inline] diff --git a/src/fallback_hash.rs b/src/fallback_hash.rs index eb55479..bc5cbfe 100644 --- a/src/fallback_hash.rs +++ b/src/fallback_hash.rs @@ -56,8 +56,8 @@ impl AHasher { #[allow(dead_code)] // Is not called if non-fallback hash is used. pub(crate) fn from_random_state(rand_state: &RandomState) -> AHasher { AHasher { - buffer: rand_state.k0, - pad: rand_state.k1, + buffer: rand_state.k1, + pad: rand_state.k0, extra_keys: [rand_state.k2, rand_state.k3], } } @@ -117,7 +117,7 @@ impl AHasher { #[inline] #[cfg(feature = "specialize")] fn short_finish(&self) -> u64 { - self.buffer.wrapping_add(self.pad) + folded_multiply(self.buffer, self.pad) } } @@ -210,8 +210,8 @@ pub(crate) struct AHasherU64 { impl Hasher for AHasherU64 { #[inline] fn finish(&self) -> u64 { - let rot = (self.pad & 63) as u32; - self.buffer.rotate_left(rot) + folded_multiply(self.buffer, self.pad) + //self.buffer } #[inline] @@ -237,7 +237,6 @@ impl Hasher for AHasherU64 { #[inline] fn write_u64(&mut self, i: u64) { self.buffer = folded_multiply(i ^ self.buffer, MULTIPLE); - self.pad = self.pad.wrapping_add(i); } #[inline] diff --git a/src/hash_quality_test.rs b/src/hash_quality_test.rs index 43f2aeb..f2fab16 100644 --- a/src/hash_quality_test.rs +++ b/src/hash_quality_test.rs @@ -338,22 +338,24 @@ fn test_length_extension(hasher: impl Fn(u128, u128) -> T) { } fn test_sparse(hasher: impl Fn() -> T) { + use smallvec::SmallVec; + let mut buf = [0u8; 256]; let mut hashes = HashMap::new(); - for idx_1 in 0..256 { - for idx_2 in idx_1 + 1..256 { + for idx_1 in 0..255_u8 { + for idx_2 in idx_1 + 1..=255_u8 { for value_1 in [1, 2, 4, 8, 16, 32, 64, 128] { for value_2 in [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 16, 17, 18, 20, 24, 31, 32, 33, 48, 64, 96, 127, 128, 129, 192, 254, 255, ] { - buf[idx_1] = value_1; - buf[idx_2] = value_2; + buf[idx_1 as usize] = value_1; + buf[idx_2 as usize] = value_2; let hash_value = hash_with(&buf, &mut hasher()); - let keys = hashes.entry(hash_value).or_insert(Vec::new()); - keys.push((idx_1, value_1, idx_2, value_2)); - buf[idx_1] = 0; - buf[idx_2] = 0; + let keys = hashes.entry(hash_value).or_insert(SmallVec::<[[u8; 4]; 1]>::new()); + keys.push([idx_1, value_1, idx_2, value_2]); + buf[idx_1 as usize] = 0; + buf[idx_2 as usize] = 0; } } } diff --git a/src/random_state.rs b/src/random_state.rs index 3ee629f..46a39ab 100644 --- a/src/random_state.rs +++ b/src/random_state.rs @@ -470,8 +470,8 @@ impl BuildHasherExt for RandomState { #[inline] fn hash_as_u64(&self, value: &T) -> u64 { let mut hasher = AHasherU64 { - buffer: self.k0, - pad: self.k1, + buffer: self.k1, + pad: self.k0, }; value.hash(&mut hasher); hasher.finish() diff --git a/tests/bench.rs b/tests/bench.rs index 59287ab..2d000c0 100644 --- a/tests/bench.rs +++ b/tests/bench.rs @@ -75,7 +75,7 @@ fn gen_strings() -> Vec { macro_rules! bench_inputs { ($group:ident, $hash:ident) => { // Number of iterations per batch should be high enough to hide timing overhead. - let size = BatchSize::NumIterations(2_000); + let size = BatchSize::NumIterations(50_000); let mut rng = rand::thread_rng(); $group.bench_function("u8", |b| b.iter_batched(|| rng.gen::(), |v| $hash(&v), size)); diff --git a/tests/map_tests.rs b/tests/map_tests.rs index 7849f4a..97fdbee 100644 --- a/tests/map_tests.rs +++ b/tests/map_tests.rs @@ -238,7 +238,7 @@ fn test_byte_dist() { let mut table: [bool; 256 * 8] = [false; 256 * 8]; let hasher = RandomState::with_seeds(r.gen(), r.gen(), r.gen(), r.gen()); for i in 0..128 { - let mut keys: [u8; 8] = hasher.hash_one(i as u64).to_ne_bytes(); + let mut keys: [u8; 8] = hasher.hash_one((i as u64) << 30).to_ne_bytes(); //let mut keys = r.next_u64().to_ne_bytes(); //This is a control to test assert sensitivity. for idx in 0..8 { while table[idx * 256 + keys[idx] as usize] { From f1bafebefd11e4c42ce68363c5f86b77ab4a49d1 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 28 Apr 2024 11:53:30 -0700 Subject: [PATCH 07/19] Apply flag to test also Signed-off-by: Tom Kaitchuck --- src/hash_quality_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hash_quality_test.rs b/src/hash_quality_test.rs index f2fab16..f85e18a 100644 --- a/src/hash_quality_test.rs +++ b/src/hash_quality_test.rs @@ -441,7 +441,7 @@ mod fallback_tests { ///Basic sanity tests of the cypto properties of aHash. #[cfg(any( all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "aes", not(miri)), - all(target_arch = "aarch64", target_feature = "aes", not(miri)), + all(feature = "nightly-arm-aes", target_arch = "aarch64", target_feature = "aes", not(miri)), all(feature = "nightly-arm-aes", target_arch = "arm", target_feature = "aes", not(miri)), ))] #[cfg(test)] From 7d5c661a74b12d5bc5448b0b83fdb429190db1a3 Mon Sep 17 00:00:00 2001 From: Paolo Barbolini Date: Sun, 28 Apr 2024 21:24:40 +0200 Subject: [PATCH 08/19] Replace atomic-polyfill with portable-atomic (#234) --- Cargo.toml | 4 ++-- src/random_state.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8fa6bcf..f4bdf53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ compile-time-rng = ["const-random"] no-rng = [] # in case this is being used on an architecture lacking core::sync::atomic::AtomicUsize and friends -atomic-polyfill = [ "dep:atomic-polyfill", "once_cell/atomic-polyfill"] +atomic-polyfill = [ "dep:portable-atomic", "once_cell/critical-section"] # Nightly-only support for AES intrinsics on 32-bit ARM nightly-arm-aes = [] @@ -82,7 +82,7 @@ version_check = "0.9.4" const-random = { version = "0.1.17", optional = true } serde = { version = "1.0.117", optional = true } cfg-if = "1.0" -atomic-polyfill = { version="1.0.1", optional=true} +portable-atomic = { version = "1.0.0", optional = true } getrandom = { version = "0.2.7", optional = true } zerocopy = { version = "0.7.31", default-features = false, features = ["simd"] } diff --git a/src/random_state.rs b/src/random_state.rs index 46a39ab..096e0a7 100644 --- a/src/random_state.rs +++ b/src/random_state.rs @@ -24,7 +24,7 @@ cfg_if::cfg_if! { } #[cfg(feature = "atomic-polyfill")] -use atomic_polyfill as atomic; +use portable_atomic as atomic; #[cfg(not(feature = "atomic-polyfill"))] use core::sync::atomic; From 600485197167533f3ff88767a729bbdab8fefc3e Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 24 Apr 2025 16:06:37 -0700 Subject: [PATCH 09/19] Remove unused conversions. (#257) This is dead code. --- src/convert.rs | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/src/convert.rs b/src/convert.rs index 712eae1..7357d1a 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -19,47 +19,19 @@ macro_rules! convert { }; } -convert!([u128; 4], [u64; 8]); -convert!([u128; 4], [u32; 16]); -convert!([u128; 4], [u16; 32]); convert!([u128; 4], [u8; 64]); convert!([u128; 2], [u64; 4]); -convert!([u128; 2], [u32; 8]); -convert!([u128; 2], [u16; 16]); convert!([u128; 2], [u8; 32]); convert!(u128, [u64; 2]); -convert!(u128, [u32; 4]); -convert!(u128, [u16; 8]); convert!(u128, [u8; 16]); -convert!([u64; 8], [u32; 16]); -convert!([u64; 8], [u16; 32]); -convert!([u64; 8], [u8; 64]); -convert!([u64; 4], [u32; 8]); -convert!([u64; 4], [u16; 16]); -convert!([u64; 4], [u8; 32]); convert!([u64; 2], [u32; 4]); -convert!([u64; 2], [u16; 8]); +#[cfg(test)] convert!([u64; 2], [u8; 16]); -convert!([u32; 4], [u16; 8]); -convert!([u32; 4], [u8; 16]); -convert!([u16; 8], [u8; 16]); -convert!(u64, [u32; 2]); -convert!(u64, [u16; 4]); convert!(u64, [u8; 8]); -convert!([u32; 2], [u16; 4]); -convert!([u32; 2], [u8; 8]); -convert!(u32, [u16; 2]); convert!(u32, [u8; 4]); -convert!([u16; 2], [u8; 4]); convert!(u16, [u8; 2]); convert!([[u64; 4]; 2], [u8; 64]); -convert!([f64; 2], [u8; 16]); -convert!([f32; 4], [u8; 16]); -convert!(f64, [u8; 8]); -convert!([f32; 2], [u8; 8]); -convert!(f32, [u8; 4]); - macro_rules! as_array { ($input:expr, $len:expr) => {{ { From 7c42342dcedb0f9edd399406582d9aeb3a4bdb1d Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 24 Apr 2025 16:08:52 -0700 Subject: [PATCH 10/19] Remove duplicate tests. (#254) This test is in src/lib.rs, and seems to have been duplicated, perhaps unintentionally, when these files were split out from lib.rs in commit 3a0deeb7143539e85595dbb812331aac5b069dd8. --- src/aes_hash.rs | 7 ------- src/fallback_hash.rs | 7 ------- 2 files changed, 14 deletions(-) diff --git a/src/aes_hash.rs b/src/aes_hash.rs index daf3ae4..cb2c0ad 100644 --- a/src/aes_hash.rs +++ b/src/aes_hash.rs @@ -423,11 +423,4 @@ mod tests { let result2: [u8; 16] = result2.convert(); assert_ne!(hex::encode(result), hex::encode(result2)); } - - #[test] - fn test_conversion() { - let input: &[u8] = "dddddddd".as_bytes(); - let bytes: u64 = as_array!(input, 8).convert(); - assert_eq!(bytes, 0x6464646464646464); - } } diff --git a/src/fallback_hash.rs b/src/fallback_hash.rs index bc5cbfe..b53c7ea 100644 --- a/src/fallback_hash.rs +++ b/src/fallback_hash.rs @@ -357,11 +357,4 @@ mod tests { let result2: [u8; 8] = result2.convert(); assert_ne!(hex::encode(result), hex::encode(result2)); } - - #[test] - fn test_conversion() { - let input: &[u8] = "dddddddd".as_bytes(); - let bytes: u64 = as_array!(input, 8).convert(); - assert_eq!(bytes, 0x6464646464646464); - } } From 08a2be6a883e5b511b85abee7d13941650039bea Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Fri, 25 Apr 2025 01:12:35 +0200 Subject: [PATCH 11/19] Bump `getrandom` to `0.3.1` (#251) * Bump `getrandom` to `0.3.1` * Update src/random_state.rs Co-authored-by: Paolo Barbolini --- Cargo.toml | 2 +- src/random_state.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f4bdf53..74c2edf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,7 @@ const-random = { version = "0.1.17", optional = true } serde = { version = "1.0.117", optional = true } cfg-if = "1.0" portable-atomic = { version = "1.0.0", optional = true } -getrandom = { version = "0.2.7", optional = true } +getrandom = { version = "0.3.1", optional = true } zerocopy = { version = "0.7.31", default-features = false, features = ["simd"] } [target.'cfg(not(all(target_arch = "arm", target_os = "none")))'.dependencies] diff --git a/src/random_state.rs b/src/random_state.rs index 096e0a7..878315e 100644 --- a/src/random_state.rs +++ b/src/random_state.rs @@ -79,7 +79,7 @@ cfg_if::cfg_if! { SEEDS.get_or_init(|| { let mut result: [u8; 64] = [0; 64]; - getrandom::getrandom(&mut result).expect("getrandom::getrandom() failed."); + getrandom::fill(&mut result).expect("getrandom::fill() failed."); Box::new(result.convert()) }) } @@ -394,16 +394,16 @@ impl BuildHasher for RandomState { ``` use ahash::{AHasher, RandomState}; use std::hash::{Hasher, BuildHasher}; - + let build_hasher = RandomState::new(); let mut hasher_1 = build_hasher.build_hasher(); let mut hasher_2 = build_hasher.build_hasher(); - + hasher_1.write_u32(1234); hasher_2.write_u32(1234); - + assert_eq!(hasher_1.finish(), hasher_2.finish()); - + let other_build_hasher = RandomState::new(); let mut different_hasher = other_build_hasher.build_hasher(); different_hasher.write_u32(1234); From b55cd03e7897b488f3622aa91ced4b33995d1521 Mon Sep 17 00:00:00 2001 From: Shablone <20610621+Shablone@users.noreply.github.com> Date: Fri, 25 Apr 2025 01:13:06 +0200 Subject: [PATCH 12/19] Fix some typos (#250) Co-authored-by: Elias <1elias.bauer@gmail.com> --- src/hash_map.rs | 8 ++++---- src/hash_set.rs | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hash_map.rs b/src/hash_map.rs index 2b6fbdc..ac30776 100644 --- a/src/hash_map.rs +++ b/src/hash_map.rs @@ -51,13 +51,13 @@ impl Into> for AHashMap { } impl AHashMap { - /// This crates a hashmap using [RandomState::new] which obtains its keys from [RandomSource]. + /// This creates a hashmap using [RandomState::new] which obtains its keys from [RandomSource]. /// See the documentation in [RandomSource] for notes about key strength. pub fn new() -> Self { AHashMap(HashMap::with_hasher(RandomState::new())) } - /// This crates a hashmap with the specified capacity using [RandomState::new]. + /// This creates a hashmap with the specified capacity using [RandomState::new]. /// See the documentation in [RandomSource] for notes about key strength. pub fn with_capacity(capacity: usize) -> Self { AHashMap(HashMap::with_capacity_and_hasher(capacity, RandomState::new())) @@ -348,7 +348,7 @@ impl FromIterator<(K, V)> for AHashMap where K: Eq + Hash, { - /// This crates a hashmap from the provided iterator using [RandomState::new]. + /// This creates a hashmap from the provided iterator using [RandomState::new]. /// See the documentation in [RandomSource] for notes about key strength. fn from_iter>(iter: T) -> Self { let mut inner = HashMap::with_hasher(RandomState::new()); @@ -404,7 +404,7 @@ where } } -/// NOTE: For safety this trait impl is only available available if either of the flags `runtime-rng` (on by default) or +/// NOTE: For safety this trait impl is only available if either of the flags `runtime-rng` (on by default) or /// `compile-time-rng` are enabled. This is to prevent weakly keyed maps from being accidentally created. Instead one of /// constructors for [RandomState] must be used. #[cfg(any(feature = "compile-time-rng", feature = "runtime-rng", feature = "no-rng"))] diff --git a/src/hash_set.rs b/src/hash_set.rs index d03bef5..e12d8b0 100644 --- a/src/hash_set.rs +++ b/src/hash_set.rs @@ -47,13 +47,13 @@ impl Into> for AHashSet { } impl AHashSet { - /// This crates a hashset using [RandomState::new]. + /// This creates a hashset using [RandomState::new]. /// See the documentation in [RandomSource] for notes about key strength. pub fn new() -> Self { AHashSet(HashSet::with_hasher(RandomState::new())) } - /// This crates a hashset with the specified capacity using [RandomState::new]. + /// This craetes a hashset with the specified capacity using [RandomState::new]. /// See the documentation in [RandomSource] for notes about key strength. pub fn with_capacity(capacity: usize) -> Self { AHashSet(HashSet::with_capacity_and_hasher(capacity, RandomState::new())) @@ -245,7 +245,7 @@ impl FromIterator for AHashSet where T: Eq + Hash, { - /// This crates a hashset from the provided iterator using [RandomState::new]. + /// This creates a hashset from the provided iterator using [RandomState::new]. /// See the documentation in [RandomSource] for notes about key strength. #[inline] fn from_iter>(iter: I) -> AHashSet { From 3a54154e997a0810f246c59d058c789abf161dce Mon Sep 17 00:00:00 2001 From: Joshua Black Date: Thu, 24 Apr 2025 18:16:09 -0500 Subject: [PATCH 13/19] Spelling error in lib.rs (#244) --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7b88324..96ce9a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ map.insert(12, 34); The above requires a source of randomness to generate keys for the hashmap. By default this obtained from the OS. It is also possible to have randomness supplied via the `compile-time-rng` flag, or manually. -### If randomess is not available +### If randomness is not available [AHasher::default()] can be used to hash using fixed keys. This works with [BuildHasherDefault](std::hash::BuildHasherDefault). For example: From a5ada48ccdcea77a0704aba95d9940b87c2900d9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 3 May 2025 21:49:08 -0700 Subject: [PATCH 14/19] Make CallHasher specific to ahash::RandomState (#261) * Make CallHasher specific to ahash::RandomState * Eliminate BuildHasherExt trait * Rename argument of CallHasher to random_state --- src/lib.rs | 61 ++------------------------------------------- src/random_state.rs | 13 +++------- src/specialize.rs | 37 +++++++++++++-------------- 3 files changed, 24 insertions(+), 87 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 96ce9a4..d937dca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -146,8 +146,6 @@ mod specialize; pub use crate::random_state::RandomState; use core::hash::BuildHasher; -use core::hash::Hash; -use core::hash::Hasher; #[cfg(feature = "std")] /// A convenience trait that can be used together with the type aliases defined to @@ -248,63 +246,6 @@ impl Default for AHasher { } } -/// Used for specialization. (Sealed) -pub(crate) trait BuildHasherExt: BuildHasher { - #[doc(hidden)] - fn hash_as_u64(&self, value: &T) -> u64; - - #[doc(hidden)] - fn hash_as_fixed_length(&self, value: &T) -> u64; - - #[doc(hidden)] - fn hash_as_str(&self, value: &T) -> u64; -} - -impl BuildHasherExt for B { - #[inline] - #[cfg(feature = "specialize")] - default fn hash_as_u64(&self, value: &T) -> u64 { - let mut hasher = self.build_hasher(); - value.hash(&mut hasher); - hasher.finish() - } - #[inline] - #[cfg(not(feature = "specialize"))] - fn hash_as_u64(&self, value: &T) -> u64 { - let mut hasher = self.build_hasher(); - value.hash(&mut hasher); - hasher.finish() - } - #[inline] - #[cfg(feature = "specialize")] - default fn hash_as_fixed_length(&self, value: &T) -> u64 { - let mut hasher = self.build_hasher(); - value.hash(&mut hasher); - hasher.finish() - } - #[inline] - #[cfg(not(feature = "specialize"))] - fn hash_as_fixed_length(&self, value: &T) -> u64 { - let mut hasher = self.build_hasher(); - value.hash(&mut hasher); - hasher.finish() - } - #[inline] - #[cfg(feature = "specialize")] - default fn hash_as_str(&self, value: &T) -> u64 { - let mut hasher = self.build_hasher(); - value.hash(&mut hasher); - hasher.finish() - } - #[inline] - #[cfg(not(feature = "specialize"))] - fn hash_as_str(&self, value: &T) -> u64 { - let mut hasher = self.build_hasher(); - value.hash(&mut hasher); - hasher.finish() - } -} - // #[inline(never)] // #[doc(hidden)] // pub fn hash_test(input: &[u8]) -> u64 { @@ -318,6 +259,8 @@ mod test { use crate::convert::Convert; use crate::specialize::CallHasher; use crate::*; + use core::hash::Hash; + use core::hash::Hasher; use std::collections::HashMap; #[test] diff --git a/src/random_state.rs b/src/random_state.rs index 878315e..114f6f9 100644 --- a/src/random_state.rs +++ b/src/random_state.rs @@ -10,11 +10,6 @@ cfg_if::cfg_if! { use crate::fallback_hash::*; } } -cfg_if::cfg_if! { - if #[cfg(feature = "specialize")]{ - use crate::BuildHasherExt; - } -} cfg_if::cfg_if! { if #[cfg(feature = "std")] { extern crate std as alloc; @@ -466,9 +461,9 @@ impl BuildHasher for RandomState { } #[cfg(feature = "specialize")] -impl BuildHasherExt for RandomState { +impl RandomState { #[inline] - fn hash_as_u64(&self, value: &T) -> u64 { + pub(crate) fn hash_as_u64(&self, value: &T) -> u64 { let mut hasher = AHasherU64 { buffer: self.k1, pad: self.k0, @@ -478,14 +473,14 @@ impl BuildHasherExt for RandomState { } #[inline] - fn hash_as_fixed_length(&self, value: &T) -> u64 { + pub(crate) fn hash_as_fixed_length(&self, value: &T) -> u64 { let mut hasher = AHasherFixed(self.build_hasher()); value.hash(&mut hasher); hasher.finish() } #[inline] - fn hash_as_str(&self, value: &T) -> u64 { + pub(crate) fn hash_as_str(&self, value: &T) -> u64 { let mut hasher = AHasherStr(self.build_hasher()); value.hash(&mut hasher); hasher.finish() diff --git a/src/specialize.rs b/src/specialize.rs index acdf7d1..09ed89d 100644 --- a/src/specialize.rs +++ b/src/specialize.rs @@ -1,3 +1,4 @@ +use crate::RandomState; use core::hash::BuildHasher; use core::hash::Hash; use core::hash::Hasher; @@ -7,8 +8,6 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std as alloc; -#[cfg(feature = "specialize")] -use crate::BuildHasherExt; #[cfg(feature = "specialize")] use alloc::string::String; #[cfg(feature = "specialize")] @@ -18,7 +17,7 @@ use alloc::vec::Vec; /// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash /// for a specific type. So this may be faster for primitive types. pub(crate) trait CallHasher { - fn get_hash(value: &H, build_hasher: &B) -> u64; + fn get_hash(value: &H, random_state: &RandomState) -> u64; } #[cfg(not(feature = "specialize"))] @@ -27,8 +26,8 @@ where T: Hash + ?Sized, { #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - let mut hasher = build_hasher.build_hasher(); + fn get_hash(value: &H, random_state: &RandomState) -> u64 { + let mut hasher = random_state.build_hasher(); value.hash(&mut hasher); hasher.finish() } @@ -40,8 +39,8 @@ where T: Hash + ?Sized, { #[inline] - default fn get_hash(value: &H, build_hasher: &B) -> u64 { - let mut hasher = build_hasher.build_hasher(); + default fn get_hash(value: &H, random_state: &RandomState) -> u64 { + let mut hasher = random_state.build_hasher(); value.hash(&mut hasher); hasher.finish() } @@ -52,8 +51,8 @@ macro_rules! call_hasher_impl_u64 { #[cfg(feature = "specialize")] impl CallHasher for $typ { #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_u64(value) + fn get_hash(value: &H, random_state: &RandomState) -> u64 { + random_state.hash_as_u64(value) } } }; @@ -80,8 +79,8 @@ macro_rules! call_hasher_impl_fixed_length{ #[cfg(feature = "specialize")] impl CallHasher for $typ { #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_fixed_length(value) + fn get_hash(value: &H, random_state: &RandomState) -> u64 { + random_state.hash_as_fixed_length(value) } } }; @@ -99,32 +98,32 @@ call_hasher_impl_fixed_length!(&isize); #[cfg(feature = "specialize")] impl CallHasher for [u8] { #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_str(value) + fn get_hash(value: &H, random_state: &RandomState) -> u64 { + random_state.hash_as_str(value) } } #[cfg(feature = "specialize")] impl CallHasher for Vec { #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_str(value) + fn get_hash(value: &H, random_state: &RandomState) -> u64 { + random_state.hash_as_str(value) } } #[cfg(feature = "specialize")] impl CallHasher for str { #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_str(value) + fn get_hash(value: &H, random_state: &RandomState) -> u64 { + random_state.hash_as_str(value) } } #[cfg(all(feature = "specialize"))] impl CallHasher for String { #[inline] - fn get_hash(value: &H, build_hasher: &B) -> u64 { - build_hasher.hash_as_str(value) + fn get_hash(value: &H, random_state: &RandomState) -> u64 { + random_state.hash_as_str(value) } } From 0b8488e1e133dbd6e18948246975c3f03ecb06eb Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Sat, 3 May 2025 22:15:05 -0700 Subject: [PATCH 15/19] Use built-in conversions for primitive <-> byte array conversions. (#256) Avoid transmutes. This is a step towards removing all transmutes from convert.rs. --- src/convert.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/convert.rs b/src/convert.rs index 7357d1a..4169f5f 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -19,17 +19,34 @@ macro_rules! convert { }; } +macro_rules! convert_primitive_bytes { + ($a:ty, $b:ty) => { + impl Convert<$b> for $a { + #[inline(always)] + fn convert(self) -> $b { + self.to_ne_bytes() + } + } + impl Convert<$a> for $b { + #[inline(always)] + fn convert(self) -> $a { + <$a>::from_ne_bytes(self) + } + } + }; +} + convert!([u128; 4], [u8; 64]); convert!([u128; 2], [u64; 4]); convert!([u128; 2], [u8; 32]); convert!(u128, [u64; 2]); -convert!(u128, [u8; 16]); +convert_primitive_bytes!(u128, [u8; 16]); convert!([u64; 2], [u32; 4]); #[cfg(test)] convert!([u64; 2], [u8; 16]); -convert!(u64, [u8; 8]); -convert!(u32, [u8; 4]); -convert!(u16, [u8; 2]); +convert_primitive_bytes!(u64, [u8; 8]); +convert_primitive_bytes!(u32, [u8; 4]); +convert_primitive_bytes!(u16, [u8; 2]); convert!([[u64; 4]; 2], [u8; 64]); macro_rules! as_array { From 222812634b888edb69fb400ccee113ae71234d76 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sat, 3 May 2025 23:12:05 -0700 Subject: [PATCH 16/19] Update no_std test (#264) * Update no_std test --- no_std_test/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/no_std_test/src/main.rs b/no_std_test/src/main.rs index d4bcced..f4b8748 100644 --- a/no_std_test/src/main.rs +++ b/no_std_test/src/main.rs @@ -1,8 +1,8 @@ //! This is a bare-bones `no-std` application that hashes a value and //! uses the hash value as the return value. - +#![no_main] #![no_std] -#![feature(alloc_error_handler, start, core_intrinsics, lang_items, link_cfg)] +#![feature(alloc_error_handler, core_intrinsics, lang_items)] #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; @@ -15,7 +15,7 @@ use core::hash::{Hash, Hasher}; #[link(name = "libcmt")] extern "C" {} -#[start] +#[no_mangle] fn main(_argc: isize, _argv: *const *const u8) -> isize { let mut h: ahash::AHasher = Default::default(); 42_i32.hash(&mut h); From 7dbeb5b7f26a2b83cab0112c73ee0f5cd163576a Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sat, 3 May 2025 23:42:00 -0700 Subject: [PATCH 17/19] chore: bump zero-copy (#265) A new version of zero-copy is available. Signed-off-by: Daniel Noland Co-authored-by: Daniel Noland --- Cargo.toml | 2 +- src/hash_quality_test.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 74c2edf..568554d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,7 @@ serde = { version = "1.0.117", optional = true } cfg-if = "1.0" portable-atomic = { version = "1.0.0", optional = true } getrandom = { version = "0.3.1", optional = true } -zerocopy = { version = "0.7.31", default-features = false, features = ["simd"] } +zerocopy = { version = "0.8.24", default-features = false, features = ["simd"] } [target.'cfg(not(all(target_arch = "arm", target_os = "none")))'.dependencies] once_cell = { version = "1.18.0", default-features = false, features = ["alloc"] } diff --git a/src/hash_quality_test.rs b/src/hash_quality_test.rs index f85e18a..a874100 100644 --- a/src/hash_quality_test.rs +++ b/src/hash_quality_test.rs @@ -70,8 +70,8 @@ fn test_no_full_collisions(gen_hash: impl Fn() -> T) { gen_combinations(&options, 7, Vec::new(), &mut combinations); let mut map: HashMap> = HashMap::new(); for combination in combinations { - use zerocopy::AsBytes; - let array = combination.as_slice().as_bytes().to_vec(); + use zerocopy::IntoBytes; + let array = combination.as_bytes().to_vec(); let mut hasher = gen_hash(); hasher.write(&array); let hash = hasher.finish(); From cc852e724a515926a1c2f14fd3680b69027c69d6 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 6 May 2025 10:10:33 -0700 Subject: [PATCH 18/19] Address unexpected_cfg lints. (#269) Replace `cfg(feature = "$X")` with `cfg($X)` for each undeclared feature X. Declare each such cfg in build.rs. This silences the warnings in recent toolchains. --- build.rs | 6 ++++-- src/aes_hash.rs | 14 +++++++------- src/fallback_hash.rs | 14 +++++++------- src/hash_quality_test.rs | 4 ++-- src/lib.rs | 2 +- src/operations.rs | 4 ++-- src/random_state.rs | 4 ++-- src/specialize.rs | 26 +++++++++++++------------- tests/bench.rs | 2 +- tests/map_tests.rs | 6 +++--- 10 files changed, 42 insertions(+), 40 deletions(-) diff --git a/build.rs b/build.rs index a136b36..f59538c 100644 --- a/build.rs +++ b/build.rs @@ -4,10 +4,12 @@ use std::env; fn main() { println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rustc-check-cfg=cfg(specialize)"); if let Some(true) = version_check::supports_feature("specialize") { - println!("cargo:rustc-cfg=feature=\"specialize\""); + println!("cargo:rustc-cfg=specialize"); } let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set"); + println!("cargo:rustc-check-cfg=cfg(folded_multiply)"); if arch.eq_ignore_ascii_case("x86_64") || arch.eq_ignore_ascii_case("aarch64") || arch.eq_ignore_ascii_case("mips64") @@ -15,6 +17,6 @@ fn main() { || arch.eq_ignore_ascii_case("riscv64gc") || arch.eq_ignore_ascii_case("s390x") { - println!("cargo:rustc-cfg=feature=\"folded_multiply\""); + println!("cargo:rustc-cfg=folded_multiply"); } } diff --git a/src/aes_hash.rs b/src/aes_hash.rs index cb2c0ad..312ea1d 100644 --- a/src/aes_hash.rs +++ b/src/aes_hash.rs @@ -94,7 +94,7 @@ impl AHasher { } #[inline] - #[cfg(feature = "specialize")] + #[cfg(specialize)] fn short_finish(&self) -> u64 { let combined = aesenc(self.sum, self.enc); let result: [u64; 2] = aesdec(combined, combined).convert(); @@ -214,14 +214,14 @@ impl Hasher for AHasher { } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] pub(crate) struct AHasherU64 { pub(crate) buffer: u64, pub(crate) pad: u64, } /// A specialized hasher for only primitives under 64 bits. -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl Hasher for AHasherU64 { #[inline] fn finish(&self) -> u64 { @@ -264,11 +264,11 @@ impl Hasher for AHasherU64 { } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] pub(crate) struct AHasherFixed(pub AHasher); /// A specialized hasher for fixed size primitives larger than 64 bits. -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl Hasher for AHasherFixed { #[inline] fn finish(&self) -> u64 { @@ -311,12 +311,12 @@ impl Hasher for AHasherFixed { } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] pub(crate) struct AHasherStr(pub AHasher); /// A specialized hasher for strings /// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec) -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl Hasher for AHasherStr { #[inline] fn finish(&self) -> u64 { diff --git a/src/fallback_hash.rs b/src/fallback_hash.rs index b53c7ea..9a2956d 100644 --- a/src/fallback_hash.rs +++ b/src/fallback_hash.rs @@ -115,7 +115,7 @@ impl AHasher { } #[inline] - #[cfg(feature = "specialize")] + #[cfg(specialize)] fn short_finish(&self) -> u64 { folded_multiply(self.buffer, self.pad) } @@ -199,14 +199,14 @@ impl Hasher for AHasher { } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] pub(crate) struct AHasherU64 { pub(crate) buffer: u64, pub(crate) pad: u64, } /// A specialized hasher for only primitives under 64 bits. -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl Hasher for AHasherU64 { #[inline] fn finish(&self) -> u64 { @@ -250,11 +250,11 @@ impl Hasher for AHasherU64 { } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] pub(crate) struct AHasherFixed(pub AHasher); /// A specialized hasher for fixed size primitives larger than 64 bits. -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl Hasher for AHasherFixed { #[inline] fn finish(&self) -> u64 { @@ -297,12 +297,12 @@ impl Hasher for AHasherFixed { } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] pub(crate) struct AHasherStr(pub AHasher); /// A specialized hasher for a single string /// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec) -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl Hasher for AHasherStr { #[inline] fn finish(&self) -> u64 { diff --git a/src/hash_quality_test.rs b/src/hash_quality_test.rs index a874100..a725380 100644 --- a/src/hash_quality_test.rs +++ b/src/hash_quality_test.rs @@ -407,7 +407,7 @@ mod fallback_tests { #[test] fn fallback_keys_affect_every_byte() { //For fallback second key is not used in every hash. - #[cfg(all(not(feature = "specialize"), feature = "folded_multiply"))] + #[cfg(all(not(specialize), folded_multiply))] test_keys_affect_every_byte(0, |a, b| AHasher::new_with_keys(a ^ b, a)); test_keys_affect_every_byte("", |a, b| AHasher::new_with_keys(a ^ b, a)); test_keys_affect_every_byte((0, 0), |a, b| AHasher::new_with_keys(a ^ b, a)); @@ -504,7 +504,7 @@ mod aes_tests { #[test] fn aes_keys_affect_every_byte() { - #[cfg(not(feature = "specialize"))] + #[cfg(not(specialize))] test_keys_affect_every_byte(0, AHasher::test_with_keys); test_keys_affect_every_byte("", AHasher::test_with_keys); test_keys_affect_every_byte((0, 0), AHasher::test_with_keys); diff --git a/src/lib.rs b/src/lib.rs index d937dca..826806b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,7 +97,7 @@ Note the import of [HashMapExt]. This is needed for the constructor. #![deny(clippy::correctness, clippy::complexity, clippy::perf)] #![allow(clippy::pedantic, clippy::cast_lossless, clippy::unreadable_literal)] #![cfg_attr(all(not(test), not(feature = "std")), no_std)] -#![cfg_attr(feature = "specialize", feature(min_specialization))] +#![cfg_attr(specialize, feature(min_specialization))] #![cfg_attr(feature = "nightly-arm-aes", feature(stdarch_arm_neon_intrinsics))] #[macro_use] diff --git a/src/operations.rs b/src/operations.rs index 4509c52..c426036 100644 --- a/src/operations.rs +++ b/src/operations.rs @@ -13,14 +13,14 @@ const SHUFFLE_MASK: u128 = 0x020a0700_0c01030e_050f0d08_06090b04_u128; //const SHUFFLE_MASK: u128 = 0x040A0700_030E0106_0D050F08_020B0C09_u128; #[inline(always)] -#[cfg(feature = "folded_multiply")] +#[cfg(folded_multiply)] pub(crate) const fn folded_multiply(s: u64, by: u64) -> u64 { let result = (s as u128).wrapping_mul(by as u128); ((result & 0xffff_ffff_ffff_ffff) as u64) ^ ((result >> 64) as u64) } #[inline(always)] -#[cfg(not(feature = "folded_multiply"))] +#[cfg(not(folded_multiply))] pub(crate) const fn folded_multiply(s: u64, by: u64) -> u64 { let b1 = s.wrapping_mul(by.swap_bytes()); let b2 = s.swap_bytes().wrapping_mul(!by); diff --git a/src/random_state.rs b/src/random_state.rs index 114f6f9..46edc2d 100644 --- a/src/random_state.rs +++ b/src/random_state.rs @@ -453,14 +453,14 @@ impl BuildHasher for RandomState { /// implementation of [`Hash`]. The way to create a combined hash of /// multiple values is to call [`Hash::hash`] multiple times using the same /// [`Hasher`], not to call this method repeatedly and combine the results. - #[cfg(feature = "specialize")] + #[cfg(specialize)] #[inline] fn hash_one(&self, x: T) -> u64 { RandomState::hash_one(self, x) } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl RandomState { #[inline] pub(crate) fn hash_as_u64(&self, value: &T) -> u64 { diff --git a/src/specialize.rs b/src/specialize.rs index 09ed89d..0ba76da 100644 --- a/src/specialize.rs +++ b/src/specialize.rs @@ -8,9 +8,9 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std as alloc; -#[cfg(feature = "specialize")] +#[cfg(specialize)] use alloc::string::String; -#[cfg(feature = "specialize")] +#[cfg(specialize)] use alloc::vec::Vec; /// Provides a way to get an optimized hasher for a given data type. @@ -20,7 +20,7 @@ pub(crate) trait CallHasher { fn get_hash(value: &H, random_state: &RandomState) -> u64; } -#[cfg(not(feature = "specialize"))] +#[cfg(not(specialize))] impl CallHasher for T where T: Hash + ?Sized, @@ -33,7 +33,7 @@ where } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl CallHasher for T where T: Hash + ?Sized, @@ -48,7 +48,7 @@ where macro_rules! call_hasher_impl_u64 { ($typ:ty) => { - #[cfg(feature = "specialize")] + #[cfg(specialize)] impl CallHasher for $typ { #[inline] fn get_hash(value: &H, random_state: &RandomState) -> u64 { @@ -76,7 +76,7 @@ call_hasher_impl_u64!(&i64); macro_rules! call_hasher_impl_fixed_length{ ($typ:ty) => { - #[cfg(feature = "specialize")] + #[cfg(specialize)] impl CallHasher for $typ { #[inline] fn get_hash(value: &H, random_state: &RandomState) -> u64 { @@ -95,7 +95,7 @@ call_hasher_impl_fixed_length!(&i128); call_hasher_impl_fixed_length!(&usize); call_hasher_impl_fixed_length!(&isize); -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl CallHasher for [u8] { #[inline] fn get_hash(value: &H, random_state: &RandomState) -> u64 { @@ -103,7 +103,7 @@ impl CallHasher for [u8] { } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl CallHasher for Vec { #[inline] fn get_hash(value: &H, random_state: &RandomState) -> u64 { @@ -111,7 +111,7 @@ impl CallHasher for Vec { } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl CallHasher for str { #[inline] fn get_hash(value: &H, random_state: &RandomState) -> u64 { @@ -119,7 +119,7 @@ impl CallHasher for str { } } -#[cfg(all(feature = "specialize"))] +#[cfg(all(specialize))] impl CallHasher for String { #[inline] fn get_hash(value: &H, random_state: &RandomState) -> u64 { @@ -133,7 +133,7 @@ mod test { use crate::*; #[test] - #[cfg(feature = "specialize")] + #[cfg(specialize)] pub fn test_specialized_invoked() { let build_hasher = RandomState::with_seeds(1, 2, 3, 4); let shortened = u64::get_hash(&0, &build_hasher); @@ -185,7 +185,7 @@ mod test { str::get_hash(&"test", &build_hasher), String::get_hash(&"test".to_string(), &build_hasher) ); - #[cfg(feature = "specialize")] + #[cfg(specialize)] assert_eq!( str::get_hash(&"test", &build_hasher), <[u8]>::get_hash("test".as_bytes(), &build_hasher) @@ -205,7 +205,7 @@ mod test { str::get_hash(&&"test", &build_hasher), String::get_hash(&"test".to_string(), &build_hasher) ); - #[cfg(feature = "specialize")] + #[cfg(specialize)] assert_eq!( str::get_hash(&&"test", &build_hasher), <[u8]>::get_hash(&"test".to_string().into_bytes(), &build_hasher) diff --git a/tests/bench.rs b/tests/bench.rs index 2d000c0..f0cc027 100644 --- a/tests/bench.rs +++ b/tests/bench.rs @@ -1,4 +1,4 @@ -#![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))] +#![cfg_attr(specialize, feature(build_hasher_simple_hash_one))] use ahash::{AHasher, RandomState}; use criterion::*; diff --git a/tests/map_tests.rs b/tests/map_tests.rs index 97fdbee..42edb57 100644 --- a/tests/map_tests.rs +++ b/tests/map_tests.rs @@ -1,4 +1,4 @@ -#![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))] +#![cfg_attr(specialize, feature(build_hasher_simple_hash_one))] use std::hash::{BuildHasher, Hash, Hasher}; @@ -151,13 +151,13 @@ fn check_for_collisions(build_hasher: &B, items: &[H], ); } -#[cfg(feature = "specialize")] +#[cfg(specialize)] #[allow(unused)] // False positive fn hash(b: &H, build_hasher: &B) -> u64 { build_hasher.hash_one(b) } -#[cfg(not(feature = "specialize"))] +#[cfg(not(specialize))] #[allow(unused)] // False positive fn hash(b: &H, build_hasher: &B) -> u64 { let mut hasher = build_hasher.build_hasher(); From c55f7e1bdd216d9c3fffc41f30c36336e19a9568 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Tue, 6 May 2025 10:15:52 -0700 Subject: [PATCH 19/19] Do not build broken doc test. (#267) This doctest cannot build successfully in recent toolchains because the function is inaccessible to it. Since it is a non-public API, not much is lost by disabling the doctest. --- src/aes_hash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/aes_hash.rs b/src/aes_hash.rs index 312ea1d..dd6f925 100644 --- a/src/aes_hash.rs +++ b/src/aes_hash.rs @@ -34,7 +34,7 @@ impl AHasher { /// /// # Example /// - /// ``` + /// ```no_build /// use std::hash::Hasher; /// use ahash::AHasher; ///