diff --git a/src/map.rs b/src/map.rs index 39b890a..20ba3ef 100644 --- a/src/map.rs +++ b/src/map.rs @@ -7,6 +7,7 @@ use std::collections::hash_map::RandomState; use std::fmt; use std::hash::{BuildHasher, Hash}; use std::marker::PhantomData; +use std::mem::ManuallyDrop; /// A concurrent hash table. /// @@ -14,7 +15,14 @@ use std::marker::PhantomData; /// [`HashMap::guard`] or using the [`HashMap::pin`] API. See the [crate-level documentation](crate#usage) /// for details. pub struct HashMap { - raw: raw::HashMap, + raw: ManuallyDrop>, +} + +impl Drop for HashMap { + fn drop(&mut self) { + // Safety: We don't access `self` after taking the inner map. + raw::drop_map(unsafe { ManuallyDrop::take(&mut self.raw) }); + } } // Safety: `HashMap` acts as a single-threaded collection on a single thread. @@ -32,7 +40,7 @@ unsafe impl Send for HashMap {} // Additionally, `HashMap` owns its `seize::Collector` and never exposes it, // so multiple threads cannot be involved in reclamation without sharing the // `HashMap` itself. If this was not true, we would require stricter bounds -// on `HashMap` operations themselves. +// on the `HashMap` operations themselves. unsafe impl Sync for HashMap {} /// A builder for a [`HashMap`]. @@ -131,7 +139,12 @@ impl HashMapBuilder { /// Construct a [`HashMap`] from the builder, using the configured options. pub fn build(self) -> HashMap { HashMap { - raw: raw::HashMap::new(self.capacity, self.hasher, self.collector, self.resize_mode), + raw: ManuallyDrop::new(raw::HashMap::new( + self.capacity, + self.hasher, + self.collector, + self.resize_mode, + )), } } } @@ -298,12 +311,12 @@ impl HashMap { /// ``` pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { HashMap { - raw: raw::HashMap::new( + raw: ManuallyDrop::new(raw::HashMap::new( capacity, hash_builder, Collector::default(), ResizeMode::default(), - ), + )), } } @@ -1006,6 +1019,35 @@ where } } + /// An iterator visiting all key-value pairs in arbitrary order, with mutable references + /// to the values. The iterator element type is `(&K, &mut V)`. + /// + /// # Examples + /// + /// ``` + /// use papaya::HashMap; + /// + /// let mut map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// // Update all values. + /// for (_, val) in map.iter_mut() { + /// *val *= 2; + /// } + /// + /// for (key, val) in map.pin().iter() { + /// println!("key: {key} val: {val}"); + /// } + #[inline] + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + IterMut { + raw: self.raw.iter_mut(), + } + } + /// An iterator visiting all keys in arbitrary order. /// The iterator element type is `&K`. /// @@ -1071,6 +1113,37 @@ where } } +impl IntoIterator for HashMap { + type Item = (K, V); + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// ``` + /// use papaya::HashMap; + /// + /// let map = HashMap::from([ + /// ("a", 1), + /// ("b", 2), + /// ("c", 3), + /// ]); + /// + /// let v: Vec<(&str, i32)> = map.into_iter().collect(); + /// ``` + fn into_iter(self) -> Self::IntoIter { + let mut map = ManuallyDrop::new(self); + + // Safety: We don't access `self` after taking the inner map. + let raw = unsafe { ManuallyDrop::take(&mut map.raw) }; + + IntoIter { + raw: raw.into_iter(), + } + } +} + /// An operation to perform on given entry in a [`HashMap`]. /// /// See [`HashMap::compute`] for details. @@ -1165,7 +1238,8 @@ where S: BuildHasher, { fn extend>(&mut self, iter: T) { - // from `hashbrown::HashMap::extend`: + // From `hashbrown::HashMap::extend`: + // // Keys may be already present or show multiple times in the iterator. // Reserve the entire hint lower bound if the map is empty. // Otherwise reserve half the hint (rounded up), so the map @@ -1572,7 +1646,7 @@ where } } -/// An iterator over a map's entries. +/// An iterator over the entries of a `HashMap`. /// /// This struct is created by the [`iter`](HashMap::iter) method on [`HashMap`]. See its documentation for details. pub struct Iter<'g, K, V, G> { @@ -1591,6 +1665,14 @@ where } } +impl Clone for Iter<'_, K, V, G> { + fn clone(&self) -> Self { + Self { + raw: self.raw.clone(), + } + } +} + impl fmt::Debug for Iter<'_, K, V, G> where K: fmt::Debug, @@ -1598,11 +1680,33 @@ where G: Guard, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list() - .entries(Iter { - raw: self.raw.clone(), - }) - .finish() + f.debug_list().entries(self.raw.clone()).finish() + } +} + +/// A mutable iterator over the entries of a `HashMap`. +/// +/// This struct is created by the [`iter_mut`](HashMap::iter_mut) method on [`HashMap`]. See its documentation for details. +pub struct IterMut<'map, K, V> { + raw: raw::IterMut<'map, K, V>, +} + +impl<'map, K, V> Iterator for IterMut<'map, K, V> { + type Item = (&'map K, &'map mut V); + + #[inline] + fn next(&mut self) -> Option { + self.raw.next() + } +} + +impl fmt::Debug for IterMut<'_, K, V> +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.raw.iter()).finish() } } @@ -1667,3 +1771,32 @@ where f.debug_tuple("Values").field(&self.iter).finish() } } + +/// An owned iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashMap`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// +/// [`into_iter`]: IntoIterator::into_iter +pub struct IntoIter { + pub(crate) raw: raw::IntoIter, +} + +impl Iterator for IntoIter { + type Item = (K, V); + + #[inline] + fn next(&mut self) -> Option { + self.raw.next() + } +} + +impl fmt::Debug for IntoIter +where + K: fmt::Debug, + V: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.raw.iter()).finish() + } +} diff --git a/src/raw/alloc.rs b/src/raw/alloc.rs index 3c5792f..b78f5ea 100644 --- a/src/raw/alloc.rs +++ b/src/raw/alloc.rs @@ -157,6 +157,25 @@ impl Table { } } + // Returns the entry at the given index. + // + // # Safety + // + // The index must be in-bounds for the length of the table. + #[inline] + pub unsafe fn entry_mut(&mut self, i: usize) -> *mut T { + debug_assert!(i < self.len()); + + // Safety: The caller guarantees the index is in-bounds. + let entry = unsafe { + let meta = self.raw.add(mem::size_of::>()); + let entries = meta.add(self.len()).cast::>(); + &mut *entries.add(i) + }; + + *entry.get_mut() + } + /// Returns the length of the table. #[inline] pub fn len(&self) -> usize { diff --git a/src/raw/mod.rs b/src/raw/mod.rs index a2369a7..fadfb99 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -4,7 +4,8 @@ mod probe; pub(crate) mod utils; use std::hash::{BuildHasher, Hash}; -use std::mem::MaybeUninit; +use std::marker::PhantomData; +use std::mem::{ManuallyDrop, MaybeUninit}; use std::sync::atomic::{AtomicPtr, AtomicU8, AtomicUsize, Ordering}; use std::sync::Mutex; use std::{hint, panic, ptr}; @@ -1227,13 +1228,41 @@ where i: 0, guard, table: root, + _entries: PhantomData, }; } // Get a clean copy of the table to iterate over. let table = self.linearize(root, guard); - Iter { i: 0, guard, table } + Iter { + i: 0, + guard, + table, + _entries: PhantomData, + } + } + + /// Returns a mutable iterator over the keys and values of this table. + #[inline] + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { + // Safety: The root table is either null or a valid table allocation. + let table = unsafe { Table::from_raw(*self.table.get_mut()) }; + + // The table has not been initialized yet, return a dummy iterator. + if table.raw.is_null() { + return IterMut { + i: 0, + table, + _entries: PhantomData, + }; + } + + IterMut { + i: 0, + table, + _entries: PhantomData, + } } /// Returns the h1 and h2 hash for the given key. @@ -1247,6 +1276,42 @@ where } } +impl IntoIterator for HashMap { + type Item = (K, V); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + let mut map = ManuallyDrop::new(HashMap { + table: self.table, + collector: self.collector, + resize: self.resize, + count: self.count, + initial_capacity: self.initial_capacity, + hasher: (), + }); + + // Safety: The root table is either null or a valid table allocation. + let table = unsafe { Table::from_raw(*map.table.get_mut()) }; + + // The table has not been initialized yet, return a dummy iterator. + if table.raw.is_null() { + return IntoIter { + i: 0, + map, + table, + _entries: PhantomData, + }; + } + + IntoIter { + i: 0, + map, + table, + _entries: PhantomData, + } + } +} + /// A wrapper around a CAS function that manages the computed state. struct ComputeState { /// The CAS function. @@ -2632,6 +2697,7 @@ pub struct Iter<'g, K, V, G> { i: usize, table: Table>, guard: &'g G, + _entries: PhantomData<(&'g K, &'g V)>, } impl<'g, K: 'g, V: 'g, G> Iterator for Iter<'g, K, V, G> @@ -2689,8 +2755,8 @@ where } } -// Safety: An iterator holds a shared reference to the HashMap -// and Guard, and outputs shared references to keys and values. +// Safety: An iterator holds a shared reference to the `HashMap` +// and `Guard`, and outputs shared references to keys and values. // Thus everything must be `Sync` for the iterator to be `Send` // or `Sync`. // @@ -2719,52 +2785,278 @@ impl Clone for Iter<'_, K, V, G> { i: self.i, table: self.table, guard: self.guard, + _entries: PhantomData, } } } -impl Drop for HashMap { - fn drop(&mut self) { - let mut raw = *self.table.get_mut(); +// A mutable iterator over the keys and values of this table. +pub struct IterMut<'map, K, V> { + i: usize, + table: Table>, + // Ensure invariance with respect to `V`. + _entries: PhantomData<(&'map K, &'map mut V)>, +} - // Make sure all objects are reclaimed before the collector is dropped. - // - // Dropping a table depends on accessing the collector for deferred retirement, - // using the shared collector pointer that is invalidated by drop. - // - // Safety: We have a unique reference to the collector. - unsafe { self.collector.reclaim_all() }; +impl<'map, K, V> Iterator for IterMut<'map, K, V> { + type Item = (&'map K, &'map mut V); + + #[inline] + fn next(&mut self) -> Option { + self.next_raw().map(|entry| { + // Safety: We have `&mut self`, and `IterMut::next_raw` is guaranteed to only yield non-null entries. + let entry_ref = unsafe { &mut *entry }; + (&entry_ref.key, &mut entry_ref.value) + }) + } +} + +impl<'map, K, V> IterMut<'map, K, V> { + // Note that this method is guaranteed to only yield entry pointers that are valid for reads + // and writes. + #[inline] + fn next_raw(&mut self) -> Option<*mut Entry> { + // The table has not yet been allocated. + if self.table.raw.is_null() { + return None; + } + + loop { + // Iterated over every entry in the table, proceed to a nested resize if there is one. + if self.i >= self.table.len() { + if let Some(next_table) = self.table.next_table() { + self.i = 0; + self.table = next_table; + continue; + } + + // Otherwise, we're done. + return None; + } + + // Load the entry. + // + // Safety: We verified that `self.i` is in-bounds above. + let entry = unsafe { self.table.entry_mut(self.i) }.unpack(); + + // The entry was deleted. + if entry.ptr.is_null() { + self.i += 1; + continue; + } + + // The entry was copied, we'll yield it when iterating over the table it was copied to. + // + // We have a mutable reference to the table, so there are no concurrent removals that + // can lead to us yielding duplicate entries. + if entry.tag() & Entry::COPIED != 0 { + self.i += 1; + continue; + } + + self.i += 1; + + // Safety: We ensured the entry is non-null. + return Some(entry.ptr); + } + } + + // Returns an immutable iterator over the remaining entries. + pub(crate) fn iter(&self) -> impl Iterator + '_ { + let mut iter = IterMut { + i: self.i, + table: self.table, + _entries: PhantomData, + }; + + std::iter::from_fn(move || { + iter.next_raw().map(|entry| { + // Safety: `IterMut::next_raw` is guaranteed to only yield non-null entries. + let entry_ref = unsafe { &*entry }; + (&entry_ref.key, &entry_ref.value) + }) + }) + } +} - // Drop all nested tables and entries. - while !raw.is_null() { - // Safety: The root and next tables are always valid pointers to a - // table allocation, or null. - let mut table = unsafe { Table::from_raw(raw) }; +// Safety: A mutable iterator does not perform any concurrent access, +// so the normal `Send` and `Sync` rules apply. +unsafe impl Send for IterMut<'_, K, V> +where + K: Send, + V: Send, +{ +} - // Read the next table pointer before dropping the current one. - let next = *table.state_mut().next.get_mut(); +unsafe impl Sync for IterMut<'_, K, V> +where + K: Sync, + V: Sync, +{ +} + +// An owned iterator over the keys and values of this table. +pub struct IntoIter { + i: usize, + table: Table>, + map: ManuallyDrop>, + _entries: PhantomData<(K, V)>, +} + +impl Iterator for IntoIter { + type Item = (K, V); + + #[inline] + fn next(&mut self) -> Option { + // The table has not yet been allocated. + if self.table.raw.is_null() { + return None; + } + + loop { + // Iterated over every entry in the table, proceed to a nested resize if there is one. + if self.i >= self.table.len() { + if let Some(next_table) = self.table.next_table() { + // Drop the previous table. + // + // Safety: We have unique access to the table and do + // not access it after this call. + unsafe { drop_table(self.table, &self.map.collector) }; + + // Reset the iterator for the next table. + self.i = 0; + self.table = next_table; + continue; + } + + // Otherwise, we're done. + return None; + } + + // Load the entry. + // + // Safety: We verified that `self.i` is in-bounds above. + let entry = unsafe { self.table.entry_mut(self.i) }.unpack(); + + // The entry was deleted. + if entry.ptr.is_null() { + self.i += 1; + continue; + } - // Safety: We have unique access to the table and do - // not access the entries after this call. - unsafe { drop_entries(table) }; + // The entry was copied, we'll yield it when iterating over the table it was copied to. + // + // We own the table, so there are no concurrent removals that can lead to us yielding + // duplicate entries. + if entry.tag() & Entry::COPIED != 0 { + self.i += 1; + continue; + } - // Safety: We have unique access to the table and do - // not access it after this call. - unsafe { drop_table(table, &self.collector) }; + // Safety: We ensured the entry is non-null. Additionally, we own the map + // and ensure not to drop already yielded entries. + let entry = unsafe { ptr::read(entry.ptr) }; - // Continue for all nested tables. - raw = next; + self.i += 1; + return Some((entry.key, entry.value)); } } } +impl IntoIter { + // Returns an immutable iterator over the remaining entries. + pub(crate) fn iter(&self) -> impl Iterator + '_ { + let mut iter = IterMut { + i: self.i, + table: self.table, + _entries: PhantomData, + }; + + std::iter::from_fn(move || { + iter.next_raw().map(|entry| { + // Safety: `IterMut::next_raw` is guaranteed to only yield non-null entries. + let entry_ref = unsafe { &*entry }; + (&entry_ref.key, &entry_ref.value) + }) + }) + } +} + +impl Drop for IntoIter { + fn drop(&mut self) { + // Drop the remaining elements that have not been yielded. + drop_parts(self.i, self.table.raw, &mut self.map.collector); + } +} + +// Safety: An owned iterator does not perform any concurrent access, +// so the normal `Send` and `Sync` rules apply. +unsafe impl Send for IntoIter +where + K: Send, + V: Send, +{ +} + +unsafe impl Sync for IntoIter +where + K: Sync, + V: Sync, +{ +} + +// Drop the `HashMap`. +// +// `HashMap` doesn't implement `Drop` due to the need for destructuring into +// an `IntoIter`, so this method is used instead. +pub fn drop_map(mut map: HashMap) { + drop_parts(0, *map.table.get_mut(), &mut map.collector); +} + +// Drop the elements of a `HashMap`. +fn drop_parts( + mut start: usize, + mut raw: *mut RawTable>, + collector: &mut Collector, +) { + // Make sure all objects are reclaimed before the collector is dropped. + // + // Dropping a table depends on accessing the collector for deferred retirement, + // using the shared collector pointer that is invalidated by drop. + // + // Safety: We have a unique reference to the collector. + unsafe { collector.reclaim_all() }; + + // Drop all nested tables and entries. + while !raw.is_null() { + // Safety: The root and next tables are always valid pointers to a + // table allocation, or null. + let mut table = unsafe { Table::from_raw(raw) }; + + // Read the next table pointer before dropping the current one. + let next = *table.state_mut().next.get_mut(); + + // Safety: We have unique access to the table and do + // not access the entries after this call. + unsafe { drop_entries(start, table) }; + + // Safety: We have unique access to the table and do + // not access it after this call. + unsafe { drop_table(table, collector) }; + + // Continue for all nested tables. + raw = next; + start = 0; + } +} + // Drop all entries in this table. // // # Safety // // The table entries must not be accessed after this call. -unsafe fn drop_entries(table: Table>) { - for i in 0..table.len() { +unsafe fn drop_entries(start: usize, table: Table>) { + for i in start..table.len() { // Safety: `i` is in-bounds and we have unique access to the table. let entry = unsafe { (*table.entry(i).as_ptr()).unpack() }; diff --git a/src/set.rs b/src/set.rs index f8f110c..d59a5fb 100644 --- a/src/set.rs +++ b/src/set.rs @@ -1,9 +1,7 @@ -use crate::raw::utils::MapGuard; -use crate::raw::{self, InsertResult}; -use crate::Equivalent; +use crate::{Equivalent, HashMap, HashMapRef}; use seize::{Collector, Guard, LocalGuard, OwnedGuard}; -use crate::map::ResizeMode; +use crate::map::{self, ResizeMode}; use std::collections::hash_map::RandomState; use std::fmt; use std::hash::{BuildHasher, Hash}; @@ -15,7 +13,7 @@ use std::marker::PhantomData; /// [`HashSet::guard`] or using the [`HashSet::pin`] API. See the [crate-level documentation](crate#usage) /// for details. pub struct HashSet { - raw: raw::HashMap, + map: HashMap, } // Safety: We only ever hand out &K through shared references to the map, @@ -120,7 +118,12 @@ impl HashSetBuilder { /// Construct a [`HashSet`] from the builder, using the configured options. pub fn build(self) -> HashSet { HashSet { - raw: raw::HashMap::new(self.capacity, self.hasher, self.collector, self.resize_mode), + map: HashMap::builder() + .capacity(self.capacity) + .hasher(self.hasher) + .collector(self.collector) + .resize_mode(self.resize_mode) + .build(), } } } @@ -244,12 +247,7 @@ impl HashSet { /// ``` pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashSet { HashSet { - raw: raw::HashMap::new( - capacity, - hash_builder, - Collector::default(), - ResizeMode::default(), - ), + map: HashMap::with_capacity_and_hasher(capacity, hash_builder), } } @@ -260,8 +258,8 @@ impl HashSet { #[inline] pub fn pin(&self) -> HashSetRef<'_, K, S, LocalGuard<'_>> { HashSetRef { - guard: self.raw.guard(), set: self, + map_ref: self.map.pin(), } } @@ -276,8 +274,8 @@ impl HashSet { #[inline] pub fn pin_owned(&self) -> HashSetRef<'_, K, S, OwnedGuard<'_>> { HashSetRef { - guard: self.raw.owned_guard(), set: self, + map_ref: self.map.pin_owned(), } } @@ -287,7 +285,7 @@ impl HashSet { /// See the [crate-level documentation](crate#usage) for details. #[inline] pub fn guard(&self) -> LocalGuard<'_> { - self.raw.collector().enter() + self.map.guard() } /// Returns an owned guard for use with this set. @@ -300,7 +298,7 @@ impl HashSet { /// See the [crate-level documentation](crate#usage) for details. #[inline] pub fn owned_guard(&self) -> OwnedGuard<'_> { - self.raw.collector().enter_owned() + self.map.owned_guard() } } @@ -324,7 +322,7 @@ where /// ``` #[inline] pub fn len(&self) -> usize { - self.raw.len() + self.map.len() } /// Returns `true` if the set is empty. Otherwise returns `false`. @@ -369,7 +367,7 @@ where where Q: Equivalent + Hash + ?Sized, { - self.get(key, self.raw.verify(guard)).is_some() + self.map.get(key, guard).is_some() } /// Returns a reference to the value corresponding to the key. @@ -396,7 +394,7 @@ where where Q: Equivalent + Hash + ?Sized, { - match self.raw.get(key, self.raw.verify(guard)) { + match self.map.get_key_value(key, guard) { Some((key, _)) => Some(key), None => None, } @@ -427,15 +425,10 @@ where /// ``` #[inline] pub fn insert(&self, key: K, guard: &impl Guard) -> bool { - match self.raw.insert(key, (), true, self.raw.verify(guard)) { - InsertResult::Inserted(_) => true, - InsertResult::Replaced(_) => false, - InsertResult::Error { .. } => unreachable!(), - } + self.map.insert(key, (), guard).is_none() } - /// Removes a key from the set, returning the value at the key if the key - /// was previously in the set. + /// Removes a value from the set. Returns whether the value was present in the set. /// /// The key may be any borrowed form of the set's key type, but /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for @@ -456,10 +449,7 @@ where where Q: Equivalent + Hash + ?Sized, { - match self.raw.remove(key, self.raw.verify(guard)) { - Some((_, _)) => true, - None => false, - } + self.map.remove(key, guard).is_some() } /// Tries to reserve capacity for `additional` more elements to be inserted @@ -484,7 +474,7 @@ where /// ``` #[inline] pub fn reserve(&self, additional: usize, guard: &impl Guard) { - self.raw.reserve(additional, self.raw.verify(guard)) + self.map.reserve(additional, guard) } /// Clears the set, removing all values. @@ -506,7 +496,7 @@ where /// ``` #[inline] pub fn clear(&self, guard: &impl Guard) { - self.raw.clear(self.raw.verify(guard)) + self.map.clear(guard) } /// Retains only the elements specified by the predicate. @@ -537,7 +527,7 @@ where where F: FnMut(&K) -> bool, { - self.raw.retain(|k, _| f(k), self.raw.verify(guard)) + self.map.retain(|k, _| f(k), guard) } /// An iterator visiting all values in arbitrary order. @@ -566,7 +556,35 @@ where G: Guard, { Iter { - raw: self.raw.iter(self.raw.verify(guard)), + inner: self.map.iter(guard), + } + } +} + +impl IntoIterator for HashSet { + type Item = K; + type IntoIter = IntoIter; + + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Examples + /// + /// ``` + /// use papaya::HashSet; + /// + /// let set = HashSet::from([ + /// "a", + /// "b", + /// "c" + /// ]); + /// + /// let v: Vec<&str> = set.into_iter().collect(); + /// ``` + fn into_iter(self) -> Self::IntoIter { + IntoIter { + inner: self.map.into_iter(), } } } @@ -577,14 +595,7 @@ where S: BuildHasher, { fn eq(&self, other: &Self) -> bool { - if self.len() != other.len() { - return false; - } - - let (guard1, guard2) = (&self.guard(), &other.guard()); - - let mut iter = self.iter(guard1); - iter.all(|key| other.get(key, guard2).is_some()) + self.map.eq(&other.map) } } @@ -612,24 +623,8 @@ where S: BuildHasher, { fn extend>(&mut self, iter: T) { - // from `hashbrown::HashSet::extend`: - // Keys may be already present or show multiple times in the iterator. - // Reserve the entire hint lower bound if the set is empty. - // Otherwise reserve half the hint (rounded up), so the set - // will only resize twice in the worst case. - let iter = iter.into_iter(); - let reserve = if self.is_empty() { - iter.size_hint().0 - } else { - (iter.size_hint().0 + 1) / 2 - }; - - let guard = self.guard(); - self.reserve(reserve, &guard); - - for key in iter { - self.insert(key, &guard); - } + let mut map = &self.map; + map.extend(iter.into_iter().map(|key| (key, ()))); } } @@ -658,27 +653,8 @@ where S: BuildHasher + Default, { fn from_iter>(iter: T) -> Self { - let mut iter = iter.into_iter(); - - if let Some(key) = iter.next() { - let (lower, _) = iter.size_hint(); - let set = HashSet::with_capacity_and_hasher(lower.saturating_add(1), S::default()); - - // Ideally we could use an unprotected guard here. However, `insert` - // returns references to values that were replaced and retired, so - // we need a "real" guard. A `raw_insert` method that strictly returns - // pointers would fix this. - { - let set = set.pin(); - set.insert(key); - for key in iter { - set.insert(key); - } - } - - set - } else { - Self::default() + HashSet { + map: HashMap::from_iter(iter.into_iter().map(|key| (key, ()))), } } } @@ -689,20 +665,9 @@ where S: BuildHasher + Clone, { fn clone(&self) -> HashSet { - let other = HashSet::builder() - .capacity(self.len()) - .hasher(self.raw.hasher.clone()) - .collector(seize::Collector::new()) - .build(); - - { - let (guard1, guard2) = (&self.guard(), &other.guard()); - for key in self.iter(guard1) { - other.insert(key.clone(), guard2); - } + HashSet { + map: self.map.clone(), } - - other } } @@ -711,8 +676,8 @@ where /// This type is created with [`HashSet::pin`] and can be used to easily access a [`HashSet`] /// without explicitly managing a guard. See the [crate-level documentation](crate#usage) for details. pub struct HashSetRef<'set, K, S, G> { - guard: MapGuard, set: &'set HashSet, + map_ref: HashMapRef<'set, K, (), S, G>, } impl<'set, K, S, G> HashSetRef<'set, K, S, G> @@ -732,7 +697,7 @@ where /// See [`HashSet::len`] for details. #[inline] pub fn len(&self) -> usize { - self.set.raw.len() + self.map_ref.len() } /// Returns `true` if the set is empty. Otherwise returns `false`. @@ -740,7 +705,7 @@ where /// See [`HashSet::is_empty`] for details. #[inline] pub fn is_empty(&self) -> bool { - self.len() == 0 + self.map_ref.is_empty() } /// Returns `true` if the set contains a value for the specified key. @@ -751,7 +716,7 @@ where where Q: Equivalent + Hash + ?Sized, { - self.get(key).is_some() + self.map_ref.get(key).is_some() } /// Returns a reference to the value corresponding to the key. @@ -762,7 +727,7 @@ where where Q: Equivalent + Hash + ?Sized, { - match self.set.raw.get(key, &self.guard) { + match self.map_ref.get_key_value(key) { Some((k, _)) => Some(k), None => None, } @@ -773,11 +738,7 @@ where /// See [`HashSet::insert`] for details. #[inline] pub fn insert(&self, key: K) -> bool { - match self.set.raw.insert(key, (), true, &self.guard) { - InsertResult::Inserted(_) => true, - InsertResult::Replaced(_) => false, - InsertResult::Error { .. } => unreachable!(), - } + self.map_ref.insert(key, ()).is_none() } /// Removes a key from the set, returning the value at the key if the key @@ -789,10 +750,7 @@ where where Q: Equivalent + Hash + ?Sized, { - match self.set.raw.remove(key, &self.guard) { - Some((_, _)) => true, - None => false, - } + self.map_ref.remove(key).is_some() } /// Clears the set, removing all values. @@ -800,7 +758,7 @@ where /// See [`HashSet::clear`] for details. #[inline] pub fn clear(&self) { - self.set.raw.clear(&self.guard) + self.map_ref.clear() } /// Retains only the elements specified by the predicate. @@ -811,7 +769,7 @@ where where F: FnMut(&K) -> bool, { - self.set.raw.retain(|k, _| f(k), &self.guard) + self.map_ref.retain(|k, _| f(k)) } /// Tries to reserve capacity for `additional` more elements to be inserted @@ -820,7 +778,7 @@ where /// See [`HashSet::reserve`] for details. #[inline] pub fn reserve(&self, additional: usize) { - self.set.raw.reserve(additional, &self.guard) + self.map_ref.reserve(additional) } /// An iterator visiting all values in arbitrary order. @@ -830,7 +788,7 @@ where #[inline] pub fn iter(&self) -> Iter<'_, K, G> { Iter { - raw: self.set.raw.iter(&self.guard), + inner: self.map_ref.iter(), } } } @@ -864,7 +822,7 @@ where /// /// This struct is created by the [`iter`](HashSet::iter) method on [`HashSet`]. See its documentation for details. pub struct Iter<'g, K, G> { - raw: raw::Iter<'g, K, (), MapGuard>, + inner: map::Iter<'g, K, (), G>, } impl<'g, K: 'g, G> Iterator for Iter<'g, K, G> @@ -875,7 +833,15 @@ where #[inline] fn next(&mut self) -> Option { - self.raw.next().map(|(k, _)| k) + self.inner.next().map(|(k, _)| k) + } +} + +impl Clone for Iter<'_, K, G> { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } } } @@ -885,10 +851,34 @@ where G: Guard, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list() - .entries(Iter { - raw: self.raw.clone(), - }) - .finish() + f.debug_list().entries(self.clone()).finish() + } +} + +/// An owned iterator over the entries of a `HashSet`. +/// +/// This `struct` is created by the [`into_iter`] method on [`HashSet`] +/// (provided by the [`IntoIterator`] trait). See its documentation for more. +/// +/// [`into_iter`]: IntoIterator::into_iter +pub struct IntoIter { + inner: map::IntoIter, +} + +impl Iterator for IntoIter { + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(k, _)| k) + } +} + +impl fmt::Debug for IntoIter +where + K: fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.raw.iter()).finish() } } diff --git a/tests/basic.rs b/tests/basic.rs index 5e48414..9922c08 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -802,6 +802,57 @@ fn iter() { }); } +#[test] +fn iter_mut() { + if cfg!(papaya_stress) { + return; + } + + with_map::(|map| { + let mut map = map(); + let len = if cfg!(miri) { 100 } else { 10_000 }; + for i in 0..len { + assert_eq!(map.pin().insert(i, i + 1), None); + } + + let v: Vec<_> = (0..len).map(|i| (i, i + 1)).collect(); + let mut got: Vec<_> = map.iter_mut().map(|(&k, &mut v)| (k, v)).collect(); + got.sort(); + assert_eq!(v, got); + }); +} + +#[test] +fn into_iter() { + if cfg!(papaya_stress) { + return; + } + + with_map::(|map| { + let map = map(); + let len = if cfg!(miri) { 100 } else { 10_000 }; + for i in 0..len { + assert_eq!(map.pin().insert(i, (i + 1).to_string()), None); + } + + let v: Vec<_> = (0..len).map(|i| (i, (i + 1).to_string())).collect(); + let mut got: Vec<_> = map.into_iter().collect(); + got.sort(); + assert_eq!(v, got); + }); + + with_map::(|map| { + let map = map(); + let len = if cfg!(miri) { 100 } else { 10_000 }; + for i in 0..len { + assert_eq!(map.pin().insert(i, (i + 1).to_string()), None); + } + + let got: Vec<_> = map.into_iter().take(len / 2).collect(); + assert_eq!(got.len(), len / 2); + }); +} + #[test] fn retain_empty() { with_map::(|map| { diff --git a/tests/stress.rs b/tests/stress.rs index 4cff28d..446bc49 100644 --- a/tests/stress.rs +++ b/tests/stress.rs @@ -107,7 +107,7 @@ fn insert_overwrite_stress() { let entries = || { let mut entries = (0..(OPERATIONS)) - .flat_map(|_| (0..ENTRIES)) + .flat_map(|_| 0..ENTRIES) .collect::>(); let mut rng = rand::thread_rng(); entries.shuffle(&mut rng); @@ -188,7 +188,7 @@ fn update_stress() { let entries = || { let mut entries = (0..(OPERATIONS)) - .flat_map(|_| (0..ENTRIES)) + .flat_map(|_| 0..ENTRIES) .collect::>(); let mut rng = rand::thread_rng(); entries.shuffle(&mut rng); @@ -307,7 +307,7 @@ fn update_or_insert_stress() { let threads = threads(); let entries = (0..(threads * OPERATIONS)) - .flat_map(|_| (0..ENTRIES)) + .flat_map(|_| 0..ENTRIES) .collect::>(); let chunk = ENTRIES * OPERATIONS; @@ -364,7 +364,7 @@ fn remove_update_or_insert_stress() { let entries = || { let mut entries = (0..(OPERATIONS)) - .flat_map(|_| (0..ENTRIES)) + .flat_map(|_| 0..ENTRIES) .collect::>(); let mut rng = rand::thread_rng(); entries.shuffle(&mut rng); @@ -445,7 +445,7 @@ fn conditional_remove_update_or_insert_stress() { let entries = || { let mut entries = (0..(OPERATIONS)) - .flat_map(|_| (0..ENTRIES)) + .flat_map(|_| 0..ENTRIES) .collect::>(); let mut rng = rand::thread_rng(); entries.shuffle(&mut rng); @@ -528,7 +528,7 @@ fn remove_if_update_or_insert_stress() { let entries = || { let mut entries = (0..(OPERATIONS)) - .flat_map(|_| (0..ENTRIES)) + .flat_map(|_| 0..ENTRIES) .collect::>(); let mut rng = rand::thread_rng(); entries.shuffle(&mut rng); @@ -606,7 +606,7 @@ fn insert_remove_stress() { let entries = || { let mut entries = (0..(OPERATIONS)) - .flat_map(|_| (0..ENTRIES)) + .flat_map(|_| 0..ENTRIES) .collect::>(); let mut rng = rand::thread_rng(); entries.shuffle(&mut rng);