Skip to content

Commit 40e7e08

Browse files
committed
Change to aHash 0.6.1 and make key type explicet
1 parent 29f39aa commit 40e7e08

File tree

3 files changed

+67
-44
lines changed

3 files changed

+67
-44
lines changed

Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ edition = "2018"
1313

1414
[dependencies]
1515
# For the default hasher
16-
ahash = { version = "0.5.6", default-features = false, optional = true }
16+
ahash = { version = "0.6.1", default-features = false, optional = true }
1717

1818
# For external trait impls
1919
rayon = { version = "1.0", optional = true }
@@ -34,9 +34,8 @@ doc-comment = "0.3.1"
3434

3535
[features]
3636
default = ["ahash", "inline-more"]
37-
ahash-run-time-rng = ["ahash/std"]
3837
ahash-compile-time-rng = ["ahash/compile-time-rng"]
39-
nightly = ["ahash/specialize"]
38+
nightly = []
4039
rustc-internal-api = []
4140
rustc-dep-of-std = [
4241
"nightly",

README.md

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ in environments without `std`, such as embedded systems and kernels.
3737

3838
Compared to the previous implementation of `std::collections::HashMap` (Rust 1.35).
3939

40-
With the hashbrown default AHash hasher ([without HashDoS-resistance](#Flags)):
40+
With the hashbrown default AHash hasher:
4141

4242
```text
4343
name oldstdhash ns/iter hashbrown ns/iter diff ns/iter diff % speedup
@@ -58,7 +58,7 @@ With the hashbrown default AHash hasher ([without HashDoS-resistance](#Flags)):
5858
lookup_fail_ahash_serial 4,902 3,240 -1,662 -33.90% x 1.51
5959
```
6060

61-
With the libstd default SipHash hasher (HashDoS-resistant):
61+
With the libstd default SipHash hasher:
6262

6363
```text
6464
name oldstdhash ns/iter hashbrown ns/iter diff ns/iter diff % speedup
@@ -99,19 +99,16 @@ map.insert(1, "one");
9999
## Flags
100100
This crate has the following Cargo features:
101101

102-
- `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost
103-
of compilation time. (enabled by default)
104-
- `ahash`: Compiles with ahash as default hasher. (enabled by default)
105-
- `ahash-run-time-rng`: Uses randomly generated keys for each hashmap to provide DOS resistance.
106-
This requires the standard library. (disabled by default)
107-
- `ahash-compile-time-rng`: This is an alternative to `ahash-run-time-rng` that works by pre-generating keys at
108-
compile time and embedding them as constants. The avoids the dependency on the standard library but means the
109-
binary will be slightly different each time it is compiled. (disabled by default)
110-
- `nightly`: Enables nightly-only features including: `#[may_dangle]` and specialization to improve performance hashing
111-
primitive types in aHash (if `ahash` is enabled).
102+
- `nightly`: Enables nightly-only features including: `#[may_dangle]`
112103
- `serde`: Enables serde serialization support.
113104
- `rayon`: Enables rayon parallel iterator support.
114105
- `raw`: Enables access to the experimental and unsafe `RawTable` API.
106+
- `inline-more`: Adds inline hints to most functions, improving run-time performance at the cost
107+
of compilation time. (enabled by default)
108+
- `ahash`: Compiles with ahash as default hasher. (enabled by default)
109+
- `ahash-compile-time-rng`: Activates the `compile-time-rng` feature of ahash. For targets with no random number generator
110+
this pre-generates seeds at compile time and embeds them as constants. See [aHash's documentation](https://github.com/tkaitchuck/aHash#flags) (disabled by default)
111+
115112

116113
## License
117114

src/map.rs

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,13 @@ impl<K: Clone, V: Clone, S: Clone> Clone for HashMap<K, V, S> {
209209
/// Ensures that a single closure type across uses of this which, in turn prevents multiple
210210
/// instances of any functions like RawTable::reserve from being generated
211211
#[cfg_attr(feature = "inline-more", inline)]
212-
pub(crate) fn make_hasher<K: Hash, V>(
213-
hash_builder: &impl BuildHasher,
214-
) -> impl Fn(&(K, V)) -> u64 + '_ {
215-
move |val| make_hash(hash_builder, &val.0)
212+
pub(crate) fn make_hasher<K, Q, V, S>(hash_builder: &S) -> impl Fn(&(Q, V)) -> u64 + '_
213+
where
214+
K: Borrow<Q>,
215+
Q: Hash,
216+
S: BuildHasher
217+
{
218+
move |val| make_hash::<K, Q, S>(hash_builder, &val.0)
216219
}
217220

218221
/// Ensures that a single closure type across uses of this which, in turn prevents multiple
@@ -238,13 +241,18 @@ where
238241
}
239242

240243
#[cfg_attr(feature = "inline-more", inline)]
241-
pub(crate) fn make_hash<K: Hash + ?Sized>(hash_builder: &impl BuildHasher, val: &K) -> u64 {
244+
pub(crate) fn make_hash<K, Q, S>(hash_builder: &S, val: &Q) -> u64
245+
where
246+
K: Borrow<Q>,
247+
Q: Hash + ?Sized,
248+
S: BuildHasher
249+
{
242250
#[cfg(feature = "ahash")]
243251
{
244252
//This enables specialization to improve performance on primitive types
245253
use ahash::CallHasher;
246254
let state = hash_builder.build_hasher();
247-
val.get_hash(state)
255+
Q::get_hash(val, state)
248256
}
249257
#[cfg(not(feature = "ahash"))]
250258
{
@@ -255,6 +263,28 @@ pub(crate) fn make_hash<K: Hash + ?Sized>(hash_builder: &impl BuildHasher, val:
255263
}
256264
}
257265

266+
#[cfg_attr(feature = "inline-more", inline)]
267+
pub(crate) fn make_insert_hash<K, S>(hash_builder: &S, val: &K) -> u64
268+
where
269+
K: Hash,
270+
S: BuildHasher
271+
{
272+
#[cfg(feature = "ahash")]
273+
{
274+
//This enables specialization to improve performance on primitive types
275+
use ahash::CallHasher;
276+
let state = hash_builder.build_hasher();
277+
K::get_hash(val, state)
278+
}
279+
#[cfg(not(feature = "ahash"))]
280+
{
281+
use core::hash::Hasher;
282+
let mut state = hash_builder.build_hasher();
283+
val.hash(&mut state);
284+
state.finish()
285+
}
286+
}
287+
258288
#[cfg(feature = "ahash")]
259289
impl<K, V> HashMap<K, V, DefaultHashBuilder> {
260290
/// Creates an empty `HashMap`.
@@ -706,7 +736,7 @@ where
706736
#[cfg_attr(feature = "inline-more", inline)]
707737
pub fn reserve(&mut self, additional: usize) {
708738
self.table
709-
.reserve(additional, make_hasher(&self.hash_builder));
739+
.reserve(additional, make_hasher::<K, _, V, S>(&self.hash_builder));
710740
}
711741

712742
/// Tries to reserve capacity for at least `additional` more elements to be inserted
@@ -728,7 +758,7 @@ where
728758
#[cfg_attr(feature = "inline-more", inline)]
729759
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
730760
self.table
731-
.try_reserve(additional, make_hasher(&self.hash_builder))
761+
.try_reserve(additional, make_hasher::<K, _, V, S>(&self.hash_builder))
732762
}
733763

734764
/// Shrinks the capacity of the map as much as possible. It will drop
@@ -749,7 +779,7 @@ where
749779
/// ```
750780
#[cfg_attr(feature = "inline-more", inline)]
751781
pub fn shrink_to_fit(&mut self) {
752-
self.table.shrink_to(0, make_hasher(&self.hash_builder));
782+
self.table.shrink_to(0, make_hasher::<K, _, V, S>(&self.hash_builder));
753783
}
754784

755785
/// Shrinks the capacity of the map with a lower limit. It will drop
@@ -778,7 +808,7 @@ where
778808
#[cfg_attr(feature = "inline-more", inline)]
779809
pub fn shrink_to(&mut self, min_capacity: usize) {
780810
self.table
781-
.shrink_to(min_capacity, make_hasher(&self.hash_builder));
811+
.shrink_to(min_capacity, make_hasher::<K, _, V, S>(&self.hash_builder));
782812
}
783813

784814
/// Gets the given key's corresponding entry in the map for in-place manipulation.
@@ -802,7 +832,7 @@ where
802832
/// ```
803833
#[cfg_attr(feature = "inline-more", inline)]
804834
pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S> {
805-
let hash = make_hash(&self.hash_builder, &key);
835+
let hash = make_insert_hash::<K, S>(&self.hash_builder, &key);
806836
if let Some(elem) = self.table.find(hash, equivalent_key(&key)) {
807837
Entry::Occupied(OccupiedEntry {
808838
hash,
@@ -889,7 +919,7 @@ where
889919
K: Borrow<Q>,
890920
Q: Hash + Eq,
891921
{
892-
let hash = make_hash(&self.hash_builder, k);
922+
let hash = make_hash::<K, Q, S>(&self.hash_builder, k);
893923
self.table.get(hash, equivalent_key(k))
894924
}
895925

@@ -997,7 +1027,7 @@ where
9971027
K: Borrow<Q>,
9981028
Q: Hash + Eq,
9991029
{
1000-
let hash = make_hash(&self.hash_builder, k);
1030+
let hash = make_hash::<K, Q, S>(&self.hash_builder, k);
10011031
self.table.get_mut(hash, equivalent_key(k))
10021032
}
10031033

@@ -1028,12 +1058,12 @@ where
10281058
/// ```
10291059
#[cfg_attr(feature = "inline-more", inline)]
10301060
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
1031-
let hash = make_hash(&self.hash_builder, &k);
1061+
let hash = make_insert_hash::<K, S>(&self.hash_builder, &k);
10321062
if let Some((_, item)) = self.table.get_mut(hash, equivalent_key(&k)) {
10331063
Some(mem::replace(item, v))
10341064
} else {
10351065
self.table
1036-
.insert(hash, (k, v), make_hasher(&self.hash_builder));
1066+
.insert(hash, (k, v), make_hasher::<K, _, V, S>(&self.hash_builder));
10371067
None
10381068
}
10391069
}
@@ -1097,7 +1127,7 @@ where
10971127
K: Borrow<Q>,
10981128
Q: Hash + Eq,
10991129
{
1100-
let hash = make_hash(&self.hash_builder, &k);
1130+
let hash = make_hash::<K, Q, S>(&self.hash_builder, k);
11011131
self.table.remove_entry(hash, equivalent_key(k))
11021132
}
11031133
}
@@ -1158,6 +1188,7 @@ impl<K, V, S> HashMap<K, V, S> {
11581188
pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> {
11591189
RawEntryBuilder { map: self }
11601190
}
1191+
11611192
}
11621193

11631194
impl<K, V, S> PartialEq for HashMap<K, V, S>
@@ -1552,7 +1583,7 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> {
15521583
K: Borrow<Q>,
15531584
Q: Hash + Eq,
15541585
{
1555-
let hash = make_hash(&self.map.hash_builder, k);
1586+
let hash = make_hash::<K, Q, S>(&self.map.hash_builder, k);
15561587
self.from_key_hashed_nocheck(hash, k)
15571588
}
15581589

@@ -1608,7 +1639,7 @@ impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> {
16081639
K: Borrow<Q>,
16091640
Q: Hash + Eq,
16101641
{
1611-
let hash = make_hash(&self.map.hash_builder, k);
1642+
let hash = make_hash::<K, Q, S>(&self.map.hash_builder, k);
16121643
self.from_key_hashed_nocheck(hash, k)
16131644
}
16141645

@@ -1966,7 +1997,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
19661997
K: Hash,
19671998
S: BuildHasher,
19681999
{
1969-
let hash = make_hash(self.hash_builder, &key);
2000+
let hash = make_insert_hash::<K, S>(self.hash_builder, &key);
19702001
self.insert_hashed_nocheck(hash, key, value)
19712002
}
19722003

@@ -1981,7 +2012,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
19812012
{
19822013
let &mut (ref mut k, ref mut v) =
19832014
self.table
1984-
.insert_entry(hash, (key, value), make_hasher(self.hash_builder));
2015+
.insert_entry(hash, (key, value), make_hasher::<K, _, V, S>(self.hash_builder));
19852016
(k, v)
19862017
}
19872018

@@ -2009,10 +2040,10 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
20092040
K: Hash,
20102041
S: BuildHasher,
20112042
{
2012-
let hash = make_hash(self.hash_builder, &key);
2043+
let hash = make_insert_hash::<K, S>(self.hash_builder, &key);
20132044
let elem = self
20142045
.table
2015-
.insert(hash, (key, value), make_hasher(self.hash_builder));
2046+
.insert(hash, (key, value), make_hasher::<K, _, V, S>(self.hash_builder));
20162047
RawOccupiedEntryMut {
20172048
elem,
20182049
table: self.table,
@@ -3009,7 +3040,7 @@ impl<'a, K, V, S> VacantEntry<'a, K, V, S> {
30093040
let entry = table.insert_entry(
30103041
self.hash,
30113042
(self.key, value),
3012-
make_hasher(&self.table.hash_builder),
3043+
make_hasher::<K, _, V, S>(&self.table.hash_builder),
30133044
);
30143045
&mut entry.1
30153046
}
@@ -3023,7 +3054,7 @@ impl<'a, K, V, S> VacantEntry<'a, K, V, S> {
30233054
let elem = self.table.table.insert(
30243055
self.hash,
30253056
(self.key, value),
3026-
make_hasher(&self.table.hash_builder),
3057+
make_hasher::<K, _, V, S>(&self.table.hash_builder),
30273058
);
30283059
OccupiedEntry {
30293060
hash: self.hash,
@@ -4322,11 +4353,7 @@ mod test_map {
43224353
let mut map: HashMap<_, _> = xs.iter().cloned().collect();
43234354

43244355
let compute_hash = |map: &HashMap<i32, i32>, k: i32| -> u64 {
4325-
use core::hash::{BuildHasher, Hash, Hasher};
4326-
4327-
let mut hasher = map.hasher().build_hasher();
4328-
k.hash(&mut hasher);
4329-
hasher.finish()
4356+
super::make_insert_hash::<i32, _>(map.hasher(), &k)
43304357
};
43314358

43324359
// Existing key (insert)

0 commit comments

Comments
 (0)