1use std::hash::Hash;
2
3use ruff_index::{FrozenIndexVec, IndexVec, newtype_index};
4use rustc_hash::FxHashMap;
5
6#[derive(Debug, Eq, PartialEq, get_size2::GetSize, salsa::SalsaValue)]
11pub struct FrozenMap<K, V>(Box<[(K, V)]>);
12
13impl<K, V> FrozenMap<K, V> {
14 pub fn iter(&self) -> std::slice::Iter<'_, (K, V)> {
15 self.0.iter()
16 }
17
18 pub fn iter_mut(
19 &mut self,
20 ) -> impl DoubleEndedIterator<Item = (&K, &mut V)> + ExactSizeIterator + std::iter::FusedIterator
21 {
22 self.into_iter()
23 }
24
25 pub(crate) fn keys(&self) -> impl DoubleEndedIterator<Item = &K> + ExactSizeIterator {
26 self.0.iter().map(|(key, _)| key)
27 }
28
29 pub fn values(&self) -> impl DoubleEndedIterator<Item = &V> + ExactSizeIterator {
30 self.0.iter().map(|(_, value)| value)
31 }
32}
33
34impl<K: Ord, V> FromIterator<(K, V)> for FrozenMap<K, V> {
35 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
36 let entries = sort_and_deduplicate(iter.into_iter().collect());
37 Self(entries.into_boxed_slice())
38 }
39}
40
41impl<K, V> From<std::collections::BTreeMap<K, V>> for FrozenMap<K, V> {
42 fn from(map: std::collections::BTreeMap<K, V>) -> Self {
43 Self(map.into_iter().collect())
44 }
45}
46
47impl<K: Ord, V, S> From<std::collections::HashMap<K, V, S>> for FrozenMap<K, V> {
48 fn from(map: std::collections::HashMap<K, V, S>) -> Self {
49 Self::from_entries(map.into_iter().collect())
50 }
51}
52
53impl<K: Ord, V> FrozenMap<K, V> {
54 pub(crate) fn from_entries(mut entries: Vec<(K, V)>) -> Self {
56 entries.sort_unstable_by(|(left, _), (right, _)| left.cmp(right));
57 debug_assert!(
58 entries
59 .windows(2)
60 .all(|entries| entries[0].0 != entries[1].0),
61 "frozen map keys must be unique",
62 );
63 Self(entries.into_boxed_slice())
64 }
65
66 pub fn get(&self, key: &K) -> Option<&V> {
67 self.0
68 .binary_search_by(|(candidate, _)| candidate.cmp(key))
69 .ok()
70 .map(|index| &self.0[index].1)
71 }
72}
73
74impl<K, V> Default for FrozenMap<K, V> {
75 fn default() -> Self {
76 Self(Box::default())
77 }
78}
79
80impl<K: Ord, V> std::ops::Index<&K> for FrozenMap<K, V> {
81 type Output = V;
82
83 #[track_caller]
84 fn index(&self, index: &K) -> &Self::Output {
85 self.get(index).expect("key not found")
86 }
87}
88
89impl<K, V> IntoIterator for FrozenMap<K, V> {
90 type Item = (K, V);
91 type IntoIter = std::vec::IntoIter<(K, V)>;
92
93 fn into_iter(self) -> Self::IntoIter {
94 self.0.into_vec().into_iter()
95 }
96}
97
98impl<'a, K, V> IntoIterator for &'a FrozenMap<K, V> {
99 type Item = &'a (K, V);
100 type IntoIter = std::slice::Iter<'a, (K, V)>;
101
102 fn into_iter(self) -> Self::IntoIter {
103 self.0.iter()
104 }
105}
106
107impl<'a, K, V> IntoIterator for &'a mut FrozenMap<K, V> {
108 type Item = (&'a K, &'a mut V);
109 type IntoIter =
110 std::iter::Map<std::slice::IterMut<'a, (K, V)>, fn(&'a mut (K, V)) -> (&'a K, &'a mut V)>;
111
112 fn into_iter(self) -> Self::IntoIter {
113 self.0.iter_mut().map(|(key, value)| (&*key, value))
114 }
115}
116
117#[newtype_index]
118#[derive(get_size2::GetSize, salsa::SalsaValue)]
119struct FrozenValueIndex;
120
121fn sort_and_deduplicate<K: Ord, V>(mut entries: Vec<(K, V)>) -> Vec<(K, V)> {
126 entries.sort_by(|(left, _), (right, _)| left.cmp(right));
127 entries.dedup_by(|(later_key, later_value), (earlier_key, earlier_value)| {
128 if later_key == earlier_key {
129 std::mem::swap(later_value, earlier_value);
131 true
132 } else {
133 false
134 }
135 });
136
137 entries
138}
139
140fn index_values<K, V>(
141 entries: impl IntoIterator<Item = (K, V)>,
142) -> (Vec<(K, FrozenValueIndex)>, IndexVec<FrozenValueIndex, V>)
143where
144 V: Copy + Eq + Hash,
145{
146 let mut values = IndexVec::new();
147 let mut value_indices = FxHashMap::default();
148 let entries = entries
149 .into_iter()
150 .map(|(key, value)| {
151 let index = *value_indices
152 .entry(value)
153 .or_insert_with(|| values.push(value));
154 (key, index)
155 })
156 .collect();
157
158 (entries, values)
159}
160
161#[derive(Debug, Eq, PartialEq, get_size2::GetSize, salsa::SalsaValue)]
163pub struct FrozenValueMap<K, V> {
164 entries: FrozenMap<K, FrozenValueIndex>,
165 values: FrozenIndexVec<FrozenValueIndex, V>,
166}
167
168impl<K, V> FrozenValueMap<K, V> {
169 pub fn get(&self, key: &K) -> Option<&V>
170 where
171 K: Ord,
172 {
173 self.entries.get(key).map(|index| &self.values[*index])
174 }
175
176 pub fn iter(&self) -> impl DoubleEndedIterator<Item = (K, V)> + ExactSizeIterator + '_
177 where
178 K: Copy,
179 V: Copy,
180 {
181 self.entries
182 .iter()
183 .map(|(key, index)| (*key, self.values[*index]))
184 }
185
186 pub fn map_values<F>(&mut self, mut map: F)
187 where
188 K: Copy + Ord,
189 V: Copy + Eq + Hash,
190 F: FnMut(K, V) -> V,
191 {
192 let (entries, values) =
193 index_values(self.iter().map(|(key, value)| (key, map(key, value))));
194 *self = Self {
195 entries: FrozenMap(entries.into_boxed_slice()),
196 values: values.into(),
197 };
198 }
199}
200
201impl<K, V> FromIterator<(K, V)> for FrozenValueMap<K, V>
202where
203 K: Ord,
204 V: Copy + Eq + Hash,
205{
206 fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
207 let source_entries = sort_and_deduplicate(iter.into_iter().collect());
208
209 let (entries, values) = index_values(source_entries);
210
211 Self {
212 entries: FrozenMap(entries.into_boxed_slice()),
213 values: values.into(),
214 }
215 }
216}
217
218impl<K, V, S> From<std::collections::HashMap<K, V, S>> for FrozenValueMap<K, V>
219where
220 K: Ord,
221 V: Copy + Eq + Hash,
222{
223 fn from(map: std::collections::HashMap<K, V, S>) -> Self {
224 let (mut entries, values) = index_values(map);
225 entries.sort_unstable_by(|(left, _), (right, _)| left.cmp(right));
226
227 Self {
228 entries: FrozenMap(entries.into_boxed_slice()),
229 values: values.into(),
230 }
231 }
232}
233
234impl<K, V> Default for FrozenValueMap<K, V> {
235 fn default() -> Self {
236 Self {
237 entries: FrozenMap::default(),
238 values: IndexVec::new().into(),
239 }
240 }
241}
242
243#[derive(Debug, Eq, PartialEq, get_size2::GetSize)]
248pub struct FrozenSet<K>(Box<[K]>);
249
250impl<K: Ord, S> From<std::collections::HashSet<K, S>> for FrozenSet<K> {
251 fn from(set: std::collections::HashSet<K, S>) -> Self {
252 let mut entries = set.into_iter().collect::<Vec<_>>();
253 entries.sort_unstable();
254 Self(entries.into_boxed_slice())
255 }
256}
257
258impl<K: Ord> FrozenSet<K> {
259 pub fn contains(&self, key: &K) -> bool {
260 self.0.binary_search(key).is_ok()
261 }
262}
263
264impl<K> FrozenSet<K> {
265 pub fn iter(&self) -> std::slice::Iter<'_, K> {
266 self.0.iter()
267 }
268}
269
270impl<'a, K> IntoIterator for &'a FrozenSet<K> {
271 type Item = &'a K;
272 type IntoIter = std::slice::Iter<'a, K>;
273
274 fn into_iter(self) -> Self::IntoIter {
275 self.0.iter()
276 }
277}
278
279impl<K> Default for FrozenSet<K> {
280 fn default() -> Self {
281 Self(Box::default())
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::{FrozenMap, FrozenValueMap};
288
289 #[test]
290 fn frozen_map_preserves_last_value_for_duplicate_keys() {
291 let map = FrozenMap::from_iter([(2, "two"), (1, "first"), (1, "last")]);
292
293 assert_eq!(
294 map.iter().copied().collect::<Vec<_>>(),
295 vec![(1, "last"), (2, "two")]
296 );
297 }
298
299 #[test]
300 fn frozen_map_iterates_with_mutable_values() {
301 let mut map = FrozenMap::from_iter([(2, 20), (1, 10)]);
302
303 for (key, value) in &mut map {
304 *value += *key;
305 }
306
307 assert_eq!(
308 map.iter().copied().collect::<Vec<_>>(),
309 vec![(1, 11), (2, 22)]
310 );
311 }
312
313 #[test]
314 fn frozen_value_map_deduplicates_values() {
315 let map = FrozenValueMap::from_iter([(3, [1; 4]), (1, [2; 4]), (2, [1; 4])]);
316
317 assert_eq!(map.values.len(), 2);
318 assert_eq!(map.get(&1), Some(&[2; 4]));
319 assert_eq!(map.get(&2), Some(&[1; 4]));
320 assert_eq!(
321 map.iter().collect::<Vec<_>>(),
322 vec![(1, [2; 4]), (2, [1; 4]), (3, [1; 4])]
323 );
324 }
325
326 #[test]
327 fn frozen_value_map_preserves_last_value_for_duplicate_keys() {
328 let map = FrozenValueMap::from_iter([(2, 20), (1, 10), (1, 11)]);
329
330 assert_eq!(map.iter().collect::<Vec<_>>(), vec![(1, 11), (2, 20)]);
331 }
332
333 #[test]
334 fn frozen_value_map_updates_and_rededuplicates_values() {
335 let mut map = FrozenValueMap::from_iter([(1, 10), (2, 20), (3, 30)]);
336
337 map.map_values(|_, _| 42);
338
339 assert_eq!(&map.values.raw, &[42]);
340 assert_eq!(
341 map.iter().collect::<Vec<_>>(),
342 vec![(1, 42), (2, 42), (3, 42)]
343 );
344 }
345
346 #[test]
347 fn frozen_value_map_uses_less_heap_for_repeated_large_values() {
348 let entries = [(1, [1; 8]), (2, [1; 8]), (3, [1; 8]), (4, [2; 8])];
349 let direct = FrozenMap::from_iter(entries);
350 let deduplicated = FrozenValueMap::from_iter(entries);
351
352 assert!(
353 ruff_memory_usage::heap_size(&deduplicated) < ruff_memory_usage::heap_size(&direct)
354 );
355 }
356}