Skip to main content

poly_commitment/
hash_map_cache.rs

1#![allow(unsafe_code)]
2
3use std::{
4    cmp::Eq,
5    collections::{hash_map::Entry, HashMap},
6    hash::Hash,
7    sync::{Arc, Mutex},
8};
9
10#[derive(Debug, Clone, Default)]
11pub struct HashMapCache<Key: Hash, Value> {
12    contents: Arc<Mutex<HashMap<Key, Value>>>,
13}
14
15impl<Key: Hash + Eq, Value> HashMapCache<Key, Value> {
16    #[must_use]
17    pub fn new() -> Self {
18        Self {
19            contents: Arc::new(Mutex::new(HashMap::new())),
20        }
21    }
22
23    #[must_use]
24    pub fn new_from_hashmap(hashmap: HashMap<Key, Value>) -> Self {
25        Self {
26            contents: Arc::new(Mutex::new(hashmap)),
27        }
28    }
29
30    /// Retrieves a cached value by key, or generates and caches it using the
31    /// provided closure.
32    ///
33    /// # Panics
34    ///
35    /// Panics if the internal mutex is poisoned.
36    pub fn get_or_generate<F: FnOnce() -> Value>(&self, key: Key, generator: F) -> &Value {
37        let mut hashmap = self.contents.lock().unwrap();
38        let entry = (*hashmap).entry(key);
39        let inner_ptr = match entry {
40            Entry::Occupied(o) => {
41                let o_ref = o.into_mut();
42                std::ptr::from_ref(o_ref)
43            }
44            Entry::Vacant(v) => {
45                let v_ref = v.insert(generator());
46                std::ptr::from_ref(v_ref)
47            }
48        };
49        drop(hashmap);
50
51        // This is safe because we never delete entries from the cache, and the
52        // value reference must live at least at most as long as the cache
53        // value.
54        unsafe { &*inner_ptr }
55    }
56
57    /// Returns `true` if the cache contains the given key.
58    ///
59    /// # Panics
60    ///
61    /// Panics if the internal mutex is poisoned.
62    pub fn contains_key(&self, key: &Key) -> bool {
63        self.contents.lock().unwrap().contains_key(key)
64    }
65}
66
67#[allow(clippy::implicit_hasher)]
68#[allow(clippy::fallible_impl_from)]
69impl<Key: Hash + Eq + Clone, Value: Clone> From<HashMapCache<Key, Value>> for HashMap<Key, Value> {
70    fn from(cache: HashMapCache<Key, Value>) -> Self {
71        cache.contents.lock().unwrap().clone()
72    }
73}