Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
10 changes: 5 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ahash"
version = "0.8.11"
version = "0.8.12"
authors = ["Tom Kaitchuck <Tom.Kaitchuck@gmail.com>"]
license = "MIT OR Apache-2.0"
description = "A non-cryptographic hash function using AES-NI for high performance"
Expand Down Expand Up @@ -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 = []
Expand Down Expand Up @@ -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"] }
Expand Down
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");
}
}
6 changes: 3 additions & 3 deletions no_std_test/src/main.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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);
Expand Down
23 changes: 8 additions & 15 deletions src/aes_hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl AHasher {
///
/// # Example
///
/// ```
/// ```no_build
/// use std::hash::Hasher;
/// use ahash::AHasher;
///
Expand Down 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 Expand Up @@ -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);
}
}
55 changes: 22 additions & 33 deletions src/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {{
{
Expand Down
21 changes: 7 additions & 14 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 Expand Up @@ -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);
}
}
8 changes: 4 additions & 4 deletions src/hash_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ impl<K, V> Into<HashMap<K, V, crate::RandomState>> for AHashMap<K, V> {
}

impl<K, V> AHashMap<K, V, RandomState> {
/// 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()))
Expand Down Expand Up @@ -348,7 +348,7 @@ impl<K, V> FromIterator<(K, V)> for AHashMap<K, V, RandomState>
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<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
let mut inner = HashMap::with_hasher(RandomState::new());
Expand Down Expand Up @@ -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"))]
Expand Down
10 changes: 5 additions & 5 deletions src/hash_quality_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ fn test_no_full_collisions<T: Hasher>(gen_hash: impl Fn() -> T) {
gen_combinations(&options, 7, Vec::new(), &mut combinations);
let mut map: HashMap<u64, Vec<u8>> = 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();
Expand Down 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 @@ -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)]
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
6 changes: 3 additions & 3 deletions src/hash_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ impl<T> Into<HashSet<T, RandomState>> for AHashSet<T> {
}

impl<T> AHashSet<T, RandomState> {
/// 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()))
Expand Down Expand Up @@ -245,7 +245,7 @@ impl<T> FromIterator<T> for AHashSet<T, RandomState>
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<I: IntoIterator<Item = T>>(iter: I) -> AHashSet<T> {
Expand Down
Loading