Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require Cargo feature opt-in for min_specialize #239

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ jobs:
run: cargo check --features serde
- name: test serde
run: cargo test --features serde
- name: check specialize
run: cargo check --features nightly-specialize
linux_arm7:
name: Linux ARMv7
runs-on: ubuntu-latest
Expand Down Expand Up @@ -153,4 +155,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
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ atomic-polyfill = [ "dep:portable-atomic", "once_cell/critical-section"]
# Nightly-only support for AES intrinsics on 32-bit ARM
nightly-arm-aes = []

# Nightly-only support for impls that work with `min_specialization`
nightly-specialize = []

[[bench]]
name = "ahash"
path = "tests/bench.rs"
Expand Down Expand Up @@ -75,9 +78,6 @@ lto = 'fat'
debug-assertions = false
codegen-units = 1

[build-dependencies]
version_check = "0.9.4"

[dependencies]
const-random = { version = "0.1.17", optional = true }
serde = { version = "1.0.117", optional = true }
Expand Down
3 changes: 0 additions & 3 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ use std::env;

fn main() {
println!("cargo:rerun-if-changed=build.rs");
if let Some(true) = version_check::supports_feature("specialize") {
println!("cargo:rustc-cfg=feature=\"specialize\"");
}
let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set");
if arch.eq_ignore_ascii_case("x86_64")
|| arch.eq_ignore_ascii_case("aarch64")
Expand Down
14 changes: 7 additions & 7 deletions src/aes_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ impl AHasher {
}

#[inline]
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
fn short_finish(&self) -> u64 {
let combined = aesenc(self.sum, self.enc);
let result: [u64; 2] = aesdec(combined, combined).convert();
Expand Down Expand Up @@ -214,14 +214,14 @@ impl Hasher for AHasher {
}
}

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-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(feature = "nightly-specialize")]
impl Hasher for AHasherU64 {
#[inline]
fn finish(&self) -> u64 {
Expand Down Expand Up @@ -264,11 +264,11 @@ impl Hasher for AHasherU64 {
}
}

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
pub(crate) struct AHasherFixed(pub AHasher);

/// A specialized hasher for fixed size primitives larger than 64 bits.
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
impl Hasher for AHasherFixed {
#[inline]
fn finish(&self) -> u64 {
Expand Down Expand Up @@ -311,12 +311,12 @@ impl Hasher for AHasherFixed {
}
}

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-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(feature = "nightly-specialize")]
impl Hasher for AHasherStr {
#[inline]
fn finish(&self) -> u64 {
Expand Down
14 changes: 7 additions & 7 deletions src/fallback_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl AHasher {
}

#[inline]
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
fn short_finish(&self) -> u64 {
folded_multiply(self.buffer, self.pad)
}
Expand Down Expand Up @@ -199,14 +199,14 @@ impl Hasher for AHasher {
}
}

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-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(feature = "nightly-specialize")]
impl Hasher for AHasherU64 {
#[inline]
fn finish(&self) -> u64 {
Expand Down Expand Up @@ -250,11 +250,11 @@ impl Hasher for AHasherU64 {
}
}

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
pub(crate) struct AHasherFixed(pub AHasher);

/// A specialized hasher for fixed size primitives larger than 64 bits.
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
impl Hasher for AHasherFixed {
#[inline]
fn finish(&self) -> u64 {
Expand Down Expand Up @@ -297,12 +297,12 @@ impl Hasher for AHasherFixed {
}
}

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-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(feature = "nightly-specialize")]
impl Hasher for AHasherStr {
#[inline]
fn finish(&self) -> u64 {
Expand Down
4 changes: 2 additions & 2 deletions src/hash_quality_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(feature = "nightly-specialize"), feature = "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));
Expand Down Expand Up @@ -504,7 +504,7 @@ mod aes_tests {

#[test]
fn aes_keys_affect_every_byte() {
#[cfg(not(feature = "specialize"))]
#[cfg(not(feature = "nightly-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);
Expand Down
14 changes: 7 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(feature = "nightly-specialize", feature(min_specialization))]
#![cfg_attr(feature = "nightly-arm-aes", feature(stdarch_arm_neon_intrinsics))]

#[macro_use]
Expand Down Expand Up @@ -262,42 +262,42 @@ pub(crate) trait BuildHasherExt: BuildHasher {

impl<B: BuildHasher> BuildHasherExt for B {
#[inline]
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
default fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
let mut hasher = self.build_hasher();
value.hash(&mut hasher);
hasher.finish()
}
#[inline]
#[cfg(not(feature = "specialize"))]
#[cfg(not(feature = "nightly-specialize"))]
fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
let mut hasher = self.build_hasher();
value.hash(&mut hasher);
hasher.finish()
}
#[inline]
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
default fn hash_as_fixed_length<T: Hash + ?Sized>(&self, value: &T) -> u64 {
let mut hasher = self.build_hasher();
value.hash(&mut hasher);
hasher.finish()
}
#[inline]
#[cfg(not(feature = "specialize"))]
#[cfg(not(feature = "nightly-specialize"))]
fn hash_as_fixed_length<T: Hash + ?Sized>(&self, value: &T) -> u64 {
let mut hasher = self.build_hasher();
value.hash(&mut hasher);
hasher.finish()
}
#[inline]
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
default fn hash_as_str<T: Hash + ?Sized>(&self, value: &T) -> u64 {
let mut hasher = self.build_hasher();
value.hash(&mut hasher);
hasher.finish()
}
#[inline]
#[cfg(not(feature = "specialize"))]
#[cfg(not(feature = "nightly-specialize"))]
fn hash_as_str<T: Hash + ?Sized>(&self, value: &T) -> u64 {
let mut hasher = self.build_hasher();
value.hash(&mut hasher);
Expand Down
6 changes: 3 additions & 3 deletions src/random_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ cfg_if::cfg_if! {
}
}
cfg_if::cfg_if! {
if #[cfg(feature = "specialize")]{
if #[cfg(feature = "nightly-specialize")]{
use crate::BuildHasherExt;
}
}
Expand Down Expand Up @@ -458,14 +458,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(feature = "nightly-specialize")]
#[inline]
fn hash_one<T: Hash>(&self, x: T) -> u64 {
RandomState::hash_one(self, x)
}
}

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
impl BuildHasherExt for RandomState {
#[inline]
fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
Expand Down
28 changes: 14 additions & 14 deletions src/specialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ extern crate alloc;
#[cfg(feature = "std")]
extern crate std as alloc;

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
use crate::BuildHasherExt;
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
use alloc::string::String;
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
use alloc::vec::Vec;

/// Provides a way to get an optimized hasher for a given data type.
Expand All @@ -21,7 +21,7 @@ pub(crate) trait CallHasher {
fn get_hash<H: Hash + ?Sized, B: BuildHasher>(value: &H, build_hasher: &B) -> u64;
}

#[cfg(not(feature = "specialize"))]
#[cfg(not(feature = "nightly-specialize"))]
impl<T> CallHasher for T
where
T: Hash + ?Sized,
Expand All @@ -34,7 +34,7 @@ where
}
}

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
impl<T> CallHasher for T
where
T: Hash + ?Sized,
Expand All @@ -49,7 +49,7 @@ where

macro_rules! call_hasher_impl_u64 {
($typ:ty) => {
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
impl CallHasher for $typ {
#[inline]
fn get_hash<H: Hash + ?Sized, B: BuildHasher>(value: &H, build_hasher: &B) -> u64 {
Expand Down Expand Up @@ -77,7 +77,7 @@ call_hasher_impl_u64!(&i64);

macro_rules! call_hasher_impl_fixed_length{
($typ:ty) => {
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
impl CallHasher for $typ {
#[inline]
fn get_hash<H: Hash + ?Sized, B: BuildHasher>(value: &H, build_hasher: &B) -> u64 {
Expand All @@ -96,31 +96,31 @@ call_hasher_impl_fixed_length!(&i128);
call_hasher_impl_fixed_length!(&usize);
call_hasher_impl_fixed_length!(&isize);

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

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

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

#[cfg(all(feature = "specialize"))]
#[cfg(all(feature = "nightly-specialize"))]
impl CallHasher for String {
#[inline]
fn get_hash<H: Hash + ?Sized, B: BuildHasher>(value: &H, build_hasher: &B) -> u64 {
Expand All @@ -134,7 +134,7 @@ mod test {
use crate::*;

#[test]
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
pub fn test_specialized_invoked() {
let build_hasher = RandomState::with_seeds(1, 2, 3, 4);
let shortened = u64::get_hash(&0, &build_hasher);
Expand Down Expand Up @@ -186,7 +186,7 @@ mod test {
str::get_hash(&"test", &build_hasher),
String::get_hash(&"test".to_string(), &build_hasher)
);
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
assert_eq!(
str::get_hash(&"test", &build_hasher),
<[u8]>::get_hash("test".as_bytes(), &build_hasher)
Expand All @@ -206,7 +206,7 @@ mod test {
str::get_hash(&&"test", &build_hasher),
String::get_hash(&"test".to_string(), &build_hasher)
);
#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
assert_eq!(
str::get_hash(&&"test", &build_hasher),
<[u8]>::get_hash(&"test".to_string().into_bytes(), &build_hasher)
Expand Down
2 changes: 1 addition & 1 deletion tests/bench.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))]
#![cfg_attr(feature = "nightly-specialize", feature(build_hasher_simple_hash_one))]

use ahash::{AHasher, RandomState};
use criterion::*;
Expand Down
6 changes: 3 additions & 3 deletions tests/map_tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(feature = "specialize", feature(build_hasher_simple_hash_one))]
#![cfg_attr(feature = "nightly-specialize", feature(build_hasher_simple_hash_one))]

use std::hash::{BuildHasher, Hash, Hasher};

Expand Down Expand Up @@ -151,13 +151,13 @@ fn check_for_collisions<H: Hash, B: BuildHasher>(build_hasher: &B, items: &[H],
);
}

#[cfg(feature = "specialize")]
#[cfg(feature = "nightly-specialize")]
#[allow(unused)] // False positive
fn hash<H: Hash, B: BuildHasher>(b: &H, build_hasher: &B) -> u64 {
build_hasher.hash_one(b)
}

#[cfg(not(feature = "specialize"))]
#[cfg(not(feature = "nightly-specialize"))]
#[allow(unused)] // False positive
fn hash<H: Hash, B: BuildHasher>(b: &H, build_hasher: &B) -> u64 {
let mut hasher = build_hasher.build_hasher();
Expand Down