Auto merge of #76233 - cuviper:unhasher, r=Mark-Simulacrum

Avoid rehashing Fingerprint as a map key

This introduces a no-op `Unhasher` for map keys that are already hash-
like, for example `Fingerprint` and its wrapper `DefPathHash`. For these
we can directly produce the `u64` hash for maps. The first use of this
is `def_path_hash_to_def_id: Option<UnhashMap<DefPathHash, DefId>>`.

cc #56308
r? @eddyb
This commit is contained in:
bors 2020-09-02 22:16:22 +00:00
commit 51f79b618d
4 changed files with 62 additions and 3 deletions

View file

@ -3,9 +3,10 @@ use rustc_serialize::{
opaque::{self, EncodeResult},
Decodable, Encodable,
};
use std::hash::{Hash, Hasher};
use std::mem;
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)]
#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
pub struct Fingerprint(u64, u64);
impl Fingerprint {
@ -76,6 +77,33 @@ impl ::std::fmt::Display for Fingerprint {
}
}
impl Hash for Fingerprint {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_fingerprint(self);
}
}
trait FingerprintHasher {
fn write_fingerprint(&mut self, fingerprint: &Fingerprint);
}
impl<H: Hasher> FingerprintHasher for H {
#[inline]
default fn write_fingerprint(&mut self, fingerprint: &Fingerprint) {
self.write_u64(fingerprint.0);
self.write_u64(fingerprint.1);
}
}
impl FingerprintHasher for crate::unhash::Unhasher {
#[inline]
fn write_fingerprint(&mut self, fingerprint: &Fingerprint) {
// `Unhasher` only wants a single `u64`
self.write_u64(fingerprint.0);
}
}
impl stable_hasher::StableHasherResult for Fingerprint {
#[inline]
fn finish(hasher: stable_hasher::StableHasher) -> Self {

View file

@ -103,6 +103,7 @@ pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;
pub struct OnDrop<F: Fn()>(pub F);

View file

@ -0,0 +1,29 @@
use std::collections::{HashMap, HashSet};
use std::hash::{BuildHasherDefault, Hasher};
pub type UnhashMap<K, V> = HashMap<K, V, BuildHasherDefault<Unhasher>>;
pub type UnhashSet<V> = HashSet<V, BuildHasherDefault<Unhasher>>;
/// This no-op hasher expects only a single `write_u64` call. It's intended for
/// map keys that already have hash-like quality, like `Fingerprint`.
#[derive(Default)]
pub struct Unhasher {
value: u64,
}
impl Hasher for Unhasher {
#[inline]
fn finish(&self) -> u64 {
self.value
}
fn write(&mut self, _bytes: &[u8]) {
unimplemented!("use write_u64");
}
#[inline]
fn write_u64(&mut self, value: u64) {
debug_assert_eq!(0, self.value, "Unhasher doesn't mix values!");
self.value = value;
}
}