Skip to content

Commit

Permalink
Rollup merge of rust-lang#67642 - Mark-Simulacrum:relax-bounds, r=Ama…
Browse files Browse the repository at this point in the history
…nieu

Relax bounds on HashMap/HashSet

These APIs changed from the old bound listed to the new bound (possibly empty):

K: Hash + Eq -> K
* new
* with_capacity

K: Eq + Hash, S: BuildHasher -> K, S
* with_hasher
* with_capacity_and_hasher
* hasher

K: Eq + Hash + Debug -> K: Debug
S: BuildHasher -> S
HashMap as Debug

K: Eq + Hash -> K
S: BuildHasher + Default -> S: Default
HashMap as Default

Resolves rust-lang#44777.
  • Loading branch information
Dylan-DPC committed Feb 13, 2020
2 parents 92d8e82 + 48859db commit 2a20133
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 90 deletions.
126 changes: 62 additions & 64 deletions src/libstd/collections/hash/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ pub struct HashMap<K, V, S = RandomState> {
base: base::HashMap<K, V, S>,
}

impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
impl<K, V> HashMap<K, V, RandomState> {
/// Creates an empty `HashMap`.
///
/// The hash map is initially created with a capacity of 0, so it will not allocate until it
Expand Down Expand Up @@ -240,6 +240,59 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
}

impl<K, V, S> HashMap<K, V, S> {
/// Creates an empty `HashMap` which will use the given hash builder to hash
/// keys.
///
/// The created map has the default initial capacity.
///
/// Warning: `hash_builder` is normally randomly generated, and
/// is designed to allow HashMaps to be resistant to attacks that
/// cause many collisions and very poor performance. Setting it
/// manually using this function can expose a DoS attack vector.
///
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
/// let mut map = HashMap::with_hasher(s);
/// map.insert(1, 2);
/// ```
#[inline]
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
HashMap { base: base::HashMap::with_hasher(hash_builder) }
}

/// Creates an empty `HashMap` with the specified capacity, using `hash_builder`
/// to hash the keys.
///
/// The hash map will be able to hold at least `capacity` elements without
/// reallocating. If `capacity` is 0, the hash map will not allocate.
///
/// Warning: `hash_builder` is normally randomly generated, and
/// is designed to allow HashMaps to be resistant to attacks that
/// cause many collisions and very poor performance. Setting it
/// manually using this function can expose a DoS attack vector.
///
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
/// let mut map = HashMap::with_capacity_and_hasher(10, s);
/// map.insert(1, 2);
/// ```
#[inline]
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hash_builder) }
}

/// Returns the number of elements the map can hold without reallocating.
///
/// This number is a lower bound; the `HashMap<K, V>` might be able to hold
Expand Down Expand Up @@ -457,65 +510,6 @@ impl<K, V, S> HashMap<K, V, S> {
pub fn clear(&mut self) {
self.base.clear();
}
}

impl<K, V, S> HashMap<K, V, S>
where
K: Eq + Hash,
S: BuildHasher,
{
/// Creates an empty `HashMap` which will use the given hash builder to hash
/// keys.
///
/// The created map has the default initial capacity.
///
/// Warning: `hash_builder` is normally randomly generated, and
/// is designed to allow HashMaps to be resistant to attacks that
/// cause many collisions and very poor performance. Setting it
/// manually using this function can expose a DoS attack vector.
///
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
/// let mut map = HashMap::with_hasher(s);
/// map.insert(1, 2);
/// ```
#[inline]
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
HashMap { base: base::HashMap::with_hasher(hash_builder) }
}

/// Creates an empty `HashMap` with the specified capacity, using `hash_builder`
/// to hash the keys.
///
/// The hash map will be able to hold at least `capacity` elements without
/// reallocating. If `capacity` is 0, the hash map will not allocate.
///
/// Warning: `hash_builder` is normally randomly generated, and
/// is designed to allow HashMaps to be resistant to attacks that
/// cause many collisions and very poor performance. Setting it
/// manually using this function can expose a DoS attack vector.
///
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
/// let mut map = HashMap::with_capacity_and_hasher(10, s);
/// map.insert(1, 2);
/// ```
#[inline]
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> HashMap<K, V, S> {
HashMap { base: base::HashMap::with_capacity_and_hasher(capacity, hash_builder) }
}

/// Returns a reference to the map's [`BuildHasher`].
///
Expand All @@ -536,7 +530,13 @@ where
pub fn hasher(&self) -> &S {
self.base.hasher()
}
}

