Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relax bounds on HashMap/HashSet #67642

Merged
merged 2 commits into from
Feb 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -896,8 +896,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 @@ -945,8 +944,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 @@ -8,24 +8,15 @@ LL | println!("{:?}", [0_usize; 33]);
= note: required by `std::fmt::Debug::fmt`

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 @@ -35,7 +26,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 @@ -45,7 +36,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 @@ -57,7 +48,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`.