]> git.lizzy.rs Git - rust.git/blob - src/bootstrap/cache.rs
Auto merge of #58649 - pnkfelix:issue-57464-avoid-ice-when-region-sneaks-into-impl...
[rust.git] / src / bootstrap / cache.rs
1 use std::any::{Any, TypeId};
2 use std::borrow::Borrow;
3 use std::cell::RefCell;
4 use std::collections::HashMap;
5 use std::convert::AsRef;
6 use std::ffi::OsStr;
7 use std::fmt;
8 use std::hash::{Hash, Hasher};
9 use std::marker::PhantomData;
10 use std::mem;
11 use std::ops::Deref;
12 use std::path::{Path, PathBuf};
13 use std::sync::Mutex;
14 use std::cmp::{PartialOrd, Ord, Ordering};
15
16 use crate::builder::Step;
17
18 pub struct Interned<T>(usize, PhantomData<*const T>);
19
20 impl Default for Interned<String> {
21     fn default() -> Self {
22         INTERNER.intern_string(String::default())
23     }
24 }
25
26 impl Default for Interned<PathBuf> {
27     fn default() -> Self {
28         INTERNER.intern_path(PathBuf::default())
29     }
30 }
31
32 impl<T> Copy for Interned<T> {}
33 impl<T> Clone for Interned<T> {
34     fn clone(&self) -> Interned<T> {
35         *self
36     }
37 }
38
39 impl<T> PartialEq for Interned<T> {
40     fn eq(&self, other: &Self) -> bool {
41         self.0 == other.0
42     }
43 }
44 impl<T> Eq for Interned<T> {}
45
46 impl PartialEq<str> for Interned<String> {
47     fn eq(&self, other: &str) -> bool {
48        *self == other
49     }
50 }
51 impl<'a> PartialEq<&'a str> for Interned<String> {
52     fn eq(&self, other: &&str) -> bool {
53         **self == **other
54     }
55 }
56 impl<'a, T> PartialEq<&'a Interned<T>> for Interned<T> {
57     fn eq(&self, other: &&Self) -> bool {
58         self.0 == other.0
59     }
60 }
61 impl<'a, T> PartialEq<Interned<T>> for &'a Interned<T> {
62     fn eq(&self, other: &Interned<T>) -> bool {
63         self.0 == other.0
64     }
65 }
66
67 unsafe impl<T> Send for Interned<T> {}
68 unsafe impl<T> Sync for Interned<T> {}
69
70 impl fmt::Display for Interned<String> {
71     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72         let s: &str = &*self;
73         f.write_str(s)
74     }
75 }
76
77 impl fmt::Debug for Interned<String> {
78     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79         let s: &str = &*self;
80         f.write_fmt(format_args!("{:?}", s))
81     }
82 }
83 impl fmt::Debug for Interned<PathBuf> {
84     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85         let s: &Path = &*self;
86         f.write_fmt(format_args!("{:?}", s))
87     }
88 }
89
90 impl Hash for Interned<String> {
91     fn hash<H: Hasher>(&self, state: &mut H) {
92         let l = INTERNER.strs.lock().unwrap();
93         l.get(*self).hash(state)
94     }
95 }
96
97 impl Hash for Interned<PathBuf> {
98     fn hash<H: Hasher>(&self, state: &mut H) {
99         let l = INTERNER.paths.lock().unwrap();
100         l.get(*self).hash(state)
101     }
102 }
103
104 impl Deref for Interned<String> {
105     type Target = str;
106     fn deref(&self) -> &'static str {
107         let l = INTERNER.strs.lock().unwrap();
108         unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) }
109     }
110 }
111
112 impl Deref for Interned<PathBuf> {
113     type Target = Path;
114     fn deref(&self) -> &'static Path {
115         let l = INTERNER.paths.lock().unwrap();
116         unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
117     }
118 }
119
120 impl AsRef<Path> for Interned<PathBuf> {
121     fn as_ref(&self) -> &'static Path {
122         let l = INTERNER.paths.lock().unwrap();
123         unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
124     }
125 }
126
127 impl AsRef<Path> for Interned<String> {
128     fn as_ref(&self) -> &'static Path {
129         let l = INTERNER.strs.lock().unwrap();
130         unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self).as_ref()) }
131     }
132 }
133
134 impl AsRef<OsStr> for Interned<PathBuf> {
135     fn as_ref(&self) -> &'static OsStr {
136         let l = INTERNER.paths.lock().unwrap();
137         unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
138     }
139 }
140
141 impl AsRef<OsStr> for Interned<String> {
142     fn as_ref(&self) -> &'static OsStr {
143         let l = INTERNER.strs.lock().unwrap();
144         unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
145     }
146 }
147
148 impl PartialOrd<Interned<String>> for Interned<String> {
149     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
150         let l = INTERNER.strs.lock().unwrap();
151         l.get(*self).partial_cmp(l.get(*other))
152     }
153 }
154
155 impl Ord for Interned<String> {
156     fn cmp(&self, other: &Self) -> Ordering {
157         let l = INTERNER.strs.lock().unwrap();
158         l.get(*self).cmp(l.get(*other))
159     }
160 }
161
162 struct TyIntern<T: Hash + Clone + Eq> {
163     items: Vec<T>,
164     set: HashMap<T, Interned<T>>,
165 }
166
167 impl<T: Hash + Clone + Eq> Default for TyIntern<T> {
168     fn default() -> Self {
169         TyIntern {
170             items: Vec::new(),
171             set: Default::default(),
172         }
173     }
174 }
175
176 impl<T: Hash + Clone + Eq> TyIntern<T> {
177     fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
178     where
179         B: Eq + Hash + ToOwned<Owned=T> + ?Sized,
180         T: Borrow<B>,
181     {
182         if let Some(i) = self.set.get(&item) {
183             return *i;
184         }
185         let item = item.to_owned();
186         let interned =  Interned(self.items.len(), PhantomData::<*const T>);
187         self.set.insert(item.clone(), interned);
188         self.items.push(item);
189         interned
190     }
191
192     fn intern(&mut self, item: T) -> Interned<T> {
193         if let Some(i) = self.set.get(&item) {
194             return *i;
195         }
196         let interned =  Interned(self.items.len(), PhantomData::<*const T>);
197         self.set.insert(item.clone(), interned);
198         self.items.push(item);
199         interned
200     }
201
202     fn get(&self, i: Interned<T>) -> &T {
203         &self.items[i.0]
204     }
205 }
206
207 #[derive(Default)]
208 pub struct Interner {
209     strs: Mutex<TyIntern<String>>,
210     paths: Mutex<TyIntern<PathBuf>>,
211 }
212
213 impl Interner {
214     pub fn intern_str(&self, s: &str) -> Interned<String> {
215         self.strs.lock().unwrap().intern_borrow(s)
216     }
217     pub fn intern_string(&self, s: String) -> Interned<String> {
218         self.strs.lock().unwrap().intern(s)
219     }
220
221     pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> {
222         self.paths.lock().unwrap().intern(s)
223     }
224 }
225
226 lazy_static! {
227     pub static ref INTERNER: Interner = Interner::default();
228 }
229
230 /// This is essentially a `HashMap` which allows storing any type in its input and
231 /// any type in its output. It is a write-once cache; values are never evicted,
232 /// which means that references to the value can safely be returned from the
233 /// `get()` method.
234 #[derive(Debug)]
235 pub struct Cache(
236     RefCell<HashMap<
237         TypeId,
238         Box<dyn Any>, // actually a HashMap<Step, Interned<Step::Output>>
239     >>
240 );
241
242 impl Cache {
243     pub fn new() -> Cache {
244         Cache(RefCell::new(HashMap::new()))
245     }
246
247     pub fn put<S: Step>(&self, step: S, value: S::Output) {
248         let mut cache = self.0.borrow_mut();
249         let type_id = TypeId::of::<S>();
250         let stepcache = cache.entry(type_id)
251                         .or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
252                         .downcast_mut::<HashMap<S, S::Output>>()
253                         .expect("invalid type mapped");
254         assert!(!stepcache.contains_key(&step), "processing {:?} a second time", step);
255         stepcache.insert(step, value);
256     }
257
258     pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> {
259         let mut cache = self.0.borrow_mut();
260         let type_id = TypeId::of::<S>();
261         let stepcache = cache.entry(type_id)
262                         .or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
263                         .downcast_mut::<HashMap<S, S::Output>>()
264                         .expect("invalid type mapped");
265         stepcache.get(step).cloned()
266     }
267
268     #[cfg(test)]
269     pub fn all<S: Ord + Copy + Step>(&mut self) -> Vec<(S, S::Output)> {
270         let cache = self.0.get_mut();
271         let type_id = TypeId::of::<S>();
272         let mut v = cache.remove(&type_id)
273             .map(|b| b.downcast::<HashMap<S, S::Output>>().expect("correct type"))
274             .map(|m| m.into_iter().collect::<Vec<_>>())
275             .unwrap_or_default();
276         v.sort_by_key(|&(a, _)| a);
277         v
278     }
279
280     #[cfg(test)]
281     pub fn contains<S: Step>(&self) -> bool {
282         self.0.borrow().contains_key(&TypeId::of::<S>())
283     }
284 }