Skip to content

Commit 85c9a26

Browse files
committed
Support specializing get_hash without nightly
1 parent 50eca1a commit 85c9a26

File tree

8 files changed

+73
-149
lines changed

8 files changed

+73
-149
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ cfg-if = "1.0"
8585
portable-atomic = { version = "1.0.0", optional = true }
8686
getrandom = { version = "0.3.1", optional = true }
8787
zerocopy = { version = "0.8.24", default-features = false, features = ["simd"] }
88+
typeid = "1.0"
8889

8990
[target.'cfg(not(all(target_arch = "arm", target_os = "none")))'.dependencies]
9091
once_cell = { version = "1.18.0", default-features = false, features = ["alloc"] }

build.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ fn main() {
77
if let Some(true) = version_check::is_min_version("1.71.0") {
88
println!("cargo:rustc-cfg=build_hasher_hash_one");
99
}
10-
if let Some(true) = version_check::supports_feature("specialize") {
11-
println!("cargo:rustc-cfg=feature=\"specialize\"");
12-
}
1310
let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("CARGO_CFG_TARGET_ARCH was not set");
1411
if arch.eq_ignore_ascii_case("x86_64")
1512
|| arch.eq_ignore_ascii_case("aarch64")

src/aes_hash.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@ impl AHasher {
9494
}
9595

9696
#[inline]
97-
#[cfg(feature = "specialize")]
9897
fn short_finish(&self) -> u64 {
9998
let combined = aesenc(self.sum, self.enc);
10099
let result: [u64; 2] = aesdec(combined, combined).convert();
@@ -214,14 +213,12 @@ impl Hasher for AHasher {
214213
}
215214
}
216215

217-
#[cfg(feature = "specialize")]
218216
pub(crate) struct AHasherU64 {
219217
pub(crate) buffer: u64,
220218
pub(crate) pad: u64,
221219
}
222220

223221
/// A specialized hasher for only primitives under 64 bits.
224-
#[cfg(feature = "specialize")]
225222
impl Hasher for AHasherU64 {
226223
#[inline]
227224
fn finish(&self) -> u64 {
@@ -264,11 +261,9 @@ impl Hasher for AHasherU64 {
264261
}
265262
}
266263

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

270266
/// A specialized hasher for fixed size primitives larger than 64 bits.
271-
#[cfg(feature = "specialize")]
272267
impl Hasher for AHasherFixed {
273268
#[inline]
274269
fn finish(&self) -> u64 {
@@ -311,12 +306,10 @@ impl Hasher for AHasherFixed {
311306
}
312307
}
313308

314-
#[cfg(feature = "specialize")]
315309
pub(crate) struct AHasherStr(pub AHasher);
316310

317311
/// A specialized hasher for strings
318312
/// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec)
319-
#[cfg(feature = "specialize")]
320313
impl Hasher for AHasherStr {
321314
#[inline]
322315
fn finish(&self) -> u64 {

src/fallback_hash.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ impl AHasher {
115115
}
116116

117117
#[inline]
118-
#[cfg(feature = "specialize")]
119118
fn short_finish(&self) -> u64 {
120119
folded_multiply(self.buffer, self.pad)
121120
}
@@ -199,14 +198,12 @@ impl Hasher for AHasher {
199198
}
200199
}
201200

202-
#[cfg(feature = "specialize")]
203201
pub(crate) struct AHasherU64 {
204202
pub(crate) buffer: u64,
205203
pub(crate) pad: u64,
206204
}
207205

208206
/// A specialized hasher for only primitives under 64 bits.
209-
#[cfg(feature = "specialize")]
210207
impl Hasher for AHasherU64 {
211208
#[inline]
212209
fn finish(&self) -> u64 {
@@ -250,11 +247,9 @@ impl Hasher for AHasherU64 {
250247
}
251248
}
252249

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

256252
/// A specialized hasher for fixed size primitives larger than 64 bits.
257-
#[cfg(feature = "specialize")]
258253
impl Hasher for AHasherFixed {
259254
#[inline]
260255
fn finish(&self) -> u64 {
@@ -297,12 +292,10 @@ impl Hasher for AHasherFixed {
297292
}
298293
}
299294

300-
#[cfg(feature = "specialize")]
301295
pub(crate) struct AHasherStr(pub AHasher);
302296

303297
/// A specialized hasher for a single string
304298
/// Note that the other types don't panic because the hash impl for String tacks on an unneeded call. (As does vec)
305-
#[cfg(feature = "specialize")]
306299
impl Hasher for AHasherStr {
307300
#[inline]
308301
fn finish(&self) -> u64 {

src/hash_quality_test.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -406,9 +406,6 @@ mod fallback_tests {
406406

407407
#[test]
408408
fn fallback_keys_affect_every_byte() {
409-
//For fallback second key is not used in every hash.
410-
#[cfg(all(not(feature = "specialize"), feature = "folded_multiply"))]
411-
test_keys_affect_every_byte(0, |a, b| AHasher::new_with_keys(a ^ b, a));
412409
test_keys_affect_every_byte("", |a, b| AHasher::new_with_keys(a ^ b, a));
413410
test_keys_affect_every_byte((0, 0), |a, b| AHasher::new_with_keys(a ^ b, a));
414411
}
@@ -504,8 +501,6 @@ mod aes_tests {
504501

505502
#[test]
506503
fn aes_keys_affect_every_byte() {
507-
#[cfg(not(feature = "specialize"))]
508-
test_keys_affect_every_byte(0, AHasher::test_with_keys);
509504
test_keys_affect_every_byte("", AHasher::test_with_keys);
510505
test_keys_affect_every_byte((0, 0), AHasher::test_with_keys);
511506
}

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,6 @@ Note the import of [HashMapExt]. This is needed for the constructor.
9797
#![deny(clippy::correctness, clippy::complexity, clippy::perf)]
9898
#![allow(clippy::pedantic, clippy::cast_lossless, clippy::unreadable_literal)]
9999
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
100-
#![cfg_attr(feature = "specialize", feature(min_specialization))]
101100
#![cfg_attr(feature = "nightly-arm-aes", feature(stdarch_arm_neon_intrinsics))]
102101

103102
#[macro_use]

src/random_state.rs

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,30 @@ impl RandomState {
356356
use crate::specialize::CallHasher;
357357
T::get_hash(&x, self)
358358
}
359+
360+
#[inline]
361+
pub(crate) fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
362+
let mut hasher = AHasherU64 {
363+
buffer: self.k1,
364+
pad: self.k0,
365+
};
366+
value.hash(&mut hasher);
367+
hasher.finish()
368+
}
369+
370+
#[inline]
371+
pub(crate) fn hash_as_fixed_length<T: Hash + ?Sized>(&self, value: &T) -> u64 {
372+
let mut hasher = AHasherFixed(self.build_hasher());
373+
value.hash(&mut hasher);
374+
hasher.finish()
375+
}
376+
377+
#[inline]
378+
pub(crate) fn hash_as_str<T: Hash + ?Sized>(&self, value: &T) -> u64 {
379+
let mut hasher = AHasherStr(self.build_hasher());
380+
value.hash(&mut hasher);
381+
hasher.finish()
382+
}
359383
}
360384

361385
/// Creates an instance of RandomState using keys obtained from the random number generator.
@@ -460,33 +484,6 @@ impl BuildHasher for RandomState {
460484
}
461485
}
462486

463-
#[cfg(feature = "specialize")]
464-
impl RandomState {
465-
#[inline]
466-
pub(crate) fn hash_as_u64<T: Hash + ?Sized>(&self, value: &T) -> u64 {
467-
let mut hasher = AHasherU64 {
468-
buffer: self.k1,
469-
pad: self.k0,
470-
};
471-
value.hash(&mut hasher);
472-
hasher.finish()
473-
}
474-
475-
#[inline]
476-
pub(crate) fn hash_as_fixed_length<T: Hash + ?Sized>(&self, value: &T) -> u64 {
477-
let mut hasher = AHasherFixed(self.build_hasher());
478-
value.hash(&mut hasher);
479-
hasher.finish()
480-
}
481-
482-
#[inline]
483-
pub(crate) fn hash_as_str<T: Hash + ?Sized>(&self, value: &T) -> u64 {
484-
let mut hasher = AHasherStr(self.build_hasher());
485-
value.hash(&mut hasher);
486-
hasher.finish()
487-
}
488-
}
489-
490487
#[cfg(test)]
491488
mod test {
492489
use super::*;

src/specialize.rs

Lines changed: 48 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::RandomState;
2+
use core::any::TypeId;
23
use core::hash::BuildHasher;
34
use core::hash::Hash;
45
use core::hash::Hasher;
@@ -8,122 +9,70 @@ extern crate alloc;
89
#[cfg(feature = "std")]
910
extern crate std as alloc;
1011

11-
#[cfg(feature = "specialize")]
1212
use alloc::string::String;
13-
#[cfg(feature = "specialize")]
1413
use alloc::vec::Vec;
1514

15+
#[inline]
16+
fn is<Generic, Expected>() -> bool
17+
where
18+
Generic: ?Sized,
19+
Expected: ?Sized + 'static,
20+
{
21+
typeid::of::<Generic>() == TypeId::of::<Expected>()
22+
}
23+
1624
/// Provides a way to get an optimized hasher for a given data type.
1725
/// Rather than using a Hasher generically which can hash any value, this provides a way to get a specialized hash
1826
/// for a specific type. So this may be faster for primitive types.
1927
pub(crate) trait CallHasher {
2028
fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64;
2129
}
2230

23-
#[cfg(not(feature = "specialize"))]
2431
impl<T> CallHasher for T
2532
where
2633
T: Hash + ?Sized,
2734
{
2835
#[inline]
2936
fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
30-
let mut hasher = random_state.build_hasher();
31-
value.hash(&mut hasher);
32-
hasher.finish()
33-
}
34-
}
35-
36-
#[cfg(feature = "specialize")]
37-
impl<T> CallHasher for T
38-
where
39-
T: Hash + ?Sized,
40-
{
41-
#[inline]
42-
default fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
43-
let mut hasher = random_state.build_hasher();
44-
value.hash(&mut hasher);
45-
hasher.finish()
46-
}
47-
}
48-
49-
macro_rules! call_hasher_impl_u64 {
50-
($typ:ty) => {
51-
#[cfg(feature = "specialize")]
52-
impl CallHasher for $typ {
53-
#[inline]
54-
fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
55-
random_state.hash_as_u64(value)
56-
}
57-
}
58-
};
59-
}
60-
call_hasher_impl_u64!(u8);
61-
call_hasher_impl_u64!(u16);
62-
call_hasher_impl_u64!(u32);
63-
call_hasher_impl_u64!(u64);
64-
call_hasher_impl_u64!(i8);
65-
call_hasher_impl_u64!(i16);
66-
call_hasher_impl_u64!(i32);
67-
call_hasher_impl_u64!(i64);
68-
call_hasher_impl_u64!(&u8);
69-
call_hasher_impl_u64!(&u16);
70-
call_hasher_impl_u64!(&u32);
71-
call_hasher_impl_u64!(&u64);
72-
call_hasher_impl_u64!(&i8);
73-
call_hasher_impl_u64!(&i16);
74-
call_hasher_impl_u64!(&i32);
75-
call_hasher_impl_u64!(&i64);
76-
77-
macro_rules! call_hasher_impl_fixed_length{
78-
($typ:ty) => {
79-
#[cfg(feature = "specialize")]
80-
impl CallHasher for $typ {
81-
#[inline]
82-
fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
83-
random_state.hash_as_fixed_length(value)
84-
}
37+
if is::<T, u8>()
38+
|| is::<T, u16>()
39+
|| is::<T, u32>()
40+
|| is::<T, u64>()
41+
|| is::<T, i8>()
42+
|| is::<T, i16>()
43+
|| is::<T, i32>()
44+
|| is::<T, i64>()
45+
|| is::<T, &u8>()
46+
|| is::<T, &u16>()
47+
|| is::<T, &u32>()
48+
|| is::<T, &u64>()
49+
|| is::<T, &i8>()
50+
|| is::<T, &i16>()
51+
|| is::<T, &i32>()
52+
|| is::<T, &i64>()
53+
{
54+
random_state.hash_as_u64(value)
55+
} else if is::<T, u128>()
56+
|| is::<T, i128>()
57+
|| is::<T, usize>()
58+
|| is::<T, isize>()
59+
|| is::<T, &u128>()
60+
|| is::<T, &i128>()
61+
|| is::<T, &usize>()
62+
|| is::<T, &isize>()
63+
{
64+
random_state.hash_as_fixed_length(value)
65+
} else if is::<T, [u8]>()
66+
|| is::<T, Vec<u8>>()
67+
|| is::<T, str>()
68+
|| is::<T, String>()
69+
{
70+
random_state.hash_as_str(value)
71+
} else {
72+
let mut hasher = random_state.build_hasher();
73+
value.hash(&mut hasher);
74+
hasher.finish()
8575
}
86-
};
87-
}
88-
89-
call_hasher_impl_fixed_length!(u128);
90-
call_hasher_impl_fixed_length!(i128);
91-
call_hasher_impl_fixed_length!(usize);
92-
call_hasher_impl_fixed_length!(isize);
93-
call_hasher_impl_fixed_length!(&u128);
94-
call_hasher_impl_fixed_length!(&i128);
95-
call_hasher_impl_fixed_length!(&usize);
96-
call_hasher_impl_fixed_length!(&isize);
97-
98-
#[cfg(feature = "specialize")]
99-
impl CallHasher for [u8] {
100-
#[inline]
101-
fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
102-
random_state.hash_as_str(value)
103-
}
104-
}
105-
106-
#[cfg(feature = "specialize")]
107-
impl CallHasher for Vec<u8> {
108-
#[inline]
109-
fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
110-
random_state.hash_as_str(value)
111-
}
112-
}
113-
114-
#[cfg(feature = "specialize")]
115-
impl CallHasher for str {
116-
#[inline]
117-
fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
118-
random_state.hash_as_str(value)
119-
}
120-
}
121-
122-
#[cfg(all(feature = "specialize"))]
123-
impl CallHasher for String {
124-
#[inline]
125-
fn get_hash<H: Hash + ?Sized>(value: &H, random_state: &RandomState) -> u64 {
126-
random_state.hash_as_str(value)
12776
}
12877
}
12978

0 commit comments

Comments
 (0)