1//! Rayon extensions for `HashMap`.
2
3use super::raw::{RawIntoParIter, RawParDrain, RawParIter};
4use crate::hash_map::HashMap;
5use crate::raw::{Allocator, Global};
6use core::fmt;
7use core::hash::{BuildHasher, Hash};
8use core::marker::PhantomData;
9use rayon::iter::plumbing::UnindexedConsumer;
10use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator};
11
12/// Parallel iterator over shared references to entries in a map.
13///
14/// This iterator is created by the [`par_iter`] method on [`HashMap`]
15/// (provided by the [`IntoParallelRefIterator`] trait).
16/// See its documentation for more.
17///
18/// [`par_iter`]: /hashbrown/struct.HashMap.html#method.par_iter
19/// [`HashMap`]: /hashbrown/struct.HashMap.html
20/// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html
21pub struct ParIter<'a, K, V> {
22 inner: RawParIter<(K, V)>,
23 marker: PhantomData<(&'a K, &'a V)>,
24}
25
26impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> {
27 type Item = (&'a K, &'a V);
28
29 #[cfg_attr(feature = "inline-more", inline)]
30 fn drive_unindexed<C>(self, consumer: C) -> C::Result
31 where
32 C: UnindexedConsumer<Self::Item>,
33 {
34 self.inner
35 .map(|x: Bucket<(K, V)>| unsafe {
36 let r: &(K, V) = x.as_ref();
37 (&r.0, &r.1)
38 })
39 .drive_unindexed(consumer)
40 }
41}
42
43impl<K, V> Clone for ParIter<'_, K, V> {
44 #[cfg_attr(feature = "inline-more", inline)]
45 fn clone(&self) -> Self {
46 Self {
47 inner: self.inner.clone(),
48 marker: PhantomData,
49 }
50 }
51}
52
53impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug> fmt::Debug for ParIter<'_, K, V> {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 let iter: impl Iterator = unsafe { self.inner.iter() }.map(|x: Bucket<(K, V)>| unsafe {
56 let r: &(K, V) = x.as_ref();
57 (&r.0, &r.1)
58 });
59 f.debug_list().entries(iter).finish()
60 }
61}
62
63/// Parallel iterator over shared references to keys in a map.
64///
65/// This iterator is created by the [`par_keys`] method on [`HashMap`].
66/// See its documentation for more.
67///
68/// [`par_keys`]: /hashbrown/struct.HashMap.html#method.par_keys
69/// [`HashMap`]: /hashbrown/struct.HashMap.html
70pub struct ParKeys<'a, K, V> {
71 inner: RawParIter<(K, V)>,
72 marker: PhantomData<(&'a K, &'a V)>,
73}
74
75impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> {
76 type Item = &'a K;
77
78 #[cfg_attr(feature = "inline-more", inline)]
79 fn drive_unindexed<C>(self, consumer: C) -> C::Result
80 where
81 C: UnindexedConsumer<Self::Item>,
82 {
83 self.inner
84 .map(|x: Bucket<(K, V)>| unsafe { &x.as_ref().0 })
85 .drive_unindexed(consumer)
86 }
87}
88
89impl<K, V> Clone for ParKeys<'_, K, V> {
90 #[cfg_attr(feature = "inline-more", inline)]
91 fn clone(&self) -> Self {
92 Self {
93 inner: self.inner.clone(),
94 marker: PhantomData,
95 }
96 }
97}
98
99impl<K: fmt::Debug + Eq + Hash, V> fmt::Debug for ParKeys<'_, K, V> {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 let iter: impl Iterator = unsafe { self.inner.iter() }.map(|x: Bucket<(K, V)>| unsafe { &x.as_ref().0 });
102 f.debug_list().entries(iter).finish()
103 }
104}
105
106/// Parallel iterator over shared references to values in a map.
107///
108/// This iterator is created by the [`par_values`] method on [`HashMap`].
109/// See its documentation for more.
110///
111/// [`par_values`]: /hashbrown/struct.HashMap.html#method.par_values
112/// [`HashMap`]: /hashbrown/struct.HashMap.html
113pub struct ParValues<'a, K, V> {
114 inner: RawParIter<(K, V)>,
115 marker: PhantomData<(&'a K, &'a V)>,
116}
117
118impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> {
119 type Item = &'a V;
120
121 #[cfg_attr(feature = "inline-more", inline)]
122 fn drive_unindexed<C>(self, consumer: C) -> C::Result
123 where
124 C: UnindexedConsumer<Self::Item>,
125 {
126 self.inner
127 .map(|x: Bucket<(K, V)>| unsafe { &x.as_ref().1 })
128 .drive_unindexed(consumer)
129 }
130}
131
132impl<K, V> Clone for ParValues<'_, K, V> {
133 #[cfg_attr(feature = "inline-more", inline)]
134 fn clone(&self) -> Self {
135 Self {
136 inner: self.inner.clone(),
137 marker: PhantomData,
138 }
139 }
140}
141
142impl<K: Eq + Hash, V: fmt::Debug> fmt::Debug for ParValues<'_, K, V> {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 let iter: impl Iterator = unsafe { self.inner.iter() }.map(|x: Bucket<(K, V)>| unsafe { &x.as_ref().1 });
145 f.debug_list().entries(iter).finish()
146 }
147}
148
149/// Parallel iterator over mutable references to entries in a map.
150///
151/// This iterator is created by the [`par_iter_mut`] method on [`HashMap`]
152/// (provided by the [`IntoParallelRefMutIterator`] trait).
153/// See its documentation for more.
154///
155/// [`par_iter_mut`]: /hashbrown/struct.HashMap.html#method.par_iter_mut
156/// [`HashMap`]: /hashbrown/struct.HashMap.html
157/// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html
158pub struct ParIterMut<'a, K, V> {
159 inner: RawParIter<(K, V)>,
160 marker: PhantomData<(&'a K, &'a mut V)>,
161}
162
163impl<'a, K: Sync, V: Send> ParallelIterator for ParIterMut<'a, K, V> {
164 type Item = (&'a K, &'a mut V);
165
166 #[cfg_attr(feature = "inline-more", inline)]
167 fn drive_unindexed<C>(self, consumer: C) -> C::Result
168 where
169 C: UnindexedConsumer<Self::Item>,
170 {
171 self.inner
172 .map(|x: Bucket<(K, V)>| unsafe {
173 let r: &mut (K, V) = x.as_mut();
174 (&r.0, &mut r.1)
175 })
176 .drive_unindexed(consumer)
177 }
178}
179
180impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug> fmt::Debug for ParIterMut<'_, K, V> {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 ParIter {
183 inner: self.inner.clone(),
184 marker: PhantomData,
185 }
186 .fmt(f)
187 }
188}
189
190/// Parallel iterator over mutable references to values in a map.
191///
192/// This iterator is created by the [`par_values_mut`] method on [`HashMap`].
193/// See its documentation for more.
194///
195/// [`par_values_mut`]: /hashbrown/struct.HashMap.html#method.par_values_mut
196/// [`HashMap`]: /hashbrown/struct.HashMap.html
197pub struct ParValuesMut<'a, K, V> {
198 inner: RawParIter<(K, V)>,
199 marker: PhantomData<(&'a K, &'a mut V)>,
200}
201
202impl<'a, K: Sync, V: Send> ParallelIterator for ParValuesMut<'a, K, V> {
203 type Item = &'a mut V;
204
205 #[cfg_attr(feature = "inline-more", inline)]
206 fn drive_unindexed<C>(self, consumer: C) -> C::Result
207 where
208 C: UnindexedConsumer<Self::Item>,
209 {
210 self.inner
211 .map(|x: Bucket<(K, V)>| unsafe { &mut x.as_mut().1 })
212 .drive_unindexed(consumer)
213 }
214}
215
216impl<K: Eq + Hash, V: fmt::Debug> fmt::Debug for ParValuesMut<'_, K, V> {
217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
218 ParValues {
219 inner: self.inner.clone(),
220 marker: PhantomData,
221 }
222 .fmt(f)
223 }
224}
225
226/// Parallel iterator over entries of a consumed map.
227///
228/// This iterator is created by the [`into_par_iter`] method on [`HashMap`]
229/// (provided by the [`IntoParallelIterator`] trait).
230/// See its documentation for more.
231///
232/// [`into_par_iter`]: /hashbrown/struct.HashMap.html#method.into_par_iter
233/// [`HashMap`]: /hashbrown/struct.HashMap.html
234/// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html
235pub struct IntoParIter<K, V, A: Allocator = Global> {
236 inner: RawIntoParIter<(K, V), A>,
237}
238
239impl<K: Send, V: Send, A: Allocator + Send> ParallelIterator for IntoParIter<K, V, A> {
240 type Item = (K, V);
241
242 #[cfg_attr(feature = "inline-more", inline)]
243 fn drive_unindexed<C>(self, consumer: C) -> C::Result
244 where
245 C: UnindexedConsumer<Self::Item>,
246 {
247 self.inner.drive_unindexed(consumer)
248 }
249}
250
251impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug, A: Allocator> fmt::Debug for IntoParIter<K, V, A> {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 ParIter {
254 inner: unsafe { self.inner.par_iter() },
255 marker: PhantomData,
256 }
257 .fmt(f)
258 }
259}
260
261/// Parallel draining iterator over entries of a map.
262///
263/// This iterator is created by the [`par_drain`] method on [`HashMap`].
264/// See its documentation for more.
265///
266/// [`par_drain`]: /hashbrown/struct.HashMap.html#method.par_drain
267/// [`HashMap`]: /hashbrown/struct.HashMap.html
268pub struct ParDrain<'a, K, V, A: Allocator = Global> {
269 inner: RawParDrain<'a, (K, V), A>,
270}
271
272impl<K: Send, V: Send, A: Allocator + Sync> ParallelIterator for ParDrain<'_, K, V, A> {
273 type Item = (K, V);
274
275 #[cfg_attr(feature = "inline-more", inline)]
276 fn drive_unindexed<C>(self, consumer: C) -> C::Result
277 where
278 C: UnindexedConsumer<Self::Item>,
279 {
280 self.inner.drive_unindexed(consumer)
281 }
282}
283
284impl<K: fmt::Debug + Eq + Hash, V: fmt::Debug, A: Allocator> fmt::Debug for ParDrain<'_, K, V, A> {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
286 ParIter {
287 inner: unsafe { self.inner.par_iter() },
288 marker: PhantomData,
289 }
290 .fmt(f)
291 }
292}
293
294impl<K: Sync, V: Sync, S, A: Allocator> HashMap<K, V, S, A> {
295 /// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order.
296 #[cfg_attr(feature = "inline-more", inline)]
297 pub fn par_keys(&self) -> ParKeys<'_, K, V> {
298 ParKeys {
299 inner: unsafe { self.table.par_iter() },
300 marker: PhantomData,
301 }
302 }
303
304 /// Visits (potentially in parallel) immutably borrowed values in an arbitrary order.
305 #[cfg_attr(feature = "inline-more", inline)]
306 pub fn par_values(&self) -> ParValues<'_, K, V> {
307 ParValues {
308 inner: unsafe { self.table.par_iter() },
309 marker: PhantomData,
310 }
311 }
312}
313
314impl<K: Send, V: Send, S, A: Allocator> HashMap<K, V, S, A> {
315 /// Visits (potentially in parallel) mutably borrowed values in an arbitrary order.
316 #[cfg_attr(feature = "inline-more", inline)]
317 pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> {
318 ParValuesMut {
319 inner: unsafe { self.table.par_iter() },
320 marker: PhantomData,
321 }
322 }
323
324 /// Consumes (potentially in parallel) all values in an arbitrary order,
325 /// while preserving the map's allocated memory for reuse.
326 #[cfg_attr(feature = "inline-more", inline)]
327 pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> {
328 ParDrain {
329 inner: self.table.par_drain(),
330 }
331 }
332}
333
334impl<K, V, S, A> HashMap<K, V, S, A>
335where
336 K: Eq + Hash + Sync,
337 V: PartialEq + Sync,
338 S: BuildHasher + Sync,
339 A: Allocator + Sync,
340{
341 /// Returns `true` if the map is equal to another,
342 /// i.e. both maps contain the same keys mapped to the same values.
343 ///
344 /// This method runs in a potentially parallel fashion.
345 pub fn par_eq(&self, other: &Self) -> bool {
346 self.len() == other.len()
347 && self
348 .into_par_iter()
349 .all(|(key: &K, value: &V)| other.get(key).map_or(default:false, |v: &V| *value == *v))
350 }
351}
352
353impl<K: Send, V: Send, S, A: Allocator + Send> IntoParallelIterator for HashMap<K, V, S, A> {
354 type Item = (K, V);
355 type Iter = IntoParIter<K, V, A>;
356
357 #[cfg_attr(feature = "inline-more", inline)]
358 fn into_par_iter(self) -> Self::Iter {
359 IntoParIter {
360 inner: self.table.into_par_iter(),
361 }
362 }
363}
364
365impl<'a, K: Sync, V: Sync, S, A: Allocator> IntoParallelIterator for &'a HashMap<K, V, S, A> {
366 type Item = (&'a K, &'a V);
367 type Iter = ParIter<'a, K, V>;
368
369 #[cfg_attr(feature = "inline-more", inline)]
370 fn into_par_iter(self) -> Self::Iter {
371 ParIter {
372 inner: unsafe { self.table.par_iter() },
373 marker: PhantomData,
374 }
375 }
376}
377
378impl<'a, K: Sync, V: Send, S, A: Allocator> IntoParallelIterator for &'a mut HashMap<K, V, S, A> {
379 type Item = (&'a K, &'a mut V);
380 type Iter = ParIterMut<'a, K, V>;
381
382 #[cfg_attr(feature = "inline-more", inline)]
383 fn into_par_iter(self) -> Self::Iter {
384 ParIterMut {
385 inner: unsafe { self.table.par_iter() },
386 marker: PhantomData,
387 }
388 }
389}
390
391/// Collect (key, value) pairs from a parallel iterator into a
392/// hashmap. If multiple pairs correspond to the same key, then the
393/// ones produced earlier in the parallel iterator will be
394/// overwritten, just as with a sequential iterator.
395impl<K, V, S> FromParallelIterator<(K, V)> for HashMap<K, V, S, Global>
396where
397 K: Eq + Hash + Send,
398 V: Send,
399 S: BuildHasher + Default,
400{
401 fn from_par_iter<P>(par_iter: P) -> Self
402 where
403 P: IntoParallelIterator<Item = (K, V)>,
404 {
405 let mut map: HashMap = HashMap::default();
406 map.par_extend(par_iter);
407 map
408 }
409}
410
411/// Extend a hash map with items from a parallel iterator.
412impl<K, V, S, A> ParallelExtend<(K, V)> for HashMap<K, V, S, A>
413where
414 K: Eq + Hash + Send,
415 V: Send,
416 S: BuildHasher,
417 A: Allocator,
418{
419 fn par_extend<I>(&mut self, par_iter: I)
420 where
421 I: IntoParallelIterator<Item = (K, V)>,
422 {
423 extend(self, par_iter);
424 }
425}
426
427/// Extend a hash map with copied items from a parallel iterator.
428impl<'a, K, V, S, A> ParallelExtend<(&'a K, &'a V)> for HashMap<K, V, S, A>
429where
430 K: Copy + Eq + Hash + Sync,
431 V: Copy + Sync,
432 S: BuildHasher,
433 A: Allocator,
434{
435 fn par_extend<I>(&mut self, par_iter: I)
436 where
437 I: IntoParallelIterator<Item = (&'a K, &'a V)>,
438 {
439 extend(self, par_iter);
440 }
441}
442
443// This is equal to the normal `HashMap` -- no custom advantage.
444fn extend<K, V, S, A, I>(map: &mut HashMap<K, V, S, A>, par_iter: I)
445where
446 K: Eq + Hash,
447 S: BuildHasher,
448 I: IntoParallelIterator,
449 A: Allocator,
450 HashMap<K, V, S, A>: Extend<I::Item>,
451{
452 let (list: LinkedList::Item>>, len: usize) = super::helpers::collect(par_iter);
453
454 // Keys may be already present or show multiple times in the iterator.
455 // Reserve the entire length if the map is empty.
456 // Otherwise reserve half the length (rounded up), so the map
457 // will only resize twice in the worst case.
458 let reserve: usize = if map.is_empty() { len } else { (len + 1) / 2 };
459 map.reserve(additional:reserve);
460 for vec: Vec<::Item> in list {
461 map.extend(iter:vec);
462 }
463}
464
465#[cfg(test)]
466mod test_par_map {
467 use alloc::vec::Vec;
468 use core::hash::{Hash, Hasher};
469 use core::sync::atomic::{AtomicUsize, Ordering};
470
471 use rayon::prelude::*;
472
473 use crate::hash_map::HashMap;
474
475 struct Droppable<'a> {
476 k: usize,
477 counter: &'a AtomicUsize,
478 }
479
480 impl Droppable<'_> {
481 fn new(k: usize, counter: &AtomicUsize) -> Droppable<'_> {
482 counter.fetch_add(1, Ordering::Relaxed);
483
484 Droppable { k, counter }
485 }
486 }
487
488 impl Drop for Droppable<'_> {
489 fn drop(&mut self) {
490 self.counter.fetch_sub(1, Ordering::Relaxed);
491 }
492 }
493
494 impl Clone for Droppable<'_> {
495 fn clone(&self) -> Self {
496 Droppable::new(self.k, self.counter)
497 }
498 }
499
500 impl Hash for Droppable<'_> {
501 fn hash<H>(&self, state: &mut H)
502 where
503 H: Hasher,
504 {
505 self.k.hash(state);
506 }
507 }
508
509 impl PartialEq for Droppable<'_> {
510 fn eq(&self, other: &Self) -> bool {
511 self.k == other.k
512 }
513 }
514
515 impl Eq for Droppable<'_> {}
516
517 #[test]
518 fn test_into_iter_drops() {
519 let key = AtomicUsize::new(0);
520 let value = AtomicUsize::new(0);
521
522 let hm = {
523 let mut hm = HashMap::new();
524
525 assert_eq!(key.load(Ordering::Relaxed), 0);
526 assert_eq!(value.load(Ordering::Relaxed), 0);
527
528 for i in 0..100 {
529 let d1 = Droppable::new(i, &key);
530 let d2 = Droppable::new(i + 100, &value);
531 hm.insert(d1, d2);
532 }
533
534 assert_eq!(key.load(Ordering::Relaxed), 100);
535 assert_eq!(value.load(Ordering::Relaxed), 100);
536
537 hm
538 };
539
540 // By the way, ensure that cloning doesn't screw up the dropping.
541 drop(hm.clone());
542
543 assert_eq!(key.load(Ordering::Relaxed), 100);
544 assert_eq!(value.load(Ordering::Relaxed), 100);
545
546 // Ensure that dropping the iterator does not leak anything.
547 drop(hm.clone().into_par_iter());
548
549 {
550 assert_eq!(key.load(Ordering::Relaxed), 100);
551 assert_eq!(value.load(Ordering::Relaxed), 100);
552
553 // retain only half
554 let _v: Vec<_> = hm.into_par_iter().filter(|(key, _)| key.k < 50).collect();
555
556 assert_eq!(key.load(Ordering::Relaxed), 50);
557 assert_eq!(value.load(Ordering::Relaxed), 50);
558 };
559
560 assert_eq!(key.load(Ordering::Relaxed), 0);
561 assert_eq!(value.load(Ordering::Relaxed), 0);
562 }
563
564 #[test]
565 fn test_drain_drops() {
566 let key = AtomicUsize::new(0);
567 let value = AtomicUsize::new(0);
568
569 let mut hm = {
570 let mut hm = HashMap::new();
571
572 assert_eq!(key.load(Ordering::Relaxed), 0);
573 assert_eq!(value.load(Ordering::Relaxed), 0);
574
575 for i in 0..100 {
576 let d1 = Droppable::new(i, &key);
577 let d2 = Droppable::new(i + 100, &value);
578 hm.insert(d1, d2);
579 }
580
581 assert_eq!(key.load(Ordering::Relaxed), 100);
582 assert_eq!(value.load(Ordering::Relaxed), 100);
583
584 hm
585 };
586
587 // By the way, ensure that cloning doesn't screw up the dropping.
588 drop(hm.clone());
589
590 assert_eq!(key.load(Ordering::Relaxed), 100);
591 assert_eq!(value.load(Ordering::Relaxed), 100);
592
593 // Ensure that dropping the drain iterator does not leak anything.
594 drop(hm.clone().par_drain());
595
596 {
597 assert_eq!(key.load(Ordering::Relaxed), 100);
598 assert_eq!(value.load(Ordering::Relaxed), 100);
599
600 // retain only half
601 let _v: Vec<_> = hm.drain().filter(|(key, _)| key.k < 50).collect();
602 assert!(hm.is_empty());
603
604 assert_eq!(key.load(Ordering::Relaxed), 50);
605 assert_eq!(value.load(Ordering::Relaxed), 50);
606 };
607
608 assert_eq!(key.load(Ordering::Relaxed), 0);
609 assert_eq!(value.load(Ordering::Relaxed), 0);
610 }
611
612 #[test]
613 fn test_empty_iter() {
614 let mut m: HashMap<isize, bool> = HashMap::new();
615 assert_eq!(m.par_drain().count(), 0);
616 assert_eq!(m.par_keys().count(), 0);
617 assert_eq!(m.par_values().count(), 0);
618 assert_eq!(m.par_values_mut().count(), 0);
619 assert_eq!(m.par_iter().count(), 0);
620 assert_eq!(m.par_iter_mut().count(), 0);
621 assert_eq!(m.len(), 0);
622 assert!(m.is_empty());
623 assert_eq!(m.into_par_iter().count(), 0);
624 }
625
626 #[test]
627 fn test_iterate() {
628 let mut m = HashMap::with_capacity(4);
629 for i in 0..32 {
630 assert!(m.insert(i, i * 2).is_none());
631 }
632 assert_eq!(m.len(), 32);
633
634 let observed = AtomicUsize::new(0);
635
636 m.par_iter().for_each(|(k, v)| {
637 assert_eq!(*v, *k * 2);
638 observed.fetch_or(1 << *k, Ordering::Relaxed);
639 });
640 assert_eq!(observed.into_inner(), 0xFFFF_FFFF);
641 }
642
643 #[test]
644 fn test_keys() {
645 let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
646 let map: HashMap<_, _> = vec.into_par_iter().collect();
647 let keys: Vec<_> = map.par_keys().cloned().collect();
648 assert_eq!(keys.len(), 3);
649 assert!(keys.contains(&1));
650 assert!(keys.contains(&2));
651 assert!(keys.contains(&3));
652 }
653
654 #[test]
655 fn test_values() {
656 let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
657 let map: HashMap<_, _> = vec.into_par_iter().collect();
658 let values: Vec<_> = map.par_values().cloned().collect();
659 assert_eq!(values.len(), 3);
660 assert!(values.contains(&'a'));
661 assert!(values.contains(&'b'));
662 assert!(values.contains(&'c'));
663 }
664
665 #[test]
666 fn test_values_mut() {
667 let vec = vec![(1, 1), (2, 2), (3, 3)];
668 let mut map: HashMap<_, _> = vec.into_par_iter().collect();
669 map.par_values_mut().for_each(|value| *value *= 2);
670 let values: Vec<_> = map.par_values().cloned().collect();
671 assert_eq!(values.len(), 3);
672 assert!(values.contains(&2));
673 assert!(values.contains(&4));
674 assert!(values.contains(&6));
675 }
676
677 #[test]
678 fn test_eq() {
679 let mut m1 = HashMap::new();
680 m1.insert(1, 2);
681 m1.insert(2, 3);
682 m1.insert(3, 4);
683
684 let mut m2 = HashMap::new();
685 m2.insert(1, 2);
686 m2.insert(2, 3);
687
688 assert!(!m1.par_eq(&m2));
689
690 m2.insert(3, 4);
691
692 assert!(m1.par_eq(&m2));
693 }
694
695 #[test]
696 fn test_from_iter() {
697 let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
698
699 let map: HashMap<_, _> = xs.par_iter().cloned().collect();
700
701 for &(k, v) in &xs {
702 assert_eq!(map.get(&k), Some(&v));
703 }
704 }
705
706 #[test]
707 fn test_extend_ref() {
708 let mut a = HashMap::new();
709 a.insert(1, "one");
710 let mut b = HashMap::new();
711 b.insert(2, "two");
712 b.insert(3, "three");
713
714 a.par_extend(&b);
715
716 assert_eq!(a.len(), 3);
717 assert_eq!(a[&1], "one");
718 assert_eq!(a[&2], "two");
719 assert_eq!(a[&3], "three");
720 }
721}
722