1#[cfg(test)]
2#[path = "unordered_hash_map_test.rs"]
3mod test;
4
5#[cfg(not(feature = "std"))]
6use alloc::vec;
7use core::borrow::Borrow;
8use core::hash::{BuildHasher, Hash};
9use core::ops::Index;
10#[cfg(feature = "std")]
11use std::collections::HashMap;
12#[cfg(feature = "std")]
13pub use std::collections::hash_map::Entry;
14#[cfg(feature = "std")]
15use std::collections::hash_map::OccupiedEntry;
16#[cfg(feature = "std")]
17use std::collections::hash_map::RandomState;
18#[cfg(feature = "std")]
19use std::vec;
20
21#[cfg(not(feature = "std"))]
22use hashbrown::HashMap;
23#[cfg(not(feature = "std"))]
24pub use hashbrown::hash_map::Entry;
25use itertools::Itertools;
26
27#[cfg(feature = "std")]
28type BHImpl = RandomState;
29#[cfg(not(feature = "std"))]
30type BHImpl = hashbrown::DefaultHashBuilder;
31
32#[derive(Clone, Debug)]
38pub struct UnorderedHashMap<Key, Value, BH = BHImpl>(HashMap<Key, Value, BH>);
39
40#[cfg(feature = "salsa")]
41unsafe impl<Key: salsa::Update + Eq + Hash, Value: salsa::Update> salsa::Update
42 for UnorderedHashMap<Key, Value, BHImpl>
43{
44 unsafe fn maybe_update(old_pointer: *mut Self, new_map: Self) -> bool {
47 let old_map: &mut Self = unsafe { &mut *old_pointer };
48
49 let same_keys =
52 old_map.len() == new_map.len() && old_map.0.keys().all(|k| new_map.0.contains_key(k));
53
54 if !same_keys {
57 old_map.0.clear();
58 old_map.0.extend(new_map.0);
59 return true;
60 }
61
62 let mut changed = false;
67 for (key, new_value) in new_map.0.into_iter() {
68 let old_value = old_map.0.get_mut(&key).unwrap();
69 changed |= unsafe { Value::maybe_update(old_value, new_value) };
70 }
71 changed
72 }
73}
74
75impl<Key, Value, BH> UnorderedHashMap<Key, Value, BH> {
76 fn with_hasher(hash_builder: BH) -> Self {
77 Self(HashMap::<Key, Value, BH>::with_hasher(hash_builder))
78 }
79}
80
81impl<Key, Value, BH> PartialEq for UnorderedHashMap<Key, Value, BH>
82where
83 Key: Eq + Hash,
84 Value: PartialEq,
85 BH: BuildHasher,
86{
87 fn eq(&self, other: &Self) -> bool {
88 self.0 == other.0
89 }
90}
91
92impl<Key, Value, BH> Eq for UnorderedHashMap<Key, Value, BH>
93where
94 Key: Eq + Hash,
95 Value: Eq,
96 BH: BuildHasher,
97{
98}
99
100impl<Key, Value, BH> UnorderedHashMap<Key, Value, BH> {
101 pub fn len(&self) -> usize {
103 self.0.len()
104 }
105
106 pub fn is_empty(&self) -> bool {
108 self.0.is_empty()
109 }
110}
111
112impl<Key: Eq + Hash, Value, BH: BuildHasher> UnorderedHashMap<Key, Value, BH> {
113 pub fn get<Q>(&self, key: &Q) -> Option<&Value>
118 where
119 Key: Borrow<Q>,
120 Q: Hash + Eq + ?Sized,
121 {
122 self.0.get(key)
123 }
124
125 pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut Value>
130 where
131 Key: Borrow<Q>,
132 Q: Hash + Eq + ?Sized,
133 {
134 self.0.get_mut(key)
135 }
136
137 pub fn insert(&mut self, key: Key, value: Value) -> Option<Value> {
145 self.0.insert(key, value)
146 }
147
148 pub fn remove<Q>(&mut self, key: &Q) -> Option<Value>
154 where
155 Key: Borrow<Q>,
156 Q: Hash + Eq + ?Sized,
157 {
158 self.0.remove(key)
159 }
160
161 #[cfg(feature = "std")]
162 pub fn entry(&mut self, key: Key) -> Entry<'_, Key, Value> {
164 self.0.entry(key)
165 }
166
167 #[cfg(not(feature = "std"))]
168 pub fn entry(&mut self, key: Key) -> Entry<'_, Key, Value, BH> {
170 self.0.entry(key)
171 }
172
173 pub fn contains_key<Q>(&self, key: &Q) -> bool
175 where
176 Q: ?Sized,
177 Key: Borrow<Q>,
178 Q: Hash + Eq,
179 {
180 self.0.contains_key(key)
181 }
182
183 pub fn map<TargetValue>(
185 &self,
186 mapper: impl Fn(&Value) -> TargetValue,
187 ) -> UnorderedHashMap<Key, TargetValue, BH>
188 where
189 Key: Clone,
190 BH: Clone,
191 {
192 self.0.iter().fold(
193 UnorderedHashMap::<_, _, _>::with_hasher(self.0.hasher().clone()),
194 |mut acc, (key, value)| {
195 match acc.entry(key.clone()) {
196 Entry::Occupied(_) => {
197 unreachable!("The original map should not contain duplicate keys.");
198 }
199 Entry::Vacant(vacant) => {
200 vacant.insert(mapper(value));
201 }
202 };
203 acc
204 },
205 )
206 }
207
208 pub fn aggregate_by<TargetKey: Eq + Hash, TargetValue>(
216 &self,
217 mapping_function: impl Fn(&Key) -> TargetKey,
218 reduce_function: impl Fn(&TargetValue, &Value) -> TargetValue,
219 default_value: &TargetValue,
220 ) -> UnorderedHashMap<TargetKey, TargetValue, BH>
221 where
222 BH: Clone,
223 {
224 self.0.iter().fold(
225 UnorderedHashMap::<_, _, _>::with_hasher(self.0.hasher().clone()),
226 |mut acc, (key, value)| {
227 let target_key = mapping_function(key);
228 match acc.entry(target_key) {
229 Entry::Occupied(occupied) => {
230 let old_target_value = occupied.into_mut();
231 let new_target_value = reduce_function(old_target_value, value);
232 *old_target_value = new_target_value;
233 }
234 Entry::Vacant(vacant) => {
235 let new_value = reduce_function(default_value, value);
236 vacant.insert(new_value);
237 }
238 };
239 acc
240 },
241 )
242 }
243
244 pub fn iter_sorted(&self) -> impl Iterator<Item = (&Key, &Value)>
252 where
253 Key: Ord,
254 {
255 self.0.iter().sorted_by_key(|(key, _)| *key)
256 }
257
258 pub fn into_iter_sorted(self) -> impl Iterator<Item = (Key, Value)>
260 where
261 Key: Ord,
262 {
263 self.0.into_iter().sorted_by(|(lhs, _), (rhs, _)| lhs.cmp(rhs))
264 }
265
266 pub fn iter_sorted_by_key<TargetKey, F>(&self, f: F) -> vec::IntoIter<(&Key, &Value)>
274 where
275 TargetKey: Ord,
276 F: FnMut(&(&Key, &Value)) -> TargetKey,
277 {
278 self.0.iter().sorted_by_key(f)
279 }
280
281 pub fn into_iter_sorted_by_key<TargetKey, F>(self, f: F) -> vec::IntoIter<(Key, Value)>
283 where
284 TargetKey: Ord,
285 F: FnMut(&(Key, Value)) -> TargetKey,
286 {
287 self.0.into_iter().sorted_by_key(f)
288 }
289
290 pub fn filter<P>(self, mut p: P) -> Self
293 where
294 BH: Default,
295 P: FnMut(&Key, &Value) -> bool,
296 {
297 Self(self.0.into_iter().filter(|(key, value)| p(key, value)).collect())
298 }
299
300 pub fn filter_cloned<P>(&self, mut p: P) -> Self
303 where
304 BH: Default,
305 P: FnMut(&Key, &Value) -> bool,
306 Key: Clone,
307 Value: Clone,
308 {
309 Self(
310 self.0
311 .iter()
312 .filter_map(
313 |(key, value)| {
314 if p(key, value) { Some((key.clone(), value.clone())) } else { None }
315 },
316 )
317 .collect(),
318 )
319 }
320
321 #[cfg(feature = "std")]
322 pub fn merge<HandleDuplicate>(&mut self, other: &Self, handle_duplicate: HandleDuplicate)
325 where
326 BH: Clone,
327 HandleDuplicate: Fn(OccupiedEntry<'_, Key, Value>, &Value),
328 Key: Clone,
329 Value: Clone,
330 {
331 for (key, value) in &other.0 {
332 match self.0.entry(key.clone()) {
333 Entry::Occupied(e) => {
334 handle_duplicate(e, value);
335 }
336 Entry::Vacant(e) => {
337 e.insert(value.clone());
338 }
339 }
340 }
341 }
342
343 pub fn clear(&mut self) {
345 self.0.clear();
346 }
347}
348
349impl<Key, Q: ?Sized, Value, BH: BuildHasher> Index<&Q> for UnorderedHashMap<Key, Value, BH>
350where
351 Key: Eq + Hash + Borrow<Q>,
352 Q: Eq + Hash,
353{
354 type Output = Value;
355
356 fn index(&self, key: &Q) -> &Self::Output {
357 self.0.index(key)
358 }
359}
360
361impl<Key, Value, BH: Default> Default for UnorderedHashMap<Key, Value, BH> {
362 #[cfg(feature = "std")]
363 fn default() -> Self {
364 Self(Default::default())
365 }
366 #[cfg(not(feature = "std"))]
367 fn default() -> Self {
368 Self(HashMap::with_hasher(Default::default()))
369 }
370}
371
372impl<Key: Hash + Eq, Value, BH: BuildHasher + Default> FromIterator<(Key, Value)>
373 for UnorderedHashMap<Key, Value, BH>
374{
375 fn from_iter<T: IntoIterator<Item = (Key, Value)>>(iter: T) -> Self {
376 Self(iter.into_iter().collect())
377 }
378}
379
380impl<Key: Hash + Eq, Value, const N: usize, BH: BuildHasher + Default> From<[(Key, Value); N]>
381 for UnorderedHashMap<Key, Value, BH>
382{
383 fn from(items: [(Key, Value); N]) -> Self {
384 Self(HashMap::from_iter(items))
385 }
386}
387
388impl<Key: Hash + Eq, Value, BH: BuildHasher> Extend<(Key, Value)>
389 for UnorderedHashMap<Key, Value, BH>
390{
391 fn extend<T: IntoIterator<Item = (Key, Value)>>(&mut self, iter: T) {
392 self.0.extend(iter)
393 }
394}