1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 use std::any::{Any, TypeId};
12 use std::borrow::Borrow;
13 use std::cell::RefCell;
14 use std::collections::HashMap;
15 use std::convert::AsRef;
18 use std::hash::{Hash, Hasher};
19 use std::marker::PhantomData;
22 use std::path::{Path, PathBuf};
24 use std::cmp::{PartialOrd, Ord, Ordering};
28 pub struct Interned<T>(usize, PhantomData<*const T>);
30 impl Default for Interned<String> {
31 fn default() -> Self {
32 INTERNER.intern_string(String::default())
36 impl Default for Interned<PathBuf> {
37 fn default() -> Self {
38 INTERNER.intern_path(PathBuf::default())
42 impl<T> Copy for Interned<T> {}
43 impl<T> Clone for Interned<T> {
44 fn clone(&self) -> Interned<T> {
49 impl<T> PartialEq for Interned<T> {
50 fn eq(&self, other: &Self) -> bool {
54 impl<T> Eq for Interned<T> {}
56 impl PartialEq<str> for Interned<String> {
57 fn eq(&self, other: &str) -> bool {
61 impl<'a> PartialEq<&'a str> for Interned<String> {
62 fn eq(&self, other: &&str) -> bool {
66 impl<'a, T> PartialEq<&'a Interned<T>> for Interned<T> {
67 fn eq(&self, other: &&Self) -> bool {
71 impl<'a, T> PartialEq<Interned<T>> for &'a Interned<T> {
72 fn eq(&self, other: &Interned<T>) -> bool {
77 unsafe impl<T> Send for Interned<T> {}
78 unsafe impl<T> Sync for Interned<T> {}
80 impl fmt::Display for Interned<String> {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87 impl fmt::Debug for Interned<String> {
88 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90 f.write_fmt(format_args!("{:?}", s))
93 impl fmt::Debug for Interned<PathBuf> {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 let s: &Path = &*self;
96 f.write_fmt(format_args!("{:?}", s))
100 impl Hash for Interned<String> {
101 fn hash<H: Hasher>(&self, state: &mut H) {
102 let l = INTERNER.strs.lock().unwrap();
103 l.get(*self).hash(state)
107 impl Hash for Interned<PathBuf> {
108 fn hash<H: Hasher>(&self, state: &mut H) {
109 let l = INTERNER.paths.lock().unwrap();
110 l.get(*self).hash(state)
114 impl Deref for Interned<String> {
116 fn deref(&self) -> &'static str {
117 let l = INTERNER.strs.lock().unwrap();
118 unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) }
122 impl Deref for Interned<PathBuf> {
124 fn deref(&self) -> &'static Path {
125 let l = INTERNER.paths.lock().unwrap();
126 unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
130 impl AsRef<Path> for Interned<PathBuf> {
131 fn as_ref(&self) -> &'static Path {
132 let l = INTERNER.paths.lock().unwrap();
133 unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
137 impl AsRef<Path> for Interned<String> {
138 fn as_ref(&self) -> &'static Path {
139 let l = INTERNER.strs.lock().unwrap();
140 unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self).as_ref()) }
144 impl AsRef<OsStr> for Interned<PathBuf> {
145 fn as_ref(&self) -> &'static OsStr {
146 let l = INTERNER.paths.lock().unwrap();
147 unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
151 impl AsRef<OsStr> for Interned<String> {
152 fn as_ref(&self) -> &'static OsStr {
153 let l = INTERNER.strs.lock().unwrap();
154 unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
158 impl PartialOrd<Interned<String>> for Interned<String> {
159 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
160 let l = INTERNER.strs.lock().unwrap();
161 l.get(*self).partial_cmp(l.get(*other))
165 impl Ord for Interned<String> {
166 fn cmp(&self, other: &Self) -> Ordering {
167 let l = INTERNER.strs.lock().unwrap();
168 l.get(*self).cmp(l.get(*other))
172 struct TyIntern<T: Hash + Clone + Eq> {
174 set: HashMap<T, Interned<T>>,
177 impl<T: Hash + Clone + Eq> Default for TyIntern<T> {
178 fn default() -> Self {
181 set: Default::default(),
186 impl<T: Hash + Clone + Eq> TyIntern<T> {
187 fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
189 B: Eq + Hash + ToOwned<Owned=T> + ?Sized,
192 if let Some(i) = self.set.get(&item) {
195 let item = item.to_owned();
196 let interned = Interned(self.items.len(), PhantomData::<*const T>);
197 self.set.insert(item.clone(), interned);
198 self.items.push(item);
202 fn intern(&mut self, item: T) -> Interned<T> {
203 if let Some(i) = self.set.get(&item) {
206 let interned = Interned(self.items.len(), PhantomData::<*const T>);
207 self.set.insert(item.clone(), interned);
208 self.items.push(item);
212 fn get(&self, i: Interned<T>) -> &T {
218 pub struct Interner {
219 strs: Mutex<TyIntern<String>>,
220 paths: Mutex<TyIntern<PathBuf>>,
224 pub fn intern_str(&self, s: &str) -> Interned<String> {
225 self.strs.lock().unwrap().intern_borrow(s)
227 pub fn intern_string(&self, s: String) -> Interned<String> {
228 self.strs.lock().unwrap().intern(s)
231 pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> {
232 self.paths.lock().unwrap().intern(s)
237 pub static ref INTERNER: Interner = Interner::default();
240 /// This is essentially a HashMap which allows storing any type in its input and
241 /// any type in its output. It is a write-once cache; values are never evicted,
242 /// which means that references to the value can safely be returned from the
248 Box<dyn Any>, // actually a HashMap<Step, Interned<Step::Output>>
253 pub fn new() -> Cache {
254 Cache(RefCell::new(HashMap::new()))
257 pub fn put<S: Step>(&self, step: S, value: S::Output) {
258 let mut cache = self.0.borrow_mut();
259 let type_id = TypeId::of::<S>();
260 let stepcache = cache.entry(type_id)
261 .or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
262 .downcast_mut::<HashMap<S, S::Output>>()
263 .expect("invalid type mapped");
264 assert!(!stepcache.contains_key(&step), "processing {:?} a second time", step);
265 stepcache.insert(step, value);
268 pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> {
269 let mut cache = self.0.borrow_mut();
270 let type_id = TypeId::of::<S>();
271 let stepcache = cache.entry(type_id)
272 .or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
273 .downcast_mut::<HashMap<S, S::Output>>()
274 .expect("invalid type mapped");
275 stepcache.get(step).cloned()
279 pub fn all<S: Ord + Copy + Step>(&mut self) -> Vec<(S, S::Output)> {
280 let cache = self.0.get_mut();
281 let type_id = TypeId::of::<S>();
282 let mut v = cache.remove(&type_id)
283 .map(|b| b.downcast::<HashMap<S, S::Output>>().expect("correct type"))
284 .map(|m| m.into_iter().collect::<Vec<_>>())
285 .unwrap_or_default();
286 v.sort_by_key(|&(a, _)| a);
291 pub fn contains<S: Step>(&self) -> bool {
292 self.0.borrow().contains_key(&TypeId::of::<S>())