From 332db4dd1a6ff07735794fed699b7ecea3da4450 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 14 Feb 2019 21:40:42 +0100 Subject: [PATCH 1/4] Prepare hashbrown for inclusion in the standard library --- Cargo.toml | 9 +- src/fx.rs | 24 +- src/lib.rs | 10 +- src/map.rs | 43 +--- src/raw/mod.rs | 21 +- src/raw/scopeguard.rs | 49 ++++ src/rustc_entry.rs | 575 ++++++++++++++++++++++++++++++++++++++++++ src/set.rs | 240 +++++++++--------- 8 files changed, 797 insertions(+), 174 deletions(-) create mode 100644 src/raw/scopeguard.rs create mode 100644 src/rustc_entry.rs diff --git a/Cargo.toml b/Cargo.toml index 82f303a335..a4b3d90ff6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,13 +11,15 @@ categories = ["data-structures", "no-std"] exclude = [".travis.yml", "bors.toml"] [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.25", 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" @@ -28,3 +30,4 @@ serde_test = "1.0" [features] default = [] nightly = [] +rustc-dep-of-std = ["nightly", "core", "compiler_builtins", "alloc"] diff --git a/src/fx.rs b/src/fx.rs index 11574f9122..7cb7bf9793 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,25 +45,29 @@ impl FxHasher { impl Hasher for FxHasher { #[inline] fn write(&mut self, mut bytes: &[u8]) { - #[cfg(target_pointer_width = "32")] - #[allow(clippy::cast_possible_truncation)] - let read_usize = |bytes| NativeEndian::read_u32(bytes) as usize; - #[cfg(target_pointer_width = "64")] - #[allow(clippy::cast_possible_truncation)] - let read_usize = |bytes| NativeEndian::read_u64(bytes) as usize; + 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 = Self { hash: self.hash }; assert!(size_of::() <= 8); while bytes.len() >= size_of::() { - hash.add_to_hash(read_usize(bytes)); + 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.is_empty() { diff --git a/src/lib.rs b/src/lib.rs index 1c0723bf11..76341dfddc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,8 +26,7 @@ #![allow(clippy::module_name_repetitions)] #[cfg(test)] -#[macro_use] -#[allow(unused_imports)] +#[cfg_attr(feature = "rayon", macro_use)] extern crate std; #[cfg(test)] extern crate rand; @@ -35,10 +34,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"))] @@ -53,11 +50,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 cda348be90..8fe440bf04 100644 --- a/src/map.rs +++ b/src/map.rs @@ -150,7 +150,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() } /// } @@ -186,12 +186,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() @@ -232,8 +232,6 @@ impl HashMap { } impl HashMap -where - S: BuildHasher, { /// Creates an empty `HashMap` which will use the given hash builder to hash /// keys. @@ -486,7 +484,7 @@ where self.table.len() } - /// Returns true if the map contains no elements. + /// Returns `true` if the map contains no elements. /// /// # Examples /// @@ -757,7 +755,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 @@ -1220,7 +1218,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 +1298,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] #[allow(clippy::wrong_self_convention)] pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S> @@ -1315,7 +1312,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] #[allow(clippy::wrong_self_convention)] pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S> @@ -1331,7 +1328,7 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> where S: BuildHasher, { - /// Create a `RawEntryMut` from the given hash. + /// Creates a `RawEntryMut` from the given hash. #[inline] #[allow(clippy::wrong_self_convention)] pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S> @@ -1706,7 +1703,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 { Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), @@ -1759,17 +1756,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>; @@ -1779,11 +1772,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>; @@ -1793,11 +1782,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 b36dfa20d3..1a05b9fa22 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 @@ -60,6 +59,9 @@ cfg_if! { mod bitmask; +mod scopeguard; + +use self::scopeguard::guard; use self::bitmask::BitMask; use self::imp::Group; @@ -714,8 +716,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()); @@ -737,7 +741,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); @@ -941,7 +954,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 923ae42f2e..67e13c9ad7 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`. /// @@ -470,81 +547,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 @@ -714,7 +716,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 @@ -1084,11 +1086,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>; @@ -1098,11 +1096,7 @@ where } } -impl IntoIterator for HashSet -where - T: Eq + Hash, - S: BuildHasher, -{ +impl IntoIterator for HashSet { type Item = T; type IntoIter = IntoIter; From 2bd15ed4c53a02c9f55996632b96552a891fb9e2 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 4 Mar 2019 17:12:26 +0000 Subject: [PATCH 2/4] Apply feedback from https://github.com/rust-lang/rust/pull/56241 --- src/external_trait_impls/rayon/raw.rs | 12 +- src/lib.rs | 2 +- src/map.rs | 7 +- src/raw/generic.rs | 6 + src/raw/mod.rs | 423 +++++++++++++++++--------- src/raw/sse2.rs | 6 + src/{raw => }/scopeguard.rs | 0 7 files changed, 293 insertions(+), 163 deletions(-) rename src/{raw => }/scopeguard.rs (100%) diff --git a/src/external_trait_impls/rayon/raw.rs b/src/external_trait_impls/rayon/raw.rs index b6dde675b3..01cf38de04 100644 --- a/src/external_trait_impls/rayon/raw.rs +++ b/src/external_trait_impls/rayon/raw.rs @@ -15,8 +15,6 @@ pub struct RawParIter { iter: RawIterRange, } -unsafe impl Send for RawParIter {} - impl ParallelIterator for RawParIter { type Item = Bucket; @@ -35,8 +33,6 @@ struct ParIterProducer { iter: RawIterRange, } -unsafe impl Send for ParIterProducer {} - impl UnindexedProducer for ParIterProducer { type Item = Bucket; @@ -62,8 +58,6 @@ pub struct RawIntoParIter { table: RawTable, } -unsafe impl Send for RawIntoParIter {} - impl ParallelIterator for RawIntoParIter { type Item = T; @@ -87,8 +81,8 @@ impl ParallelIterator for RawIntoParIter { /// Parallel iterator which consumes elements without freeing the table storage. pub struct RawParDrain<'a, T> { - // We don't use a &'a RawTable because we want RawParDrain to be - // covariant over 'a. + // We don't use a &'a mut RawTable because we want RawParDrain to be + // covariant over T. table: NonNull>, _marker: PhantomData<&'a RawTable>, } @@ -126,8 +120,6 @@ struct ParDrainProducer { iter: RawIterRange, } -unsafe impl Send for ParDrainProducer {} - impl UnindexedProducer for ParDrainProducer { type Item = T; diff --git a/src/lib.rs b/src/lib.rs index 76341dfddc..b807c9bcdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,6 @@ #![allow(clippy::module_name_repetitions)] #[cfg(test)] -#[cfg_attr(feature = "rayon", macro_use)] extern crate std; #[cfg(test)] extern crate rand; @@ -45,6 +44,7 @@ extern crate std as alloc; #[macro_use] mod macros; +mod scopeguard; mod external_trait_impls; mod fx; mod map; diff --git a/src/map.rs b/src/map.rs index 8fe440bf04..bd3533eb02 100644 --- a/src/map.rs +++ b/src/map.rs @@ -231,8 +231,7 @@ impl HashMap { } } -impl HashMap -{ +impl HashMap { /// Creates an empty `HashMap` which will use the given hash builder to hash /// keys. /// @@ -1090,7 +1089,7 @@ where /// [`HashMap`]: struct.HashMap.html pub struct Iter<'a, K: 'a, V: 'a> { inner: RawIter<(K, V)>, - _marker: PhantomData<&'a HashMap>, + _marker: PhantomData<(&'a K, &'a V)>, } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` @@ -1120,7 +1119,7 @@ impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> { pub struct IterMut<'a, K: 'a, V: 'a> { inner: RawIter<(K, V)>, // To ensure invariance with respect to V - _marker: PhantomData<&'a mut V>, + _marker: PhantomData<(&'a K, &'a mut V)>, } impl<'a, K, V> IterMut<'a, K, V> { diff --git a/src/raw/generic.rs b/src/raw/generic.rs index 797654149b..2dee2ea512 100644 --- a/src/raw/generic.rs +++ b/src/raw/generic.rs @@ -132,6 +132,12 @@ impl Group { BitMask((self.0 & repeat(0x80)).to_le()) } + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub fn match_full(&self) -> BitMask { + self.match_empty_or_deleted().invert() + } + /// Performs the following transformation on all bytes in the group: /// - `EMPTY => EMPTY` /// - `DELETED => EMPTY` diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 1a05b9fa22..dc68bd77a9 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -5,36 +5,10 @@ use core::iter::FusedIterator; use core::marker::PhantomData; 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 -// consistently improves performance by 10-15%. -#[cfg(feature = "nightly")] -use core::intrinsics::{likely, unlikely}; -#[cfg(not(feature = "nightly"))] -#[inline] -fn likely(b: bool) -> bool { - b -} -#[cfg(not(feature = "nightly"))] -#[inline] -fn unlikely(b: bool) -> bool { - b -} - -#[cfg(feature = "nightly")] -#[inline] -unsafe fn offset_from(to: *const T, from: *const T) -> usize { - to.offset_from(from) as usize -} -#[cfg(not(feature = "nightly"))] -#[inline] -unsafe fn offset_from(to: *const T, from: *const T) -> usize { - (to as usize - from as usize) / mem::size_of::() -} - cfg_if! { // Use the SSE2 implementation if possible: it allows us to scan 16 buckets // at once instead of 8. We don't bother with AVX since it would require @@ -59,12 +33,35 @@ cfg_if! { mod bitmask; -mod scopeguard; - -use self::scopeguard::guard; use self::bitmask::BitMask; use self::imp::Group; +// Branch prediction hint. This is currently only available on nightly but it +// consistently improves performance by 10-15%. +#[cfg(feature = "nightly")] +use core::intrinsics::{likely, unlikely}; +#[cfg(not(feature = "nightly"))] +#[inline] +fn likely(b: bool) -> bool { + b +} +#[cfg(not(feature = "nightly"))] +#[inline] +fn unlikely(b: bool) -> bool { + b +} + +#[cfg(feature = "nightly")] +#[inline] +unsafe fn offset_from(to: *const T, from: *const T) -> usize { + to.offset_from(from) as usize +} +#[cfg(not(feature = "nightly"))] +#[inline] +unsafe fn offset_from(to: *const T, from: *const T) -> usize { + (to as usize - from as usize) / mem::size_of::() +} + /// Whether memory allocation errors should return an error or abort. #[derive(Copy, Clone)] enum Fallibility { @@ -142,10 +139,17 @@ fn h2(hash: u64) -> u8 { /// Probe sequence based on triangular numbers, which is guaranteed (since our /// table size is a power of two) to visit every group of elements exactly once. +/// +/// A triangular probe has us jump by 1 more group every time. So first we +/// jump by 1 group (meaning we just continue our linear scan), then 2 groups +/// (skipping over 1 group), then 3 groups (skipping over 2 groups), and so on. +/// +/// Proof that the probe will visit every group in the table: +/// https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/ struct ProbeSeq { - mask: usize, - offset: usize, - index: usize, + bucket_mask: usize, + pos: usize, + stride: usize, } impl Iterator for ProbeSeq { @@ -154,12 +158,15 @@ impl Iterator for ProbeSeq { #[inline] fn next(&mut self) -> Option { // We should have found an empty bucket by now and ended the probe. - debug_assert!(self.index <= self.mask, "Went past end of probe sequence"); - - let result = self.offset; - self.index += Group::WIDTH; - self.offset += self.index; - self.offset &= self.mask; + debug_assert!( + self.stride <= self.bucket_mask, + "Went past end of probe sequence" + ); + + let result = self.pos; + self.stride += Group::WIDTH; + self.pos += self.stride; + self.pos &= self.bucket_mask; Some(result) } } @@ -181,7 +188,9 @@ fn capacity_to_buckets(cap: usize) -> Option { cap.checked_mul(8)? / 7 }; - // Any overflows will have been caught by the checked_mul. + // Any overflows will have been caught by the checked_mul. Also, any + // rounding errors from the division above will be cleaned up by + // next_power_of_two (which can't overflow because of the previous divison). Some(adjusted_cap.next_power_of_two()) } @@ -190,8 +199,11 @@ fn capacity_to_buckets(cap: usize) -> Option { #[inline] fn bucket_mask_to_capacity(bucket_mask: usize) -> usize { if bucket_mask < 8 { + // For tables with 1/2/4/8 buckets, we always reserve one empty slot. + // Keep in mind that the bucket mask is one less than the bucket count. bucket_mask } else { + // For larger tables we reserve 12.5% of the slots as empty. ((bucket_mask + 1) / 8) * 7 } } @@ -240,8 +252,13 @@ fn calculate_layout(buckets: usize) -> Option<(Layout, usize)> { } /// A reference to a hash table bucket containing a `T`. +/// +/// This is usually just a pointer to the element itself. However if the element +/// is a ZST, then we instead track the index of the element in the table so +/// that `erase` works properly. pub struct Bucket { - ptr: NonNull, + // Using *const for variance + ptr: *const T, } // This Send impl is needed for rayon support. This is safe since Bucket is @@ -257,40 +274,75 @@ impl Clone for Bucket { impl Bucket { #[inline] - unsafe fn from_ptr(ptr: *const T) -> Self { - Self { - ptr: NonNull::new_unchecked(ptr as *mut T), + unsafe fn from_base_index(base: *const T, index: usize) -> Self { + let ptr = if mem::size_of::() == 0 { + index as *const T + } else { + base.add(index) + }; + Self { ptr } + } + #[inline] + pub unsafe fn as_ptr(&self) -> *mut T { + if mem::size_of::() == 0 { + // Just return an arbitrary ZST pointer which is properly aligned + mem::align_of::() as *mut T + } else { + self.ptr as *mut T } } #[inline] + unsafe fn add(&self, offset: usize) -> Self { + let ptr = if mem::size_of::() == 0 { + (self.ptr as usize + offset) as *const T + } else { + self.ptr.add(offset) + }; + Bucket { ptr } + } + #[inline] pub unsafe fn drop(&self) { - self.ptr.as_ptr().drop_in_place(); + self.as_ptr().drop_in_place(); } #[inline] pub unsafe fn read(&self) -> T { - self.ptr.as_ptr().read() + self.as_ptr().read() } #[inline] pub unsafe fn write(&self, val: T) { - self.ptr.as_ptr().write(val); + self.as_ptr().write(val); } #[inline] pub unsafe fn as_ref<'a>(&self) -> &'a T { - &*self.ptr.as_ptr() + &*self.as_ptr() } #[inline] pub unsafe fn as_mut<'a>(&self) -> &'a mut T { - &mut *self.ptr.as_ptr() + &mut *self.as_ptr() + } + #[inline] + pub unsafe fn copy_from_nonoverlapping(&self, other: Bucket) { + self.as_ptr().copy_from_nonoverlapping(other.as_ptr(), 1); } } /// A raw hash table with an unsafe API. pub struct RawTable { - ctrl: NonNull, + // Mask to get an index from a hash value. The value is one less than the + // number of buckets in the table. bucket_mask: usize, + + // Pointer to the array of control bytes + ctrl: NonNull, + + // Pointer to the array of buckets data: NonNull, - items: usize, + + // Number of elements that can be inserted before we need to grow the table growth_left: usize, + + // Number of elements in the table, only really used by len() + items: usize, } impl RawTable { @@ -344,18 +396,7 @@ impl RawTable { let buckets = capacity_to_buckets(capacity).ok_or_else(|| fallability.capacity_overflow())?; let result = Self::new_uninitialized(buckets, fallability)?; - result - .ctrl(0) - .write_bytes(EMPTY, result.buckets() + Group::WIDTH); - - // If we have fewer buckets than the group width then we need to - // fill in unused spaces in the trailing control bytes with - // DELETED entries. See the comments in set_ctrl. - if result.buckets() < Group::WIDTH { - result - .ctrl(result.buckets()) - .write_bytes(DELETED, Group::WIDTH - result.buckets()); - } + result.ctrl(0).write_bytes(EMPTY, result.num_ctrl_bytes()); Ok(result) } @@ -380,13 +421,17 @@ impl RawTable { /// Returns the index of a bucket from a `Bucket`. #[inline] unsafe fn bucket_index(&self, bucket: &Bucket) -> usize { - offset_from(bucket.ptr.as_ptr(), self.data.as_ptr()) + if mem::size_of::() == 0 { + bucket.ptr as usize + } else { + offset_from(bucket.ptr, self.data.as_ptr()) + } } /// Returns a pointer to a control byte. #[inline] unsafe fn ctrl(&self, index: usize) -> *mut u8 { - debug_assert!(index < self.buckets() + Group::WIDTH); + debug_assert!(index < self.num_ctrl_bytes()); self.ctrl.as_ptr().add(index) } @@ -395,7 +440,7 @@ impl RawTable { pub unsafe fn bucket(&self, index: usize) -> Bucket { debug_assert_ne!(self.bucket_mask, 0); debug_assert!(index < self.buckets()); - Bucket::from_ptr(self.data.as_ptr().add(index)) + Bucket::from_base_index(self.data.as_ptr(), index) } /// Erases an element from the table without dropping it. @@ -410,6 +455,10 @@ impl RawTable { // cells then a probe window may have seen a full block when trying to // insert. We therefore need to keep that block non-empty so that // lookups will continue searching to the next probe window. + // + // Note that in this context `leading_zeros` refers to the bytes at the + // end of a group, while `trailing_zeros` refers to the bytes at the + // begining of a group. let ctrl = if empty_before.leading_zeros() + empty_after.trailing_zeros() >= Group::WIDTH { DELETED } else { @@ -423,13 +472,14 @@ impl RawTable { /// Returns an iterator for a probe sequence on the table. /// /// This iterator never terminates, but is guaranteed to visit each bucket - /// group exactly once. + /// group exactly once. The loop using `probe_seq` must terminate upon + /// reaching a group containing an empty bucket. #[inline] fn probe_seq(&self, hash: u64) -> ProbeSeq { ProbeSeq { - mask: self.bucket_mask, - offset: h1(hash) & self.bucket_mask, - index: 0, + bucket_mask: self.bucket_mask, + pos: h1(hash) & self.bucket_mask, + stride: 0, } } @@ -452,9 +502,9 @@ impl RawTable { // like this: // // Real | Replicated - // ------------------------------------------------- - // | [A] | [B] | [DELETED] | [DELETED] | [A] | [B] | - // ------------------------------------------------- + // --------------------------------------------- + // | [A] | [B] | [EMPTY] | [EMPTY] | [A] | [B] | + // --------------------------------------------- let index2 = ((index.wrapping_sub(Group::WIDTH)) & self.bucket_mask) + Group::WIDTH; *self.ctrl(index) = ctrl; @@ -475,13 +525,13 @@ impl RawTable { // In tables smaller than the group width, trailing control // bytes outside the range of the table are filled with - // DELETED entries. These will unfortunately trigger a - // match, but once masked will point to a full bucket that + // EMPTY entries. These will unfortunately trigger a + // match, but once masked may point to a full bucket that // is already occupied. We detect this situation here and // perform a second scan starting at the begining of the // table. This second scan is guaranteed to find an empty // slot (due to the load factor) before hitting the trailing - // control bytes (containing DELETED). + // control bytes (containing EMPTY). if unlikely(is_full(*self.ctrl(result))) { debug_assert!(self.bucket_mask < Group::WIDTH); debug_assert_ne!(pos, 0); @@ -502,10 +552,9 @@ impl RawTable { /// Marks all table buckets as empty without dropping their contents. #[inline] pub fn clear_no_drop(&mut self) { - if self.bucket_mask != 0 { + if !self.is_empty_singleton() { unsafe { - self.ctrl(0) - .write_bytes(EMPTY, self.buckets() + Group::WIDTH); + self.ctrl(0).write_bytes(EMPTY, self.num_ctrl_bytes()); } } self.items = 0; @@ -530,10 +579,34 @@ impl RawTable { /// Shrinks the table to fit `max(self.len(), min_size)` elements. #[inline] pub fn shrink_to(&mut self, min_size: usize, hasher: impl Fn(&T) -> u64) { + // Calculate the minimal number of elements that we need to reserve + // space for. let min_size = usize::max(self.items, min_size); - if self.bucket_mask != 0 && bucket_mask_to_capacity(self.bucket_mask) >= min_size * 2 { - self.resize(min_size, hasher, Fallibility::Infallible) - .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); + if min_size == 0 { + *self = Self::new(); + return; + } + + // Calculate the number of buckets that we need for this number of + // elements. If the calculation overflows then the requested bucket + // count must be larger than what we have right and nothing needs to be + // done. + let min_buckets = match capacity_to_buckets(min_size) { + Some(buckets) => buckets, + None => return, + }; + + // If we have more buckets than we need, shrink the table. + if min_buckets != self.buckets() { + debug_assert!(min_buckets < self.buckets()); + + // Fast path if the table is empty + if self.items == 0 { + *self = Self::with_capacity(min_size) + } else { + self.resize(min_size, hasher, Fallibility::Infallible) + .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() }); + } } } @@ -601,12 +674,11 @@ impl RawTable { group.store_aligned(self.ctrl(i)); } - // Fix up the trailing control bytes. See the comments in set_ctrl. + // Fix up the trailing control bytes. See the comments in set_ctrl + // for the handling of tables smaller than the group width. if self.buckets() < Group::WIDTH { self.ctrl(0) .copy_to(self.ctrl(Group::WIDTH), self.buckets()); - self.ctrl(self.buckets()) - .write_bytes(DELETED, Group::WIDTH - self.buckets()); } else { self.ctrl(0) .copy_to(self.ctrl(self.buckets()), Group::WIDTH); @@ -650,7 +722,7 @@ impl RawTable { // same unaligned group, then there is no benefit in moving // it and we can just continue to the next item. let probe_index = |pos: usize| { - (pos.wrapping_sub(guard.probe_seq(hash).offset) & guard.bucket_mask) + (pos.wrapping_sub(guard.probe_seq(hash).pos) & guard.bucket_mask) / Group::WIDTH }; if likely(probe_index(i) == probe_index(new_i)) { @@ -668,7 +740,7 @@ impl RawTable { // element into the new slot and clear the old control // byte. guard.set_ctrl(i, EMPTY); - guard.bucket(new_i).write(item.read()); + guard.bucket(new_i).copy_from_nonoverlapping(item); continue 'outer; } else { // If the target slot is occupied, swap the two elements @@ -705,8 +777,11 @@ impl RawTable { // The hash function may panic, in which case we simply free the new // table without dropping any elements that may have been copied into // it. + // + // This guard is also used to free the old table on success, see + // the comment at the bottom of this function. let mut new_table = guard(ManuallyDrop::new(new_table), |new_table| { - if new_table.bucket_mask != 0 { + if !new_table.is_empty_singleton() { new_table.free_buckets(); } }); @@ -722,7 +797,7 @@ impl RawTable { // - 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()); + new_table.bucket(index).copy_from_nonoverlapping(item); } // We successfully copied all elements without panicking. Now replace @@ -811,14 +886,28 @@ impl RawTable { self.bucket_mask + 1 } + /// Returns the number of control bytes in the table. + #[inline] + fn num_ctrl_bytes(&self) -> usize { + self.bucket_mask + 1 + Group::WIDTH + } + + /// Returns whether this table points to the empty singleton with a capacity + /// of 0. + #[inline] + fn is_empty_singleton(&self) -> bool { + self.bucket_mask == 0 + } + /// Returns an iterator over every element in the table. It is up to /// the caller to ensure that the `RawTable` outlives the `RawIter`. /// Because we cannot make the `next` method unsafe on the `RawIter` /// struct, we have to make the `iter` method unsafe. #[inline] pub unsafe fn iter(&self) -> RawIter { + let data = Bucket::from_base_index(self.data.as_ptr(), 0); RawIter { - iter: RawIterRange::new(self.ctrl.as_ptr(), self.data.as_ptr(), 0..self.buckets()), + iter: RawIterRange::new(self.ctrl.as_ptr(), data, self.buckets()), items: self.items, } } @@ -831,7 +920,8 @@ impl RawTable { pub unsafe fn drain(&mut self) -> RawDrain { RawDrain { iter: self.iter(), - table: NonNull::from(self), + table: ManuallyDrop::new(mem::replace(self, Self::new())), + orig_table: NonNull::from(self), _marker: PhantomData, } } @@ -840,12 +930,12 @@ impl RawTable { /// should be dropped using a `RawIter` before freeing the allocation. #[inline] pub fn into_alloc(self) -> Option<(NonNull, Layout)> { - let alloc = if self.bucket_mask == 0 { - None - } else { + let alloc = if !self.is_empty_singleton() { let (layout, _) = calculate_layout::(self.buckets()) .unwrap_or_else(|| unsafe { hint::unreachable_unchecked() }); Some((self.ctrl.cast(), layout)) + } else { + None }; mem::forget(self); alloc @@ -857,7 +947,7 @@ unsafe impl Sync for RawTable where T: Sync {} impl Clone for RawTable { fn clone(&self) -> Self { - if self.bucket_mask == 0 { + if self.is_empty_singleton() { Self::new() } else { unsafe { @@ -868,7 +958,7 @@ impl Clone for RawTable { // Copy the control bytes unchanged. We do this in a single pass self.ctrl(0) - .copy_to_nonoverlapping(new_table.ctrl(0), self.buckets() + Group::WIDTH); + .copy_to_nonoverlapping(new_table.ctrl(0), self.num_ctrl_bytes()); { // The cloning of elements may panic, in which case we need @@ -911,7 +1001,7 @@ impl Clone for RawTable { unsafe impl<#[may_dangle] T> Drop for RawTable { #[inline] fn drop(&mut self) { - if self.bucket_mask != 0 { + if !self.is_empty_singleton() { unsafe { if mem::needs_drop::() { for item in self.iter() { @@ -927,7 +1017,7 @@ unsafe impl<#[may_dangle] T> Drop for RawTable { impl Drop for RawTable { #[inline] fn drop(&mut self) { - if self.bucket_mask != 0 { + if !self.is_empty_singleton() { unsafe { if mem::needs_drop::() { for item in self.iter() { @@ -957,67 +1047,96 @@ impl IntoIterator for RawTable { /// 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 - data: *const T, - ctrl: *const u8, + // Mask of full buckets in the current group. Bits are cleared from this + // mask as each element is processed. current_group: BitMask, + + // Pointer to the buckets for the current group. + data: Bucket, + + // Pointer to the next group of control bytes, + // Must be aligned to the group size. + next_ctrl: *const u8, + + // Pointer one past the last control byte of this range. end: *const u8, } impl RawIterRange { /// Returns a `RawIterRange` covering a subset of a table. /// - /// The start offset must be aligned to the group width. + /// The control byte address must be aligned to the group size. #[inline] - unsafe fn new(input_ctrl: *const u8, input_data: *const T, range: Range) -> Self { - debug_assert_eq!(range.start % Group::WIDTH, 0); - let ctrl = input_ctrl.add(range.start); - let data = input_data.add(range.start); - let end = input_ctrl.add(range.end); - debug_assert_eq!(offset_from(end, ctrl), range.end - range.start); - let current_group = Group::load_aligned(ctrl).match_empty_or_deleted().invert(); + unsafe fn new(ctrl: *const u8, data: Bucket, len: usize) -> Self { + debug_assert_ne!(len, 0); + debug_assert_eq!(ctrl as usize % Group::WIDTH, 0); + let end = ctrl.add(len); + + // Load the first group and advance ctrl to point to the next group + let current_group = Group::load_aligned(ctrl).match_full(); + let next_ctrl = ctrl.add(Group::WIDTH); + Self { - data, - ctrl, current_group, + data, + next_ctrl, end, } } /// Splits a `RawIterRange` into two halves. /// - /// This will fail if the total range is smaller than the group width. + /// Returns `None` if the remaining range is smaller than or equal to the + /// group width. #[inline] #[cfg(feature = "rayon")] pub fn split(mut self) -> (Self, Option>) { unsafe { - let len = offset_from(self.end, self.ctrl); - debug_assert!(len.is_power_of_two()); - if len <= Group::WIDTH { + if self.end <= self.next_ctrl { + // Nothing to split if the group that we are current processing + // is the last one. (self, None) } else { - debug_assert_eq!(len % (Group::WIDTH * 2), 0); - let mid = len / 2; - let tail = Self::new(self.ctrl, self.data, mid..len); - debug_assert_eq!(self.data.add(mid), tail.data); + // len is the remaining number of elements after the group that + // we are currently processing. It must be a multiple of the + // group size (small tables are caught by the check above). + let len = offset_from(self.end, self.next_ctrl); + debug_assert_eq!(len % Group::WIDTH, 0); + + // Split the remaining elements into two halves, but round the + // midpoint down in case there is an odd number of groups + // remaining. This ensures that: + // - The tail is at least 1 group long. + // - The split is roughly even considering we still have the + // current group to process. + let mid = (len / 2) & !(Group::WIDTH - 1); + + let tail = Self::new( + self.next_ctrl.add(mid), + self.data.add(Group::WIDTH).add(mid), + len - mid, + ); + debug_assert_eq!(self.data.add(Group::WIDTH).add(mid).ptr, tail.data.ptr); debug_assert_eq!(self.end, tail.end); - self.end = self.ctrl.add(mid); - debug_assert_eq!(self.end, tail.ctrl); + self.end = self.next_ctrl.add(mid); + debug_assert_eq!(self.end.add(Group::WIDTH), tail.next_ctrl); (self, Some(tail)) } } } } -unsafe impl Send for RawIterRange where T: Send {} -unsafe impl Sync for RawIterRange where T: Sync {} +// We make raw iterators unconditionally Send and Sync, and let the PhantomData +// in the actual iterator implementations determine the real Send/Sync bounds. +unsafe impl Send for RawIterRange {} +unsafe impl Sync for RawIterRange {} impl Clone for RawIterRange { #[inline] fn clone(&self) -> Self { Self { - data: self.data, - ctrl: self.ctrl, + data: self.data.clone(), + next_ctrl: self.next_ctrl, current_group: self.current_group, end: self.end, } @@ -1033,18 +1152,21 @@ impl Iterator for RawIterRange { loop { if let Some(index) = self.current_group.lowest_set_bit() { self.current_group = self.current_group.remove_lowest_bit(); - return Some(Bucket::from_ptr(self.data.add(index))); + return Some(self.data.add(index)); } - self.ctrl = self.ctrl.add(Group::WIDTH); - if self.ctrl >= self.end { + if self.next_ctrl >= self.end { return None; } + // We might read past self.end up to the next group boundary, + // but this is fine because it only occurs on tables smaller + // than the group size where the trailing control bytes are all + // EMPTY. On larger tables self.end is guaranteed to be aligned + // to the group size (since tables are power-of-two sized). + self.current_group = Group::load_aligned(self.next_ctrl).match_full(); self.data = self.data.add(Group::WIDTH); - self.current_group = Group::load_aligned(self.ctrl) - .match_empty_or_deleted() - .invert(); + self.next_ctrl = self.next_ctrl.add(Group::WIDTH); } } } @@ -1052,7 +1174,10 @@ impl Iterator for RawIterRange { #[inline] fn size_hint(&self) -> (usize, Option) { // We don't have an item count, so just guess based on the range size. - (0, Some(unsafe { offset_from(self.end, self.ctrl) })) + ( + 0, + Some(unsafe { offset_from(self.end, self.next_ctrl) + Group::WIDTH }), + ) } } @@ -1156,9 +1281,14 @@ impl FusedIterator for RawIntoIter {} pub struct RawDrain<'a, T: 'a> { iter: RawIter, - // We don't use a &'a RawTable because we want RawDrain to be covariant - // over 'a. - table: NonNull>, + // The table is moved into the iterator for the duration of the drain. This + // ensures that an empty table is left if the drain iterator is leaked + // without dropping. + table: ManuallyDrop>, + orig_table: NonNull>, + + // We don't use a &'a mut RawTable because we want RawDrain to be + // covariant over T. _marker: PhantomData<&'a RawTable>, } @@ -1176,15 +1306,21 @@ impl<'a, T> Drop for RawDrain<'a, T> { #[inline] fn drop(&mut self) { unsafe { - // Ensure that the table is reset even if one of the drops panic - let _guard = guard(self.table, |table| table.as_mut().clear_no_drop()); - - // Drop all remaining elements + // Drop all remaining elements. Note that this may panic. if mem::needs_drop::() { while let Some(item) = self.iter.next() { item.drop(); } } + + // Reset the contents of the table now that all elements have been + // dropped. + self.table.clear_no_drop(); + + // Move the now empty table back to its original location. + self.orig_table + .as_ptr() + .copy_from_nonoverlapping(&*self.table, 1); } } } @@ -1196,15 +1332,6 @@ impl<'a, T> Iterator for RawDrain<'a, T> { fn next(&mut self) -> Option { unsafe { let item = self.iter.next()?; - - // Mark the item as DELETED in the table and decrement the item - // counter. We don't need to use the full delete algorithm like - // erase_no_drop since we will just clear the control bytes when - // the RawDrain is dropped. - let index = self.table.as_ref().bucket_index(&item); - *self.table.as_mut().ctrl(index) = DELETED; - self.table.as_mut().items -= 1; - Some(item.read()) } } diff --git a/src/raw/sse2.rs b/src/raw/sse2.rs index 8e1abdfe71..c9a1c54110 100644 --- a/src/raw/sse2.rs +++ b/src/raw/sse2.rs @@ -109,6 +109,12 @@ impl Group { } } + /// Returns a `BitMask` indicating all bytes in the group which are full. + #[inline] + pub fn match_full(&self) -> BitMask { + self.match_empty_or_deleted().invert() + } + /// Performs the following transformation on all bytes in the group: /// - `EMPTY => EMPTY` /// - `DELETED => EMPTY` diff --git a/src/raw/scopeguard.rs b/src/scopeguard.rs similarity index 100% rename from src/raw/scopeguard.rs rename to src/scopeguard.rs From b11f8cd9abb1a2c567757d0c1b7a5d46b31a75bd Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 8 Mar 2019 02:15:42 +0000 Subject: [PATCH 3/4] Upgrade to 2018 edition --- .travis.yml | 2 +- Cargo.toml | 1 + benches/bench.rs | 2 - src/external_trait_impls/rayon/map.rs | 84 ++++++------- src/external_trait_impls/rayon/raw.rs | 14 +-- src/external_trait_impls/rayon/set.rs | 18 +-- src/external_trait_impls/serde.rs | 12 +- src/fx.rs | 3 +- src/lib.rs | 27 ++--- src/map.rs | 168 +++++++++++++------------- src/raw/mod.rs | 30 ++--- src/rustc_entry.rs | 42 +++---- src/set.rs | 90 +++++++------- tests/rayon.rs | 2 - tests/serde.rs | 3 - tests/set.rs | 2 - 16 files changed, 241 insertions(+), 259 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5d85b235bf..960898e325 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ matrix: - name: "x86_64-unknown-linux-gnu (stable)" rust: stable env: TARGET=x86_64-unknown-linux-gnu - - name: "x86_64-unknown-linux-gnu (Rust 1.29.0)" + - name: "x86_64-unknown-linux-gnu (Rust 1.31.0)" rust: 1.31.0 env: TARGET=x86_64-unknown-linux-gnu - name: "i686-unknown-linux-gnu" diff --git a/Cargo.toml b/Cargo.toml index a4b3d90ff6..0da22dcf5b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ readme = "README.md" keywords = ["hash", "no_std", "hashmap", "swisstable"] categories = ["data-structures", "no-std"] exclude = [".travis.yml", "bors.toml"] +edition = "2018" [dependencies] # For external trait impls diff --git a/benches/bench.rs b/benches/bench.rs index 52cb3c0256..7de450530f 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,7 +1,5 @@ #![feature(test)] -extern crate hashbrown; -extern crate rustc_hash; extern crate test; use std::hash::Hash; diff --git a/src/external_trait_impls/rayon/map.rs b/src/external_trait_impls/rayon/map.rs index aa25b83154..6f869ae0a0 100644 --- a/src/external_trait_impls/rayon/map.rs +++ b/src/external_trait_impls/rayon/map.rs @@ -1,8 +1,8 @@ //! Rayon extensions for `HashMap`. +use crate::hash_map::HashMap; use core::fmt; use core::hash::{BuildHasher, Hash}; -use hash_map::HashMap; use rayon::iter::plumbing::UnindexedConsumer; use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; @@ -15,7 +15,7 @@ use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, Pa /// [`par_iter`]: /hashbrown/struct.HashMap.html#method.par_iter /// [`HashMap`]: /hashbrown/struct.HashMap.html /// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html -pub struct ParIter<'a, K: 'a, V: 'a, S: 'a> { +pub struct ParIter<'a, K, V, S> { map: &'a HashMap, } @@ -38,17 +38,15 @@ impl<'a, K: Sync, V: Sync, S: Sync> ParallelIterator for ParIter<'a, K, V, S> { } } -impl<'a, K, V, S> Clone for ParIter<'a, K, V, S> { +impl Clone for ParIter<'_, K, V, S> { #[inline] fn clone(&self) -> Self { ParIter { map: self.map } } } -impl<'a, K: fmt::Debug + Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug - for ParIter<'a, K, V, S> -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for ParIter<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.map.iter().fmt(f) } } @@ -60,7 +58,7 @@ impl<'a, K: fmt::Debug + Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug /// /// [`par_keys`]: /hashbrown/struct.HashMap.html#method.par_keys /// [`HashMap`]: /hashbrown/struct.HashMap.html -pub struct ParKeys<'a, K: 'a, V: 'a, S: 'a> { +pub struct ParKeys<'a, K, V, S> { map: &'a HashMap, } @@ -80,15 +78,15 @@ impl<'a, K: Sync, V: Sync, S: Sync> ParallelIterator for ParKeys<'a, K, V, S> { } } -impl<'a, K, V, S> Clone for ParKeys<'a, K, V, S> { +impl Clone for ParKeys<'_, K, V, S> { #[inline] fn clone(&self) -> Self { ParKeys { map: self.map } } } -impl<'a, K: fmt::Debug + Eq + Hash, V, S: BuildHasher> fmt::Debug for ParKeys<'a, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for ParKeys<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.map.keys().fmt(f) } } @@ -100,7 +98,7 @@ impl<'a, K: fmt::Debug + Eq + Hash, V, S: BuildHasher> fmt::Debug for ParKeys<'a /// /// [`par_values`]: /hashbrown/struct.HashMap.html#method.par_values /// [`HashMap`]: /hashbrown/struct.HashMap.html -pub struct ParValues<'a, K: 'a, V: 'a, S: 'a> { +pub struct ParValues<'a, K, V, S> { map: &'a HashMap, } @@ -120,15 +118,15 @@ impl<'a, K: Sync, V: Sync, S: Sync> ParallelIterator for ParValues<'a, K, V, S> } } -impl<'a, K, V, S> Clone for ParValues<'a, K, V, S> { +impl Clone for ParValues<'_, K, V, S> { #[inline] fn clone(&self) -> Self { ParValues { map: self.map } } } -impl<'a, K: Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug for ParValues<'a, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for ParValues<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.map.values().fmt(f) } } @@ -142,7 +140,7 @@ impl<'a, K: Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug for ParValues<' /// [`par_iter_mut`]: /hashbrown/struct.HashMap.html#method.par_iter_mut /// [`HashMap`]: /hashbrown/struct.HashMap.html /// [`IntoParallelRefMutIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefMutIterator.html -pub struct ParIterMut<'a, K: 'a, V: 'a, S: 'a> { +pub struct ParIterMut<'a, K, V, S> { map: &'a mut HashMap, } @@ -165,10 +163,10 @@ impl<'a, K: Send + Sync, V: Send, S: Send> ParallelIterator for ParIterMut<'a, K } } -impl<'a, K: fmt::Debug + Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug - for ParIterMut<'a, K, V, S> +impl fmt::Debug + for ParIterMut<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.map.iter().fmt(f) } } @@ -180,7 +178,7 @@ impl<'a, K: fmt::Debug + Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug /// /// [`par_values_mut`]: /hashbrown/struct.HashMap.html#method.par_values_mut /// [`HashMap`]: /hashbrown/struct.HashMap.html -pub struct ParValuesMut<'a, K: 'a, V: 'a, S: 'a> { +pub struct ParValuesMut<'a, K, V, S> { map: &'a mut HashMap, } @@ -200,8 +198,8 @@ impl<'a, K: Send, V: Send, S: Send> ParallelIterator for ParValuesMut<'a, K, V, } } -impl<'a, K: Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug for ParValuesMut<'a, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for ParValuesMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.map.values().fmt(f) } } @@ -231,10 +229,8 @@ impl ParallelIterator for IntoParIter { } } -impl<'a, K: fmt::Debug + Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug - for IntoParIter -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for IntoParIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.map.iter().fmt(f) } } @@ -246,11 +242,11 @@ impl<'a, K: fmt::Debug + Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug /// /// [`par_drain`]: /hashbrown/struct.HashMap.html#method.par_drain /// [`HashMap`]: /hashbrown/struct.HashMap.html -pub struct ParDrain<'a, K: 'a, V: 'a, S: 'a> { +pub struct ParDrain<'a, K, V, S> { map: &'a mut HashMap, } -impl<'a, K: Send, V: Send, S: Send> ParallelIterator for ParDrain<'a, K, V, S> { +impl ParallelIterator for ParDrain<'_, K, V, S> { type Item = (K, V); #[inline] @@ -262,10 +258,10 @@ impl<'a, K: Send, V: Send, S: Send> ParallelIterator for ParDrain<'a, K, V, S> { } } -impl<'a, K: fmt::Debug + Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug - for ParDrain<'a, K, V, S> +impl fmt::Debug + for ParDrain<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.map.iter().fmt(f) } } @@ -273,13 +269,13 @@ impl<'a, K: fmt::Debug + Eq + Hash, V: fmt::Debug, S: BuildHasher> fmt::Debug impl HashMap { /// Visits (potentially in parallel) immutably borrowed keys in an arbitrary order. #[inline] - pub fn par_keys(&self) -> ParKeys { + pub fn par_keys(&self) -> ParKeys<'_, K, V, S> { ParKeys { map: self } } /// Visits (potentially in parallel) immutably borrowed values in an arbitrary order. #[inline] - pub fn par_values(&self) -> ParValues { + pub fn par_values(&self) -> ParValues<'_, K, V, S> { ParValues { map: self } } } @@ -287,14 +283,14 @@ impl HashMap { impl HashMap { /// Visits (potentially in parallel) mutably borrowed values in an arbitrary order. #[inline] - pub fn par_values_mut(&mut self) -> ParValuesMut { + pub fn par_values_mut(&mut self) -> ParValuesMut<'_, K, V, S> { ParValuesMut { map: self } } /// Consumes (potentially in parallel) all values in an arbitrary order, /// while preserving the map's allocated memory for reuse. #[inline] - pub fn par_drain(&mut self) -> ParDrain { + pub fn par_drain(&mut self) -> ParDrain<'_, K, V, S> { ParDrain { map: self } } } @@ -426,34 +422,34 @@ mod test_par_map { use rayon::prelude::*; - use hash_map::HashMap; + use crate::hash_map::HashMap; struct Dropable<'a> { k: usize, counter: &'a AtomicUsize, } - impl<'a> Dropable<'a> { - fn new(k: usize, counter: &AtomicUsize) -> Dropable { + impl Dropable<'_> { + fn new(k: usize, counter: &AtomicUsize) -> Dropable<'_> { counter.fetch_add(1, Ordering::Relaxed); Dropable { k, counter } } } - impl<'a> Drop for Dropable<'a> { + impl Drop for Dropable<'_> { fn drop(&mut self) { self.counter.fetch_sub(1, Ordering::Relaxed); } } - impl<'a> Clone for Dropable<'a> { - fn clone(&self) -> Dropable<'a> { + impl Clone for Dropable<'_> { + fn clone(&self) -> Self { Dropable::new(self.k, self.counter) } } - impl<'a> Hash for Dropable<'a> { + impl Hash for Dropable<'_> { fn hash(&self, state: &mut H) where H: Hasher, @@ -462,13 +458,13 @@ mod test_par_map { } } - impl<'a> PartialEq for Dropable<'a> { + impl PartialEq for Dropable<'_> { fn eq(&self, other: &Self) -> bool { self.k == other.k } } - impl<'a> Eq for Dropable<'a> {} + impl Eq for Dropable<'_> {} #[test] fn test_into_iter_drops() { diff --git a/src/external_trait_impls/rayon/raw.rs b/src/external_trait_impls/rayon/raw.rs index 01cf38de04..047b5858d2 100644 --- a/src/external_trait_impls/rayon/raw.rs +++ b/src/external_trait_impls/rayon/raw.rs @@ -1,14 +1,14 @@ +use crate::raw::Bucket; +use crate::raw::{RawIterRange, RawTable}; +use crate::scopeguard::guard; use alloc::alloc::dealloc; use core::marker::PhantomData; use core::mem; use core::ptr::NonNull; -use raw::Bucket; -use raw::{RawIterRange, RawTable}; use rayon::iter::{ plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer}, ParallelIterator, }; -use scopeguard::guard; /// Parallel iterator which returns a raw pointer to every full bucket in the table. pub struct RawParIter { @@ -87,9 +87,9 @@ pub struct RawParDrain<'a, T> { _marker: PhantomData<&'a RawTable>, } -unsafe impl<'a, T> Send for RawParDrain<'a, T> {} +unsafe impl Send for RawParDrain<'_, T> {} -impl<'a, T: Send> ParallelIterator for RawParDrain<'a, T> { +impl ParallelIterator for RawParDrain<'_, T> { type Item = T; #[inline] @@ -107,7 +107,7 @@ impl<'a, T: Send> ParallelIterator for RawParDrain<'a, T> { } } -impl<'a, T> Drop for RawParDrain<'a, T> { +impl Drop for RawParDrain<'_, T> { fn drop(&mut self) { // If drive_unindexed is not called then simply clear the table. unsafe { self.table.as_mut().clear() } @@ -184,7 +184,7 @@ impl RawTable { /// Returns a parallel iterator which consumes all elements of a `RawTable` /// without freeing its memory allocation. #[inline] - pub fn par_drain(&mut self) -> RawParDrain { + pub fn par_drain(&mut self) -> RawParDrain<'_, T> { RawParDrain { table: NonNull::from(self), _marker: PhantomData, diff --git a/src/external_trait_impls/rayon/set.rs b/src/external_trait_impls/rayon/set.rs index 6c12c5b78f..d5f50d3b87 100644 --- a/src/external_trait_impls/rayon/set.rs +++ b/src/external_trait_impls/rayon/set.rs @@ -1,7 +1,7 @@ //! Rayon extensions for `HashSet`. +use crate::hash_set::HashSet; use core::hash::{BuildHasher, Hash}; -use hash_set::HashSet; use rayon::iter::plumbing::UnindexedConsumer; use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelExtend, ParallelIterator}; @@ -44,7 +44,7 @@ pub struct ParDrain<'a, T, S> { set: &'a mut HashSet, } -impl<'a, T: Send, S: Send> ParallelIterator for ParDrain<'a, T, S> { +impl ParallelIterator for ParDrain<'_, T, S> { type Item = T; fn drive_unindexed(self, consumer: C) -> C::Result @@ -68,7 +68,7 @@ impl<'a, T: Send, S: Send> ParallelIterator for ParDrain<'a, T, S> { /// [`par_iter`]: /hashbrown/struct.HashSet.html#method.par_iter /// [`HashSet`]: /hashbrown/struct.HashSet.html /// [`IntoParallelRefIterator`]: https://docs.rs/rayon/1.0/rayon/iter/trait.IntoParallelRefIterator.html -pub struct ParIter<'a, T: 'a, S: 'a> { +pub struct ParIter<'a, T, S> { set: &'a HashSet, } @@ -91,7 +91,7 @@ impl<'a, T: Sync, S: Sync> ParallelIterator for ParIter<'a, T, S> { /// /// [`par_difference`]: /hashbrown/struct.HashSet.html#method.par_difference /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParDifference<'a, T: 'a, S: 'a> { +pub struct ParDifference<'a, T, S> { a: &'a HashSet, b: &'a HashSet, } @@ -123,7 +123,7 @@ where /// /// [`par_symmetric_difference`]: /hashbrown/struct.HashSet.html#method.par_symmetric_difference /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParSymmetricDifference<'a, T: 'a, S: 'a> { +pub struct ParSymmetricDifference<'a, T, S> { a: &'a HashSet, b: &'a HashSet, } @@ -154,7 +154,7 @@ where /// /// [`par_intersection`]: /hashbrown/struct.HashSet.html#method.par_intersection /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParIntersection<'a, T: 'a, S: 'a> { +pub struct ParIntersection<'a, T, S> { a: &'a HashSet, b: &'a HashSet, } @@ -184,7 +184,7 @@ where /// /// [`par_union`]: /hashbrown/struct.HashSet.html#method.par_union /// [`HashSet`]: /hashbrown/struct.HashSet.html -pub struct ParUnion<'a, T: 'a, S: 'a> { +pub struct ParUnion<'a, T, S> { a: &'a HashSet, b: &'a HashSet, } @@ -284,7 +284,7 @@ where /// Consumes (potentially in parallel) all values in an arbitrary order, /// while preserving the set's allocated memory for reuse. #[inline] - pub fn par_drain(&mut self) -> ParDrain { + pub fn par_drain(&mut self) -> ParDrain<'_, T, S> { ParDrain { set: self } } } @@ -381,7 +381,7 @@ mod test_par_set { use rayon::prelude::*; - use hash_set::HashSet; + use crate::hash_set::HashSet; #[test] fn test_disjoint() { diff --git a/src/external_trait_impls/serde.rs b/src/external_trait_impls/serde.rs index 760a1a75d7..5adac8cd43 100644 --- a/src/external_trait_impls/serde.rs +++ b/src/external_trait_impls/serde.rs @@ -17,7 +17,7 @@ mod map { use serde::de::{Deserialize, Deserializer, MapAccess, Visitor}; use serde::ser::{Serialize, Serializer}; - use hash_map::HashMap; + use crate::hash_map::HashMap; use super::size_hint; @@ -58,7 +58,7 @@ mod map { { type Value = HashMap; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a map") } @@ -95,7 +95,7 @@ mod set { use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; use serde::ser::{Serialize, Serializer}; - use hash_set::HashSet; + use crate::hash_set::HashSet; use super::size_hint; @@ -133,7 +133,7 @@ mod set { { type Value = HashSet; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a sequence") } @@ -165,7 +165,7 @@ mod set { where D: Deserializer<'de>, { - struct SeqInPlaceVisitor<'a, T: 'a, S: 'a>(&'a mut HashSet); + struct SeqInPlaceVisitor<'a, T, S>(&'a mut HashSet); impl<'a, 'de, T, S> Visitor<'de> for SeqInPlaceVisitor<'a, T, S> where @@ -174,7 +174,7 @@ mod set { { type Value = (); - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a sequence") } diff --git a/src/fx.rs b/src/fx.rs index 7cb7bf9793..c7eb37624b 100644 --- a/src/fx.rs +++ b/src/fx.rs @@ -50,7 +50,8 @@ impl Hasher for FxHasher { 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>()); + $src.as_ptr() + .copy_to_nonoverlapping(&mut data as *mut $ty as *mut u8, size_of::<$ty>()); } data }}; diff --git a/src/lib.rs b/src/lib.rs index b807c9bcdf..aa352446bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,41 +24,36 @@ )] #![warn(missing_docs)] #![allow(clippy::module_name_repetitions)] +#![warn(rust_2018_idioms)] #[cfg(test)] +#[macro_use] extern crate std; -#[cfg(test)] -extern crate rand; #[cfg(feature = "nightly")] #[cfg_attr(test, macro_use)] extern crate alloc; -#[cfg(feature = "rayon")] -extern crate rayon; -#[cfg(feature = "serde")] -extern crate serde; #[cfg(not(feature = "nightly"))] -#[cfg_attr(test, macro_use)] extern crate std as alloc; #[macro_use] mod macros; -mod scopeguard; mod external_trait_impls; mod fx; mod map; mod raw; -mod set; #[cfg(feature = "rustc-dep-of-std")] mod rustc_entry; +mod scopeguard; +mod set; pub mod hash_map { //! A hash map implemented with quadratic probing and SIMD lookup. - pub use map::*; + pub use crate::map::*; #[cfg(feature = "rustc-dep-of-std")] - pub use rustc_entry::*; + pub use crate::rustc_entry::*; #[cfg(feature = "rayon")] /// [rayon]-based parallel iterator types for hash maps. @@ -67,12 +62,12 @@ pub mod hash_map { /// /// [rayon]: https://docs.rs/rayon/1.0/rayon pub mod rayon { - pub use external_trait_impls::rayon::map::*; + pub use crate::external_trait_impls::rayon::map::*; } } pub mod hash_set { //! A hash set implemented as a `HashMap` where the value is `()`. - pub use set::*; + pub use crate::set::*; #[cfg(feature = "rayon")] /// [rayon]-based parallel iterator types for hash sets. @@ -81,12 +76,12 @@ pub mod hash_set { /// /// [rayon]: https://docs.rs/rayon/1.0/rayon pub mod rayon { - pub use external_trait_impls::rayon::set::*; + pub use crate::external_trait_impls::rayon::set::*; } } -pub use map::HashMap; -pub use set::HashSet; +pub use crate::map::HashMap; +pub use crate::set::HashSet; /// Augments `AllocErr` with a `CapacityOverflow` variant. #[derive(Clone, PartialEq, Eq, Debug)] diff --git a/src/map.rs b/src/map.rs index bd3533eb02..3f3d1311ca 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,3 +1,5 @@ +use crate::raw::{Bucket, RawDrain, RawIntoIter, RawIter, RawTable}; +use crate::CollectionAllocErr; use core::borrow::Borrow; use core::fmt::{self, Debug}; use core::hash::{BuildHasher, Hash, Hasher}; @@ -5,10 +7,8 @@ use core::iter::{FromIterator, FusedIterator}; use core::marker::PhantomData; use core::mem; use core::ops::Index; -use raw::{Bucket, RawDrain, RawIntoIter, RawIter, RawTable}; -use CollectionAllocErr; -pub use fx::FxHashBuilder as DefaultHashBuilder; +pub use crate::fx::FxHashBuilder as DefaultHashBuilder; /// A hash map implemented with quadratic probing and SIMD lookup. /// @@ -343,7 +343,7 @@ impl HashMap { /// } /// ``` #[inline] - pub fn keys(&self) -> Keys { + pub fn keys(&self) -> Keys<'_, K, V> { Keys { inner: self.iter() } } @@ -365,7 +365,7 @@ impl HashMap { /// } /// ``` #[inline] - pub fn values(&self) -> Values { + pub fn values(&self) -> Values<'_, K, V> { Values { inner: self.iter() } } @@ -392,7 +392,7 @@ impl HashMap { /// } /// ``` #[inline] - pub fn values_mut(&mut self) -> ValuesMut { + pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> { ValuesMut { inner: self.iter_mut(), } @@ -416,7 +416,7 @@ impl HashMap { /// } /// ``` #[inline] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, K, V> { // Here we tie the lifetime of self to the iter. unsafe { Iter { @@ -450,7 +450,7 @@ impl HashMap { /// } /// ``` #[inline] - pub fn iter_mut(&mut self) -> IterMut { + pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { // Here we tie the lifetime of self to the iter. unsafe { IterMut { @@ -520,7 +520,7 @@ impl HashMap { /// assert!(a.is_empty()); /// ``` #[inline] - pub fn drain(&mut self) -> Drain { + pub fn drain(&mut self) -> Drain<'_, K, V> { // Here we tie the lifetime of self to the iter. unsafe { Drain { @@ -675,7 +675,7 @@ where /// assert_eq!(letters.get(&'y'), None); /// ``` #[inline] - pub fn entry(&mut self, key: K) -> Entry { + pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S> { let hash = make_hash(&self.hash_builder, &key); if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { Entry::Occupied(OccupiedEntry { @@ -990,7 +990,7 @@ where /// acting erratically, with two keys randomly masking each other. Implementations /// are free to assume this doesn't happen (within the limits of memory-safety). #[inline] - pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut { + pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S> { RawEntryBuilderMut { map: self } } @@ -1010,7 +1010,7 @@ where /// /// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`. #[inline] - pub fn raw_entry(&self) -> RawEntryBuilder { + pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> { RawEntryBuilder { map: self } } } @@ -1045,7 +1045,7 @@ where V: Debug, S: BuildHasher, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_map().entries(self.iter()).finish() } } @@ -1061,7 +1061,7 @@ where } } -impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap +impl Index<&Q> for HashMap where K: Eq + Hash + Borrow, Q: Eq + Hash, @@ -1087,15 +1087,15 @@ where /// /// [`iter`]: struct.HashMap.html#method.iter /// [`HashMap`]: struct.HashMap.html -pub struct Iter<'a, K: 'a, V: 'a> { +pub struct Iter<'a, K, V> { inner: RawIter<(K, V)>, _marker: PhantomData<(&'a K, &'a V)>, } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl<'a, K, V> Clone for Iter<'a, K, V> { +impl Clone for Iter<'_, K, V> { #[inline] - fn clone(&self) -> Iter<'a, K, V> { + fn clone(&self) -> Self { Iter { inner: self.inner.clone(), _marker: PhantomData, @@ -1103,8 +1103,8 @@ impl<'a, K, V> Clone for Iter<'a, K, V> { } } -impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Iter<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -1116,16 +1116,16 @@ impl<'a, K: Debug, V: Debug> fmt::Debug for Iter<'a, K, V> { /// /// [`iter_mut`]: struct.HashMap.html#method.iter_mut /// [`HashMap`]: struct.HashMap.html -pub struct IterMut<'a, K: 'a, V: 'a> { +pub struct IterMut<'a, K, V> { inner: RawIter<(K, V)>, // To ensure invariance with respect to V _marker: PhantomData<(&'a K, &'a mut V)>, } -impl<'a, K, V> IterMut<'a, K, V> { +impl IterMut<'_, K, V> { /// Returns a iterator of references over the remaining items. #[inline] - pub(super) fn iter(&self) -> Iter { + pub(super) fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.inner.clone(), _marker: PhantomData, @@ -1147,7 +1147,7 @@ pub struct IntoIter { impl IntoIter { /// Returns a iterator of references over the remaining items. #[inline] - pub(super) fn iter(&self) -> Iter { + pub(super) fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.inner.iter(), _marker: PhantomData, @@ -1162,22 +1162,22 @@ impl IntoIter { /// /// [`keys`]: struct.HashMap.html#method.keys /// [`HashMap`]: struct.HashMap.html -pub struct Keys<'a, K: 'a, V: 'a> { +pub struct Keys<'a, K, V> { inner: Iter<'a, K, V>, } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl<'a, K, V> Clone for Keys<'a, K, V> { +impl Clone for Keys<'_, K, V> { #[inline] - fn clone(&self) -> Keys<'a, K, V> { + fn clone(&self) -> Self { Keys { inner: self.inner.clone(), } } } -impl<'a, K: Debug, V> fmt::Debug for Keys<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Keys<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -1189,22 +1189,22 @@ impl<'a, K: Debug, V> fmt::Debug for Keys<'a, K, V> { /// /// [`values`]: struct.HashMap.html#method.values /// [`HashMap`]: struct.HashMap.html -pub struct Values<'a, K: 'a, V: 'a> { +pub struct Values<'a, K, V> { inner: Iter<'a, K, V>, } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -impl<'a, K, V> Clone for Values<'a, K, V> { +impl Clone for Values<'_, K, V> { #[inline] - fn clone(&self) -> Values<'a, K, V> { + fn clone(&self) -> Self { Values { inner: self.inner.clone(), } } } -impl<'a, K, V: Debug> fmt::Debug for Values<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Values<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -1216,14 +1216,14 @@ 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 struct Drain<'a, K, V> { inner: RawDrain<'a, (K, V)>, } -impl<'a, K, V> Drain<'a, K, V> { +impl Drain<'_, K, V> { /// Returns a iterator of references over the remaining items. #[inline] - pub(super) fn iter(&self) -> Iter { + pub(super) fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.inner.iter(), _marker: PhantomData, @@ -1238,7 +1238,7 @@ impl<'a, K, V> Drain<'a, K, V> { /// /// [`values_mut`]: struct.HashMap.html#method.values_mut /// [`HashMap`]: struct.HashMap.html -pub struct ValuesMut<'a, K: 'a, V: 'a> { +pub struct ValuesMut<'a, K, V> { inner: IterMut<'a, K, V>, } @@ -1247,7 +1247,7 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// See the [`HashMap::raw_entry_mut`] docs for usage examples. /// /// [`HashMap::raw_entry_mut`]: struct.HashMap.html#method.raw_entry_mut -pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { +pub struct RawEntryBuilderMut<'a, K, V, S> { map: &'a mut HashMap, } @@ -1271,7 +1271,7 @@ pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// It is part of the [`RawEntryMut`] enum. /// /// [`RawEntryMut`]: enum.RawEntryMut.html -pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> { +pub struct RawOccupiedEntryMut<'a, K, V> { elem: Bucket<(K, V)>, table: &'a mut RawTable<(K, V)>, } @@ -1280,7 +1280,7 @@ pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> { /// It is part of the [`RawEntryMut`] enum. /// /// [`RawEntryMut`]: enum.RawEntryMut.html -pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> { +pub struct RawVacantEntryMut<'a, K, V, S> { table: &'a mut RawTable<(K, V)>, hash_builder: &'a S, } @@ -1290,7 +1290,7 @@ pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// See the [`HashMap::raw_entry`] docs for usage examples. /// /// [`HashMap::raw_entry`]: struct.HashMap.html#method.raw_entry -pub struct RawEntryBuilder<'a, K: 'a, V: 'a, S: 'a> { +pub struct RawEntryBuilder<'a, K, V, S> { map: &'a HashMap, } @@ -1652,14 +1652,14 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { } } -impl<'a, K, V, S> Debug for RawEntryBuilderMut<'a, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for RawEntryBuilderMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawEntryBuilder").finish() } } -impl<'a, K: Debug, V: Debug, S> Debug for RawEntryMut<'a, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for RawEntryMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), RawEntryMut::Occupied(ref o) => f.debug_tuple("RawEntry").field(o).finish(), @@ -1667,8 +1667,8 @@ impl<'a, K: Debug, V: Debug, S> Debug for RawEntryMut<'a, K, V, S> { } } -impl<'a, K: Debug, V: Debug> Debug for RawOccupiedEntryMut<'a, K, V> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for RawOccupiedEntryMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawOccupiedEntryMut") .field("key", self.key()) .field("value", self.get()) @@ -1676,14 +1676,14 @@ impl<'a, K: Debug, V: Debug> Debug for RawOccupiedEntryMut<'a, K, V> { } } -impl<'a, K, V, S> Debug for RawVacantEntryMut<'a, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for RawVacantEntryMut<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawVacantEntryMut").finish() } } -impl<'a, K, V, S> Debug for RawEntryBuilder<'a, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for RawEntryBuilder<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawEntryBuilder").finish() } } @@ -1702,8 +1702,8 @@ pub enum Entry<'a, K: 'a, V: 'a, S: 'a> { Vacant(VacantEntry<'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 { +impl Debug for Entry<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(), Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(), @@ -1715,20 +1715,20 @@ impl<'a, K: 'a + Debug, V: 'a + Debug, S: 'a> Debug for Entry<'a, K, V, S> { /// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html -pub struct OccupiedEntry<'a, K: 'a, V: 'a, S: 'a> { +pub struct OccupiedEntry<'a, K, V, S> { key: Option, elem: Bucket<(K, V)>, table: &'a mut HashMap, } -unsafe impl<'a, K, V, S> Send for OccupiedEntry<'a, K, V, S> +unsafe impl Send for OccupiedEntry<'_, K, V, S> where K: Send, V: Send, S: Send, { } -unsafe impl<'a, K, V, S> Sync for OccupiedEntry<'a, K, V, S> +unsafe impl Sync for OccupiedEntry<'_, K, V, S> where K: Sync, V: Sync, @@ -1736,8 +1736,8 @@ where { } -impl<'a, K: 'a + Debug, V: 'a + Debug, S> Debug for OccupiedEntry<'a, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for OccupiedEntry<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) .field("value", self.get()) @@ -1749,14 +1749,14 @@ impl<'a, K: 'a + Debug, V: 'a + Debug, S> Debug for OccupiedEntry<'a, K, V, S> { /// It is part of the [`Entry`] enum. /// /// [`Entry`]: enum.Entry.html -pub struct VacantEntry<'a, K: 'a, V: 'a, S: 'a> { +pub struct VacantEntry<'a, K, V, S> { hash: u64, key: K, table: &'a mut HashMap, } -impl<'a, K: 'a + Debug, V: 'a, S> Debug for VacantEntry<'a, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl Debug for VacantEntry<'_, K, V, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.key()).finish() } } @@ -1825,14 +1825,14 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { self.inner.size_hint() } } -impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> { +impl ExactSizeIterator for Iter<'_, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl<'a, K, V> FusedIterator for Iter<'a, K, V> {} +impl FusedIterator for Iter<'_, K, V> {} impl<'a, K, V> Iterator for IterMut<'a, K, V> { type Item = (&'a K, &'a mut V); @@ -1849,20 +1849,20 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { self.inner.size_hint() } } -impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> { +impl ExactSizeIterator for IterMut<'_, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {} +impl FusedIterator for IterMut<'_, K, V> {} -impl<'a, K, V> fmt::Debug for IterMut<'a, K, V> +impl fmt::Debug for IterMut<'_, K, V> where K: fmt::Debug, V: fmt::Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } @@ -1888,7 +1888,7 @@ impl ExactSizeIterator for IntoIter { impl FusedIterator for IntoIter {} impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } @@ -1905,13 +1905,13 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> { self.inner.size_hint() } } -impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> { +impl ExactSizeIterator for Keys<'_, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl<'a, K, V> FusedIterator for Keys<'a, K, V> {} +impl FusedIterator for Keys<'_, K, V> {} impl<'a, K, V> Iterator for Values<'a, K, V> { type Item = &'a V; @@ -1925,13 +1925,13 @@ impl<'a, K, V> Iterator for Values<'a, K, V> { self.inner.size_hint() } } -impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> { +impl ExactSizeIterator for Values<'_, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl<'a, K, V> FusedIterator for Values<'a, K, V> {} +impl FusedIterator for Values<'_, K, V> {} impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { type Item = &'a mut V; @@ -1945,20 +1945,20 @@ impl<'a, K, V> Iterator for ValuesMut<'a, K, V> { self.inner.size_hint() } } -impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> { +impl ExactSizeIterator for ValuesMut<'_, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {} +impl FusedIterator for ValuesMut<'_, K, V> {} -impl<'a, K, V> fmt::Debug for ValuesMut<'a, K, V> +impl fmt::Debug for ValuesMut<'_, K, V> where K: fmt::Debug, V: fmt::Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter()).finish() } } @@ -1975,20 +1975,20 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> { self.inner.size_hint() } } -impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { +impl ExactSizeIterator for Drain<'_, K, V> { #[inline] fn len(&self) -> usize { self.inner.len() } } -impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} +impl FusedIterator for Drain<'_, K, V> {} -impl<'a, K, V> fmt::Debug for Drain<'a, K, V> +impl fmt::Debug for Drain<'_, K, V> where K: fmt::Debug, V: fmt::Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } } @@ -2361,7 +2361,7 @@ impl<'a, K, V, S> OccupiedEntry<'a, K, V, S> { } } -impl<'a, K: 'a, V: 'a, S> VacantEntry<'a, K, V, S> { +impl<'a, K, V, S> VacantEntry<'a, K, V, S> { /// Gets a reference to the key that would be used when inserting a value /// through the `VacantEntry`. /// @@ -2523,12 +2523,12 @@ mod test_map { use super::DefaultHashBuilder; use super::Entry::{Occupied, Vacant}; use super::{HashMap, RawEntryMut}; + #[cfg(not(miri))] + use crate::CollectionAllocErr::*; use rand::{rngs::SmallRng, Rng, SeedableRng}; use std::cell::RefCell; use std::usize; use std::vec::Vec; - #[cfg(not(miri))] - use CollectionAllocErr::*; #[test] fn test_zero_capacities() { @@ -2624,7 +2624,7 @@ mod test_map { } impl Clone for Droppable { - fn clone(&self) -> Droppable { + fn clone(&self) -> Self { Droppable::new(self.k) } } diff --git a/src/raw/mod.rs b/src/raw/mod.rs index dc68bd77a9..85a81c7122 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -1,4 +1,6 @@ -use alloc::alloc::{alloc, dealloc, handle_alloc_error}; +use crate::alloc::alloc::{alloc, dealloc, handle_alloc_error}; +use crate::scopeguard::guard; +use crate::CollectionAllocErr; use core::alloc::Layout; use core::hint; use core::iter::FusedIterator; @@ -6,8 +8,6 @@ use core::marker::PhantomData; use core::mem; use core::mem::ManuallyDrop; use core::ptr::NonNull; -use scopeguard::guard; -use CollectionAllocErr; cfg_if! { // Use the SSE2 implementation if possible: it allows us to scan 16 buckets @@ -139,11 +139,11 @@ fn h2(hash: u64) -> u8 { /// Probe sequence based on triangular numbers, which is guaranteed (since our /// table size is a power of two) to visit every group of elements exactly once. -/// +/// /// A triangular probe has us jump by 1 more group every time. So first we /// jump by 1 group (meaning we just continue our linear scan), then 2 groups /// (skipping over 1 group), then 3 groups (skipping over 2 groups), and so on. -/// +/// /// Proof that the probe will visit every group in the table: /// https://fgiesen.wordpress.com/2015/02/22/triangular-numbers-mod-2n/ struct ProbeSeq { @@ -917,7 +917,7 @@ impl RawTable { /// outlives the `RawDrain`. Because we cannot make the `next` method unsafe /// on the `RawDrain`, we have to make the `drain` method unsafe. #[inline] - pub unsafe fn drain(&mut self) -> RawDrain { + pub unsafe fn drain(&mut self) -> RawDrain<'_, T> { RawDrain { iter: self.iter(), table: ManuallyDrop::new(mem::replace(self, Self::new())), @@ -1231,7 +1231,7 @@ pub struct RawIntoIter { alloc: Option<(NonNull, Layout)>, } -impl<'a, T> RawIntoIter { +impl RawIntoIter { #[inline] pub fn iter(&self) -> RawIter { self.iter.clone() @@ -1278,7 +1278,7 @@ impl ExactSizeIterator for RawIntoIter {} impl FusedIterator for RawIntoIter {} /// Iterator which consumes elements without freeing the table storage. -pub struct RawDrain<'a, T: 'a> { +pub struct RawDrain<'a, T> { iter: RawIter, // The table is moved into the iterator for the duration of the drain. This @@ -1292,17 +1292,17 @@ pub struct RawDrain<'a, T: 'a> { _marker: PhantomData<&'a RawTable>, } -impl<'a, T> RawDrain<'a, T> { +impl RawDrain<'_, T> { #[inline] pub fn iter(&self) -> RawIter { self.iter.clone() } } -unsafe impl<'a, T> Send for RawDrain<'a, T> where T: Send {} -unsafe impl<'a, T> Sync for RawDrain<'a, T> where T: Sync {} +unsafe impl Send for RawDrain<'_, T> where T: Send {} +unsafe impl Sync for RawDrain<'_, T> where T: Sync {} -impl<'a, T> Drop for RawDrain<'a, T> { +impl Drop for RawDrain<'_, T> { #[inline] fn drop(&mut self) { unsafe { @@ -1325,7 +1325,7 @@ impl<'a, T> Drop for RawDrain<'a, T> { } } -impl<'a, T> Iterator for RawDrain<'a, T> { +impl Iterator for RawDrain<'_, T> { type Item = T; #[inline] @@ -1342,5 +1342,5 @@ impl<'a, T> Iterator for RawDrain<'a, T> { } } -impl<'a, T> ExactSizeIterator for RawDrain<'a, T> {} -impl<'a, T> FusedIterator for RawDrain<'a, T> {} +impl ExactSizeIterator for RawDrain<'_, T> {} +impl FusedIterator for RawDrain<'_, T> {} diff --git a/src/rustc_entry.rs b/src/rustc_entry.rs index 2a640a2fde..5cc3bd51ae 100644 --- a/src/rustc_entry.rs +++ b/src/rustc_entry.rs @@ -1,9 +1,9 @@ use self::RustcEntry::*; +use crate::map::{make_hash, Drain, HashMap, IntoIter, Iter, IterMut}; +use crate::raw::{Bucket, RawTable}; 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 @@ -30,7 +30,7 @@ where /// assert_eq!(letters.get(&'y'), None); /// ``` #[inline] - pub fn rustc_entry(&mut self, key: K) -> RustcEntry { + pub fn rustc_entry(&mut self, key: K) -> RustcEntry<'_, K, V> { let hash = make_hash(&self.hash_builder, &key); if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { RustcEntry::Occupied(RustcOccupiedEntry { @@ -67,8 +67,8 @@ pub enum RustcEntry<'a, K: 'a, V: 'a> { 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 { +impl Debug for RustcEntry<'_, 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(), @@ -80,27 +80,27 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for RustcEntry<'a, K, V> { /// It is part of the [`RustcEntry`] enum. /// /// [`RustcEntry`]: enum.RustcEntry.html -pub struct RustcOccupiedEntry<'a, K: 'a, V: 'a> { +pub struct RustcOccupiedEntry<'a, K, V> { key: Option, elem: Bucket<(K, V)>, table: &'a mut RawTable<(K, V)>, } -unsafe impl<'a, K, V> Send for RustcOccupiedEntry<'a, K, V> +unsafe impl Send for RustcOccupiedEntry<'_, K, V> where K: Send, V: Send, { } -unsafe impl<'a, K, V> Sync for RustcOccupiedEntry<'a, K, V> +unsafe impl Sync for RustcOccupiedEntry<'_, 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 { +impl Debug for RustcOccupiedEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) .field("value", self.get()) @@ -112,14 +112,14 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for RustcOccupiedEntry<'a, K, V> { /// It is part of the [`RustcEntry`] enum. /// /// [`RustcEntry`]: enum.RustcEntry.html -pub struct RustcVacantEntry<'a, K: 'a, V: 'a> { +pub struct RustcVacantEntry<'a, K, V> { 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 { +impl Debug for RustcVacantEntry<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("VacantEntry").field(self.key()).finish() } } @@ -489,7 +489,7 @@ impl<'a, K, V> RustcOccupiedEntry<'a, K, V> { } } -impl<'a, K: 'a, V: 'a> RustcVacantEntry<'a, K, V> { +impl<'a, K, V> RustcVacantEntry<'a, K, V> { /// Gets a reference to the key that would be used when inserting a value /// through the `RustcVacantEntry`. /// @@ -542,18 +542,16 @@ impl<'a, K: 'a, V: 'a> RustcVacantEntry<'a, K, V> { /// assert_eq!(map["poneyland"], 37); /// ``` #[inline] - pub fn insert(self, value: V) -> &'a mut V - { + 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> { +impl IterMut<'_, K, V> { /// Returns a iterator of references over the remaining items. #[inline] - pub fn rustc_iter(&self) -> Iter { + pub fn rustc_iter(&self) -> Iter<'_, K, V> { self.iter() } } @@ -561,15 +559,15 @@ impl<'a, K, V> IterMut<'a, K, V> { impl IntoIter { /// Returns a iterator of references over the remaining items. #[inline] - pub fn rustc_iter(&self) -> Iter { + pub fn rustc_iter(&self) -> Iter<'_, K, V> { self.iter() } } -impl<'a, K, V> Drain<'a, K, V> { +impl Drain<'_, K, V> { /// Returns a iterator of references over the remaining items. #[inline] - pub fn rustc_iter(&self) -> Iter { + pub fn rustc_iter(&self) -> Iter<'_, K, V> { self.iter() } } diff --git a/src/set.rs b/src/set.rs index 67e13c9ad7..8659a256fd 100644 --- a/src/set.rs +++ b/src/set.rs @@ -1,9 +1,9 @@ +use crate::CollectionAllocErr; use core::borrow::Borrow; use core::fmt; use core::hash::{BuildHasher, Hash}; use core::iter::{Chain, FromIterator, FusedIterator}; use core::ops::{BitAnd, BitOr, BitXor, Sub}; -use CollectionAllocErr; use super::map::{self, DefaultHashBuilder, HashMap, Keys}; @@ -187,7 +187,7 @@ impl HashSet { /// } /// ``` #[inline] - pub fn iter(&self) -> Iter { + pub fn iter(&self) -> Iter<'_, T> { Iter { iter: self.map.keys(), } @@ -245,7 +245,7 @@ impl HashSet { /// assert!(set.is_empty()); /// ``` #[inline] - pub fn drain(&mut self) -> Drain { + pub fn drain(&mut self) -> Drain<'_, T> { Drain { iter: self.map.drain(), } @@ -821,7 +821,7 @@ where T: Eq + Hash + fmt::Debug, S: BuildHasher, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_set().entries(self.iter()).finish() } } @@ -875,7 +875,7 @@ where } } -impl<'a, 'b, T, S> BitOr<&'b HashSet> for &'a HashSet +impl BitOr<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default, @@ -907,7 +907,7 @@ where } } -impl<'a, 'b, T, S> BitAnd<&'b HashSet> for &'a HashSet +impl BitAnd<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default, @@ -939,7 +939,7 @@ where } } -impl<'a, 'b, T, S> BitXor<&'b HashSet> for &'a HashSet +impl BitXor<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default, @@ -971,7 +971,7 @@ where } } -impl<'a, 'b, T, S> Sub<&'b HashSet> for &'a HashSet +impl Sub<&HashSet> for &HashSet where T: Eq + Hash + Clone, S: BuildHasher + Default, @@ -1010,7 +1010,7 @@ where /// /// [`HashSet`]: struct.HashSet.html /// [`iter`]: struct.HashSet.html#method.iter -pub struct Iter<'a, K: 'a> { +pub struct Iter<'a, K> { iter: Keys<'a, K, ()>, } @@ -1032,7 +1032,7 @@ pub struct IntoIter { /// /// [`HashSet`]: struct.HashSet.html /// [`drain`]: struct.HashSet.html#method.drain -pub struct Drain<'a, K: 'a> { +pub struct Drain<'a, K> { iter: map::Drain<'a, K, ()>, } @@ -1043,7 +1043,7 @@ pub struct Drain<'a, K: 'a> { /// /// [`HashSet`]: struct.HashSet.html /// [`intersection`]: struct.HashSet.html#method.intersection -pub struct Intersection<'a, T: 'a, S: 'a> { +pub struct Intersection<'a, T, S> { // iterator of the first set iter: Iter<'a, T>, // the second set @@ -1057,7 +1057,7 @@ pub struct Intersection<'a, T: 'a, S: 'a> { /// /// [`HashSet`]: struct.HashSet.html /// [`difference`]: struct.HashSet.html#method.difference -pub struct Difference<'a, T: 'a, S: 'a> { +pub struct Difference<'a, T, S> { // iterator of the first set iter: Iter<'a, T>, // the second set @@ -1071,7 +1071,7 @@ pub struct Difference<'a, T: 'a, S: 'a> { /// /// [`HashSet`]: struct.HashSet.html /// [`symmetric_difference`]: struct.HashSet.html#method.symmetric_difference -pub struct SymmetricDifference<'a, T: 'a, S: 'a> { +pub struct SymmetricDifference<'a, T, S> { iter: Chain, Difference<'a, T, S>>, } @@ -1082,7 +1082,7 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> { /// /// [`HashSet`]: struct.HashSet.html /// [`union`]: struct.HashSet.html#method.union -pub struct Union<'a, T: 'a, S: 'a> { +pub struct Union<'a, T, S> { iter: Chain, Difference<'a, T, S>>, } @@ -1128,9 +1128,9 @@ impl IntoIterator for HashSet { } } -impl<'a, K> Clone for Iter<'a, K> { +impl Clone for Iter<'_, K> { #[inline] - fn clone(&self) -> Iter<'a, K> { + fn clone(&self) -> Self { Iter { iter: self.iter.clone(), } @@ -1154,10 +1154,10 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> { self.iter.len() } } -impl<'a, K> FusedIterator for Iter<'a, K> {} +impl FusedIterator for Iter<'_, K> {} -impl<'a, K: fmt::Debug> fmt::Debug for Iter<'a, K> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Iter<'_, K> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } @@ -1183,13 +1183,13 @@ impl ExactSizeIterator for IntoIter { impl FusedIterator for IntoIter {} impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let entries_iter = self.iter.iter().map(|(k, _)| k); f.debug_list().entries(entries_iter).finish() } } -impl<'a, K> Iterator for Drain<'a, K> { +impl Iterator for Drain<'_, K> { type Item = K; #[inline] @@ -1201,24 +1201,24 @@ impl<'a, K> Iterator for Drain<'a, K> { self.iter.size_hint() } } -impl<'a, K> ExactSizeIterator for Drain<'a, K> { +impl ExactSizeIterator for Drain<'_, K> { #[inline] fn len(&self) -> usize { self.iter.len() } } -impl<'a, K> FusedIterator for Drain<'a, K> {} +impl FusedIterator for Drain<'_, K> {} -impl<'a, K: fmt::Debug> fmt::Debug for Drain<'a, K> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +impl fmt::Debug for Drain<'_, K> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let entries_iter = self.iter.iter().map(|(k, _)| k); f.debug_list().entries(entries_iter).finish() } } -impl<'a, T, S> Clone for Intersection<'a, T, S> { +impl Clone for Intersection<'_, T, S> { #[inline] - fn clone(&self) -> Intersection<'a, T, S> { + fn clone(&self) -> Self { Intersection { iter: self.iter.clone(), ..*self @@ -1250,26 +1250,26 @@ where } } -impl<'a, T, S> fmt::Debug for Intersection<'a, T, S> +impl fmt::Debug for Intersection<'_, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } -impl<'a, T, S> FusedIterator for Intersection<'a, T, S> +impl FusedIterator for Intersection<'_, T, S> where T: Eq + Hash, S: BuildHasher, { } -impl<'a, T, S> Clone for Difference<'a, T, S> { +impl Clone for Difference<'_, T, S> { #[inline] - fn clone(&self) -> Difference<'a, T, S> { + fn clone(&self) -> Self { Difference { iter: self.iter.clone(), ..*self @@ -1301,26 +1301,26 @@ where } } -impl<'a, T, S> FusedIterator for Difference<'a, T, S> +impl FusedIterator for Difference<'_, T, S> where T: Eq + Hash, S: BuildHasher, { } -impl<'a, T, S> fmt::Debug for Difference<'a, T, S> +impl fmt::Debug for Difference<'_, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } -impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> { +impl Clone for SymmetricDifference<'_, T, S> { #[inline] - fn clone(&self) -> SymmetricDifference<'a, T, S> { + fn clone(&self) -> Self { SymmetricDifference { iter: self.iter.clone(), } @@ -1344,45 +1344,45 @@ where } } -impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S> +impl FusedIterator for SymmetricDifference<'_, T, S> where T: Eq + Hash, S: BuildHasher, { } -impl<'a, T, S> fmt::Debug for SymmetricDifference<'a, T, S> +impl fmt::Debug for SymmetricDifference<'_, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } -impl<'a, T, S> Clone for Union<'a, T, S> { +impl Clone for Union<'_, T, S> { #[inline] - fn clone(&self) -> Union<'a, T, S> { + fn clone(&self) -> Self { Union { iter: self.iter.clone(), } } } -impl<'a, T, S> FusedIterator for Union<'a, T, S> +impl FusedIterator for Union<'_, T, S> where T: Eq + Hash, S: BuildHasher, { } -impl<'a, T, S> fmt::Debug for Union<'a, T, S> +impl fmt::Debug for Union<'_, T, S> where T: fmt::Debug + Eq + Hash, S: BuildHasher, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.clone()).finish() } } diff --git a/tests/rayon.rs b/tests/rayon.rs index 581021f69b..39b47708dd 100644 --- a/tests/rayon.rs +++ b/tests/rayon.rs @@ -1,9 +1,7 @@ #![cfg(feature = "rayon")] -extern crate hashbrown; #[macro_use] extern crate lazy_static; -extern crate rayon; use hashbrown::{HashMap, HashSet}; use rayon::iter::{ diff --git a/tests/serde.rs b/tests/serde.rs index db93607bf6..f32cd98481 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -1,8 +1,5 @@ #![cfg(feature = "serde")] -extern crate hashbrown; -extern crate serde_test; - use hashbrown::{HashMap, HashSet}; use serde_test::{assert_tokens, Token}; diff --git a/tests/set.rs b/tests/set.rs index a500af905d..332f3f6f07 100644 --- a/tests/set.rs +++ b/tests/set.rs @@ -1,6 +1,4 @@ #![cfg(not(miri))] // FIXME: takes too long -extern crate hashbrown; -extern crate rand; use hashbrown::HashSet; use rand::{distributions::Alphanumeric, Rng, SeedableRng, XorShiftRng}; From f9bcc42d9fc2d8ead2d2de076e0b41ed9ea32ee5 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sat, 9 Mar 2019 01:19:12 +0000 Subject: [PATCH 4/4] Add #[may_dangle] to RawIntoIter Also adds PhantomData to RawTable and RawIntoIter --- src/external_trait_impls/rayon/raw.rs | 4 +-- src/map.rs | 16 ++++++------ src/raw/mod.rs | 36 ++++++++++++++++++++++++--- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/external_trait_impls/rayon/raw.rs b/src/external_trait_impls/rayon/raw.rs index 047b5858d2..6834705cfd 100644 --- a/src/external_trait_impls/rayon/raw.rs +++ b/src/external_trait_impls/rayon/raw.rs @@ -84,7 +84,7 @@ pub struct RawParDrain<'a, T> { // We don't use a &'a mut RawTable because we want RawParDrain to be // covariant over T. table: NonNull>, - _marker: PhantomData<&'a RawTable>, + marker: PhantomData<&'a RawTable>, } unsafe impl Send for RawParDrain<'_, T> {} @@ -187,7 +187,7 @@ impl RawTable { pub fn par_drain(&mut self) -> RawParDrain<'_, T> { RawParDrain { table: NonNull::from(self), - _marker: PhantomData, + marker: PhantomData, } } } diff --git a/src/map.rs b/src/map.rs index 3f3d1311ca..674a40bba8 100644 --- a/src/map.rs +++ b/src/map.rs @@ -421,7 +421,7 @@ impl HashMap { unsafe { Iter { inner: self.table.iter(), - _marker: PhantomData, + marker: PhantomData, } } } @@ -455,7 +455,7 @@ impl HashMap { unsafe { IterMut { inner: self.table.iter(), - _marker: PhantomData, + marker: PhantomData, } } } @@ -1089,7 +1089,7 @@ where /// [`HashMap`]: struct.HashMap.html pub struct Iter<'a, K, V> { inner: RawIter<(K, V)>, - _marker: PhantomData<(&'a K, &'a V)>, + marker: PhantomData<(&'a K, &'a V)>, } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` @@ -1098,7 +1098,7 @@ impl Clone for Iter<'_, K, V> { fn clone(&self) -> Self { Iter { inner: self.inner.clone(), - _marker: PhantomData, + marker: PhantomData, } } } @@ -1119,7 +1119,7 @@ impl fmt::Debug for Iter<'_, K, V> { pub struct IterMut<'a, K, V> { inner: RawIter<(K, V)>, // To ensure invariance with respect to V - _marker: PhantomData<(&'a K, &'a mut V)>, + marker: PhantomData<(&'a K, &'a mut V)>, } impl IterMut<'_, K, V> { @@ -1128,7 +1128,7 @@ impl IterMut<'_, K, V> { pub(super) fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.inner.clone(), - _marker: PhantomData, + marker: PhantomData, } } } @@ -1150,7 +1150,7 @@ impl IntoIter { pub(super) fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.inner.iter(), - _marker: PhantomData, + marker: PhantomData, } } } @@ -1226,7 +1226,7 @@ impl Drain<'_, K, V> { pub(super) fn iter(&self) -> Iter<'_, K, V> { Iter { inner: self.inner.iter(), - _marker: PhantomData, + marker: PhantomData, } } } diff --git a/src/raw/mod.rs b/src/raw/mod.rs index 85a81c7122..199bdf1205 100644 --- a/src/raw/mod.rs +++ b/src/raw/mod.rs @@ -343,6 +343,9 @@ pub struct RawTable { // Number of elements in the table, only really used by len() items: usize, + + // Tell dropck that we own instances of T. + marker: PhantomData, } impl RawTable { @@ -359,6 +362,7 @@ impl RawTable { bucket_mask: 0, items: 0, growth_left: 0, + marker: PhantomData, } } @@ -380,6 +384,7 @@ impl RawTable { bucket_mask: buckets - 1, items: 0, growth_left: bucket_mask_to_capacity(buckets - 1), + marker: PhantomData, }) } @@ -922,7 +927,7 @@ impl RawTable { iter: self.iter(), table: ManuallyDrop::new(mem::replace(self, Self::new())), orig_table: NonNull::from(self), - _marker: PhantomData, + marker: PhantomData, } } @@ -1039,7 +1044,11 @@ impl IntoIterator for RawTable { unsafe { let iter = self.iter(); let alloc = self.into_alloc(); - RawIntoIter { iter, alloc } + RawIntoIter { + iter, + alloc, + marker: PhantomData, + } } } } @@ -1229,6 +1238,7 @@ impl FusedIterator for RawIter {} pub struct RawIntoIter { iter: RawIter, alloc: Option<(NonNull, Layout)>, + marker: PhantomData, } impl RawIntoIter { @@ -1241,6 +1251,26 @@ impl RawIntoIter { unsafe impl Send for RawIntoIter where T: Send {} unsafe impl Sync for RawIntoIter where T: Sync {} +#[cfg(feature = "nightly")] +unsafe impl<#[may_dangle] T> Drop for RawIntoIter { + #[inline] + fn drop(&mut self) { + unsafe { + // Drop all remaining elements + if mem::needs_drop::() { + while let Some(item) = self.iter.next() { + item.drop(); + } + } + + // Free the table + if let Some((ptr, layout)) = self.alloc { + dealloc(ptr.as_ptr(), layout); + } + } + } +} +#[cfg(not(feature = "nightly"))] impl Drop for RawIntoIter { #[inline] fn drop(&mut self) { @@ -1289,7 +1319,7 @@ pub struct RawDrain<'a, T> { // We don't use a &'a mut RawTable because we want RawDrain to be // covariant over T. - _marker: PhantomData<&'a RawTable>, + marker: PhantomData<&'a RawTable>, } impl RawDrain<'_, T> {