Skip to content

Commit

Permalink
Sync with upstream changes in rust-lang/rust
Browse files Browse the repository at this point in the history
  • Loading branch information
Amanieu committed Jun 17, 2020
1 parent 9498006 commit 80ce422
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 41 deletions.
10 changes: 6 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
core_intrinsics,
dropck_eyepatch,
specialization,
extend_one,
)
)]
#![allow(
Expand Down Expand Up @@ -107,14 +108,15 @@ pub mod hash_set {
pub use crate::map::HashMap;
pub use crate::set::HashSet;

/// Augments `AllocErr` with a `CapacityOverflow` variant.
/// The error type for `try_reserve` methods.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum CollectionAllocErr {
pub enum TryReserveError {
/// Error due to the computed capacity exceeding the collection's maximum
/// (usually `isize::MAX` bytes).
CapacityOverflow,
/// Error due to the allocator.
AllocErr {

/// The memory allocator returned an error
AllocError {
/// The layout of the allocation request that failed.
layout: alloc::alloc::Layout,
},
Expand Down
68 changes: 56 additions & 12 deletions src/map.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::raw::{Bucket, RawDrain, RawIntoIter, RawIter, RawTable};
use crate::CollectionAllocErr;
use crate::TryReserveError;
use core::borrow::Borrow;
use core::fmt::{self, Debug};
use core::hash::{BuildHasher, Hash, Hasher};
Expand Down Expand Up @@ -181,11 +181,8 @@ pub enum DefaultHashBuilder {}
/// ```
/// use hashbrown::HashMap;
///
/// let timber_resources: HashMap<&str, i32> =
/// [("Norway", 100),
/// ("Denmark", 50),
/// ("Iceland", 10)]
/// .iter().cloned().collect();
/// let timber_resources: HashMap<&str, i32> = [("Norway", 100), ("Denmark", 50), ("Iceland", 10)]
/// .iter().cloned().collect();
/// // use the values stored in map
/// ```
pub struct HashMap<K, V, S = DefaultHashBuilder> {
Expand Down Expand Up @@ -262,6 +259,9 @@ impl<K, V, S> HashMap<K, V, S> {
/// cause many collisions and very poor performance. Setting it
/// manually using this function can expose a DoS attack vector.
///
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
/// the HashMap to be useful, see its documentation for details.
///
/// # Examples
///
/// ```
Expand All @@ -272,6 +272,8 @@ impl<K, V, S> HashMap<K, V, S> {
/// let mut map = HashMap::with_hasher(s);
/// map.insert(1, 2);
/// ```
///
/// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
#[cfg_attr(feature = "inline-more", inline)]
pub fn with_hasher(hash_builder: S) -> Self {
Self {
Expand All @@ -291,6 +293,9 @@ impl<K, V, S> HashMap<K, V, S> {
/// cause many collisions and very poor performance. Setting it
/// manually using this function can expose a DoS attack vector.
///
/// The `hash_builder` passed should implement the [`BuildHasher`] trait for
/// the HashMap to be useful, see its documentation for details.
///
/// # Examples
///
/// ```
Expand All @@ -301,6 +306,8 @@ impl<K, V, S> HashMap<K, V, S> {
/// let mut map = HashMap::with_capacity_and_hasher(10, s);
/// map.insert(1, 2);
/// ```
///
/// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html
#[cfg_attr(feature = "inline-more", inline)]
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self {
Self {
Expand Down Expand Up @@ -614,7 +621,7 @@ where
/// map.try_reserve(10).expect("why is the test harness OOMing on 10 bytes?");
/// ```
#[cfg_attr(feature = "inline-more", inline)]
pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
let hash_builder = &self.hash_builder;
self.table
.try_reserve(additional, |x| make_hash(hash_builder, &x.0))
Expand Down Expand Up @@ -1218,7 +1225,7 @@ impl<K, V> IterMut<'_, K, V> {

/// An owning iterator over the entries of a `HashMap`.
///
/// This `struct` is created by the [`into_iter`] method on [`HashMap`][`HashMap`]
/// This `struct` is created by the [`into_iter`] method on [`HashMap`]
/// (provided by the `IntoIterator` trait). See its documentation for more.
///
/// [`into_iter`]: struct.HashMap.html#method.into_iter
Expand Down Expand Up @@ -2711,6 +2718,8 @@ where
}
}

/// Inserts all new key-values from the iterator and replaces values with existing
/// keys with new values returned from the iterator.
impl<K, V, S> Extend<(K, V)> for HashMap<K, V, S>
where
K: Eq + Hash,
Expand All @@ -2733,6 +2742,27 @@ where
self.insert(k, v);
});
}

#[inline]
#[cfg(feature = "nightly")]
fn extend_one(&mut self, (k, v): (K, V)) {
self.insert(k, v);
}

#[inline]
#[cfg(feature = "nightly")]
fn extend_reserve(&mut self, additional: usize) {
// Keys may be already present or show multiple times in the iterator.
// Reserve the entire hint lower bound if the map is empty.
// Otherwise reserve half the hint (rounded up), so the map
// will only resize twice in the worst case.
let reserve = if self.is_empty() {
additional
} else {
(additional + 1) / 2
};
self.reserve(reserve);
}
}

impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S>
Expand All @@ -2745,6 +2775,18 @@ where
fn extend<T: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: T) {
self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
}

#[inline]
#[cfg(feature = "nightly")]
fn extend_one(&mut self, (k, v): (&'a K, &'a V)) {
self.insert(*k, *v);
}

#[inline]
#[cfg(feature = "nightly")]
fn extend_reserve(&mut self, additional: usize) {
Extend::<(K, V)>::extend_reserve(self, additional);
}
}

#[allow(dead_code)]
Expand Down Expand Up @@ -2791,7 +2833,7 @@ mod test_map {
use super::DefaultHashBuilder;
use super::Entry::{Occupied, Vacant};
use super::{HashMap, RawEntryMut};
use crate::CollectionAllocErr::*;
use crate::TryReserveError::*;
use rand::{rngs::SmallRng, Rng, SeedableRng};
use std::cell::RefCell;
use std::usize;
Expand Down Expand Up @@ -3411,13 +3453,15 @@ mod test_map {

#[test]
fn test_from_iter() {
let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];
let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)];

let map: HashMap<_, _> = xs.iter().cloned().collect();

for &(k, v) in &xs {
assert_eq!(map.get(&k), Some(&v));
}

assert_eq!(map.iter().len(), xs.len() - 1);
}

#[test]
Expand Down Expand Up @@ -3698,12 +3742,12 @@ mod test_map {
panic!("usize::MAX should trigger an overflow!");
}

if let Err(AllocErr { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) {
if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) {
} else {
// This may succeed if there is enough free memory. Attempt to
// allocate a second hashmap to ensure the allocation will fail.
let mut empty_bytes2: HashMap<u8, u8> = HashMap::new();
if let Err(AllocErr { .. }) = empty_bytes2.try_reserve(MAX_USIZE / 8) {
if let Err(AllocError { .. }) = empty_bytes2.try_reserve(MAX_USIZE / 8) {
} else {
panic!("usize::MAX / 8 should trigger an OOM!");
}
Expand Down
38 changes: 23 additions & 15 deletions src/raw/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::alloc::alloc::{alloc, dealloc, handle_alloc_error};
use crate::scopeguard::guard;
use crate::CollectionAllocErr;
use crate::TryReserveError;
use core::alloc::Layout;
use core::hint;
use core::iter::FusedIterator;
Expand Down Expand Up @@ -73,18 +73,18 @@ enum Fallibility {
impl Fallibility {
/// Error to return on capacity overflow.
#[cfg_attr(feature = "inline-more", inline)]
fn capacity_overflow(self) -> CollectionAllocErr {
fn capacity_overflow(self) -> TryReserveError {
match self {
Fallibility::Fallible => CollectionAllocErr::CapacityOverflow,
Fallibility::Fallible => TryReserveError::CapacityOverflow,
Fallibility::Infallible => panic!("Hash table capacity overflow"),
}
}

/// Error to return on allocation error.
#[cfg_attr(feature = "inline-more", inline)]
fn alloc_err(self, layout: Layout) -> CollectionAllocErr {
fn alloc_err(self, layout: Layout) -> TryReserveError {
match self {
Fallibility::Fallible => CollectionAllocErr::AllocErr { layout },
Fallibility::Fallible => TryReserveError::AllocError { layout },
Fallibility::Infallible => handle_alloc_error(layout),
}
}
Expand Down Expand Up @@ -246,13 +246,15 @@ fn calculate_layout<T>(buckets: usize) -> Option<(Layout, usize)> {

// Manual layout calculation since Layout methods are not yet stable.
let ctrl_align = usize::max(mem::align_of::<T>(), Group::WIDTH);
let ctrl_offset = mem::size_of::<T>().checked_mul(buckets)?
.checked_add(ctrl_align - 1)? & !(ctrl_align - 1);
let ctrl_offset = mem::size_of::<T>()
.checked_mul(buckets)?
.checked_add(ctrl_align - 1)?
& !(ctrl_align - 1);
let len = ctrl_offset.checked_add(buckets + Group::WIDTH)?;

Some((
unsafe { Layout::from_size_align_unchecked(len, ctrl_align) },
ctrl_offset
ctrl_offset,
))
}

Expand Down Expand Up @@ -392,7 +394,7 @@ impl<T> RawTable<T> {
unsafe fn new_uninitialized(
buckets: usize,
fallability: Fallibility,
) -> Result<Self, CollectionAllocErr> {
) -> Result<Self, TryReserveError> {
debug_assert!(buckets.is_power_of_two());
let (layout, ctrl_offset) =
calculate_layout::<T>(buckets).ok_or_else(|| fallability.capacity_overflow())?;
Expand All @@ -412,7 +414,7 @@ impl<T> RawTable<T> {
fn try_with_capacity(
capacity: usize,
fallability: Fallibility,
) -> Result<Self, CollectionAllocErr> {
) -> Result<Self, TryReserveError> {
if capacity == 0 {
Ok(Self::new())
} else {
Expand Down Expand Up @@ -659,7 +661,7 @@ impl<T> RawTable<T> {
&mut self,
additional: usize,
hasher: impl Fn(&T) -> u64,
) -> Result<(), CollectionAllocErr> {
) -> Result<(), TryReserveError> {
if additional > self.growth_left {
self.reserve_rehash(additional, hasher, Fallibility::Fallible)
} else {
Expand All @@ -675,7 +677,7 @@ impl<T> RawTable<T> {
additional: usize,
hasher: impl Fn(&T) -> u64,
fallability: Fallibility,
) -> Result<(), CollectionAllocErr> {
) -> Result<(), TryReserveError> {
let new_items = self
.items
.checked_add(additional)
Expand Down Expand Up @@ -804,7 +806,7 @@ impl<T> RawTable<T> {
capacity: usize,
hasher: impl Fn(&T) -> u64,
fallability: Fallibility,
) -> Result<(), CollectionAllocErr> {
) -> Result<(), TryReserveError> {
unsafe {
debug_assert!(self.items <= capacity);

Expand Down Expand Up @@ -992,7 +994,10 @@ impl<T> RawTable<T> {
} else {
let (layout, ctrl_offset) = calculate_layout::<T>(self.buckets())
.unwrap_or_else(|| unsafe { hint::unreachable_unchecked() });
Some((unsafe { NonNull::new_unchecked(self.ctrl.as_ptr().sub(ctrl_offset)) }, layout))
Some((
unsafe { NonNull::new_unchecked(self.ctrl.as_ptr().sub(ctrl_offset)) },
layout,
))
};
mem::forget(self);
alloc
Expand Down Expand Up @@ -1297,7 +1302,10 @@ impl<T> RawIterRange<T> {
self.data.next_n(Group::WIDTH).next_n(mid),
len - mid,
);
debug_assert_eq!(self.data.next_n(Group::WIDTH).next_n(mid).ptr, tail.data.ptr);
debug_assert_eq!(
self.data.next_n(Group::WIDTH).next_n(mid).ptr,
tail.data.ptr
);
debug_assert_eq!(self.end, tail.end);
self.end = self.next_ctrl.add(mid);
debug_assert_eq!(self.end.add(Group::WIDTH), tail.next_ctrl);
Expand Down
Loading

0 comments on commit 80ce422

Please sign in to comment.