Skip to content
Merged
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
6 changes: 4 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ 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")
|| arch.eq_ignore_ascii_case("powerpc64")
|| 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");
}
}
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(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(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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
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(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(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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
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(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));
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion 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(specialize, feature(min_specialization))]
#![cfg_attr(feature = "nightly-arm-aes", feature(stdarch_arm_neon_intrinsics))]

#[macro_use]
Expand Down
4 changes: 2 additions & 2 deletions src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/random_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: Hash>(&self, x: T) -> u64 {
RandomState::hash_one(self, x)
}
}

#[cfg(feature = "specialize")]
#[cfg(specialize)]
impl RandomState {
#[inline]
pub(crate) fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
Expand Down
26 changes: 13 additions & 13 deletions src/specialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -20,7 +20,7 @@ pub(crate) trait CallHasher {
fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64;
}

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

#[cfg(feature = "specialize")]
#[cfg(specialize)]
impl<T> CallHasher for T
where
T: Hash + ?Sized,
Expand All @@ -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<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
Expand Down Expand Up @@ -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<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
Expand All @@ -95,31 +95,31 @@ 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<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
random_state.hash_as_str(value)
}
}

#[cfg(feature = "specialize")]
#[cfg(specialize)]
impl CallHasher for Vec<u8> {
#[inline]
fn get_hash<H: Hash + ?Sized>(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<H: Hash + ?Sized>(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<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand All @@ -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)
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(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(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(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(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