From 4f1cfb0afdac18e6ece8c74f38e5e78e1c68ee17 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 14 Feb 2019 21:40:42 +0100 Subject: [PATCH] Prepare hashbrown for inclusion in the standard library --- Cargo.toml | 9 +- src/fx.rs | 22 +- src/lib.rs | 9 +- src/map.rs | 485 +++++++++++++++++------------------ src/raw/mod.rs | 21 +- src/raw/scopeguard.rs | 49 ++++ src/rustc_entry.rs | 575 ++++++++++++++++++++++++++++++++++++++++++ src/set.rs | 240 +++++++++--------- 8 files changed, 1019 insertions(+), 391 deletions(-) create mode 100644 src/raw/scopeguard.rs create mode 100644 src/rustc_entry.rs diff --git a/Cargo.toml b/Cargo.toml index 2d48ea409b..a0d9a811ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,13 +10,15 @@ keywords = ["hash", "no_std", "hashmap", "swisstable"] categories = ["data-structures", "no-std"] [dependencies] -byteorder = { version = "1.0", default-features = false } -scopeguard = { version = "0.3", default-features = false } - # For external trait impls rayon = { version = "1.0", optional = true } serde = { version = "1.0", default-features = false, optional = true } +# When built as part of libstd +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +compiler_builtins = { version = "0.1.2", optional = true } +alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" } + [dev-dependencies] lazy_static = "~1.2" rand = "0.5.1" @@ -26,3 +28,4 @@ serde_test = "1.0" [features] nightly = [] +rustc-dep-of-std = ["nightly", "core", "compiler_builtins", "alloc"] diff --git a/src/fx.rs b/src/fx.rs index f45399fdc6..6960eb6c21 100644 --- a/src/fx.rs +++ b/src/fx.rs @@ -5,8 +5,6 @@ use core::hash::{BuildHasherDefault, Hasher}; use core::mem::size_of; use core::ops::BitXor; -use byteorder::{ByteOrder, NativeEndian}; - /// Type alias for a `HashBuilder` using the `fx` hash algorithm. pub type FxHashBuilder = BuildHasherDefault; @@ -47,23 +45,29 @@ impl FxHasher { impl Hasher for FxHasher { #[inline] fn write(&mut self, mut bytes: &[u8]) { - #[cfg(target_pointer_width = "32")] - let read_usize = |bytes| NativeEndian::read_u32(bytes); - #[cfg(target_pointer_width = "64")] - let read_usize = |bytes| NativeEndian::read_u64(bytes); + macro_rules! read_bytes { + ($ty:ty, $src:expr) => {{ + assert!(size_of::<$ty>() <= $src.len()); + let mut data: $ty = 0; + unsafe { + $src.as_ptr().copy_to_nonoverlapping(&mut data as *mut $ty as *mut u8, size_of::<$ty>()); + } + data + }}; + } let mut hash = FxHasher { hash: self.hash }; assert!(size_of::() <= 8); while bytes.len() >= size_of::() { - hash.add_to_hash(read_usize(bytes) as usize); + hash.add_to_hash(read_bytes!(usize, bytes) as usize); bytes = &bytes[size_of::()..]; } if (size_of::() > 4) && (bytes.len() >= 4) { - hash.add_to_hash(NativeEndian::read_u32(bytes) as usize); + hash.add_to_hash(read_bytes!(u32, bytes) as usize); bytes = &bytes[4..]; } if (size_of::() > 2) && bytes.len() >= 2 { - hash.add_to_hash(NativeEndian::read_u16(bytes) as usize); + hash.add_to_hash(read_bytes!(u16, bytes) as usize); bytes = &bytes[2..]; } if (size_of::() > 1) && bytes.len() >= 1 { diff --git a/src/lib.rs b/src/lib.rs index ad66fe0bcf..bae9504e85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ #![warn(missing_docs)] #[cfg(test)] -#[macro_use] +#[cfg_attr(feature = "rayon", macro_use)] extern crate std; #[cfg(test)] extern crate rand; @@ -33,10 +33,8 @@ extern crate rand; #[cfg(feature = "nightly")] #[cfg_attr(test, macro_use)] extern crate alloc; -extern crate byteorder; #[cfg(feature = "rayon")] extern crate rayon; -extern crate scopeguard; #[cfg(feature = "serde")] extern crate serde; #[cfg(not(feature = "nightly"))] @@ -48,11 +46,16 @@ mod fx; mod map; mod raw; mod set; +#[cfg(feature = "rustc-dep-of-std")] +mod rustc_entry; pub mod hash_map { //! A hash map implemented with quadratic probing and SIMD lookup. pub use map::*; + #[cfg(feature = "rustc-dep-of-std")] + pub use rustc_entry::*; + #[cfg(feature = "rayon")] /// [rayon]-based parallel iterator types for hash maps. /// You will rarely need to interact with it directly unless you have need diff --git a/src/map.rs b/src/map.rs index d151e37cb7..661e19b085 100644 --- a/src/map.rs +++ b/src/map.rs @@ -152,7 +152,7 @@ pub use fx::FxHashBuilder as DefaultHashBuilder; /// } /// /// impl Viking { -/// /// Create a new Viking. +/// /// Creates a new Viking. /// fn new(name: &str, country: &str) -> Viking { /// Viking { name: name.to_string(), country: country.to_string() } /// } @@ -188,12 +188,12 @@ pub use fx::FxHashBuilder as DefaultHashBuilder; #[derive(Clone)] pub struct HashMap { - hash_builder: S, + pub(crate) hash_builder: S, pub(crate) table: RawTable<(K, V)>, } #[inline] -fn make_hash(hash_builder: &impl BuildHasher, val: &K) -> u64 { +pub(crate) fn make_hash(hash_builder: &impl BuildHasher, val: &K) -> u64 { let mut state = hash_builder.build_hasher(); val.hash(&mut state); state.finish() @@ -233,87 +233,7 @@ impl HashMap { } } -impl HashMap -where - K: Eq + Hash, - S: BuildHasher, -{ - /// Creates an empty `HashMap` which will use the given hash builder to hash - /// keys. - /// - /// The created map has the default initial capacity. - /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashMap; - /// use hashbrown::hash_map::DefaultHashBuilder; - /// - /// let s = DefaultHashBuilder::default(); - /// let mut map = HashMap::with_hasher(s); - /// map.insert(1, 2); - /// ``` - #[inline] - pub fn with_hasher(hash_builder: S) -> HashMap { - HashMap { - hash_builder, - table: RawTable::new(), - } - } - - /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` - /// to hash the keys. - /// - /// The hash map will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash map will not allocate. - /// - /// Warning: `hash_builder` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashMap; - /// use hashbrown::hash_map::DefaultHashBuilder; - /// - /// let s = DefaultHashBuilder::default(); - /// let mut map = HashMap::with_capacity_and_hasher(10, s); - /// map.insert(1, 2); - /// ``` - #[inline] - pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { - HashMap { - hash_builder, - table: RawTable::with_capacity(capacity), - } - } - - /// Returns a reference to the map's [`BuildHasher`]. - /// - /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashMap; - /// use hashbrown::hash_map::DefaultHashBuilder; - /// - /// let hasher = DefaultHashBuilder::default(); - /// let map: HashMap = HashMap::with_hasher(hasher); - /// let hasher: &DefaultHashBuilder = map.hasher(); - /// ``` - #[inline] - pub fn hasher(&self) -> &S { - &self.hash_builder - } - +impl HashMap { /// Returns the number of elements the map can hold without reallocating. /// /// This number is a lower bound; the `HashMap` might be able to hold @@ -331,108 +251,6 @@ where self.table.capacity() } - /// Reserves capacity for at least `additional` more elements to be inserted - /// in the `HashMap`. The collection may reserve more space to avoid - /// frequent reallocations. - /// - /// # Panics - /// - /// Panics if the new allocation size overflows [`usize`]. - /// - /// [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashMap; - /// let mut map: HashMap<&str, i32> = HashMap::new(); - /// map.reserve(10); - /// ``` - #[inline] - pub fn reserve(&mut self, additional: usize) { - let hash_builder = &self.hash_builder; - self.table - .reserve(additional, |x| make_hash(hash_builder, &x.0)); - } - - /// Tries to reserve capacity for at least `additional` more elements to be inserted - /// in the given `HashMap`. The collection may reserve more space to avoid - /// frequent reallocations. - /// - /// # Errors - /// - /// If the capacity overflows, or the allocator reports a failure, then an error - /// is returned. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashMap; - /// let mut map: HashMap<&str, isize> = HashMap::new(); - /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); - /// ``` - #[inline] - pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { - let hash_builder = &self.hash_builder; - self.table - .try_reserve(additional, |x| make_hash(hash_builder, &x.0)) - } - - /// Shrinks the capacity of the map as much as possible. It will drop - /// down as much as possible while maintaining the internal rules - /// and possibly leaving some space in accordance with the resize policy. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashMap; - /// - /// let mut map: HashMap = HashMap::with_capacity(100); - /// map.insert(1, 2); - /// map.insert(3, 4); - /// assert!(map.capacity() >= 100); - /// map.shrink_to_fit(); - /// assert!(map.capacity() >= 2); - /// ``` - #[inline] - pub fn shrink_to_fit(&mut self) { - let hash_builder = &self.hash_builder; - self.table.shrink_to(0, |x| make_hash(hash_builder, &x.0)); - } - - /// Shrinks the capacity of the map with a lower limit. It will drop - /// down no lower than the supplied limit while maintaining the internal rules - /// and possibly leaving some space in accordance with the resize policy. - /// - /// Panics if the current capacity is smaller than the supplied - /// minimum capacity. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashMap; - /// - /// let mut map: HashMap = HashMap::with_capacity(100); - /// map.insert(1, 2); - /// map.insert(3, 4); - /// assert!(map.capacity() >= 100); - /// map.shrink_to(10); - /// assert!(map.capacity() >= 10); - /// map.shrink_to(0); - /// assert!(map.capacity() >= 2); - /// ``` - #[inline] - pub fn shrink_to(&mut self, min_capacity: usize) { - assert!( - self.capacity() >= min_capacity, - "Tried to shrink to a larger capacity" - ); - - let hash_builder = &self.hash_builder; - self.table - .shrink_to(min_capacity, |x| make_hash(hash_builder, &x.0)); - } - /// An iterator visiting all keys in arbitrary order. /// The iterator element type is `&'a K`. /// @@ -568,43 +386,6 @@ where } } - /// Gets the given key's corresponding entry in the map for in-place manipulation. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashMap; - /// - /// let mut letters = HashMap::new(); - /// - /// for ch in "a short treatise on fungi".chars() { - /// let counter = letters.entry(ch).or_insert(0); - /// *counter += 1; - /// } - /// - /// assert_eq!(letters[&'s'], 2); - /// assert_eq!(letters[&'t'], 3); - /// assert_eq!(letters[&'u'], 1); - /// assert_eq!(letters.get(&'y'), None); - /// ``` - #[inline] - pub fn entry(&mut self, key: K) -> Entry { - let hash = make_hash(&self.hash_builder, &key); - if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { - Entry::Occupied(OccupiedEntry { - key: Some(key), - elem, - table: self, - }) - } else { - Entry::Vacant(VacantEntry { - hash, - key, - table: self, - }) - } - } - #[cfg(test)] #[inline] fn raw_capacity(&self) -> usize { @@ -628,7 +409,7 @@ where self.table.len() } - /// Returns true if the map contains no elements. + /// Returns `true` if the map contains no elements. /// /// # Examples /// @@ -691,6 +472,227 @@ where pub fn clear(&mut self) { self.table.clear(); } +} + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, +{ + /// Creates an empty `HashMap` which will use the given hash builder to hash + /// keys. + /// + /// The created map has the default initial capacity. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_hasher(s); + /// map.insert(1, 2); + /// ``` + #[inline] + pub fn with_hasher(hash_builder: S) -> HashMap { + HashMap { + hash_builder, + table: RawTable::new(), + } + } + + /// Creates an empty `HashMap` with the specified capacity, using `hash_builder` + /// to hash the keys. + /// + /// The hash map will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash map will not allocate. + /// + /// Warning: `hash_builder` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); + /// map.insert(1, 2); + /// ``` + #[inline] + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap { + HashMap { + hash_builder, + table: RawTable::with_capacity(capacity), + } + } + + /// Returns a reference to the map's [`BuildHasher`]. + /// + /// [`BuildHasher`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let hasher = DefaultHashBuilder::default(); + /// let map: HashMap = HashMap::with_hasher(hasher); + /// let hasher: &DefaultHashBuilder = map.hasher(); + /// ``` + #[inline] + pub fn hasher(&self) -> &S { + &self.hash_builder + } + + /// Reserves capacity for at least `additional` more elements to be inserted + /// in the `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Panics + /// + /// Panics if the new allocation size overflows [`usize`]. + /// + /// [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, i32> = HashMap::new(); + /// map.reserve(10); + /// ``` + #[inline] + pub fn reserve(&mut self, additional: usize) { + let hash_builder = &self.hash_builder; + self.table + .reserve(additional, |x| make_hash(hash_builder, &x.0)); + } + + /// Tries to reserve capacity for at least `additional` more elements to be inserted + /// in the given `HashMap`. The collection may reserve more space to avoid + /// frequent reallocations. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// let mut map: HashMap<&str, isize> = HashMap::new(); + /// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?"); + /// ``` + #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { + let hash_builder = &self.hash_builder; + self.table + .try_reserve(additional, |x| make_hash(hash_builder, &x.0)) + } + + /// Shrinks the capacity of the map as much as possible. It will drop + /// down as much as possible while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to_fit(); + /// assert!(map.capacity() >= 2); + /// ``` + #[inline] + pub fn shrink_to_fit(&mut self) { + let hash_builder = &self.hash_builder; + self.table.shrink_to(0, |x| make_hash(hash_builder, &x.0)); + } + + /// Shrinks the capacity of the map with a lower limit. It will drop + /// down no lower than the supplied limit while maintaining the internal rules + /// and possibly leaving some space in accordance with the resize policy. + /// + /// Panics if the current capacity is smaller than the supplied + /// minimum capacity. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap = HashMap::with_capacity(100); + /// map.insert(1, 2); + /// map.insert(3, 4); + /// assert!(map.capacity() >= 100); + /// map.shrink_to(10); + /// assert!(map.capacity() >= 10); + /// map.shrink_to(0); + /// assert!(map.capacity() >= 2); + /// ``` + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + assert!( + self.capacity() >= min_capacity, + "Tried to shrink to a larger capacity" + ); + + let hash_builder = &self.hash_builder; + self.table + .shrink_to(min_capacity, |x| make_hash(hash_builder, &x.0)); + } + + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[inline] + pub fn entry(&mut self, key: K) -> Entry { + let hash = make_hash(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { + Entry::Occupied(OccupiedEntry { + key: Some(key), + elem, + table: self, + }) + } else { + Entry::Vacant(VacantEntry { + hash, + key, + table: self, + }) + } + } /// Returns a reference to the value corresponding to the key. /// @@ -754,7 +756,7 @@ where }) } - /// Returns true if the map contains a value for the specified key. + /// Returns `true` if the map contains a value for the specified key. /// /// The key may be any borrowed form of the map's key type, but /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for @@ -956,7 +958,6 @@ where impl HashMap where - K: Eq + Hash, S: BuildHasher, { /// Creates a raw entry builder for the HashMap. @@ -992,7 +993,6 @@ where /// are free to assume this doesn't happen (within the limits of memory-safety). #[inline] pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut { - self.reserve(1); RawEntryBuilderMut { map: self } } @@ -1220,7 +1220,7 @@ impl<'a, K, V: Debug> fmt::Debug for Values<'a, K, V> { /// [`drain`]: struct.HashMap.html#method.drain /// [`HashMap`]: struct.HashMap.html pub struct Drain<'a, K: 'a, V: 'a> { - pub(super) inner: RawDrain<'a, (K, V)>, + inner: RawDrain<'a, (K, V)>, } impl<'a, K, V> Drain<'a, K, V> { @@ -1300,9 +1300,8 @@ pub struct RawEntryBuilder<'a, K: 'a, V: 'a, S: 'a> { impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> where S: BuildHasher, - K: Eq + Hash, { - /// Create a `RawEntryMut` from the given key. + /// Creates a `RawEntryMut` from the given key. #[inline] pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S> where @@ -1314,7 +1313,7 @@ where self.from_key_hashed_nocheck(hasher.finish(), k) } - /// Create a `RawEntryMut` from the given key and its hash. + /// Creates a `RawEntryMut` from the given key and its hash. #[inline] pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S> where @@ -1341,7 +1340,7 @@ where } } - /// Create a `RawEntryMut` from the given hash. + /// Creates a `RawEntryMut` from the given hash. #[inline] pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S> where @@ -1680,7 +1679,7 @@ pub enum Entry<'a, K: 'a, V: 'a, S: 'a> { Vacant(VacantEntry<'a, K, V, S>), } -impl<'a, K: 'a + Debug + Eq + Hash, V: 'a + Debug, S: 'a> Debug for Entry<'a, K, V, S> { +impl<'a, K: 'a + Debug, V: 'a + Debug, S: 'a> Debug for Entry<'a, K, V, S> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), @@ -1733,17 +1732,13 @@ pub struct VacantEntry<'a, K: 'a, V: 'a, S: 'a> { table: &'a mut HashMap, } -impl<'a, K: 'a + Debug + Eq + Hash, V: 'a, S> Debug for VacantEntry<'a, K, V, S> { +impl<'a, K: 'a + Debug, V: 'a, S> Debug for VacantEntry<'a, K, V, S> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.key()).finish() } } -impl<'a, K, V, S> IntoIterator for &'a HashMap -where - K: Eq + Hash, - S: BuildHasher, -{ +impl<'a, K, V, S> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1753,11 +1748,7 @@ where } } -impl<'a, K, V, S> IntoIterator for &'a mut HashMap -where - K: Eq + Hash, - S: BuildHasher, -{ +impl<'a, K, V, S> IntoIterator for &'a mut HashMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -1767,11 +1758,7 @@ where } } -impl IntoIterator for HashMap -where - K: Eq + Hash, - S: BuildHasher, -{ +impl IntoIterator for HashMap { type Item = (K, V); type IntoIter = IntoIter; diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 4358755828..5078c424dd 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -7,7 +7,6 @@ use core::mem; use core::mem::ManuallyDrop; use core::ops::Range; use core::ptr::NonNull; -use scopeguard::guard; use CollectionAllocErr; // Branch prediction hint. This is currently only available on nightly but it @@ -59,6 +58,9 @@ mod imp; mod bitmask; +mod scopeguard; + +use self::scopeguard::guard; use self::bitmask::BitMask; use self::imp::Group; @@ -706,8 +708,10 @@ impl RawTable { // This may panic. let hash = hasher(item.as_ref()); - // We can use a simpler version of insert() here since there are no - // DELETED entries. + // We can use a simpler version of insert() here since: + // - there are no DELETED entries. + // - we know there is enough space in the table. + // - all elements are unique. let index = new_table.find_insert_slot(hash); new_table.set_ctrl(index, h2(hash)); new_table.bucket(index).write(item.read()); @@ -729,7 +733,16 @@ impl RawTable { #[inline] pub fn insert(&mut self, hash: u64, value: T, hasher: impl Fn(&T) -> u64) -> Bucket { self.reserve(1, hasher); + self.insert_no_grow(hash, value) + } + /// Inserts a new element into the table, without growing the table. + /// + /// There must be enough space in the table to insert the new element. + /// + /// This does not check if the given element already exists in the table. + #[inline] + pub fn insert_no_grow(&mut self, hash: u64, value: T) -> Bucket { unsafe { let index = self.find_insert_slot(hash); let bucket = self.bucket(index); @@ -933,7 +946,7 @@ impl IntoIterator for RawTable { } } -/// Iterator over a a sub-range of a table. Unlike `RawIter` this iterator does +/// Iterator over a sub-range of a table. Unlike `RawIter` this iterator does /// not track an item count. pub struct RawIterRange { // Using *const here for covariance diff --git a/src/raw/scopeguard.rs b/src/raw/scopeguard.rs new file mode 100644 index 0000000000..4e9bf045ad --- /dev/null +++ b/src/raw/scopeguard.rs @@ -0,0 +1,49 @@ +// Extracted from the scopeguard crate +use core::ops::{Deref, DerefMut}; + +pub struct ScopeGuard +where + F: FnMut(&mut T), +{ + dropfn: F, + value: T, +} + +#[inline] +pub fn guard(value: T, dropfn: F) -> ScopeGuard +where + F: FnMut(&mut T), +{ + ScopeGuard { dropfn, value } +} + +impl Deref for ScopeGuard +where + F: FnMut(&mut T), +{ + type Target = T; + #[inline] + fn deref(&self) -> &T { + &self.value + } +} + +impl DerefMut for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl Drop for ScopeGuard +where + F: FnMut(&mut T), +{ + #[inline] + fn drop(&mut self) { + (self.dropfn)(&mut self.value) + } +} diff --git a/src/rustc_entry.rs b/src/rustc_entry.rs new file mode 100644 index 0000000000..2a640a2fde --- /dev/null +++ b/src/rustc_entry.rs @@ -0,0 +1,575 @@ +use self::RustcEntry::*; +use core::fmt::{self, Debug}; +use core::hash::{BuildHasher, Hash}; +use core::mem; +use map::{make_hash, HashMap, Iter, IterMut, IntoIter, Drain}; +use raw::{Bucket, RawTable}; + +impl HashMap +where + K: Eq + Hash, + S: BuildHasher, +{ + /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.rustc_entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` + #[inline] + pub fn rustc_entry(&mut self, key: K) -> RustcEntry { + let hash = make_hash(&self.hash_builder, &key); + if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { + RustcEntry::Occupied(RustcOccupiedEntry { + key: Some(key), + elem, + table: &mut self.table, + }) + } else { + // Ideally we would put this in VacantEntry::insert, but Entry is not + // generic over the BuildHasher and adding a generic parameter would be + // a breaking change. + self.reserve(1); + + RustcEntry::Vacant(RustcVacantEntry { + hash, + key, + table: &mut self.table, + }) + } + } +} + +/// A view into a single entry in a map, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`HashMap`]. +/// +/// [`HashMap`]: struct.HashMap.html +/// [`entry`]: struct.HashMap.html#method.rustc_entry +pub enum RustcEntry<'a, K: 'a, V: 'a> { + /// An occupied entry. + Occupied(RustcOccupiedEntry<'a, K, V>), + + /// A vacant entry. + Vacant(RustcVacantEntry<'a, K, V>), +} + +impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for RustcEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), + Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), + } + } +} + +/// A view into an occupied entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcOccupiedEntry<'a, K: 'a, V: 'a> { + key: Option, + elem: Bucket<(K, V)>, + table: &'a mut RawTable<(K, V)>, +} + +unsafe impl<'a, K, V> Send for RustcOccupiedEntry<'a, K, V> +where + K: Send, + V: Send, +{ +} +unsafe impl<'a, K, V> Sync for RustcOccupiedEntry<'a, K, V> +where + K: Sync, + V: Sync, +{ +} + +impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for RustcOccupiedEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("key", self.key()) + .field("value", self.get()) + .finish() + } +} + +/// A view into a vacant entry in a `HashMap`. +/// It is part of the [`RustcEntry`] enum. +/// +/// [`RustcEntry`]: enum.RustcEntry.html +pub struct RustcVacantEntry<'a, K: 'a, V: 'a> { + hash: u64, + key: K, + table: &'a mut RawTable<(K, V)>, +} + +impl<'a, K: 'a + Debug, V: 'a> Debug for RustcVacantEntry<'a, K, V> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("VacantEntry").field(self.key()).finish() + } +} + +impl<'a, K, V> RustcEntry<'a, K, V> { + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland").or_insert(3); + /// assert_eq!(map["poneyland"], 3); + /// + /// *map.rustc_entry("poneyland").or_insert(10) *= 2; + /// assert_eq!(map["poneyland"], 6); + /// ``` + #[inline] + pub fn or_insert(self, default: V) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, String> = HashMap::new(); + /// let s = "hoho".to_string(); + /// + /// map.rustc_entry("poneyland").or_insert_with(|| s); + /// + /// assert_eq!(map["poneyland"], "hoho".to_string()); + /// ``` + #[inline] + pub fn or_insert_with V>(self, default: F) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(default()), + } + } + + /// Returns a reference to this entry's key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[inline] + pub fn key(&self) -> &K { + match *self { + Occupied(ref entry) => entry.key(), + Vacant(ref entry) => entry.key(), + } + } + + /// Provides in-place mutable access to an occupied entry before any + /// potential inserts into the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 42); + /// + /// map.rustc_entry("poneyland") + /// .and_modify(|e| { *e += 1 }) + /// .or_insert(42); + /// assert_eq!(map["poneyland"], 43); + /// ``` + #[inline] + pub fn and_modify(self, f: F) -> Self + where + F: FnOnce(&mut V), + { + match self { + Occupied(mut entry) => { + f(entry.get_mut()); + Occupied(entry) + } + Vacant(entry) => Vacant(entry), + } + } +} + +impl<'a, K, V: Default> RustcEntry<'a, K, V> { + /// Ensures a value is in the entry by inserting the default value if empty, + /// and returns a mutable reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// # fn main() { + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, Option> = HashMap::new(); + /// map.rustc_entry("poneyland").or_default(); + /// + /// assert_eq!(map["poneyland"], None); + /// # } + /// ``` + #[inline] + pub fn or_default(self) -> &'a mut V + where + K: Hash, + { + match self { + Occupied(entry) => entry.into_mut(), + Vacant(entry) => entry.insert(Default::default()), + } + } +} + +impl<'a, K, V> RustcOccupiedEntry<'a, K, V> { + /// Gets a reference to the key in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[inline] + pub fn key(&self) -> &K { + unsafe { &self.elem.as_ref().0 } + } + + /// Take the ownership of the key and value from the map. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// // We delete the entry from the map. + /// o.remove_entry(); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[inline] + pub fn remove_entry(self) -> (K, V) { + unsafe { + self.table.erase_no_drop(&self.elem); + self.elem.read() + } + } + + /// Gets a reference to the value in the entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.get(), &12); + /// } + /// ``` + #[inline] + pub fn get(&self) -> &V { + unsafe { &self.elem.as_ref().1 } + } + + /// Gets a mutable reference to the value in the entry. + /// + /// If you need a reference to the `RustcOccupiedEntry` which may outlive the + /// destruction of the `RustcEntry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same RustcEntry multiple times. + /// *o.get_mut() += 2; + /// } + /// + /// assert_eq!(map["poneyland"], 24); + /// ``` + #[inline] + pub fn get_mut(&mut self) -> &mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Converts the RustcOccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself. + /// + /// If you need multiple references to the `RustcOccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// assert_eq!(map["poneyland"], 12); + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// *o.into_mut() += 10; + /// } + /// + /// assert_eq!(map["poneyland"], 22); + /// ``` + #[inline] + pub fn into_mut(self) -> &'a mut V { + unsafe { &mut self.elem.as_mut().1 } + } + + /// Sets the value of the entry, and returns the entry's old value. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(mut o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.insert(15), 12); + /// } + /// + /// assert_eq!(map["poneyland"], 15); + /// ``` + #[inline] + pub fn insert(&mut self, mut value: V) -> V { + let old_value = self.get_mut(); + mem::swap(&mut value, old_value); + value + } + + /// Takes the value out of the entry, and returns it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.rustc_entry("poneyland").or_insert(12); + /// + /// if let RustcEntry::Occupied(o) = map.rustc_entry("poneyland") { + /// assert_eq!(o.remove(), 12); + /// } + /// + /// assert_eq!(map.contains_key("poneyland"), false); + /// ``` + #[inline] + pub fn remove(self) -> V { + self.remove_entry().1 + } + + /// Replaces the entry, returning the old key and value. The new key in the hash map will be + /// the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{RustcEntry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// map.insert(Rc::new("Stringthing".to_string()), 15); + /// + /// let my_key = Rc::new("Stringthing".to_string()); + /// + /// if let RustcEntry::Occupied(entry) = map.rustc_entry(my_key) { + /// // Also replace the key with a handle to our other key. + /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); + /// } + /// + /// ``` + #[inline] + pub fn replace_entry(self, value: V) -> (K, V) { + let entry = unsafe { self.elem.as_mut() }; + + let old_key = mem::replace(&mut entry.0, self.key.unwrap()); + let old_value = mem::replace(&mut entry.1, value); + + (old_key, old_value) + } + + /// Replaces the key in the hash map with the key used to create this entry. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::hash_map::{RustcEntry, HashMap}; + /// use std::rc::Rc; + /// + /// let mut map: HashMap, u32> = HashMap::new(); + /// let mut known_strings: Vec> = Vec::new(); + /// + /// // Initialise known strings, run program, etc. + /// + /// reclaim_memory(&mut map, &known_strings); + /// + /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { + /// for s in known_strings { + /// if let RustcEntry::Occupied(entry) = map.rustc_entry(s.clone()) { + /// // Replaces the entry's key with our version of it in `known_strings`. + /// entry.replace_key(); + /// } + /// } + /// } + /// ``` + #[inline] + pub fn replace_key(self) -> K { + let entry = unsafe { self.elem.as_mut() }; + mem::replace(&mut entry.0, self.key.unwrap()) + } +} + +impl<'a, K: 'a, V: 'a> RustcVacantEntry<'a, K, V> { + /// Gets a reference to the key that would be used when inserting a value + /// through the `RustcVacantEntry`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// assert_eq!(map.rustc_entry("poneyland").key(), &"poneyland"); + /// ``` + #[inline] + pub fn key(&self) -> &K { + &self.key + } + + /// Take ownership of the key. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(v) = map.rustc_entry("poneyland") { + /// v.into_key(); + /// } + /// ``` + #[inline] + pub fn into_key(self) -> K { + self.key + } + + /// Sets the value of the entry with the RustcVacantEntry's key, + /// and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RustcEntry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// if let RustcEntry::Vacant(o) = map.rustc_entry("poneyland") { + /// o.insert(37); + /// } + /// assert_eq!(map["poneyland"], 37); + /// ``` + #[inline] + pub fn insert(self, value: V) -> &'a mut V + { + let bucket = self.table.insert_no_grow(self.hash, (self.key, value)); + unsafe { &mut bucket.as_mut().1 } + } +} + + +impl<'a, K, V> IterMut<'a, K, V> { + /// Returns a iterator of references over the remaining items. + #[inline] + pub fn rustc_iter(&self) -> Iter { + self.iter() + } +} + +impl IntoIter { + /// Returns a iterator of references over the remaining items. + #[inline] + pub fn rustc_iter(&self) -> Iter { + self.iter() + } +} + +impl<'a, K, V> Drain<'a, K, V> { + /// Returns a iterator of references over the remaining items. + #[inline] + pub fn rustc_iter(&self) -> Iter { + self.iter() + } +} diff --git a/src/set.rs b/src/set.rs index 7c81fcb915..ea5e5059c5 100644 --- a/src/set.rs +++ b/src/set.rs @@ -155,6 +155,120 @@ impl HashSet { } } +impl HashSet { + /// Returns the number of elements the set can hold without reallocating. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let set: HashSet = HashSet::with_capacity(100); + /// assert!(set.capacity() >= 100); + /// ``` + #[inline] + pub fn capacity(&self) -> usize { + self.map.capacity() + } + + /// An iterator visiting all elements in arbitrary order. + /// The iterator element type is `&'a T`. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` + #[inline] + pub fn iter(&self) -> Iter { + Iter { + iter: self.map.keys(), + } + } + + /// Returns the number of elements in the set. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1); + /// assert_eq!(v.len(), 1); + /// ``` + #[inline] + pub fn len(&self) -> usize { + self.map.len() + } + + /// Returns `true` if the set contains no elements. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1); + /// assert!(!v.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + self.map.is_empty() + } + + /// Clears the set, returning all elements in an iterator. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); + /// assert!(!set.is_empty()); + /// + /// // print 1, 2, 3 in an arbitrary order + /// for i in set.drain() { + /// println!("{}", i); + /// } + /// + /// assert!(set.is_empty()); + /// ``` + #[inline] + pub fn drain(&mut self) -> Drain { + Drain { + iter: self.map.drain(), + } + } + + /// Clears the set, removing all values. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// + /// let mut v = HashSet::new(); + /// v.insert(1); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[inline] + pub fn clear(&mut self) { + self.map.clear() + } +} + impl HashSet where T: Eq + Hash, @@ -234,20 +348,6 @@ where self.map.hasher() } - /// Returns the number of elements the set can hold without reallocating. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// let set: HashSet = HashSet::with_capacity(100); - /// assert!(set.capacity() >= 100); - /// ``` - #[inline] - pub fn capacity(&self) -> usize { - self.map.capacity() - } - /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashSet`. The collection may reserve more space to avoid /// frequent reallocations. @@ -337,29 +437,6 @@ where self.map.shrink_to(min_capacity) } - /// An iterator visiting all elements in arbitrary order. - /// The iterator element type is `&'a T`. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// let mut set = HashSet::new(); - /// set.insert("a"); - /// set.insert("b"); - /// - /// // Will print in an arbitrary order. - /// for x in set.iter() { - /// println!("{}", x); - /// } - /// ``` - #[inline] - pub fn iter(&self) -> Iter { - Iter { - iter: self.map.keys(), - } - } - /// Visits the values representing the difference, /// i.e., the values that are in `self` but not in `other`. /// @@ -473,81 +550,6 @@ where } } - /// Returns the number of elements in the set. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// - /// let mut v = HashSet::new(); - /// assert_eq!(v.len(), 0); - /// v.insert(1); - /// assert_eq!(v.len(), 1); - /// ``` - #[inline] - pub fn len(&self) -> usize { - self.map.len() - } - - /// Returns true if the set contains no elements. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// - /// let mut v = HashSet::new(); - /// assert!(v.is_empty()); - /// v.insert(1); - /// assert!(!v.is_empty()); - /// ``` - #[inline] - pub fn is_empty(&self) -> bool { - self.map.is_empty() - } - - /// Clears the set, returning all elements in an iterator. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// - /// let mut set: HashSet<_> = [1, 2, 3].iter().cloned().collect(); - /// assert!(!set.is_empty()); - /// - /// // print 1, 2, 3 in an arbitrary order - /// for i in set.drain() { - /// println!("{}", i); - /// } - /// - /// assert!(set.is_empty()); - /// ``` - #[inline] - pub fn drain(&mut self) -> Drain { - Drain { - iter: self.map.drain(), - } - } - - /// Clears the set, removing all values. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// - /// let mut v = HashSet::new(); - /// v.insert(1); - /// v.clear(); - /// assert!(v.is_empty()); - /// ``` - #[inline] - pub fn clear(&mut self) { - self.map.clear() - } - /// Returns `true` if the set contains a value. /// /// The value may be any borrowed form of the set's value type, but @@ -717,7 +719,7 @@ where } } - /// Removes a value from the set. Returns `true` if the value was + /// Removes a value from the set. Returns whether the value was /// present in the set. /// /// The value may be any borrowed form of the set's value type, but @@ -1087,11 +1089,7 @@ pub struct Union<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>>, } -impl<'a, T, S> IntoIterator for &'a HashSet -where - T: Eq + Hash, - S: BuildHasher, -{ +impl<'a, T, S> IntoIterator for &'a HashSet { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -1101,11 +1099,7 @@ where } } -impl IntoIterator for HashSet -where - T: Eq + Hash, - S: BuildHasher, -{ +impl IntoIterator for HashSet { type Item = T; type IntoIter = IntoIter;