miri/borrow_tracker/tree_borrows/unimap.rs
1//! This module implements the `UniMap`, which is a way to get efficient mappings
2//! optimized for the setting of `tree_borrows/tree.rs`.
3//!
4//! A `UniKeyMap<K>` is a (slow) mapping from `K` to `UniIndex`,
5//! and `UniValMap<V>` is a (fast) mapping from `UniIndex` to `V`.
6//! Thus a pair `(UniKeyMap<K>, UniValMap<V>)` acts as a virtual `HashMap<K, V>`.
7//!
8//! Because of the asymmetry in access time, the use-case for `UniMap` is the following:
9//! a tuple `(UniKeyMap<K>, Vec<UniValMap<V>>)` is much more efficient than
10//! the equivalent `Vec<HashMap<K, V>>` it represents if all maps have similar
11//! sets of keys.
12
13#![allow(dead_code)]
14
15use std::hash::Hash;
16use std::mem;
17
18use rustc_data_structures::fx::FxHashMap;
19
20use crate::helpers::ToUsize;
21
22/// Intermediate key between a UniKeyMap and a UniValMap.
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct UniIndex {
25 idx: u32,
26}
27
28/// From K to UniIndex
29#[derive(Debug, Clone, Default)]
30pub struct UniKeyMap<K> {
31 /// Underlying map that does all the hard work.
32 /// Key invariant: the contents of `deassigned` are disjoint from the
33 /// keys of `mapping`, and together they form the set of contiguous integers
34 /// `0 .. (mapping.len() + deassigned.len())`.
35 mapping: FxHashMap<K, u32>,
36 /// Indexes that can be reused: memory gain when the map gets sparse
37 /// due to many deletions.
38 deassigned: Vec<u32>,
39}
40
41/// From UniIndex to V
42#[derive(Debug, Clone, Eq)]
43pub struct UniValMap<V> {
44 /// The mapping data. Thanks to Vec we get both fast accesses, and
45 /// a memory-optimal representation if there are few deletions.
46 data: Vec<Option<V>>,
47}
48
49impl<V: PartialEq> UniValMap<V> {
50 /// Exact equality of two maps.
51 /// Less accurate but faster than `equivalent`, mostly because
52 /// of the fast path when the lengths are different.
53 pub fn identical(&self, other: &Self) -> bool {
54 self.data == other.data
55 }
56
57 /// Equality up to trailing `None`s of two maps, i.e.
58 /// do they represent the same mapping ?
59 pub fn equivalent(&self, other: &Self) -> bool {
60 let min_len = self.data.len().min(other.data.len());
61 self.data[min_len..].iter().all(Option::is_none)
62 && other.data[min_len..].iter().all(Option::is_none)
63 && (self.data[..min_len] == other.data[..min_len])
64 }
65}
66
67impl<V: PartialEq> PartialEq for UniValMap<V> {
68 /// 2023-05: We found that using `equivalent` rather than `identical`
69 /// in the equality testing of the `RangeMap` is neutral for most
70 /// benchmarks, while being quite beneficial for `zip-equal`
71 /// and to a lesser extent for `unicode`, `slice-get-unchecked` and
72 /// `backtraces` as well.
73 fn eq(&self, other: &Self) -> bool {
74 self.equivalent(other)
75 }
76}
77
78impl<V> Default for UniValMap<V> {
79 fn default() -> Self {
80 Self { data: Vec::default() }
81 }
82}
83
84impl<K> UniKeyMap<K>
85where
86 K: Hash + Eq,
87{
88 /// How many keys/index pairs are currently active.
89 pub fn len(&self) -> usize {
90 self.mapping.len()
91 }
92
93 /// Whether this key has an associated index or not.
94 pub fn contains_key(&self, key: &K) -> bool {
95 self.mapping.contains_key(key)
96 }
97
98 /// Assign this key to a new index. Panics if the key is already assigned,
99 /// use `get_or_insert` for a version that instead returns the existing
100 /// assignment.
101 #[track_caller]
102 pub fn insert(&mut self, key: K) -> UniIndex {
103 // We want an unused index. First we attempt to find one from `deassigned`,
104 // and if `deassigned` is empty we generate a fresh index.
105 let idx = self.deassigned.pop().unwrap_or_else(|| {
106 // `deassigned` is empty, so all keys in use are already in `mapping`.
107 // The next available key is `mapping.len()`.
108 self.mapping.len().try_into().expect("UniMap ran out of useable keys")
109 });
110 if self.mapping.insert(key, idx).is_some() {
111 panic!(
112 "This key is already assigned to a different index; either use `get_or_insert` instead if you care about this data, or first call `remove` to undo the preexisting assignment."
113 );
114 };
115 UniIndex { idx }
116 }
117
118 /// If it exists, the index this key maps to.
119 pub fn get(&self, key: &K) -> Option<UniIndex> {
120 self.mapping.get(key).map(|&idx| UniIndex { idx })
121 }
122
123 /// Either get a previously existing entry, or create a new one if it
124 /// is not yet present.
125 pub fn get_or_insert(&mut self, key: K) -> UniIndex {
126 self.get(&key).unwrap_or_else(|| self.insert(key))
127 }
128
129 /// Return whatever index this key was using to the deassigned pool.
130 ///
131 /// Note: calling this function can be dangerous. If the index still exists
132 /// somewhere in a `UniValMap` and is reassigned by the `UniKeyMap` then
133 /// it will inherit the old value of a completely unrelated key.
134 /// If you `UniKeyMap::remove` a key you should make sure to also `UniValMap::remove`
135 /// the associated `UniIndex` from ALL `UniValMap`s.
136 ///
137 /// Example of such behavior:
138 /// ```rust,ignore (private type can't be doctested)
139 /// let mut keymap = UniKeyMap::<char>::default();
140 /// let mut valmap = UniValMap::<char>::default();
141 /// // Insert 'a' -> _ -> 'A'
142 /// let idx_a = keymap.insert('a');
143 /// valmap.insert(idx_a, 'A');
144 /// // Remove 'a' -> _, but forget to remove _ -> 'A'
145 /// keymap.remove(&'a');
146 /// // valmap.remove(idx_a); // If we uncomment this line the issue is fixed
147 /// // Insert 'b' -> _
148 /// let idx_b = keymap.insert('b');
149 /// let val_b = valmap.get(idx_b);
150 /// assert_eq!(val_b, Some('A')); // Oh no
151 /// // assert_eq!(val_b, None); // This is what we would have expected
152 /// ```
153 pub fn remove(&mut self, key: &K) {
154 if let Some(idx) = self.mapping.remove(key) {
155 self.deassigned.push(idx);
156 }
157 }
158}
159
160impl<V> UniValMap<V> {
161 /// Whether this index has an associated value.
162 pub fn contains_idx(&self, idx: UniIndex) -> bool {
163 self.data.get(idx.idx.to_usize()).and_then(Option::as_ref).is_some()
164 }
165
166 /// Reserve enough space to insert the value at the right index.
167 fn extend_to_length(&mut self, len: usize) {
168 if len > self.data.len() {
169 let nb = len - self.data.len();
170 self.data.reserve(nb);
171 for _ in 0..nb {
172 self.data.push(None);
173 }
174 }
175 }
176
177 /// Assign a value to the index. Permanently overwrites any previous value.
178 pub fn insert(&mut self, idx: UniIndex, val: V) {
179 self.extend_to_length(idx.idx.to_usize() + 1);
180 self.data[idx.idx.to_usize()] = Some(val)
181 }
182
183 /// Get the value at this index, if it exists.
184 pub fn get(&self, idx: UniIndex) -> Option<&V> {
185 self.data.get(idx.idx.to_usize()).and_then(Option::as_ref)
186 }
187
188 /// Get the value at this index mutably, if it exists.
189 pub fn get_mut(&mut self, idx: UniIndex) -> Option<&mut V> {
190 self.data.get_mut(idx.idx.to_usize()).and_then(Option::as_mut)
191 }
192
193 /// Delete any value associated with this index.
194 /// Returns None if the value was not present, otherwise
195 /// returns the previously stored value.
196 pub fn remove(&mut self, idx: UniIndex) -> Option<V> {
197 if idx.idx.to_usize() >= self.data.len() {
198 return None;
199 }
200 let mut res = None;
201 mem::swap(&mut res, &mut self.data[idx.idx.to_usize()]);
202 res
203 }
204}
205
206/// An access to a single value of the map.
207pub struct UniEntry<'a, V> {
208 inner: &'a mut Option<V>,
209}
210
211impl<'a, V> UniValMap<V> {
212 /// Get a wrapper around a mutable access to the value corresponding to `idx`.
213 pub fn entry(&'a mut self, idx: UniIndex) -> UniEntry<'a, V> {
214 self.extend_to_length(idx.idx.to_usize() + 1);
215 UniEntry { inner: &mut self.data[idx.idx.to_usize()] }
216 }
217}
218
219impl<'a, V> UniEntry<'a, V> {
220 /// Insert in the map and get the value.
221 pub fn or_insert(&mut self, default: V) -> &mut V {
222 if self.inner.is_none() {
223 *self.inner = Some(default);
224 }
225 self.inner.as_mut().unwrap()
226 }
227
228 pub fn get(&self) -> Option<&V> {
229 self.inner.as_ref()
230 }
231}
232
233mod tests {
234 use super::*;
235
236 #[test]
237 fn extend_to_length() {
238 let mut km = UniValMap::<char>::default();
239 km.extend_to_length(10);
240 assert!(km.data.len() == 10);
241 km.extend_to_length(0);
242 assert!(km.data.len() == 10);
243 km.extend_to_length(10);
244 assert!(km.data.len() == 10);
245 km.extend_to_length(11);
246 assert!(km.data.len() == 11);
247 }
248
249 #[derive(Default)]
250 struct MapWitness<K, V> {
251 key: UniKeyMap<K>,
252 val: UniValMap<V>,
253 map: FxHashMap<K, V>,
254 }
255
256 impl<K, V> MapWitness<K, V>
257 where
258 K: Copy + Hash + Eq,
259 V: Copy + Eq + std::fmt::Debug,
260 {
261 fn insert(&mut self, k: K, v: V) {
262 // UniMap
263 let i = self.key.get_or_insert(k);
264 self.val.insert(i, v);
265 // HashMap
266 self.map.insert(k, v);
267 // Consistency: nothing to check
268 }
269
270 fn get(&self, k: &K) {
271 // UniMap
272 let v1 = self.key.get(k).and_then(|i| self.val.get(i));
273 // HashMap
274 let v2 = self.map.get(k);
275 // Consistency
276 assert_eq!(v1, v2);
277 }
278
279 fn get_mut(&mut self, k: &K) {
280 // UniMap
281 let v1 = self.key.get(k).and_then(|i| self.val.get_mut(i));
282 // HashMap
283 let v2 = self.map.get_mut(k);
284 // Consistency
285 assert_eq!(v1, v2);
286 }
287 fn remove(&mut self, k: &K) {
288 // UniMap
289 if let Some(i) = self.key.get(k) {
290 self.val.remove(i);
291 }
292 self.key.remove(k);
293 // HashMap
294 self.map.remove(k);
295 // Consistency: nothing to check
296 }
297 }
298
299 #[test]
300 fn consistency_small() {
301 let mut m = MapWitness::<u64, char>::default();
302 m.insert(1, 'a');
303 m.insert(2, 'b');
304 m.get(&1);
305 m.get_mut(&2);
306 m.remove(&2);
307 m.insert(1, 'c');
308 m.get(&1);
309 m.insert(3, 'd');
310 m.insert(4, 'e');
311 m.insert(4, 'f');
312 m.get(&2);
313 m.get(&3);
314 m.get(&4);
315 m.get(&5);
316 m.remove(&100);
317 m.get_mut(&100);
318 m.get(&100);
319 }
320
321 #[test]
322 fn consistency_large() {
323 use std::collections::hash_map::DefaultHasher;
324 use std::hash::{Hash, Hasher};
325 let mut hasher = DefaultHasher::new();
326 let mut map = MapWitness::<u64, u64>::default();
327 for i in 0..1000 {
328 i.hash(&mut hasher);
329 let rng = hasher.finish();
330 let op = rng % 3 == 0;
331 let key = (rng / 2) % 50;
332 let val = (rng / 100) % 1000;
333 if op {
334 map.insert(key, val);
335 } else {
336 map.get(&key);
337 }
338 }
339 }
340}