Skip to main content

prune_lang/utils/
env_map.rs

1use std::borrow::Borrow;
2use std::collections::{HashMap, hash_map};
3use std::fmt::Debug;
4use std::hash::Hash;
5
6/// `EnvOpr<K,V>` records all the operation have done.
7/// When the `EnvMap` do [`EnvMap::insert`] or [`EnvMap::remove`], an `EnvOpr` is created
8
9#[derive(Clone, Debug, PartialEq)]
10enum EnvOpr<K, V> {
11    /// When doing [`EnvMap::insert`]
12    /// If has such key in environment, the old value is covered.
13    /// `Update(K,V)` record the key `K` and old value `V`
14    Update(K, V),
15    /// When doing [`EnvMap::insert`]
16    /// If there was no such key in environment, the key and new value were inserted
17    /// `Insert(K)` record only the key `K`
18    Insert(K),
19    /// When doing [`EnvMap::remove`]
20    /// If has such key in environment, the old value is deleted.
21    /// `Delete(K,V)` record the key `K` and old value `V`
22    Delete(K, V),
23    /// When doing [`EnvMap::remove`]
24    /// If there was no such key in environment, nothing happend.
25    /// Therefore, nothing to record.
26    Nothing,
27}
28
29/// EnvMap is a wrapper of HashMap, but with the ability to backtrack and recover from modification
30#[derive(Clone, Debug)]
31pub struct EnvMap<K, V> {
32    /// The wrapped HashMap allow us to do all the work.
33    base_map: HashMap<K, V>,
34    /// History records all the operations that have done.
35    history: Vec<EnvOpr<K, V>>,
36    /// Scopes records the hisory pivot for each scope
37    scopes: Vec<usize>,
38}
39
40/// Many implementations are just the same as HashMap
41impl<K, V> Default for EnvMap<K, V>
42where
43    K: Eq + Hash + Clone,
44{
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl<K, V> EnvMap<K, V>
51where
52    K: Eq + Hash + Clone,
53{
54    /// Creating an empty EnvMap
55    pub fn new() -> EnvMap<K, V> {
56        EnvMap {
57            base_map: HashMap::new(),
58            history: Vec::new(),
59            scopes: Vec::new(),
60        }
61    }
62
63    /// Creating an empty EnvMap with capacity
64    pub fn with_capacity(capacity: usize) -> EnvMap<K, V> {
65        EnvMap {
66            base_map: HashMap::with_capacity(capacity),
67            history: Vec::new(),
68            scopes: Vec::new(),
69        }
70    }
71
72    /// Returns the number of elements the map can hold without reallocating.
73    pub fn capacity(&self) -> usize {
74        self.base_map.capacity()
75    }
76
77    /// An iterator visiting all keys in arbitrary order.
78    pub fn keys(&self) -> hash_map::Keys<'_, K, V> {
79        self.base_map.keys()
80    }
81
82    /// An iterator visiting all values in arbitrary order.
83    pub fn values(&self) -> hash_map::Values<'_, K, V> {
84        self.base_map.values()
85    }
86
87    /// An iterator visiting all key-value pairs in arbitrary order.
88    pub fn iter(&self) -> hash_map::Iter<'_, K, V> {
89        self.base_map.iter()
90    }
91
92    /// Returns `true` if the map contains no elements.
93    pub fn is_empty(&self) -> bool {
94        self.base_map.is_empty()
95    }
96
97    /// Returns `true` if there is no saved scope frame
98    pub fn is_scope_empty(&self) -> bool {
99        self.scopes.is_empty()
100    }
101
102    /// Clears the map, removing all key-value pairs. Keeps the allocated memory
103    /// for reuse.
104    pub fn clear(&mut self) {
105        self.base_map.clear();
106        self.history.clear();
107        self.scopes.clear();
108    }
109
110    /// Returns a reference to the value corresponding to the key.
111    pub fn get<Q>(&self, k: &Q) -> Option<&V>
112    where
113        K: Borrow<Q>,
114        Q: ?Sized + Hash + Eq,
115    {
116        self.base_map.get(k)
117    }
118
119    /// Returns the key-value pair corresponding to the supplied key.
120    pub fn get_key_value<Q>(&self, k: &Q) -> Option<(&K, &V)>
121    where
122        K: Borrow<Q>,
123        Q: ?Sized + Hash + Eq,
124    {
125        self.base_map.get_key_value(k)
126    }
127
128    /// Returns `true` if the map contains a value for the specified key.
129    pub fn contains_key<Q>(&self, k: &Q) -> bool
130    where
131        K: Borrow<Q>,
132        Q: ?Sized + Hash + Eq,
133    {
134        self.base_map.contains_key(k)
135    }
136
137    /// Inserts a key-value pair into the map.
138    pub fn insert(&mut self, k: K, v: V) -> bool {
139        if let Some(old) = self.base_map.insert(k.clone(), v) {
140            self.history.push(EnvOpr::Update(k, old));
141            true
142        } else {
143            self.history.push(EnvOpr::Insert(k));
144            false
145        }
146    }
147
148    /// Removes a key from the map
149    pub fn remove(&mut self, k: &K) -> bool {
150        if let Some(old) = self.base_map.remove(k) {
151            self.history.push(EnvOpr::Delete(k.clone(), old));
152            true
153        } else {
154            self.history.push(EnvOpr::Nothing);
155            false
156        }
157    }
158
159    /// Enter a new scope, record the current pivot of history
160    pub fn enter_scope(&mut self) {
161        self.scopes.push(self.history.len())
162    }
163
164    /// Leave from a scope, unwind the history and recover.
165    pub fn leave_scope(&mut self) {
166        let n = self.scopes.pop().unwrap();
167        for _ in n..self.history.len() {
168            match self.history.pop().unwrap() {
169                EnvOpr::Update(k, v) => {
170                    // recover the old value that was covered by insert
171                    let r = self.base_map.insert(k, v);
172                    assert!(r.is_some());
173                }
174                EnvOpr::Insert(k) => {
175                    // remove the inserted key and value
176                    let r = self.base_map.remove(&k);
177                    assert!(r.is_some());
178                }
179                EnvOpr::Delete(k, v) => {
180                    // recover the deleted key and value
181                    let r = self.base_map.insert(k, v);
182                    assert!(r.is_none());
183                }
184                EnvOpr::Nothing => {
185                    // Well, do nothing...
186                }
187            }
188        }
189    }
190}
191
192impl<K, V> std::ops::Index<&K> for EnvMap<K, V>
193where
194    K: Hash + Eq,
195{
196    type Output = V;
197
198    fn index(&self, index: &K) -> &Self::Output {
199        &self.base_map[index]
200    }
201}
202
203#[test]
204fn env_map_test() {
205    let mut env = EnvMap::new();
206    env.insert(&1, 'a');
207    env.enter_scope();
208    env.insert(&1, 'd');
209    env.insert(&2, 'b');
210    env.insert(&3, 'c');
211    assert_eq!(env.get(&1), Some(&'d'));
212    assert_eq!(env.get(&2), Some(&'b'));
213    assert_eq!(env.get(&3), Some(&'c'));
214    env.leave_scope();
215    assert_eq!(env.get(&1), Some(&'a'));
216    assert_eq!(env.get(&2), None);
217    assert_eq!(env.get(&3), None);
218}