From 6be06a691c859b3a5243adf774dc71ef68baab25 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Tue, 24 Oct 2023 18:14:29 -0700 Subject: [PATCH 01/14] Update zerocopy to 0.7.14 for new license (#177) (#178) Signed-off-by: Tom Kaitchuck --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b340522..aea0d44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ahash" -version = "0.8.5" +version = "0.8.6" authors = ["Tom Kaitchuck "] license = "MIT OR Apache-2.0" description = "A non-cryptographic hash function using AES-NI for high performance" @@ -80,7 +80,7 @@ serde = { version = "1.0.117", optional = true } cfg-if = "1.0" atomic-polyfill = { version="1.0.1", optional=true} getrandom = { version = "0.2.7", optional = true } -zerocopy = { version = "0.7.0", default-features = false, features = ["simd"] } +zerocopy = { version = "0.7.14", default-features = false, features = ["simd"] } [target.'cfg(not(all(target_arch = "arm", target_os = "none")))'.dependencies] once_cell = { version = "1.13.1", default-features = false, features = ["unstable", "alloc"] } From 96d5524a0ac1d730160065f8e3118563f35de0e8 Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Tue, 2 Jan 2024 18:07:04 +0100 Subject: [PATCH 02/14] Fix some typos (#192) --- compare/readme.md | 4 ++-- src/hash_quality_test.rs | 24 ++++++++++++------------ src/lib.rs | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compare/readme.md b/compare/readme.md index 58146e5..e7a6c53 100644 --- a/compare/readme.md +++ b/compare/readme.md @@ -25,7 +25,7 @@ Even the fallback algorithm is in the top 5 in terms of throughput, beating out aHash is the fastest non-trivial hasher implementation in Rust. Below is a comparison with 10 other popular hashing algorithms. -![Hasher perfromance](https://docs.google.com/spreadsheets/d/e/2PACX-1vSK7Li2nS-Bur9arAYF9IfT37MP-ohAe1v19lZu5fd9MajI1fSveLAQZyEie4Ea9k5-SWHTff7nL2DW/pubchart?oid=1323618938&format=image) +![Hasher performance](https://docs.google.com/spreadsheets/d/e/2PACX-1vSK7Li2nS-Bur9arAYF9IfT37MP-ohAe1v19lZu5fd9MajI1fSveLAQZyEie4Ea9k5-SWHTff7nL2DW/pubchart?oid=1323618938&format=image) ## DOS resistance @@ -120,4 +120,4 @@ Similarly, wyHash is targeted at hashmaps. WyHash is quite fast, but is not DOS There are fixed strings which when encountered caused the internal state to reset. This makes wyHash trivial to attack. -AHash outperforms wyHash across all input sizes, regardless of which CPU instructions are available. \ No newline at end of file +AHash outperforms wyHash across all input sizes, regardless of which CPU instructions are available. diff --git a/src/hash_quality_test.rs b/src/hash_quality_test.rs index 4f6091a..43f2aeb 100644 --- a/src/hash_quality_test.rs +++ b/src/hash_quality_test.rs @@ -108,13 +108,13 @@ fn test_keys_change_output(constructor: impl Fn(u128, u128) -> T) { fn test_input_affect_every_byte(constructor: impl Fn(u128, u128) -> T) { let base = hash_with(&0, constructor(0, 0)); for shift in 0..16 { - let mut alternitives = vec![]; + let mut alternatives = vec![]; for v in 0..256 { let input = (v as u128) << (shift * 8); let hasher = constructor(0, 0); - alternitives.push(hash_with(&input, hasher)); + alternatives.push(hash_with(&input, hasher)); } - assert_each_byte_differs(shift, base, alternitives); + assert_each_byte_differs(shift, base, alternatives); } } @@ -122,26 +122,26 @@ fn test_input_affect_every_byte(constructor: impl Fn(u128, u128) -> T fn test_keys_affect_every_byte(item: H, constructor: impl Fn(u128, u128) -> T) { let base = hash_with(&item, constructor(0, 0)); for shift in 0..16 { - let mut alternitives1 = vec![]; - let mut alternitives2 = vec![]; + let mut alternatives1 = vec![]; + let mut alternatives2 = vec![]; for v in 0..256 { let input = (v as u128) << (shift * 8); let hasher1 = constructor(input, 0); let hasher2 = constructor(0, input); let h1 = hash_with(&item, hasher1); let h2 = hash_with(&item, hasher2); - alternitives1.push(h1); - alternitives2.push(h2); + alternatives1.push(h1); + alternatives2.push(h2); } - assert_each_byte_differs(shift, base, alternitives1); - assert_each_byte_differs(shift, base, alternitives2); + assert_each_byte_differs(shift, base, alternatives1); + assert_each_byte_differs(shift, base, alternatives2); } } -fn assert_each_byte_differs(num: u64, base: u64, alternitives: Vec) { +fn assert_each_byte_differs(num: u64, base: u64, alternatives: Vec) { let mut changed_bits = 0_u64; - for alternitive in alternitives { - changed_bits |= base ^ alternitive + for alternative in alternatives { + changed_bits |= base ^ alternative } assert_eq!( core::u64::MAX, diff --git a/src/lib.rs b/src/lib.rs index 2086513..500f430 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,7 +77,7 @@ use ahash::AHashMap; let mut map: AHashMap = AHashMap::new(); map.insert(12, 34); ``` -This avoids the need to type "RandomState". (For convience `From`, `Into`, and `Deref` are provided). +This avoids the need to type "RandomState". (For convenience `From`, `Into`, and `Deref` are provided). # Aliases From c7e8a125e68df42786cae1f41b88b8da76efaffc Mon Sep 17 00:00:00 2001 From: Dirk Stolle Date: Tue, 2 Jan 2024 18:07:59 +0100 Subject: [PATCH 03/14] Update GitHub Actions CI (#193) The following updates are performed: * update actions/checkout to v4 * replace unmaintained actions-rs/toolchain by dtolnay/rust-toolchain * replace unmaintained actions-rs/cargo by direct invocation of cargo --- .github/workflows/rust.yml | 156 +++++++++++-------------------------- 1 file changed, 47 insertions(+), 109 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1d440a5..6907df1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -6,191 +6,129 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install latest stable - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: stable components: clippy - name: check nostd - uses: actions-rs/cargo@v1 - with: - command: check - args: --no-default-features + run: cargo check --no-default-features - name: test nostd - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features + run: cargo test --no-default-features - name: check constrandom - uses: actions-rs/cargo@v1 - with: - command: check - args: --no-default-features --features compile-time-rng + run: cargo check --no-default-features --features compile-time-rng - name: test constrandom - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features compile-time-rng + run: cargo test --no-default-features --features compile-time-rng - name: check fixed-seed - uses: actions-rs/cargo@v1 - with: - command: check - args: --no-default-features --features std + run: cargo check --no-default-features --features std - name: check - uses: actions-rs/cargo@v1 - with: - command: check + run: cargo check - name: test - uses: actions-rs/cargo@v1 - with: - command: test + run: cargo test nightly: name: nightly runs-on: ubuntu-latest env: RUSTFLAGS: -C target-cpu=native steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install latest nightly - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: nightly - override: true components: clippy - name: check nightly - uses: actions-rs/cargo@v1 - with: - command: check - args: -Z msrv-policy + run: cargo check -Z msrv-policy - name: test nightly - uses: actions-rs/cargo@v1 - with: - command: test + run: cargo test - name: check serde - uses: actions-rs/cargo@v1 - with: - command: check - args: --features serde + run: cargo check --features serde - name: test serde - uses: actions-rs/cargo@v1 - with: - command: test - args: --features serde + run: cargo test --features serde linux_arm7: name: Linux ARMv7 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: toolchain: stable - target: armv7-unknown-linux-gnueabihf - - uses: actions-rs/cargo@v1 - with: - command: check - args: --target armv7-unknown-linux-gnueabihf + targets: armv7-unknown-linux-gnueabihf + - run: cargo check --target armv7-unknown-linux-gnueabihf aarch64-apple-darwin: name: Aarch64 Apple Darwin runs-on: macos-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: toolchain: stable - target: aarch64-apple-darwin - - uses: actions-rs/cargo@v1 - with: - command: check - args: --target aarch64-apple-darwin + targets: aarch64-apple-darwin + - run: cargo check --target aarch64-apple-darwin i686-unknown-linux-gnu: name: Linux i686 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: toolchain: stable - target: i686-unknown-linux-gnu + targets: i686-unknown-linux-gnu - name: Install cross compile tools run: sudo apt-get install -y gcc-multilib libc6-i386 libc6-dev-i386 - - uses: actions-rs/cargo@v1 - with: - command: check - args: --target i686-unknown-linux-gnu - - uses: actions-rs/cargo@v1 - with: - command: test - args: --target i686-unknown-linux-gnu + - run: cargo check --target i686-unknown-linux-gnu + - run: cargo test --target i686-unknown-linux-gnu x86_64-unknown-linux-gnu: name: Linux x86_64 - nightly runs-on: ubuntu-latest env: RUSTFLAGS: -C target-cpu=skylake -C target-feature=+aes steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: toolchain: nightly - override: true - target: x86_64-unknown-linux-gnu - - uses: actions-rs/cargo@v1 - with: - command: check - args: --target x86_64-unknown-linux-gnu - - uses: actions-rs/cargo@v1 - with: - command: test - args: --target x86_64-unknown-linux-gnu + targets: x86_64-unknown-linux-gnu + - run: cargo check --target x86_64-unknown-linux-gnu + - run: cargo test --target x86_64-unknown-linux-gnu thumbv6m: name: thumbv6m runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: toolchain: stable - target: thumbv6m-none-eabi - - uses: actions-rs/cargo@v1 - with: - command: check - args: --target thumbv6m-none-eabi --no-default-features + targets: thumbv6m-none-eabi + - run: cargo check --target thumbv6m-none-eabi --no-default-features wasm32-unknown-unknown: name: wasm runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: toolchain: stable - target: wasm32-unknown-unknown - - uses: actions-rs/cargo@v1 - with: - command: check - args: --target wasm32-unknown-unknown --no-default-features + targets: wasm32-unknown-unknown + - run: cargo check --target wasm32-unknown-unknown --no-default-features msrv: name: MSRV runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Install 1.60.0 - uses: actions-rs/toolchain@v1 + uses: dtolnay/rust-toolchain@master with: toolchain: 1.60.0 - name: check - uses: actions-rs/cargo@v1 - with: - command: check + run: cargo check no_std: name: no-std build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master with: toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: build - args: --manifest-path=no_std_test/Cargo.toml + - run: cargo build --manifest-path=no_std_test/Cargo.toml From 6caa72776481067c7cb73e5497df162448e73440 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sat, 10 Feb 2024 15:52:54 -0800 Subject: [PATCH 04/14] Add test for key ref invariance Signed-off-by: Tom Kaitchuck --- tests/map_tests.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/map_tests.rs b/tests/map_tests.rs index 8d798a0..bdf37d8 100644 --- a/tests/map_tests.rs +++ b/tests/map_tests.rs @@ -200,6 +200,32 @@ fn test_ahash_alias_set_construction() { set.insert(1); } + +#[cfg(feature = "std")] +#[test] +fn test_key_ref() { + let mut map = ahash::HashMap::default(); + map.insert(1, "test"); + assert_eq!(Some((1, "test")), map.remove_entry(&1)); + + let mut map = ahash::HashMap::default(); + map.insert(&1, "test"); + assert_eq!(Some((&1, "test")), map.remove_entry(&&1)); + + let mut m = ahash::HashSet::>::default(); + m.insert(Box::from("hello".to_string())); + assert!(m.contains(&"hello".to_string())); + + let mut m = ahash::HashSet::::default(); + m.insert("hello".to_string()); + assert!(m.contains("hello")); + + let mut m = ahash::HashSet::>::default(); + m.insert(Box::from(&b"hello"[..])); + assert!(m.contains(&b"hello"[..])); +} + + fn ahash_vec(b: &Vec) -> u64 { let mut total: u64 = 0; for item in b { From 2c22a60f4db15d14c0cae7fc90a732def8112847 Mon Sep 17 00:00:00 2001 From: Jeffrey Vo Date: Sun, 11 Feb 2024 15:52:31 +1100 Subject: [PATCH 05/14] Bump rust-version to 1.72.0 (#196) * Bump rust-version to 1.72.0 * Bump rust version in MSRC CI check --- .github/workflows/rust.yml | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6907df1..327397e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -117,10 +117,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Install 1.60.0 + - name: Install 1.72.0 uses: dtolnay/rust-toolchain@master with: - toolchain: 1.60.0 + toolchain: 1.72.0 - name: check run: cargo check no_std: diff --git a/Cargo.toml b/Cargo.toml index 7f2901f..2d65614 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.60.0" +rust-version = "1.72.0" [lib] name = "ahash" From a0b012a0bf86d3ae200fc13858329d10fc3b5d14 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sat, 10 Feb 2024 21:06:48 -0800 Subject: [PATCH 06/14] Increase the MSRV presubmit checks to include multiple architectures (#197) Increase the MSRV presubmit checks to include multiple architectures Signed-off-by: Tom Kaitchuck --- .github/workflows/rust.yml | 48 +++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 327397e..7e28cda 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -56,6 +56,12 @@ jobs: toolchain: stable targets: armv7-unknown-linux-gnueabihf - run: cargo check --target armv7-unknown-linux-gnueabihf + - name: Install 1.72.0 + uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.72.0 + targets: armv7-unknown-linux-gnueabihf + - run: cargo +1.72.0 check --target armv7-unknown-linux-gnueabihf aarch64-apple-darwin: name: Aarch64 Apple Darwin runs-on: macos-latest @@ -66,6 +72,14 @@ jobs: toolchain: stable targets: aarch64-apple-darwin - run: cargo check --target aarch64-apple-darwin + - run: cargo test + - run: cargo test --no-default-features --features compile-time-rng + - name: Install 1.72.0 + uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.72.0 + targets: aarch64-apple-darwin + - run: cargo +1.72.0 check --target aarch64-apple-darwin i686-unknown-linux-gnu: name: Linux i686 runs-on: ubuntu-latest @@ -79,8 +93,18 @@ jobs: run: sudo apt-get install -y gcc-multilib libc6-i386 libc6-dev-i386 - run: cargo check --target i686-unknown-linux-gnu - run: cargo test --target i686-unknown-linux-gnu + - name: check constrandom + run: cargo check --no-default-features --features compile-time-rng --target i686-unknown-linux-gnu + - name: Install 1.72.0 + uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.72.0 + targets: i686-unknown-linux-gnu + - run: cargo +1.72.0 check --target i686-unknown-linux-gnu + - name: check constrandom + run: cargo +1.72.0 check --no-default-features --features compile-time-rng --target i686-unknown-linux-gnu x86_64-unknown-linux-gnu: - name: Linux x86_64 - nightly + name: Linux x86_64 runs-on: ubuntu-latest env: RUSTFLAGS: -C target-cpu=skylake -C target-feature=+aes @@ -92,6 +116,15 @@ jobs: targets: x86_64-unknown-linux-gnu - run: cargo check --target x86_64-unknown-linux-gnu - run: cargo test --target x86_64-unknown-linux-gnu + - name: check constrandom + run: cargo check --no-default-features --features compile-time-rng --target x86_64-unknown-linux-gnu + - name: Install 1.72.0 + uses: dtolnay/rust-toolchain@master + with: + toolchain: 1.72.0 + - run: cargo +1.72.0 check --target x86_64-unknown-linux-gnu + - name: check constrandom + run: cargo +1.72.0 check --no-default-features --features compile-time-rng --target x86_64-unknown-linux-gnu thumbv6m: name: thumbv6m runs-on: ubuntu-latest @@ -112,17 +145,6 @@ jobs: toolchain: stable targets: wasm32-unknown-unknown - run: cargo check --target wasm32-unknown-unknown --no-default-features - msrv: - name: MSRV - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Install 1.72.0 - uses: dtolnay/rust-toolchain@master - with: - toolchain: 1.72.0 - - name: check - run: cargo check no_std: name: no-std build runs-on: ubuntu-latest @@ -131,4 +153,4 @@ jobs: - uses: dtolnay/rust-toolchain@master with: toolchain: nightly - - run: cargo build --manifest-path=no_std_test/Cargo.toml + - run: cargo build --manifest-path=no_std_test/Cargo.toml \ No newline at end of file From 669de234e4c7653ff814bed8244cb4d48356c594 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sat, 10 Feb 2024 21:45:22 -0800 Subject: [PATCH 07/14] Bump version to 0.8.8 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 95eb4f47109189dff2e59d18e24e789976bd6c1b Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Mon, 19 Feb 2024 17:24:35 -0800 Subject: [PATCH 08/14] 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 a420587..1970cbf 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 3f908902a9428c185ca333855e20b9385af7cce4 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Mon, 19 Feb 2024 17:27:52 -0800 Subject: [PATCH 09/14] Bump version to 0.8.9 Signed-off-by: Tom Kaitchuck --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 01faf1e..7e388c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ahash" -version = "0.8.8" +version = "0.8.9" authors = ["Tom Kaitchuck "] license = "MIT OR Apache-2.0" description = "A non-cryptographic hash function using AES-NI for high performance" From f29d59e4ee047d2cefd6fc13363d286f35f249c0 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Tue, 27 Feb 2024 10:32:01 -0800 Subject: [PATCH 10/14] 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 7e388c4..cba3897 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 1970cbf..8395007 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 545a200b43fee2404c812d5d5c05c2734fb790bd Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Tue, 27 Feb 2024 10:38:18 -0800 Subject: [PATCH 11/14] Bump version to 0.8.10 Signed-off-by: Tom Kaitchuck --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cba3897..77e963c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ahash" -version = "0.8.9" +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" From f79214281ac17f0529b893110d2c3f6671eb6865 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 3 Mar 2024 09:23:31 -0800 Subject: [PATCH 12/14] 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 | 1 + 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, 56 insertions(+), 21 deletions(-) create mode 100644 compare/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 77e963c..8fa6bcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 db36e4c4f0606b786bc617eefaffbe4ae9100762 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Sun, 3 Mar 2024 09:28:23 -0800 Subject: [PATCH 13/14] Bump version to 0.8.11 Signed-off-by: Tom Kaitchuck --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8fa6bcf..a63f6d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ahash" -version = "0.8.10" +version = "0.8.11" authors = ["Tom Kaitchuck "] license = "MIT OR Apache-2.0" description = "A non-cryptographic hash function using AES-NI for high performance" From 9aa1ba20f05ed582eda04ea625d5658c92195a57 Mon Sep 17 00:00:00 2001 From: Tom Kaitchuck Date: Wed, 7 May 2025 22:02:58 -0700 Subject: [PATCH 14/14] Merge master changes into 0.8 release branch (#272) * Bump version to 0.8.12 --- Cargo.toml | 10 +-- build.rs | 6 +- no_std_test/src/main.rs | 6 +- src/aes_hash.rs | 23 +++---- src/convert.rs | 55 +++++++--------- src/fallback_hash.rs | 21 +++---- src/hash_map.rs | 8 +-- src/hash_quality_test.rs | 10 +-- src/hash_set.rs | 6 +- src/lib.rs | 84 +++++++------------------ src/operations.rs | 12 ++-- src/random_state.rs | 29 ++++----- src/specialize.rs | 132 +++++++++++++++++++-------------------- tests/bench.rs | 2 +- tests/map_tests.rs | 6 +- 15 files changed, 171 insertions(+), 239 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a63f6d5..b1c7d40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ahash" -version = "0.8.11" +version = "0.8.12" authors = ["Tom Kaitchuck "] license = "MIT OR Apache-2.0" description = "A non-cryptographic hash function using AES-NI for high performance" @@ -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,9 +82,9 @@ 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} -getrandom = { version = "0.2.7", optional = true } -zerocopy = { version = "0.7.31", default-features = false, features = ["simd"] } +portable-atomic = { version = "1.0.0", optional = true } +getrandom = { version = "0.3.1", optional = true } +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/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/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); diff --git a/src/aes_hash.rs b/src/aes_hash.rs index daf3ae4..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; /// @@ -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 { @@ -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/convert.rs b/src/convert.rs index 712eae1..4169f5f 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -19,47 +19,36 @@ macro_rules! convert { }; } -convert!([u128; 4], [u64; 8]); -convert!([u128; 4], [u32; 16]); -convert!([u128; 4], [u16; 32]); +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], [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_primitive_bytes!(u128, [u8; 16]); 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_primitive_bytes!(u64, [u8; 8]); +convert_primitive_bytes!(u32, [u8; 4]); +convert_primitive_bytes!(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) => {{ { diff --git a/src/fallback_hash.rs b/src/fallback_hash.rs index bc5cbfe..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 { @@ -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); - } } 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_quality_test.rs b/src/hash_quality_test.rs index f2fab16..a725380 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(); @@ -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)); @@ -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)] @@ -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/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 { diff --git a/src/lib.rs b/src/lib.rs index 69fb2ca..826806b 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: @@ -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] @@ -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] @@ -393,4 +336,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/operations.rs b/src/operations.rs index 8395007..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); @@ -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); } } diff --git a/src/random_state.rs b/src/random_state.rs index 46a39ab..46edc2d 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; @@ -24,7 +19,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; @@ -79,7 +74,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 +389,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); @@ -458,17 +453,17 @@ 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")] -impl BuildHasherExt for RandomState { +#[cfg(specialize)] +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 05d335b..0ba76da 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,127 +8,122 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std as alloc; -#[cfg(feature = "specialize")] -use crate::BuildHasherExt; -#[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. /// 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"))] +#[cfg(not(specialize))] impl CallHasher for T 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() } } -#[cfg(feature = "specialize")] +#[cfg(specialize)] impl CallHasher for T 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() } } -macro_rules! call_hasher_impl { +macro_rules! call_hasher_impl_u64 { ($typ:ty) => { - #[cfg(feature = "specialize")] + #[cfg(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) } } }; } -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(specialize)] + impl CallHasher for $typ { + #[inline] + fn get_hash(value: &H, random_state: &RandomState) -> u64 { + random_state.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")] +#[cfg(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")] +#[cfg(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")] +#[cfg(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"))] +#[cfg(all(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) } } @@ -137,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); @@ -189,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) @@ -209,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();