Skip to content

Commit adf06c2

Browse files
committed
Auto merge of #204 - Marwes:less_ir, r=Amanieu
fix: Only instantiate RawTable's reserve functions once ...per key-value. Each of the previous closures would cause an entirely new reserve/resize function to be instantiated. By using this trick (which std uses for iterator adaptors), we always get a single instantiatiation per key (modulo the insert_with_hasher method).
2 parents 34c1189 + 5e11d32 commit adf06c2

File tree

1 file changed

+63
-32
lines changed

1 file changed

+63
-32
lines changed

src/map.rs

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,37 @@ impl<K: Clone, V: Clone, S: Clone> Clone for HashMap<K, V, S> {
206206
}
207207
}
208208

209+
/// Ensures that a single closure type across uses of this which, in turn prevents multiple
210+
/// instances of any functions like RawTable::reserve from being generated
211+
#[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)
216+
}
217+
218+
/// Ensures that a single closure type across uses of this which, in turn prevents multiple
219+
/// instances of any functions like RawTable::reserve from being generated
220+
#[cfg_attr(feature = "inline-more", inline)]
221+
fn equivalent_key<Q, K, V>(k: &Q) -> impl Fn(&(K, V)) -> bool + '_
222+
where
223+
K: Borrow<Q>,
224+
Q: ?Sized + Eq,
225+
{
226+
move |x| k.eq(x.0.borrow())
227+
}
228+
229+
/// Ensures that a single closure type across uses of this which, in turn prevents multiple
230+
/// instances of any functions like RawTable::reserve from being generated
231+
#[cfg_attr(feature = "inline-more", inline)]
232+
fn equivalent<Q, K>(k: &Q) -> impl Fn(&K) -> bool + '_
233+
where
234+
K: Borrow<Q>,
235+
Q: ?Sized + Eq,
236+
{
237+
move |x| k.eq(x.borrow())
238+
}
239+
209240
#[cfg_attr(feature = "inline-more", inline)]
210241
pub(crate) fn make_hash<K: Hash + ?Sized>(hash_builder: &impl BuildHasher, val: &K) -> u64 {
211242
let mut state = hash_builder.build_hasher();
@@ -663,9 +694,8 @@ where
663694
/// ```
664695
#[cfg_attr(feature = "inline-more", inline)]
665696
pub fn reserve(&mut self, additional: usize) {
666-
let hash_builder = &self.hash_builder;
667697
self.table
668-
.reserve(additional, |x| make_hash(hash_builder, &x.0));
698+
.reserve(additional, make_hasher(&self.hash_builder));
669699
}
670700

671701
/// Tries to reserve capacity for at least `additional` more elements to be inserted
@@ -686,9 +716,8 @@ where
686716
/// ```
687717
#[cfg_attr(feature = "inline-more", inline)]
688718
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
689-
let hash_builder = &self.hash_builder;
690719
self.table
691-
.try_reserve(additional, |x| make_hash(hash_builder, &x.0))
720+
.try_reserve(additional, make_hasher(&self.hash_builder))
692721
}
693722

694723
/// Shrinks the capacity of the map as much as possible. It will drop
@@ -709,8 +738,7 @@ where
709738
/// ```
710739
#[cfg_attr(feature = "inline-more", inline)]
711740
pub fn shrink_to_fit(&mut self) {
712-
let hash_builder = &self.hash_builder;
713-
self.table.shrink_to(0, |x| make_hash(hash_builder, &x.0));
741+
self.table.shrink_to(0, make_hasher(&self.hash_builder));
714742
}
715743

716744
/// Shrinks the capacity of the map with a lower limit. It will drop
@@ -738,9 +766,8 @@ where
738766
/// ```
739767
#[cfg_attr(feature = "inline-more", inline)]
740768
pub fn shrink_to(&mut self, min_capacity: usize) {
741-
let hash_builder = &self.hash_builder;
742769
self.table
743-
.shrink_to(min_capacity, |x| make_hash(hash_builder, &x.0));
770+
.shrink_to(min_capacity, make_hasher(&self.hash_builder));
744771
}
745772

