]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_data_structures/src/fingerprint.rs
Auto merge of #79336 - camelid:rename-feature-oibit-to-auto, r=oli-obk
[rust.git] / compiler / rustc_data_structures / src / fingerprint.rs
1 use crate::stable_hasher;
2 use rustc_serialize::{
3     opaque::{self, EncodeResult},
4     Decodable, Encodable,
5 };
6 use std::hash::{Hash, Hasher};
7 use std::mem;
8
9 #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)]
10 pub struct Fingerprint(u64, u64);
11
12 impl Fingerprint {
13     pub const ZERO: Fingerprint = Fingerprint(0, 0);
14
15     #[inline]
16     pub fn from_smaller_hash(hash: u64) -> Fingerprint {
17         Fingerprint(hash, hash)
18     }
19
20     #[inline]
21     pub fn to_smaller_hash(&self) -> u64 {
22         self.0
23     }
24
25     #[inline]
26     pub fn as_value(&self) -> (u64, u64) {
27         (self.0, self.1)
28     }
29
30     #[inline]
31     pub fn combine(self, other: Fingerprint) -> Fingerprint {
32         // See https://stackoverflow.com/a/27952689 on why this function is
33         // implemented this way.
34         Fingerprint(
35             self.0.wrapping_mul(3).wrapping_add(other.0),
36             self.1.wrapping_mul(3).wrapping_add(other.1),
37         )
38     }
39
40     // Combines two hashes in an order independent way. Make sure this is what
41     // you want.
42     #[inline]
43     pub fn combine_commutative(self, other: Fingerprint) -> Fingerprint {
44         let a = u128::from(self.1) << 64 | u128::from(self.0);
45         let b = u128::from(other.1) << 64 | u128::from(other.0);
46
47         let c = a.wrapping_add(b);
48
49         Fingerprint((c >> 64) as u64, c as u64)
50     }
51
52     pub fn to_hex(&self) -> String {
53         format!("{:x}{:x}", self.0, self.1)
54     }
55
56     pub fn encode_opaque(&self, encoder: &mut opaque::Encoder) -> EncodeResult {
57         let bytes: [u8; 16] = unsafe { mem::transmute([self.0.to_le(), self.1.to_le()]) };
58
59         encoder.emit_raw_bytes(&bytes);
60         Ok(())
61     }
62
63     pub fn decode_opaque(decoder: &mut opaque::Decoder<'_>) -> Result<Fingerprint, String> {
64         let mut bytes = [0; 16];
65
66         decoder.read_raw_bytes(&mut bytes)?;
67
68         let [l, r]: [u64; 2] = unsafe { mem::transmute(bytes) };
69
70         Ok(Fingerprint(u64::from_le(l), u64::from_le(r)))
71     }
72 }
73
74 impl std::fmt::Display for Fingerprint {
75     fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76         write!(formatter, "{:x}-{:x}", self.0, self.1)
77     }
78 }
79
80 impl Hash for Fingerprint {
81     #[inline]
82     fn hash<H: Hasher>(&self, state: &mut H) {
83         state.write_fingerprint(self);
84     }
85 }
86
87 trait FingerprintHasher {
88     fn write_fingerprint(&mut self, fingerprint: &Fingerprint);
89 }
90
91 impl<H: Hasher> FingerprintHasher for H {
92     #[inline]
93     default fn write_fingerprint(&mut self, fingerprint: &Fingerprint) {
94         self.write_u64(fingerprint.0);
95         self.write_u64(fingerprint.1);
96     }
97 }
98
99 impl FingerprintHasher for crate::unhash::Unhasher {
100     #[inline]
101     fn write_fingerprint(&mut self, fingerprint: &Fingerprint) {
102         // `Unhasher` only wants a single `u64`
103         self.write_u64(fingerprint.0);
104     }
105 }
106
107 impl stable_hasher::StableHasherResult for Fingerprint {
108     #[inline]
109     fn finish(hasher: stable_hasher::StableHasher) -> Self {
110         let (_0, _1) = hasher.finalize();
111         Fingerprint(_0, _1)
112     }
113 }
114
115 impl_stable_hash_via_hash!(Fingerprint);
116
117 impl<E: rustc_serialize::Encoder> Encodable<E> for Fingerprint {
118     fn encode(&self, s: &mut E) -> Result<(), E::Error> {
119         s.encode_fingerprint(self)
120     }
121 }
122
123 impl<D: rustc_serialize::Decoder> Decodable<D> for Fingerprint {
124     fn decode(d: &mut D) -> Result<Self, D::Error> {
125         d.decode_fingerprint()
126     }
127 }
128
129 pub trait FingerprintEncoder: rustc_serialize::Encoder {
130     fn encode_fingerprint(&mut self, f: &Fingerprint) -> Result<(), Self::Error>;
131 }
132
133 pub trait FingerprintDecoder: rustc_serialize::Decoder {
134     fn decode_fingerprint(&mut self) -> Result<Fingerprint, Self::Error>;
135 }
136
137 impl<E: rustc_serialize::Encoder> FingerprintEncoder for E {
138     default fn encode_fingerprint(&mut self, _: &Fingerprint) -> Result<(), E::Error> {
139         panic!("Cannot encode `Fingerprint` with `{}`", std::any::type_name::<E>());
140     }
141 }
142
143 impl FingerprintEncoder for opaque::Encoder {
144     fn encode_fingerprint(&mut self, f: &Fingerprint) -> EncodeResult {
145         f.encode_opaque(self)
146     }
147 }
148
149 impl<D: rustc_serialize::Decoder> FingerprintDecoder for D {
150     default fn decode_fingerprint(&mut self) -> Result<Fingerprint, D::Error> {
151         panic!("Cannot decode `Fingerprint` with `{}`", std::any::type_name::<D>());
152     }
153 }
154
155 impl FingerprintDecoder for opaque::Decoder<'_> {
156     fn decode_fingerprint(&mut self) -> Result<Fingerprint, String> {
157         Fingerprint::decode_opaque(self)
158     }
159 }
160
161 // `PackedFingerprint` wraps a `Fingerprint`. Its purpose is to, on certain
162 // architectures, behave like a `Fingerprint` without alignment requirements.
163 // This behavior is only enabled on x86 and x86_64, where the impact of
164 // unaligned accesses is tolerable in small doses.
165 //
166 // This may be preferable to use in large collections of structs containing
167 // fingerprints, as it can reduce memory consumption by preventing the padding
168 // that the more strictly-aligned `Fingerprint` can introduce. An application of
169 // this is in the query dependency graph, which contains a large collection of
170 // `DepNode`s. As of this writing, the size of a `DepNode` decreases by ~30%
171 // (from 24 bytes to 17) by using the packed representation here, which
172 // noticeably decreases total memory usage when compiling large crates.
173 //
174 // The wrapped `Fingerprint` is private to reduce the chance of a client
175 // invoking undefined behavior by taking a reference to the packed field.
176 #[cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), repr(packed))]
177 #[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy, Hash)]
178 pub struct PackedFingerprint(Fingerprint);
179
180 impl std::fmt::Display for PackedFingerprint {
181     #[inline]
182     fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183         // Copy to avoid taking reference to packed field.
184         let copy = self.0;
185         copy.fmt(formatter)
186     }
187 }
188
189 impl<E: rustc_serialize::Encoder> Encodable<E> for PackedFingerprint {
190     #[inline]
191     fn encode(&self, s: &mut E) -> Result<(), E::Error> {
192         // Copy to avoid taking reference to packed field.
193         let copy = self.0;
194         copy.encode(s)
195     }
196 }
197
198 impl<D: rustc_serialize::Decoder> Decodable<D> for PackedFingerprint {
199     #[inline]
200     fn decode(d: &mut D) -> Result<Self, D::Error> {
201         Fingerprint::decode(d).map(|f| PackedFingerprint(f))
202     }
203 }
204
205 impl From<Fingerprint> for PackedFingerprint {
206     #[inline]
207     fn from(f: Fingerprint) -> PackedFingerprint {
208         PackedFingerprint(f)
209     }
210 }
211
212 impl From<PackedFingerprint> for Fingerprint {
213     #[inline]
214     fn from(f: PackedFingerprint) -> Fingerprint {
215         f.0
216     }
217 }