impl<K, V, S> HashMap<K, V, S>
where
K: Eq + Hash,
S: BuildHasher,
{
/// Reserves capacity for at least `additional` more elements to be inserted
/// in the `HashMap`. The collection may reserve more space to avoid
/// frequent reallocations.
Expand Down Expand Up @@ -984,9 +984,8 @@ where
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> Debug for HashMap<K, V, S>
where
K: Eq + Hash + Debug,
K: Debug,
V: Debug,
S: BuildHasher,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
Expand All @@ -996,8 +995,7 @@ where
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V, S> Default for HashMap<K, V, S>
where
K: Eq + Hash,
S: BuildHasher + Default,
S: Default,
{
/// Creates an empty `HashMap<K, V, S>`, with the `Default` value for the hasher.
#[inline]
Expand Down
20 changes: 9 additions & 11 deletions src/libstd/collections/hash/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ pub struct HashSet<T, S = RandomState> {
map: HashMap<T, (), S>,
}

impl<T: Hash + Eq> HashSet<T, RandomState> {
impl<T> HashSet<T, RandomState> {
/// Creates an empty `HashSet`.
///
/// The hash set is initially created with a capacity of 0, so it will not allocate until it
Expand Down Expand Up @@ -261,13 +261,7 @@ impl<T, S> HashSet<T, S> {
pub fn clear(&mut self) {
self.map.clear()
}
}

impl<T, S> HashSet<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
/// Creates a new empty hash set which will use the given hasher to hash
/// keys.
///
Expand Down Expand Up @@ -340,7 +334,13 @@ where
pub fn hasher(&self) -> &S {
self.map.hasher()
}
}

impl<T, S> HashSet<T, S>
where
T: Eq + Hash,
S: BuildHasher,
{
/// Reserves capacity for at least `additional` more elements to be inserted
/// in the `HashSet`. The collection may reserve more space to avoid
/// frequent reallocations.
Expand Down Expand Up @@ -928,8 +928,7 @@ where
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> fmt::Debug for HashSet<T, S>
where
T: Eq + Hash + fmt::Debug,
S: BuildHasher,
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_set().entries(self.iter()).finish()
Expand Down Expand Up @@ -977,8 +976,7 @@ where
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, S> Default for HashSet<T, S>
where
T: Eq + Hash,
S: BuildHasher + Default,
S: Default,
{
/// Creates an empty `HashSet<T, S>` with the `Default` value for the hasher.
#[inline]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ pub fn no_debug() {
pub fn no_hash() {
use std::collections::HashSet;
let mut set = HashSet::new();
//~^ ERROR arrays only have std trait implementations for lengths 0..=32
set.insert([0_usize; 33]);
//~^ ERROR arrays only have std trait implementations for lengths 0..=32
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,15 @@ LL | println!("{:?}", [0_usize; 33]);
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: arrays only have std trait implementations for lengths 0..=32
--> $DIR/core-traits-no-impls-length-33.rs:10:16
--> $DIR/core-traits-no-impls-length-33.rs:9:16
|
LL | set.insert([0_usize; 33]);
| ^^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]`
|
= note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]`

error[E0277]: arrays only have std trait implementations for lengths 0..=32
--> $DIR/core-traits-no-impls-length-33.rs:8:19
|
LL | let mut set = HashSet::new();
| ^^^^^^^^^^^^ the trait `std::array::LengthAtMost32` is not implemented for `[usize; 33]`
|
= note: required because of the requirements on the impl of `std::cmp::Eq` for `[usize; 33]`
= note: required by `std::collections::HashSet::<T>::new`

error[E0369]: binary operation `==` cannot be applied to type `[usize; 33]`
--> $DIR/core-traits-no-impls-length-33.rs:15:19
--> $DIR/core-traits-no-impls-length-33.rs:14:19
|
LL | [0_usize; 33] == [1_usize; 33]
| ------------- ^^ ------------- [usize; 33]
Expand All @@ -36,7 +27,7 @@ LL | [0_usize; 33] == [1_usize; 33]
= note: an implementation of `std::cmp::PartialEq` might be missing for `[usize; 33]`

error[E0369]: binary operation `<` cannot be applied to type `[usize; 33]`
--> $DIR/core-traits-no-impls-length-33.rs:20:19
--> $DIR/core-traits-no-impls-length-33.rs:19:19
|
LL | [0_usize; 33] < [1_usize; 33]
| ------------- ^ ------------- [usize; 33]
Expand All @@ -46,7 +37,7 @@ LL | [0_usize; 33] < [1_usize; 33]
= note: an implementation of `std::cmp::PartialOrd` might be missing for `[usize; 33]`

error[E0277]: the trait bound `&[usize; 33]: std::iter::IntoIterator` is not satisfied
--> $DIR/core-traits-no-impls-length-33.rs:25:14
--> $DIR/core-traits-no-impls-length-33.rs:24:14
|
LL | for _ in &[0_usize; 33] {
| ^^^^^^^^^^^^^^ the trait `std::iter::IntoIterator` is not implemented for `&[usize; 33]`
Expand All @@ -58,7 +49,7 @@ LL | for _ in &[0_usize; 33] {
<&'a mut [T] as std::iter::IntoIterator>
= note: required by `std::iter::IntoIterator::into_iter`

error: aborting due to 6 previous errors
error: aborting due to 5 previous errors

Some errors have detailed explanations: E0277, E0369.
For more information about an error, try `rustc --explain E0277`.

0 comments on commit 2a20133

Please sign in to comment.