X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fmono_hash_map.rs;h=fb0169920ee28fedc71d6b8882935c8429797cd1;hb=20e31dbdad67080eb83aa3b5330dfe2f116f9900;hp=278bbd9cf2b13d5ead44c7b1de87f615d0542fba;hpb=5958fa6a7049cd003e87d6d8502ae1237262c378;p=rust.git diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 278bbd9cf2b..fb0169920ee 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -1,14 +1,14 @@ -//! This is a "monotonic HashMap": A HashMap that, when shared, can be pushed to but not -//! otherwise mutated. We also Box items in the map. This means we can safely provide -//! shared references into existing items in the HashMap, because they will not be dropped +//! This is a "monotonic `FxHashMap`": A `FxHashMap` that, when shared, can be pushed to but not +//! otherwise mutated. We also box items in the map. This means we can safely provide +//! shared references into existing items in the `FxHashMap`, because they will not be dropped //! (from being removed) or moved (because they are boxed). //! The API is is completely tailored to what `memory.rs` needs. It is still in //! a separate file to minimize the amount of code that has to care about the unsafety. -use std::collections::hash_map::Entry; +use std::borrow::Borrow; use std::cell::RefCell; +use std::collections::hash_map::Entry; use std::hash::Hash; -use std::borrow::Borrow; use rustc_data_structures::fx::FxHashMap; @@ -18,8 +18,16 @@ pub struct MonoHashMap(RefCell>>); impl MonoHashMap { - pub fn values(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { - f(&mut self.0.borrow().values().map(|v| &**v)) + /// This function exists for priroda to be able to iterate over all evaluator memory. + /// + /// The function is somewhat roundabout with the closure argument because internally the + /// `MonoHashMap` uses a `RefCell`. When iterating over the `FxHashMap` inside the `RefCell`, + /// we need to keep a borrow to the `FxHashMap` inside the iterator. The borrow is only alive + /// as long as the `Ref` returned by `RefCell::borrow()` is alive. So we can't return the + /// iterator, as that would drop the `Ref`. We can't return both, as it's not possible in Rust + /// to have a struct/tuple with a field that refers to another field. + pub fn iter(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { + f(&mut self.0.borrow().iter().map(|(k, v)| (k, &**v))) } } @@ -32,44 +40,38 @@ fn default() -> Self { impl AllocMap for MonoHashMap { #[inline(always)] fn contains_key(&mut self, k: &Q) -> bool - where K: Borrow + where + K: Borrow, { self.0.get_mut().contains_key(k) } #[inline(always)] - fn insert(&mut self, k: K, v: V) -> Option - { + fn insert(&mut self, k: K, v: V) -> Option { self.0.get_mut().insert(k, Box::new(v)).map(|x| *x) } #[inline(always)] fn remove(&mut self, k: &Q) -> Option - where K: Borrow + where + K: Borrow, { self.0.get_mut().remove(k).map(|x| *x) } #[inline(always)] fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { - self.0.borrow() - .iter() - .filter_map(move |(k, v)| f(k, &*v)) - .collect() + self.0.borrow().iter().filter_map(move |(k, v)| f(k, &*v)).collect() } - /// The most interesting method: Providing a shared ref without + /// The most interesting method: Providing a shared reference without /// holding the `RefCell` open, and inserting new data if the key /// is not used yet. /// `vacant` is called if the key is not found in the map; /// if it returns a reference, that is used directly, if it /// returns owned data, that is put into the map and returned. #[inline(always)] - fn get_or( - &self, - k: K, - vacant: impl FnOnce() -> Result - ) -> Result<&V, E> { + fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E> { let val: *const V = match self.0.borrow_mut().entry(k) { Entry::Occupied(entry) => &**entry.get(), Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)), @@ -80,12 +82,7 @@ fn get_or( } #[inline(always)] - fn get_mut_or( - &mut self, - k: K, - vacant: impl FnOnce() -> Result - ) -> Result<&mut V, E> - { + fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E> { match self.0.get_mut().entry(k) { Entry::Occupied(e) => Ok(e.into_mut()), Entry::Vacant(e) => {