diff --git a/src/external_trait_impls/rayon/map.rs b/src/external_trait_impls/rayon/map.rs index 9623ca747..b191bc7d4 100644 --- a/src/external_trait_impls/rayon/map.rs +++ b/src/external_trait_impls/rayon/map.rs @@ -296,7 +296,7 @@ impl HashMap { #[cfg_attr(feature = "inline-more", inline)] pub fn par_keys(&self) -> ParKeys<'_, K, V> { ParKeys { - inner: unsafe { self.table.par_iter() }, + inner: unsafe { self.table.raw.par_iter() }, marker: PhantomData, } } @@ -305,7 +305,7 @@ impl HashMap { #[cfg_attr(feature = "inline-more", inline)] pub fn par_values(&self) -> ParValues<'_, K, V> { ParValues { - inner: unsafe { self.table.par_iter() }, + inner: unsafe { self.table.raw.par_iter() }, marker: PhantomData, } } @@ -316,7 +316,7 @@ impl HashMap { #[cfg_attr(feature = "inline-more", inline)] pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V> { ParValuesMut { - inner: unsafe { self.table.par_iter() }, + inner: unsafe { self.table.raw.par_iter() }, marker: PhantomData, } } @@ -326,7 +326,7 @@ impl HashMap { #[cfg_attr(feature = "inline-more", inline)] pub fn par_drain(&mut self) -> ParDrain<'_, K, V, A> { ParDrain { - inner: self.table.par_drain(), + inner: self.table.raw.par_drain(), } } } @@ -357,7 +357,7 @@ impl IntoParallelIterator for HashMap< #[cfg_attr(feature = "inline-more", inline)] fn into_par_iter(self) -> Self::Iter { IntoParIter { - inner: self.table.into_par_iter(), + inner: self.table.raw.into_par_iter(), } } } @@ -369,7 +369,7 @@ impl<'a, K: Sync, V: Sync, S, A: Allocator> IntoParallelIterator for &'a HashMap #[cfg_attr(feature = "inline-more", inline)] fn into_par_iter(self) -> Self::Iter { ParIter { - inner: unsafe { self.table.par_iter() }, + inner: unsafe { self.table.raw.par_iter() }, marker: PhantomData, } } @@ -382,7 +382,7 @@ impl<'a, K: Sync, V: Send, S, A: Allocator> IntoParallelIterator for &'a mut Has #[cfg_attr(feature = "inline-more", inline)] fn into_par_iter(self) -> Self::Iter { ParIterMut { - inner: unsafe { self.table.par_iter() }, + inner: unsafe { self.table.raw.par_iter() }, marker: PhantomData, } } diff --git a/src/map.rs b/src/map.rs index f37bafa02..07504166e 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,7 +1,5 @@ -use crate::raw::{ - Allocator, Bucket, Global, RawDrain, RawExtractIf, RawIntoIter, RawIter, RawTable, -}; -use crate::{DefaultHashBuilder, Equivalent, TryReserveError}; +use crate::raw::{Allocator, Bucket, Global}; +use crate::{table, DefaultHashBuilder, Equivalent, HashTable, TryReserveError}; use ::alloc::borrow::ToOwned; use core::borrow::Borrow; use core::fmt::{self, Debug}; @@ -185,7 +183,7 @@ pub use crate::raw_entry::*; /// ``` pub struct HashMap { pub(crate) hash_builder: S, - pub(crate) table: RawTable<(K, V), A>, + pub(crate) table: HashTable<(K, V), A>, } impl Clone for HashMap { @@ -205,7 +203,7 @@ impl Clone for HashMap(hash_builder: &S) -> impl Fn(&(Q, V)) -> u64 + '_ where @@ -216,7 +214,7 @@ where } /// Ensures that a single closure type across uses of this which, in turn prevents multiple -/// instances of any functions like `RawTable::reserve` from being generated +/// instances of any functions like `HashTable::reserve` from being generated #[cfg_attr(feature = "inline-more", inline)] pub(crate) fn equivalent_key(k: &Q) -> impl Fn(&(K, V)) -> bool + '_ where @@ -226,7 +224,7 @@ where } /// Ensures that a single closure type across uses of this which, in turn prevents multiple -/// instances of any functions like `RawTable::reserve` from being generated +/// instances of any functions like `HashTable::reserve` from being generated #[cfg_attr(feature = "inline-more", inline)] #[allow(dead_code)] pub(crate) fn equivalent(k: &Q) -> impl Fn(&K) -> bool + '_ @@ -458,7 +456,7 @@ impl HashMap { pub const fn with_hasher(hash_builder: S) -> Self { Self { hash_builder, - table: RawTable::new(), + table: HashTable::new(), } } @@ -500,7 +498,7 @@ impl HashMap { pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self { Self { hash_builder, - table: RawTable::with_capacity(capacity), + table: HashTable::with_capacity(capacity), } } } @@ -544,7 +542,7 @@ impl HashMap { pub const fn with_hasher_in(hash_builder: S, alloc: A) -> Self { Self { hash_builder, - table: RawTable::new_in(alloc), + table: HashTable::new_in(alloc), } } @@ -579,7 +577,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_in(capacity, alloc), + table: HashTable::with_capacity_in(capacity, alloc), } } @@ -753,12 +751,8 @@ impl HashMap { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn iter(&self) -> Iter<'_, K, V> { - // Here we tie the lifetime of self to the iter. - unsafe { - Iter { - inner: self.table.iter(), - marker: PhantomData, - } + Iter { + inner: self.table.iter(), } } @@ -798,12 +792,9 @@ impl HashMap { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { - // Here we tie the lifetime of self to the iter. - unsafe { - IterMut { - inner: self.table.iter(), - marker: PhantomData, - } + IterMut { + inner: self.table.unsafe_iter(), + marker: PhantomData, } } @@ -919,15 +910,8 @@ impl HashMap { where F: FnMut(&K, &mut V) -> bool, { - // Here we only use `iter` as a temporary, preventing use-after-free - unsafe { - for item in self.table.iter() { - let &mut (ref key, ref mut value) = item.as_mut(); - if !f(key, value) { - self.table.erase(item); - } - } - } + self.table + .retain(move |&mut (ref key, ref mut val)| f(key, val)) } /// Drains elements which are true under the given predicate, @@ -976,14 +960,10 @@ impl HashMap { #[cfg_attr(feature = "inline-more", inline)] pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, K, V, F, A> where - F: FnMut(&K, &mut V) -> bool, + F: Filter, { ExtractIf { - f, - inner: RawExtractIf { - iter: unsafe { self.table.iter() }, - table: &mut self.table, - }, + inner: self.table.extract_if(KeyVal(f)), } } @@ -1229,18 +1209,17 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S, A> { let hash = make_hash::(&self.hash_builder, &key); - if let Some(elem) = self.table.find(hash, equivalent_key(&key)) { - Entry::Occupied(OccupiedEntry { - hash, - elem, - table: self, - }) - } else { - Entry::Vacant(VacantEntry { - hash, + let hasher = make_hasher(&self.hash_builder); + match self.table.entry(hash, equivalent_key(&key), hasher) { + table::Entry::Occupied(inner) => Entry::Occupied(OccupiedEntry { + inner, + marker: PhantomData, + }), + table::Entry::Vacant(inner) => Entry::Vacant(VacantEntry { + inner, key, - table: self, - }) + marker: PhantomData, + }), } } @@ -1267,18 +1246,17 @@ where Q: Hash + Equivalent + ?Sized, { let hash = make_hash::(&self.hash_builder, key); - if let Some(elem) = self.table.find(hash, equivalent_key(key)) { - EntryRef::Occupied(OccupiedEntry { - hash, - elem, - table: self, - }) - } else { - EntryRef::Vacant(VacantEntryRef { - hash, + let hasher = make_hasher(&self.hash_builder); + match self.table.entry(hash, equivalent_key(key), hasher) { + table::Entry::Occupied(inner) => EntryRef::Occupied(OccupiedEntry { + inner, + marker: PhantomData, + }), + table::Entry::Vacant(inner) => EntryRef::Vacant(VacantEntryRef { + inner, key, - table: self, - }) + marker: PhantomData, + }), } } @@ -1309,7 +1287,7 @@ where // Avoid `Option::map` because it bloats LLVM IR. if !self.table.is_empty() { let hash = make_hash::(&self.hash_builder, k); - match self.table.get(hash, equivalent_key(k)) { + match self.table.find(hash, equivalent_key(k)) { Some((_, v)) => Some(v), None => None, } @@ -1345,7 +1323,7 @@ where // Avoid `Option::map` because it bloats LLVM IR. if !self.table.is_empty() { let hash = make_hash::(&self.hash_builder, k); - match self.table.get(hash, equivalent_key(k)) { + match self.table.find(hash, equivalent_key(k)) { Some((key, value)) => Some((key, value)), None => None, } @@ -1385,7 +1363,7 @@ where // Avoid `Option::map` because it bloats LLVM IR. if !self.table.is_empty() { let hash = make_hash::(&self.hash_builder, k); - match self.table.get_mut(hash, equivalent_key(k)) { + match self.table.find_mut(hash, equivalent_key(k)) { Some(&mut (ref key, ref mut value)) => Some((key, value)), None => None, } @@ -1420,7 +1398,7 @@ where { if !self.table.is_empty() { let hash = make_hash::(&self.hash_builder, k); - self.table.get(hash, equivalent_key(k)).is_some() + self.table.find(hash, equivalent_key(k)).is_some() } else { false } @@ -1457,7 +1435,7 @@ where // Avoid `Option::map` because it bloats LLVM IR. if !self.table.is_empty() { let hash = make_hash::(&self.hash_builder, k); - match self.table.get_mut(hash, equivalent_key(k)) { + match self.table.find_mut(hash, equivalent_key(k)) { Some(&mut (_, ref mut v)) => Some(v), None => None, } @@ -1840,13 +1818,10 @@ where /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn insert(&mut self, k: K, v: V) -> Option { - let hash = make_hash::(&self.hash_builder, &k); - match self.find_or_find_insert_index(hash, &k) { - Ok(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().1 }, v)), - Err(index) => { - unsafe { - self.table.insert_at_index(hash, index, (k, v)); - } + match self.entry(k) { + Entry::Occupied(mut entry) => Some(entry.insert(v)), + Entry::Vacant(entry) => { + entry.insert(v); None } } @@ -1861,7 +1836,7 @@ where where Q: Equivalent + ?Sized, { - self.table.find_or_find_insert_index( + self.table.raw.find_or_find_insert_index( hash, equivalent_key(key), make_hasher(&self.hash_builder), @@ -1928,10 +1903,10 @@ where #[cfg_attr(feature = "inline-more", inline)] pub unsafe fn insert_unique_unchecked(&mut self, k: K, v: V) -> (&K, &mut V) { let hash = make_hash::(&self.hash_builder, &k); - let bucket = self - .table - .insert(hash, (k, v), make_hasher::<_, V, S>(&self.hash_builder)); - let (k_ref, v_ref) = unsafe { bucket.as_mut() }; + let entry = + self.table + .insert_unique(hash, (k, v), make_hasher::<_, V, S>(&self.hash_builder)); + let (k_ref, v_ref) = entry.into_mut(); (k_ref, v_ref) } @@ -2047,7 +2022,7 @@ where Q: Hash + Equivalent + ?Sized, { let hash = make_hash::(&self.hash_builder, k); - self.table.remove_entry(hash, equivalent_key(k)) + self.table.raw.remove_entry(hash, equivalent_key(k)) } /// Returns the total amount of memory allocated internally by the hash @@ -2205,8 +2180,7 @@ where /// assert_eq!(iter.next(), None); /// ``` pub struct Iter<'a, K, V> { - inner: RawIter<(K, V)>, - marker: PhantomData<(&'a K, &'a V)>, + inner: table::Iter<'a, (K, V)>, } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` @@ -2215,7 +2189,6 @@ impl Clone for Iter<'_, K, V> { fn clone(&self) -> Self { Iter { inner: self.inner.clone(), - marker: PhantomData, } } } @@ -2254,7 +2227,7 @@ impl fmt::Debug for Iter<'_, K, V> { /// assert_eq!(map.get(&2).unwrap(), &"Two Mississippi".to_owned()); /// ``` pub struct IterMut<'a, K, V> { - inner: RawIter<(K, V)>, + inner: table::UnsafeIter<'a, (K, V)>, // To ensure invariance with respect to V marker: PhantomData<(&'a K, &'a mut V)>, } @@ -2269,8 +2242,7 @@ impl IterMut<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] pub(super) fn iter(&self) -> Iter<'_, K, V> { Iter { - inner: self.inner.clone(), - marker: PhantomData, + inner: self.inner.iter(), } } } @@ -2306,7 +2278,7 @@ impl IterMut<'_, K, V> { /// assert_eq!(iter.next(), None); /// ``` pub struct IntoIter { - inner: RawIntoIter<(K, V), A>, + inner: table::IntoIter<(K, V), A>, } impl IntoIter { @@ -2315,7 +2287,6 @@ impl IntoIter { pub(super) fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.inner.iter(), - marker: PhantomData, } } } @@ -2602,7 +2573,7 @@ impl fmt::Debug for Values<'_, K, V> { /// assert_eq!(drain_iter.next(), None); /// ``` pub struct Drain<'a, K, V, A: Allocator = Global> { - inner: RawDrain<'a, (K, V), A>, + inner: table::Drain<'a, (K, V), A>, } impl Drain<'_, K, V, A> { @@ -2611,11 +2582,33 @@ impl Drain<'_, K, V, A> { pub(super) fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.inner.iter(), - marker: PhantomData, } } } +/// Adapter between [`map::Filter`](Filter) and [`table::Filter`]. +struct KeyVal(F); +impl> table::Filter<(K, V)> for KeyVal { + #[inline] + fn should_extract(&mut self, (ref key, ref mut val): &mut (K, V)) -> bool { + self.0.should_extract(key, val) + } +} + +/// Filter for [`ExtractIf`]. +/// +/// Accepts `FnMut(&K, &mut V) -> bool`, but can be implemented directly. +pub trait Filter { + /// Whether the element should be extracted. + fn should_extract(&mut self, key: &K, value: &mut V) -> bool; +} +impl bool> Filter for F { + #[inline] + fn should_extract(&mut self, key: &K, value: &mut V) -> bool { + (self)(key, value) + } +} + /// A draining iterator over entries of a `HashMap` which don't satisfy the predicate /// `f(&k, &mut v)` in arbitrary order. The iterator element type is `(K, V)`. /// @@ -2649,25 +2642,24 @@ impl Drain<'_, K, V, A> { /// ``` #[must_use = "Iterators are lazy unless consumed"] pub struct ExtractIf<'a, K, V, F, A: Allocator = Global> { - f: F, - inner: RawExtractIf<'a, (K, V), A>, + inner: table::ExtractIf<'a, (K, V), KeyVal, A>, } impl Iterator for ExtractIf<'_, K, V, F, A> where - F: FnMut(&K, &mut V) -> bool, + F: Filter, A: Allocator, { type Item = (K, V); #[cfg_attr(feature = "inline-more", inline)] fn next(&mut self) -> Option { - self.inner.next(|&mut (ref k, ref mut v)| (self.f)(k, v)) + self.inner.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - (0, self.inner.iter.size_hint().1) + self.inner.size_hint() } } @@ -2830,9 +2822,8 @@ impl Debug for Entry<'_, K, V, S, A> { /// assert_eq!(map.len(), 2); /// ``` pub struct OccupiedEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { - hash: u64, - elem: Bucket<(K, V)>, - table: &'a mut HashMap, + inner: table::OccupiedEntry<'a, (K, V), A>, + marker: PhantomData<&'a mut S>, } unsafe impl Send for OccupiedEntry<'_, K, V, S, A> @@ -2892,9 +2883,9 @@ impl Debug for OccupiedEntry<'_, K, V, S, A /// assert!(map[&"b"] == 20 && map.len() == 2); /// ``` pub struct VacantEntry<'a, K, V, S = DefaultHashBuilder, A: Allocator = Global> { - hash: u64, + inner: table::VacantEntry<'a, (K, V), A>, key: K, - table: &'a mut HashMap, + marker: PhantomData<&'a mut S>, } impl Debug for VacantEntry<'_, K, V, S, A> { @@ -3034,9 +3025,9 @@ where /// assert!(map["b"] == 20 && map.len() == 2); /// ``` pub struct VacantEntryRef<'map, 'key, K, Q: ?Sized, V, S, A: Allocator = Global> { - hash: u64, + inner: table::VacantEntry<'map, (K, V), A>, key: &'key Q, - table: &'map mut HashMap, + marker: PhantomData<&'map mut S>, } impl Debug for VacantEntryRef<'_, '_, K, Q, V, S, A> @@ -3207,21 +3198,17 @@ impl Default for Iter<'_, K, V> { fn default() -> Self { Self { inner: Default::default(), - marker: PhantomData, } } } -impl<'a, K, V> Iterator for Iter<'a, K, V> { +impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { type Item = (&'a K, &'a V); #[cfg_attr(feature = "inline-more", inline)] fn next(&mut self) -> Option<(&'a K, &'a V)> { // Avoid `Option::map` because it bloats LLVM IR. match self.inner.next() { - Some(x) => unsafe { - let r = x.as_ref(); - Some((&r.0, &r.1)) - }, + Some(x) => Some((&x.0, &x.1)), None => None, } } @@ -3235,20 +3222,17 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { Self: Sized, F: FnMut(B, Self::Item) -> B, { - self.inner.fold(init, |acc, x| unsafe { - let (k, v) = x.as_ref(); - f(acc, (k, v)) - }) + self.inner.fold(init, |acc, (k, v)| f(acc, (k, v))) } } -impl ExactSizeIterator for Iter<'_, K, V> { +impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> { #[cfg_attr(feature = "inline-more", inline)] fn len(&self) -> usize { self.inner.len() } } -impl FusedIterator for Iter<'_, K, V> {} +impl<'a, K: 'a, V: 'a> FusedIterator for Iter<'a, K, V> {} impl Default for IterMut<'_, K, V> { #[cfg_attr(feature = "inline-more", inline)] @@ -3266,10 +3250,12 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { fn next(&mut self) -> Option<(&'a K, &'a mut V)> { // Avoid `Option::map` because it bloats LLVM IR. match self.inner.next() { - Some(x) => unsafe { - let r = x.as_mut(); - Some((&r.0, &mut r.1)) - }, + Some(mut x) => { + // SAFETY: We match the lifetime of the original iterator + // with the correct variance provided by PhantomData. + let (ref k, ref mut v) = unsafe { x.as_mut() }; + Some((k, v)) + } None => None, } } @@ -3283,8 +3269,10 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { Self: Sized, F: FnMut(B, Self::Item) -> B, { - self.inner.fold(init, |acc, x| unsafe { - let (k, v) = x.as_mut(); + self.inner.fold(init, |acc, mut x| { + // SAFETY: We match the lifetime of the original iterator + // with the correct variance provided by PhantomData. + let (ref k, ref mut v) = unsafe { x.as_mut() }; f(acc, (k, v)) }) } @@ -3846,7 +3834,7 @@ impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn key(&self) -> &K { - unsafe { &self.elem.as_ref().0 } + &self.inner.get().0 } /// Take the ownership of the key and value from the map. @@ -3875,7 +3863,7 @@ impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn remove_entry(self) -> (K, V) { - unsafe { self.table.table.remove(self.elem).0 } + self.inner.remove().0 } /// Gets a reference to the value in the entry. @@ -3896,7 +3884,7 @@ impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn get(&self) -> &V { - unsafe { &self.elem.as_ref().1 } + &self.inner.get().1 } /// Gets a mutable reference to the value in the entry. @@ -3928,7 +3916,7 @@ impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn get_mut(&mut self) -> &mut V { - unsafe { &mut self.elem.as_mut().1 } + &mut self.inner.get_mut().1 } /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry @@ -3959,7 +3947,7 @@ impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn into_mut(self) -> &'a mut V { - unsafe { &mut self.elem.as_mut().1 } + &mut self.inner.into_mut().1 } /// Converts the `OccupiedEntry` into a reference to the key and a @@ -3994,7 +3982,7 @@ impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn into_entry(self) -> (&'a K, &'a mut V) { - let (key, val) = unsafe { self.elem.as_mut() }; + let (key, val) = self.inner.into_mut(); (key, val) } @@ -4101,29 +4089,25 @@ impl<'a, K, V, S, A: Allocator> OccupiedEntry<'a, K, V, S, A> { where F: FnOnce(&K, V) -> Option, { - unsafe { - let mut spare_key = None; + let mut spare_key = None; - self.table - .table - .replace_bucket_with(self.elem.clone(), |(key, value)| { - if let Some(new_value) = f(&key, value) { - Some((key, new_value)) - } else { - spare_key = Some(key); - None - } - }); - - if let Some(key) = spare_key { - Entry::Vacant(VacantEntry { - hash: self.hash, - key, - table: self.table, - }) + match self.inner.replace_entry_with(|(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) } else { - Entry::Occupied(self) + spare_key = Some(key); + None } + }) { + table::Entry::Vacant(inner) => Entry::Vacant(VacantEntry { + inner, + key: unsafe { spare_key.unwrap_unchecked() }, + marker: PhantomData, + }), + table::Entry::Occupied(inner) => Entry::Occupied(OccupiedEntry { + inner, + marker: PhantomData, + }), } } } @@ -4186,13 +4170,7 @@ impl<'a, K, V, S, A: Allocator> VacantEntry<'a, K, V, S, A> { K: Hash, S: BuildHasher, { - let table = &mut self.table.table; - let entry = table.insert_entry( - self.hash, - (self.key, value), - make_hasher::<_, V, S>(&self.table.hash_builder), - ); - &mut entry.1 + &mut self.inner.insert((self.key, value)).into_mut().1 } /// Sets the value of the entry with the [`VacantEntry`]'s key, @@ -4217,15 +4195,9 @@ impl<'a, K, V, S, A: Allocator> VacantEntry<'a, K, V, S, A> { K: Hash, S: BuildHasher, { - let elem = self.table.table.insert( - self.hash, - (self.key, value), - make_hasher::<_, V, S>(&self.table.hash_builder), - ); OccupiedEntry { - hash: self.hash, - elem, - table: self.table, + inner: self.inner.insert((self.key, value)), + marker: PhantomData, } } } @@ -4526,13 +4498,7 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K, Q: ToOwned, S: BuildHasher, { - let table = &mut self.table.table; - let entry = table.insert_entry( - self.hash, - (self.key.to_owned(), value), - make_hasher::<_, V, S>(&self.table.hash_builder), - ); - &mut entry.1 + &mut self.inner.insert((self.key.to_owned(), value)).into_mut().1 } /// Sets the key and value of the entry and returns a mutable reference to @@ -4597,15 +4563,9 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K, Q: ToOwned, S: BuildHasher, { - let elem = self.table.table.insert( - self.hash, - (self.key.to_owned(), value), - make_hasher::<_, V, S>(&self.table.hash_builder), - ); OccupiedEntry { - hash: self.hash, - elem, - table: self.table, + inner: self.inner.insert((self.key.to_owned(), value)), + marker: PhantomData, } } @@ -4648,15 +4608,9 @@ impl<'map, 'key, K, Q: ?Sized, V, S, A: Allocator> VacantEntryRef<'map, 'key, K, (self.key).equivalent(&key), "key used for Entry creation is not equivalent to the one used for insertion" ); - let elem = self.table.table.insert( - self.hash, - (key, value), - make_hasher::<_, V, S>(&self.table.hash_builder), - ); OccupiedEntry { - hash: self.hash, - elem, - table: self.table, + inner: self.inner.insert((key, value)), + marker: PhantomData, } } } @@ -6494,7 +6448,7 @@ mod test_map { "panic_in_drop can be set with a type that doesn't need to be dropped", )); } - guard.table.insert( + guard.table.raw.insert( count, ( count, @@ -6664,8 +6618,8 @@ mod test_map { // the returned `RawIter / RawIterRange` iterator. assert_eq!(map.len(), 0); assert_eq!(map.iter().count(), 0); - assert_eq!(unsafe { map.table.iter().count() }, 0); - assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + assert_eq!(unsafe { map.table.raw.iter().count() }, 0); + assert_eq!(unsafe { map.table.raw.iter().iter.count() }, 0); for idx in 0..map.table.num_buckets() { let idx = idx as u64; @@ -6732,8 +6686,8 @@ mod test_map { // the returned `RawIter / RawIterRange` iterator. assert_eq!(map.len(), 0); assert_eq!(map.iter().count(), 0); - assert_eq!(unsafe { map.table.iter().count() }, 0); - assert_eq!(unsafe { map.table.iter().iter.count() }, 0); + assert_eq!(unsafe { map.table.raw.iter().count() }, 0); + assert_eq!(unsafe { map.table.raw.iter().iter.count() }, 0); for idx in 0..map.table.num_buckets() { let idx = idx as u64; diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 235b6141e..0e1664c7f 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -1096,14 +1096,6 @@ impl RawTable { } } - /// Inserts a new element into the table, and returns a mutable reference to it. - /// - /// This does not check if the given element already exists in the table. - #[cfg_attr(feature = "inline-more", inline)] - pub fn insert_entry(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> &mut T { - unsafe { self.insert(hash, value, hasher).as_mut() } - } - /// Inserts a new element into the table, without growing the table. /// /// There must be enough space in the table to insert the new element. diff --git a/src/raw_entry.rs b/src/raw_entry.rs index 20623a83b..72d2de6e6 100644 --- a/src/raw_entry.rs +++ b/src/raw_entry.rs @@ -600,14 +600,14 @@ impl<'a, K, V, S, A: Allocator> RawEntryBuilderMut<'a, K, V, S, A> { where for<'b> F: FnMut(&'b K) -> bool, { - match self.map.table.find(hash, |(k, _)| is_match(k)) { + match self.map.table.raw.find(hash, |(k, _)| is_match(k)) { Some(elem) => RawEntryMut::Occupied(RawOccupiedEntryMut { elem, - table: &mut self.map.table, + table: &mut self.map.table.raw, hash_builder: &self.map.hash_builder, }), None => RawEntryMut::Vacant(RawVacantEntryMut { - table: &mut self.map.table, + table: &mut self.map.table.raw, hash_builder: &self.map.hash_builder, }), } @@ -671,7 +671,7 @@ impl<'a, K, V, S, A: Allocator> RawEntryBuilder<'a, K, V, S, A> { where F: FnMut(&K) -> bool, { - match self.map.table.get(hash, |(k, _)| is_match(k)) { + match self.map.table.raw.get(hash, |(k, _)| is_match(k)) { Some((key, value)) => Some((key, value)), None => None, } @@ -1365,11 +1365,15 @@ impl<'a, K, V, S, A: Allocator> RawVacantEntryMut<'a, K, V, S, A> { K: Hash, S: BuildHasher, { - let &mut (ref mut k, ref mut v) = self.table.insert_entry( - hash, - (key, value), - make_hasher::<_, V, S>(self.hash_builder), - ); + let &mut (ref mut k, ref mut v) = unsafe { + self.table + .insert( + hash, + (key, value), + make_hasher::<_, V, S>(self.hash_builder), + ) + .as_mut() + }; (k, v) } @@ -1420,9 +1424,11 @@ impl<'a, K, V, S, A: Allocator> RawVacantEntryMut<'a, K, V, S, A> { where H: Fn(&K) -> u64, { - let &mut (ref mut k, ref mut v) = self - .table - .insert_entry(hash, (key, value), |x| hasher(&x.0)); + let &mut (ref mut k, ref mut v) = unsafe { + self.table + .insert(hash, (key, value), |x| hasher(&x.0)) + .as_mut() + }; (k, v) } diff --git a/src/rustc_entry.rs b/src/rustc_entry.rs index 233fe7a2d..446bac151 100644 --- a/src/rustc_entry.rs +++ b/src/rustc_entry.rs @@ -33,10 +33,10 @@ where #[cfg_attr(feature = "inline-more", inline)] pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V, A> { let hash = make_hash(&self.hash_builder, &key); - if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { + if let Some(elem) = self.table.raw.find(hash, |q| q.0.eq(&key)) { RustcEntry::Occupied(RustcOccupiedEntry { elem, - table: &mut self.table, + table: &mut self.table.raw, }) } else { // Ideally we would put this in VacantEntry::insert, but Entry is not @@ -47,7 +47,7 @@ where RustcEntry::Vacant(RustcVacantEntry { hash, key, - table: &mut self.table, + table: &mut self.table.raw, }) } } diff --git a/src/set.rs b/src/set.rs index 36fb60a36..c00a12d7c 100644 --- a/src/set.rs +++ b/src/set.rs @@ -5,8 +5,8 @@ use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, use core::{fmt, mem}; use map::make_hash; -use super::map::{self, HashMap, Keys}; -use crate::raw::{Allocator, Global, RawExtractIf}; +use crate::map::{self, HashMap, Keys}; +use crate::raw::{Allocator, Global}; use crate::DefaultHashBuilder; // Future Optimization (FIXME!) @@ -403,14 +403,10 @@ impl HashSet { #[cfg_attr(feature = "inline-more", inline)] pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> where - F: FnMut(&T) -> bool, + F: Filter, { ExtractIf { - f, - inner: RawExtractIf { - iter: unsafe { self.map.table.iter() }, - table: &mut self.map.table, - }, + inner: self.map.extract_if(Key(f)), } } @@ -1139,7 +1135,7 @@ where Ok(bucket) => Some(mem::replace(unsafe { &mut bucket.as_mut().0 }, value)), Err(index) => { unsafe { - self.map.table.insert_at_index(hash, index, (value, ())); + self.map.table.raw.insert_at_index(hash, index, (value, ())); } None } @@ -1663,6 +1659,29 @@ pub struct Drain<'a, K, A: Allocator = Global> { iter: map::Drain<'a, K, (), A>, } +/// Adapter between [`set::Filter`](Filter) and [`map::Filter`]. +struct Key(F); +impl> map::Filter for Key { + #[inline] + fn should_extract(&mut self, key: &T, (): &mut ()) -> bool { + self.0.should_extract(key) + } +} + +/// Filter for [`ExtractIf`]. +/// +/// Accepts `FnMut(&K) -> bool`, but can be implemented directly. +pub trait Filter { + /// Whether the element should be extracted. + fn should_extract(&mut self, key: &K) -> bool; +} +impl bool> Filter for F { + #[inline] + fn should_extract(&mut self, key: &K) -> bool { + (self)(key) + } +} + /// A draining iterator over entries of a `HashSet` which don't satisfy the predicate `f`. /// /// This `struct` is created by the [`extract_if`] method on [`HashSet`]. See its @@ -1672,8 +1691,7 @@ pub struct Drain<'a, K, A: Allocator = Global> { /// [`HashSet`]: struct.HashSet.html #[must_use = "Iterators are lazy unless consumed"] pub struct ExtractIf<'a, K, F, A: Allocator = Global> { - f: F, - inner: RawExtractIf<'a, (K, ()), A>, + inner: map::ExtractIf<'a, K, (), Key, A>, } /// A lazy iterator producing elements in the intersection of `HashSet`s. @@ -1906,20 +1924,18 @@ impl fmt::Debug for Drain<'_, K, A> { impl Iterator for ExtractIf<'_, K, F, A> where - F: FnMut(&K) -> bool, + F: Filter, { type Item = K; #[cfg_attr(feature = "inline-more", inline)] fn next(&mut self) -> Option { - self.inner - .next(|&mut (ref k, ())| (self.f)(k)) - .map(|(k, ())| k) + self.inner.next().map(|(k, ())| k) } #[inline] fn size_hint(&self) -> (usize, Option) { - (0, self.inner.iter.size_hint().1) + self.inner.size_hint() } } diff --git a/src/table.rs b/src/table.rs index a890e29c2..e59afe7c0 100644 --- a/src/table.rs +++ b/src/table.rs @@ -66,6 +66,7 @@ impl HashTable { /// assert_eq!(table.len(), 0); /// assert_eq!(table.capacity(), 0); /// ``` + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] pub const fn new() -> Self { Self { raw: RawTable::new(), @@ -133,6 +134,7 @@ where /// # test() /// # } /// ``` + #[cfg_attr(feature = "rustc-dep-of-std", rustc_const_stable_indirect)] pub const fn new_in(alloc: A) -> Self { Self { raw: RawTable::new_in(alloc), @@ -1379,7 +1381,7 @@ where /// ``` pub fn extract_if(&mut self, f: F) -> ExtractIf<'_, T, F, A> where - F: FnMut(&mut T) -> bool, + F: Filter, { ExtractIf { f, @@ -3155,6 +3157,20 @@ impl fmt::Debug for Drain<'_, T, A> { } } +/// Filter for [`ExtractIf`]. +/// +/// Accepts `FnMut(&mut T) -> bool`, but can be implemented directly. +pub trait Filter { + /// Whether the element should be extracted. + fn should_extract(&mut self, elem: &mut T) -> bool; +} +impl bool> Filter for F { + #[inline] + fn should_extract(&mut self, elem: &mut T) -> bool { + (self)(elem) + } +} + /// A draining iterator over entries of a `HashTable` which don't satisfy the predicate `f`. /// /// This `struct` is created by [`HashTable::extract_if`]. See its @@ -3165,15 +3181,12 @@ pub struct ExtractIf<'a, T, F, A: Allocator = Global> { inner: RawExtractIf<'a, T, A>, } -impl Iterator for ExtractIf<'_, T, F, A> -where - F: FnMut(&mut T) -> bool, -{ +impl, A: Allocator> Iterator for ExtractIf<'_, T, F, A> { type Item = T; #[inline] fn next(&mut self) -> Option { - self.inner.next(|val| (self.f)(val)) + self.inner.next(|val| self.f.should_extract(val)) } #[inline]