746773
/// Gets the given key's corresponding entry in the map for in-place manipulation.
@@ -765,7 +792,7 @@ where
765792
#[cfg_attr(feature = "inline-more", inline)]
766793
pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S> {
767794
let hash = make_hash(&self.hash_builder, &key);
768-
if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) {
795+
if let Some(elem) = self.table.find(hash, equivalent_key(&key)) {
769796
Entry::Occupied(OccupiedEntry {
770797
hash,
771798
key: Some(key),
@@ -852,7 +879,7 @@ where
852879
Q: Hash + Eq,
853880
{
854881
let hash = make_hash(&self.hash_builder, k);
855-
self.table.get(hash, |x| k.eq(x.0.borrow()))
882+
self.table.get(hash, equivalent_key(k))
856883
}
857884

858885
/// Returns the key-value pair corresponding to the supplied key, with a mutable reference to value.
@@ -960,7 +987,7 @@ where
960987
Q: Hash + Eq,
961988
{
962989
let hash = make_hash(&self.hash_builder, k);
963-
self.table.get_mut(hash, |x| k.eq(x.0.borrow()))
990+
self.table.get_mut(hash, equivalent_key(k))
964991
}
965992

966993
/// Inserts a key-value pair into the map.
@@ -991,12 +1018,11 @@ where
9911018
#[cfg_attr(feature = "inline-more", inline)]
9921019
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
9931020
let hash = make_hash(&self.hash_builder, &k);
994-
if let Some((_, item)) = self.table.get_mut(hash, |x| k.eq(&x.0)) {
1021+
if let Some((_, item)) = self.table.get_mut(hash, equivalent_key(&k)) {
9951022
Some(mem::replace(item, v))
9961023
} else {
997-
let hash_builder = &self.hash_builder;
9981024
self.table
999-
.insert(hash, (k, v), |x| make_hash(hash_builder, &x.0));
1025+
.insert(hash, (k, v), make_hasher(&self.hash_builder));
10001026
None
10011027
}
10021028
}
@@ -1061,7 +1087,7 @@ where
10611087
Q: Hash + Eq,
10621088
{
10631089
let hash = make_hash(&self.hash_builder, &k);
1064-
self.table.remove_entry(hash, |x| k.eq(x.0.borrow()))
1090+
self.table.remove_entry(hash, equivalent_key(k))
10651091
}
10661092
}
10671093

@@ -1528,7 +1554,7 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> {
15281554
K: Borrow<Q>,
15291555
Q: Eq,
15301556
{
1531-
self.from_hash(hash, |q| q.borrow().eq(k))
1557+
self.from_hash(hash, equivalent(k))
15321558
}
15331559
}
15341560

@@ -1585,7 +1611,7 @@ impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> {
15851611
K: Borrow<Q>,
15861612
Q: Eq,
15871613
{
1588-
self.from_hash(hash, |q| q.borrow().eq(k))
1614+
self.from_hash(hash, equivalent(k))
15891615
}
15901616

15911617
#[cfg_attr(feature = "inline-more", inline)]
@@ -1945,8 +1971,10 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
19451971
K: Hash,
19461972
S: BuildHasher,
19471973
{
1948-
let hash_builder = self.hash_builder;
1949-
self.insert_with_hasher(hash, key, value, |k| make_hash(hash_builder, k))
1974+
let &mut (ref mut k, ref mut v) =
1975+
self.table
1976+
.insert_entry(hash, (key, value), make_hasher(self.hash_builder));
1977+
(k, v)
19501978
}
19511979

19521980
/// Set the value of an entry with a custom hasher function.
@@ -1973,13 +2001,14 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
19732001
K: Hash,
19742002
S: BuildHasher,
19752003
{
1976-
let hash_builder = self.hash_builder;
19772004
let mut hasher = self.hash_builder.build_hasher();
19782005
key.hash(&mut hasher);
19792006

1980-
let elem = self.table.insert(hasher.finish(), (key, value), |k| {
1981-
make_hash(hash_builder, &k.0)
1982-
});
2007+
let elem = self.table.insert(
2008+
hasher.finish(),
2009+
(key, value),
2010+
make_hasher(self.hash_builder),
2011+
);
19832012
RawOccupiedEntryMut {
19842013
elem,
19852014
table: self.table,
@@ -2972,11 +3001,12 @@ impl<'a, K, V, S> VacantEntry<'a, K, V, S> {
29723001
K: Hash,
29733002
S: BuildHasher,
29743003
{
2975-
let hash_builder = &self.table.hash_builder;
29763004
let table = &mut self.table.table;
2977-
let entry = table.insert_entry(self.hash, (self.key, value), |x| {
2978-
make_hash(hash_builder, &x.0)
2979-
});
3005+
let entry = table.insert_entry(
3006+
self.hash,
3007+
(self.key, value),
3008+
make_hasher(&self.table.hash_builder),
3009+
);
29803010
&mut entry.1
29813011
}
29823012

@@ -2986,10 +3016,11 @@ impl<'a, K, V, S> VacantEntry<'a, K, V, S> {
29863016
K: Hash,
29873017
S: BuildHasher,
29883018
{
2989-
let hash_builder = &self.table.hash_builder;
2990-
let elem = self.table.table.insert(self.hash, (self.key, value), |x| {
2991-
make_hash(hash_builder, &x.0)
2992-
});
3019+
let elem = self.table.table.insert(
3020+
self.hash,
3021+
(self.key, value),
3022+
make_hasher(&self.table.hash_builder),
3023+
);
29933024
OccupiedEntry {
29943025
hash: self.hash,
29953026
key: None,
@@ -4470,7 +4501,7 @@ mod test_map {
44704501
assert!(removed.contains(&(i, 2 * i)), "{} not in {:?}", i, removed);
44714502
let e = m
44724503
.table
4473-
.insert(hash, (i, 2 * i), |x| super::make_hash(&hasher, &x.0));
4504+
.insert(hash, (i, 2 * i), super::make_hasher(&hasher));
44744505
it.reflect_insert(&e);
44754506
if let Some(p) = removed.iter().position(|e| e == &(i, 2 * i)) {
44764507
removed.swap_remove(p);

0 commit comments

Comments
 (0)