From 507de8bd6e47a40a9ffa8f4c2bd2ecff4d7bc0fe Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 18 Jan 2021 10:54:01 -0800 Subject: [PATCH 1/6] Remove the nonsensical default V=Global from Keys --- src/map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.rs b/src/map.rs index 9b19b1a10e..aabd495485 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1428,7 +1428,7 @@ impl IntoIter { /// /// [`keys`]: struct.HashMap.html#method.keys /// [`HashMap`]: struct.HashMap.html -pub struct Keys<'a, K, V = Global> { +pub struct Keys<'a, K, V> { inner: Iter<'a, K, V>, } From a586f25df81890d63c607c43063b5a99ec92c58b Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 18 Jan 2021 12:53:56 -0800 Subject: [PATCH 2/6] default A=Global for Entry and RawEntryMut --- src/map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/map.rs b/src/map.rs index aabd495485..09e569470f 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1611,7 +1611,7 @@ pub struct RawEntryBuilderMut<'a, K, V, S, A: Allocator + Clone = Global> { /// [`Entry`]: enum.Entry.html /// [`raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut /// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html -pub enum RawEntryMut<'a, K, V, S, A: Allocator + Clone> { +pub enum RawEntryMut<'a, K, V, S, A: Allocator + Clone = Global> { /// An occupied entry. Occupied(RawOccupiedEntryMut<'a, K, V, S, A>), /// A vacant entry. @@ -2186,7 +2186,7 @@ impl Debug for RawEntryBuilder<'_, K, V, S, A> { /// /// [`HashMap`]: struct.HashMap.html /// [`entry`]: struct.HashMap.html#method.entry -pub enum Entry<'a, K, V, S, A> +pub enum Entry<'a, K, V, S, A = Global> where A: Allocator + Clone, { From f46bff491349ef6dfc88c2883efd91937b9faf50 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 18 Jan 2021 12:56:57 -0800 Subject: [PATCH 3/6] default A=Global for raw types --- src/raw/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 15970743cb..e8421a13a3 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -367,7 +367,7 @@ impl Bucket { } /// A raw hash table with an unsafe API. -pub struct RawTable { +pub struct RawTable { // Mask to get an index from a hash value. The value is one less than the // number of buckets in the table. bucket_mask: usize, @@ -1770,7 +1770,7 @@ impl ExactSizeIterator for RawIter {} impl FusedIterator for RawIter {} /// Iterator which consumes a table and returns elements. -pub struct RawIntoIter { +pub struct RawIntoIter { iter: RawIter, allocation: Option<(NonNull, Layout)>, marker: PhantomData, @@ -1845,7 +1845,7 @@ impl ExactSizeIterator for RawIntoIter {} impl FusedIterator for RawIntoIter {} /// Iterator which consumes elements without freeing the table storage. -pub struct RawDrain<'a, T, A: Allocator + Clone> { +pub struct RawDrain<'a, T, A: Allocator + Clone = Global> { iter: RawIter, // The table is moved into the iterator for the duration of the drain. This @@ -1915,7 +1915,7 @@ impl FusedIterator for RawDrain<'_, T, A> {} /// Iterator over occupied buckets that could match a given hash. /// /// In rare cases, the iterator may return a bucket with a different hash. -pub struct RawIterHash<'a, T, A: Allocator + Clone> { +pub struct RawIterHash<'a, T, A: Allocator + Clone = Global> { table: &'a RawTable, // The top 7 bits of the hash. From bbcdf7c5a29ef339b7c6155c8caf95419745acac Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 18 Jan 2021 12:57:59 -0800 Subject: [PATCH 4/6] Clean up generic parameters of parallel iterators Many of the parallel iterators don't need the `S` hasher or `A` allocator at all if they convert to a tighter inner type upon construction. For those that do need `A`, default to `A=Global`. --- src/external_trait_impls/rayon/map.rs | 219 +++++++++++++++----------- src/external_trait_impls/rayon/raw.rs | 36 ++++- src/external_trait_impls/rayon/set.rs | 81 ++++------ 3 files changed, 194 insertions(+), 142 deletions(-) diff --git a/src/external_trait_impls/rayon/map.rs b/src/external_trait_impls/rayon/map.rs index 04bea7b38e..61b7380611 100644 --- a/src/external_trait_impls/rayon/map.rs +++ b/src/external_trait_impls/rayon/map.rs @@ -1,9 +1,11 @@ //! Rayon extensions for `HashMap`. +use super::raw::{RawIntoParIter, RawParDrain, RawParIter}; use crate::hash_map::HashMap; use crate::raw::{Allocator, Global}; use core::fmt; use core::hash::{BuildHasher, Hash}; +use core::marker::PhantomData; use rayon::iter::plumbing::UnindexedConsumer; use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; @@ -16,13 +18,12 @@ use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, Pa /// [`par_iter`]: /hashbrown/struct.HashMap.html#method.par_iter /// [`HashMap`]: /hashbrown/struct.HashMap.html /// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html -pub struct ParIter<'a, K, V, S, A: Allocator + Clone = Global> { - map: &'a HashMap, +pub struct ParIter<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, } -impl<'a, K: Sync, V: Sync, S: Sync, A: Allocator + Clone + Sync> ParallelIterator - for ParIter<'a, K, V, S, A> -{ +impl<'a, K: Sync, V: Sync> ParallelIterator for ParIter<'a, K, V> { type Item = (&'a K, &'a V); #[cfg_attr(feature = "inline-more", inline)] @@ -30,7 +31,7 @@ impl<'a, K: Sync, V: Sync, S: Sync, A: Allocator + Clone + Sync> ParallelIterato where C: UnindexedConsumer, { - unsafe { self.map.table.par_iter() } + self.inner .map(|x| unsafe { let r = x.as_ref(); (&r.0, &r.1) @@ -39,18 +40,23 @@ impl<'a, K: Sync, V: Sync, S: Sync, A: Allocator + Clone + Sync> ParallelIterato } } -impl Clone for ParIter<'_, K, V, S, A> { +impl Clone for ParIter<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] fn clone(&self) -> Self { - ParIter { map: self.map } + Self { + inner: self.inner.clone(), + marker: PhantomData, + } } } -impl fmt::Debug - for ParIter<'_, K, V, S, A> -{ +impl fmt::Debug for ParIter<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.map.iter().fmt(f) + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { + let r = x.as_ref(); + (&r.0, &r.1) + }); + f.debug_list().entries(iter).finish() } } @@ -61,13 +67,12 @@ impl { - map: &'a HashMap, +pub struct ParKeys<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, } -impl<'a, K: Sync, V: Sync, S: Sync, A: Allocator + Clone + Sync> ParallelIterator - for ParKeys<'a, K, V, S, A> -{ +impl<'a, K: Sync, V: Sync> ParallelIterator for ParKeys<'a, K, V> { type Item = &'a K; #[cfg_attr(feature = "inline-more", inline)] @@ -75,24 +80,26 @@ impl<'a, K: Sync, V: Sync, S: Sync, A: Allocator + Clone + Sync> ParallelIterato where C: UnindexedConsumer, { - unsafe { self.map.table.par_iter() } + self.inner .map(|x| unsafe { &x.as_ref().0 }) .drive_unindexed(consumer) } } -impl Clone for ParKeys<'_, K, V, S, A> { +impl Clone for ParKeys<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] fn clone(&self) -> Self { - ParKeys { map: self.map } + Self { + inner: self.inner.clone(), + marker: PhantomData, + } } } -impl fmt::Debug - for ParKeys<'_, K, V, S, A> -{ +impl fmt::Debug for ParKeys<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.map.keys().fmt(f) + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().0 }); + f.debug_list().entries(iter).finish() } } @@ -103,13 +110,12 @@ impl fmt::De /// /// [`par_values`]: /hashbrown/struct.HashMap.html#method.par_values /// [`HashMap`]: /hashbrown/struct.HashMap.html -pub struct ParValues<'a, K, V, S, A: Allocator + Clone = Global> { - map: &'a HashMap, +pub struct ParValues<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a V)>, } -impl<'a, K: Sync, V: Sync, S: Sync, A: Allocator + Clone + Sync> ParallelIterator - for ParValues<'a, K, V, S, A> -{ +impl<'a, K: Sync, V: Sync> ParallelIterator for ParValues<'a, K, V> { type Item = &'a V; #[cfg_attr(feature = "inline-more", inline)] @@ -117,24 +123,26 @@ impl<'a, K: Sync, V: Sync, S: Sync, A: Allocator + Clone + Sync> ParallelIterato where C: UnindexedConsumer, { - unsafe { self.map.table.par_iter() } + self.inner .map(|x| unsafe { &x.as_ref().1 }) .drive_unindexed(consumer) } } -impl Clone for ParValues<'_, K, V, S, A> { +impl Clone for ParValues<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] fn clone(&self) -> Self { - ParValues { map: self.map } + Self { + inner: self.inner.clone(), + marker: PhantomData, + } } } -impl fmt::Debug - for ParValues<'_, K, V, S, A> -{ +impl fmt::Debug for ParValues<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.map.values().fmt(f) + let iter = unsafe { self.inner.iter() }.map(|x| unsafe { &x.as_ref().1 }); + f.debug_list().entries(iter).finish() } } @@ -147,13 +155,12 @@ impl fmt::Deb /// [`par_iter_mut`]: /hashbrown/struct.HashMap.html#method.par_iter_mut /// [`HashMap`]: /hashbrown/struct.HashMap.html /// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html -pub struct ParIterMut<'a, K, V, S, A: Allocator + Clone> { - map: &'a mut HashMap, +pub struct ParIterMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, } -impl<'a, K: Send + Sync, V: Send, S: Send, A: Allocator + Clone + Sync> ParallelIterator - for ParIterMut<'a, K, V, S, A> -{ +impl<'a, K: Sync, V: Send> ParallelIterator for ParIterMut<'a, K, V> { type Item = (&'a K, &'a mut V); #[cfg_attr(feature = "inline-more", inline)] @@ -161,7 +168,7 @@ impl<'a, K: Send + Sync, V: Send, S: Send, A: Allocator + Clone + Sync> Parallel where C: UnindexedConsumer, { - unsafe { self.map.table.par_iter() } + self.inner .map(|x| unsafe { let r = x.as_mut(); (&r.0, &mut r.1) @@ -170,11 +177,13 @@ impl<'a, K: Send + Sync, V: Send, S: Send, A: Allocator + Clone + Sync> Parallel } } -impl fmt::Debug - for ParIterMut<'_, K, V, S, A> -{ +impl fmt::Debug for ParIterMut<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.map.iter().fmt(f) + ParIter { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) } } @@ -185,13 +194,12 @@ impl { - map: &'a mut HashMap, +pub struct ParValuesMut<'a, K, V> { + inner: RawParIter<(K, V)>, + marker: PhantomData<(&'a K, &'a mut V)>, } -impl<'a, K: Send, V: Send, S: Send, A: Allocator + Clone + Send> ParallelIterator - for ParValuesMut<'a, K, V, S, A> -{ +impl<'a, K: Sync, V: Send> ParallelIterator for ParValuesMut<'a, K, V> { type Item = &'a mut V; #[cfg_attr(feature = "inline-more", inline)] @@ -199,17 +207,19 @@ impl<'a, K: Send, V: Send, S: Send, A: Allocator + Clone + Send> ParallelIterato where C: UnindexedConsumer, { - unsafe { self.map.table.par_iter() } + self.inner .map(|x| unsafe { &mut x.as_mut().1 }) .drive_unindexed(consumer) } } -impl fmt::Debug - for ParValuesMut<'_, K, V, S, A> -{ +impl fmt::Debug for ParValuesMut<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.map.values().fmt(f) + ParValues { + inner: self.inner.clone(), + marker: PhantomData, + } + .fmt(f) } } @@ -222,13 +232,11 @@ impl fmt::Deb /// [`into_par_iter`]: /hashbrown/struct.HashMap.html#method.into_par_iter /// [`HashMap`]: /hashbrown/struct.HashMap.html /// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html -pub struct IntoParIter { - map: HashMap, +pub struct IntoParIter { + inner: RawIntoParIter<(K, V), A>, } -impl ParallelIterator - for IntoParIter -{ +impl ParallelIterator for IntoParIter { type Item = (K, V); #[cfg_attr(feature = "inline-more", inline)] @@ -236,15 +244,19 @@ impl ParallelIterator where C: UnindexedConsumer, { - self.map.table.into_par_iter().drive_unindexed(consumer) + self.inner.drive_unindexed(consumer) } } -impl fmt::Debug - for IntoParIter +impl fmt::Debug + for IntoParIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.map.iter().fmt(f) + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) } } @@ -255,13 +267,11 @@ impl { - map: &'a mut HashMap, +pub struct ParDrain<'a, K, V, A: Allocator + Clone = Global> { + inner: RawParDrain<'a, (K, V), A>, } -impl ParallelIterator - for ParDrain<'_, K, V, S, A> -{ +impl ParallelIterator for ParDrain<'_, K, V, A> { type Item = (K, V); #[cfg_attr(feature = "inline-more", inline)] @@ -269,44 +279,59 @@ impl ParallelIterator where C: UnindexedConsumer, { - self.map.table.par_drain().drive_unindexed(consumer) + self.inner.drive_unindexed(consumer) } } -impl fmt::Debug - for ParDrain<'_, K, V, S, A> +impl fmt::Debug + for ParDrain<'_, K, V, A> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.map.iter().fmt(f) + ParIter { + inner: unsafe { self.inner.par_iter() }, + marker: PhantomData, + } + .fmt(f) } } -impl HashMap { +impl HashMap { /// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order. #[cfg_attr(feature = "inline-more", inline)] - pub fn par_keys(&self) -> ParKeys<'_, K, V, S, A> { - ParKeys { map: self } + pub fn par_keys(&self) -> ParKeys<'_, K, V> { + ParKeys { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } } /// Visits (potentially in parallel) immutably borrowed values in an arbitrary order. #[cfg_attr(feature = "inline-more", inline)] - pub fn par_values(&self) -> ParValues<'_, K, V, S, A> { - ParValues { map: self } + pub fn par_values(&self) -> ParValues<'_, K, V> { + ParValues { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } } } -impl HashMap { +impl HashMap { /// Visits (potentially in parallel) mutably borrowed values in an arbitrary order. #[cfg_attr(feature = "inline-more", inline)] - pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V, S, A> { - ParValuesMut { map: self } + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { + ParValuesMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } } /// Consumes (potentially in parallel) all values in an arbitrary order, /// while preserving the map's allocated memory for reuse. #[cfg_attr(feature = "inline-more", inline)] - pub fn par_drain(&mut self) -> ParDrain<'_, K, V, S, A> { - ParDrain { map: self } + pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> { + ParDrain { + inner: self.table.par_drain(), + } } } @@ -329,39 +354,47 @@ where } } -impl IntoParallelIterator +impl IntoParallelIterator for HashMap { type Item = (K, V); - type Iter = IntoParIter; + type Iter = IntoParIter; #[cfg_attr(feature = "inline-more", inline)] fn into_par_iter(self) -> Self::Iter { - IntoParIter { map: self } + IntoParIter { + inner: self.table.into_par_iter(), + } } } -impl<'a, K: Sync, V: Sync, S: Sync, A: Allocator + Clone + Sync> IntoParallelIterator +impl<'a, K: Sync, V: Sync, S, A: Allocator + Clone> IntoParallelIterator for &'a HashMap { type Item = (&'a K, &'a V); - type Iter = ParIter<'a, K, V, S, A>; + type Iter = ParIter<'a, K, V>; #[cfg_attr(feature = "inline-more", inline)] fn into_par_iter(self) -> Self::Iter { - ParIter { map: self } + ParIter { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } } } -impl<'a, K: Send + Sync, V: Send, S: Send, A: Allocator + Clone + Sync> IntoParallelIterator +impl<'a, K: Sync, V: Send, S, A: Allocator + Clone> IntoParallelIterator for &'a mut HashMap { type Item = (&'a K, &'a mut V); - type Iter = ParIterMut<'a, K, V, S, A>; + type Iter = ParIterMut<'a, K, V>; #[cfg_attr(feature = "inline-more", inline)] fn into_par_iter(self) -> Self::Iter { - ParIterMut { map: self } + ParIterMut { + inner: unsafe { self.table.par_iter() }, + marker: PhantomData, + } } } diff --git a/src/external_trait_impls/rayon/raw.rs b/src/external_trait_impls/rayon/raw.rs index 9d64486785..18da1eacdc 100644 --- a/src/external_trait_impls/rayon/raw.rs +++ b/src/external_trait_impls/rayon/raw.rs @@ -1,5 +1,5 @@ use crate::raw::Bucket; -use crate::raw::{Allocator, RawIter, RawIterRange, RawTable}; +use crate::raw::{Allocator, Global, RawIter, RawIterRange, RawTable}; use crate::scopeguard::guard; use alloc::alloc::dealloc; use core::marker::PhantomData; @@ -15,6 +15,22 @@ pub struct RawParIter { iter: RawIterRange, } +impl RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn iter(&self) -> RawIterRange { + self.iter.clone() + } +} + +impl Clone for RawParIter { + #[cfg_attr(feature = "inline-more", inline)] + fn clone(&self) -> Self { + Self { + iter: self.iter.clone(), + } + } +} + impl From> for RawParIter { fn from(it: RawIter) -> Self { RawParIter { iter: it.iter } @@ -60,10 +76,17 @@ impl UnindexedProducer for ParIterProducer { } /// Parallel iterator which consumes a table and returns elements. -pub struct RawIntoParIter { +pub struct RawIntoParIter { table: RawTable, } +impl RawIntoParIter { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.par_iter() + } +} + impl ParallelIterator for RawIntoParIter { type Item = T; @@ -86,7 +109,7 @@ impl ParallelIterator for RawIntoParIter { } /// Parallel iterator which consumes elements without freeing the table storage. -pub struct RawParDrain<'a, T, A: Allocator + Clone> { +pub struct RawParDrain<'a, T, A: Allocator + Clone = Global> { // We don't use a &'a mut RawTable because we want RawParDrain to be // covariant over T. table: NonNull>, @@ -95,6 +118,13 @@ pub struct RawParDrain<'a, T, A: Allocator + Clone> { unsafe impl Send for RawParDrain<'_, T, A> {} +impl RawParDrain<'_, T, A> { + #[cfg_attr(feature = "inline-more", inline)] + pub(super) unsafe fn par_iter(&self) -> RawParIter { + self.table.as_ref().par_iter() + } +} + impl ParallelIterator for RawParDrain<'_, T, A> { type Item = T; diff --git a/src/external_trait_impls/rayon/set.rs b/src/external_trait_impls/rayon/set.rs index 9d6b743695..bbdfa7799d 100644 --- a/src/external_trait_impls/rayon/set.rs +++ b/src/external_trait_impls/rayon/set.rs @@ -1,5 +1,6 @@ //! Rayon extensions for `HashSet`. +use super::map; use crate::hash_set::HashSet; use crate::raw::{Allocator, Global}; use core::hash::{BuildHasher, Hash}; @@ -15,22 +16,18 @@ use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, Pa /// [`into_par_iter`]: /hashbrown/struct.HashSet.html#method.into_par_iter /// [`HashSet`]: /hashbrown/struct.HashSet.html /// [`IntoParallelIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelIterator.html -pub struct IntoParIter { - set: HashSet, +pub struct IntoParIter { + inner: map::IntoParIter, } -impl ParallelIterator for IntoParIter { +impl ParallelIterator for IntoParIter { type Item = T; fn drive_unindexed(self, consumer: C) -> C::Result where C: UnindexedConsumer, { - self.set - .map - .into_par_iter() - .map(|(k, _)| k) - .drive_unindexed(consumer) + self.inner.map(|(k, _)| k).drive_unindexed(consumer) } } @@ -41,24 +38,18 @@ impl ParallelIterator for IntoPar /// /// [`par_drain`]: /hashbrown/struct.HashSet.html#method.par_drain /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParDrain<'a, T, S, A: Allocator + Clone = Global> { - set: &'a mut HashSet, +pub struct ParDrain<'a, T, A: Allocator + Clone = Global> { + inner: map::ParDrain<'a, T, (), A>, } -impl ParallelIterator - for ParDrain<'_, T, S, A> -{ +impl ParallelIterator for ParDrain<'_, T, A> { type Item = T; fn drive_unindexed(self, consumer: C) -> C::Result where C: UnindexedConsumer, { - self.set - .map - .par_drain() - .map(|(k, _)| k) - .drive_unindexed(consumer) + self.inner.map(|(k, _)| k).drive_unindexed(consumer) } } @@ -71,18 +62,18 @@ impl ParallelIterator /// [`par_iter`]: /hashbrown/struct.HashSet.html#method.par_iter /// [`HashSet`]: /hashbrown/struct.HashSet.html /// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html -pub struct ParIter<'a, T, S, A: Allocator + Clone = Global> { - set: &'a HashSet, +pub struct ParIter<'a, T> { + inner: map::ParKeys<'a, T, ()>, } -impl<'a, T: Sync, S: Sync, A: Allocator + Clone + Sync> ParallelIterator for ParIter<'a, T, S, A> { +impl<'a, T: Sync> ParallelIterator for ParIter<'a, T> { type Item = &'a T; fn drive_unindexed(self, consumer: C) -> C::Result where C: UnindexedConsumer, { - self.set.map.par_keys().drive_unindexed(consumer) + self.inner.drive_unindexed(consumer) } } @@ -190,15 +181,16 @@ where /// /// [`par_union`]: /hashbrown/struct.HashSet.html#method.par_union /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParUnion<'a, T, S> { - a: &'a HashSet, - b: &'a HashSet, +pub struct ParUnion<'a, T, S, A: Allocator + Clone = Global> { + a: &'a HashSet, + b: &'a HashSet, } -impl<'a, T, S> ParallelIterator for ParUnion<'a, T, S> +impl<'a, T, S, A> ParallelIterator for ParUnion<'a, T, S, A> where T: Eq + Hash + Sync, S: BuildHasher + Sync, + A: Allocator + Clone + Sync, { type Item = &'a T; @@ -213,25 +205,19 @@ where } } -impl HashSet +impl HashSet where T: Eq + Hash + Sync, S: BuildHasher + Sync, + A: Allocator + Clone + Sync, { /// Visits (potentially in parallel) the values representing the union, /// i.e. all the values in `self` or `other`, without duplicates. #[cfg_attr(feature = "inline-more", inline)] - pub fn par_union<'a>(&'a self, other: &'a Self) -> ParUnion<'a, T, S> { + pub fn par_union<'a>(&'a self, other: &'a Self) -> ParUnion<'a, T, S, A> { ParUnion { a: self, b: other } } -} -impl HashSet -where - T: Eq + Hash + Sync, - S: BuildHasher + Sync, - A: Allocator + Clone + Sync, -{ /// Visits (potentially in parallel) the values representing the difference, /// i.e. the values that are in `self` but not in `other`. #[cfg_attr(feature = "inline-more", inline)] @@ -296,36 +282,39 @@ where impl HashSet where T: Eq + Hash + Send, - S: BuildHasher + Send, A: Allocator + Clone + Send, { /// Consumes (potentially in parallel) all values in an arbitrary order, /// while preserving the set's allocated memory for reuse. #[cfg_attr(feature = "inline-more", inline)] - pub fn par_drain(&mut self) -> ParDrain<'_, T, S, A> { - ParDrain { set: self } + pub fn par_drain(&mut self) -> ParDrain<'_, T, A> { + ParDrain { + inner: self.map.par_drain(), + } } } -impl IntoParallelIterator for HashSet { +impl IntoParallelIterator for HashSet { type Item = T; - type Iter = IntoParIter; + type Iter = IntoParIter; #[cfg_attr(feature = "inline-more", inline)] fn into_par_iter(self) -> Self::Iter { - IntoParIter { set: self } + IntoParIter { + inner: self.map.into_par_iter(), + } } } -impl<'a, T: Sync, S: Sync, A: Allocator + Clone + Sync> IntoParallelIterator - for &'a HashSet -{ +impl<'a, T: Sync, S, A: Allocator + Clone> IntoParallelIterator for &'a HashSet { type Item = &'a T; - type Iter = ParIter<'a, T, S, A>; + type Iter = ParIter<'a, T>; #[cfg_attr(feature = "inline-more", inline)] fn into_par_iter(self) -> Self::Iter { - ParIter { set: self } + ParIter { + inner: self.map.par_keys(), + } } } From ae86b4e0bfde3187ccde155024935587f3bcc464 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 18 Jan 2021 13:00:51 -0800 Subject: [PATCH 5/6] Limit the stable allocator shims to internal use --- src/raw/alloc.rs | 4 ++-- src/raw/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/raw/alloc.rs b/src/raw/alloc.rs index eb563f4cbf..20fcd1cd0f 100644 --- a/src/raw/alloc.rs +++ b/src/raw/alloc.rs @@ -1,9 +1,9 @@ -pub use self::inner::*; +pub(crate) use self::inner::{do_alloc, Allocator, Global}; #[cfg(feature = "nightly")] mod inner { use crate::alloc::alloc::Layout; - pub use crate::alloc::alloc::{AllocError, Allocator, Global}; + pub use crate::alloc::alloc::{Allocator, Global}; use core::ptr::NonNull; #[allow(clippy::map_err_ignore)] diff --git a/src/raw/mod.rs b/src/raw/mod.rs index e8421a13a3..ac30f9f0bc 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -32,7 +32,7 @@ cfg_if! { } mod alloc; -pub use self::alloc::{do_alloc, AllocError, Allocator, Global}; +pub(crate) use self::alloc::{do_alloc, Allocator, Global}; mod bitmask; From dac885a87fe14812ef9aaed95f29391703b62e41 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 18 Jan 2021 13:23:42 -0800 Subject: [PATCH 6/6] use Global for with_capacity, and add with_capacity_in --- src/map.rs | 4 ++-- src/raw/mod.rs | 27 ++++++++++++++++++++------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/map.rs b/src/map.rs index 09e569470f..8154e87734 100644 --- a/src/map.rs +++ b/src/map.rs @@ -405,7 +405,7 @@ impl HashMap { pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { Self { hash_builder, - table: RawTable::with_capacity(Global, capacity), + table: RawTable::with_capacity(capacity), } } } @@ -464,7 +464,7 @@ impl HashMap { pub fn with_capacity_and_hasher_in(capacity: usize, hash_builder: S, alloc: A) -> Self { Self { hash_builder, - table: RawTable::with_capacity(alloc, capacity), + table: RawTable::with_capacity_in(capacity, alloc), } } diff --git a/src/raw/mod.rs b/src/raw/mod.rs index ac30f9f0bc..d17abf7096 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -406,6 +406,19 @@ impl RawTable { alloc: Global, } } + + /// Attempts to allocate a new hash table with at least enough capacity + /// for inserting the given number of elements without reallocating. + #[cfg(feature = "raw")] + pub fn try_with_capacity(capacity: usize) -> Result { + Self::try_with_capacity_in(capacity, Global) + } + + /// Allocates a new hash table with at least enough capacity for inserting + /// the given number of elements without reallocating. + pub fn with_capacity(capacity: usize) -> Self { + Self::with_capacity_in(capacity, Global) + } } impl RawTable { @@ -483,16 +496,16 @@ impl RawTable { } } - /// Attempts to allocate a new hash table with at least enough capacity - /// for inserting the given number of elements without reallocating. + /// Attempts to allocate a new hash table using the given allocator, with at least enough + /// capacity for inserting the given number of elements without reallocating. #[cfg(feature = "raw")] - pub fn try_with_capacity(alloc: A, capacity: usize) -> Result { + pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result { Self::fallible_with_capacity(alloc, capacity, Fallibility::Fallible) } - /// Allocates a new hash table with at least enough capacity for inserting - /// the given number of elements without reallocating. - pub fn with_capacity(alloc: A, capacity: usize) -> Self { + /// Allocates a new hash table using the given allocator, with at least enough capacity for + /// inserting the given number of elements without reallocating. + pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. match Self::fallible_with_capacity(alloc, capacity, Fallibility::Infallible) { Ok(capacity) => capacity, @@ -748,7 +761,7 @@ impl RawTable { if min_buckets < self.buckets() { // Fast path if the table is empty if self.items == 0 { - *self = Self::with_capacity(self.alloc.clone(), min_size) + *self = Self::with_capacity_in(min_size, self.alloc.clone()) } else { // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. if self