1 //! This is a "monotonic HashMap": A HashMap that, when shared, can be pushed to but not
2 //! otherwise mutated. We also Box items in the map. This means we can safely provide
3 //! shared references into existing items in the HashMap, because they will not be dropped
4 //! (from being removed) or moved (because they are boxed).
5 //! The API is is completely tailored to what `memory.rs` needs. It is still in
6 //! a separate file to minimize the amount of code that has to care about the unsafety.
8 use std::collections::hash_map::Entry;
9 use std::cell::RefCell;
11 use std::borrow::Borrow;
13 use rustc_data_structures::fx::FxHashMap;
17 #[derive(Debug, Clone)]
18 pub struct MonoHashMap<K: Hash + Eq, V>(RefCell<FxHashMap<K, Box<V>>>);
20 impl<K: Hash + Eq, V> MonoHashMap<K, V> {
21 /// This function exists for priroda to be able to iterate over all evaluator memory
23 /// The memory of constants does not show up in this list.
24 pub fn iter<T>(&self, f: impl FnOnce(&mut dyn Iterator<Item=(&K, &V)>) -> T) -> T {
25 f(&mut self.0.borrow().iter().map(|(k, v)| (k, &**v)))
29 impl<K: Hash + Eq, V> Default for MonoHashMap<K, V> {
30 fn default() -> Self {
31 MonoHashMap(RefCell::new(Default::default()))
35 impl<K: Hash + Eq, V> AllocMap<K, V> for MonoHashMap<K, V> {
37 fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
40 self.0.get_mut().contains_key(k)
44 fn insert(&mut self, k: K, v: V) -> Option<V>
46 self.0.get_mut().insert(k, Box::new(v)).map(|x| *x)
50 fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
53 self.0.get_mut().remove(k).map(|x| *x)
57 fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
60 .filter_map(move |(k, v)| f(k, &*v))
64 /// The most interesting method: Providing a shared ref without
65 /// holding the `RefCell` open, and inserting new data if the key
67 /// `vacant` is called if the key is not found in the map;
68 /// if it returns a reference, that is used directly, if it
69 /// returns owned data, that is put into the map and returned.
74 vacant: impl FnOnce() -> Result<V, E>
76 let val: *const V = match self.0.borrow_mut().entry(k) {
77 Entry::Occupied(entry) => &**entry.get(),
78 Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)),
80 // This is safe because `val` points into a `Box`, that we know will not move and
81 // will also not be dropped as long as the shared reference `self` is live.
89 vacant: impl FnOnce() -> Result<V, E>
90 ) -> Result<&mut V, E>
92 match self.0.get_mut().entry(k) {
93 Entry::Occupied(e) => Ok(e.into_mut()),
96 Ok(e.insert(Box::new(v)))