From eb8f43cc25d21b8b987553ad50c601ded28e1d33 Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Thu, 21 Jan 2016 10:28:39 -0800 Subject: [PATCH 1/2] std: Stabilize custom hasher support in HashMap This commit implements the stabilization of the custom hasher support intended for 1.7 but left out due to some last-minute questions that needed some decisions. A summary of the actions done in this PR are: Stable * `std::hash::BuildHasher` * `BuildHasher::Hasher` * `BuildHasher::build_hasher` * `std::hash::BuildHasherDefault` * `HashMap::with_hasher` * `HashMap::with_capacity_and_hasher` * `HashSet::with_hasher` * `HashSet::with_capacity_and_hasher` * `std::collections::hash_map::RandomState` * `RandomState::new` Deprecated * `std::collections::hash_state` * `std::collections::hash_state::HashState` - this trait was also moved into `std::hash` with a reexport here to ensure that we can have a blanket impl to prevent immediate breakage on nightly. Note that this is unstable in both location. * `HashMap::with_hash_state` - renamed * `HashMap::with_capacity_and_hash_state` - renamed * `HashSet::with_hash_state` - renamed * `HashSet::with_capacity_and_hash_state` - renamed Closes #27713 --- src/libcore/hash/mod.rs | 72 ++++++++++++++++ src/librustc/lib.rs | 1 - src/librustc/util/common.rs | 5 +- src/librustc_data_structures/fnv.rs | 11 ++- src/librustc_data_structures/lib.rs | 1 - src/libserialize/collection_impls.rs | 15 ++-- src/libserialize/lib.rs | 1 - src/libstd/collections/hash/map.rs | 124 ++++++++++++++------------- src/libstd/collections/hash/set.rs | 95 +++++++++++--------- src/libstd/collections/hash/state.rs | 22 +---- src/libstd/collections/hash/table.rs | 7 +- src/libstd/collections/mod.rs | 2 + src/libstd/lib.rs | 1 + 13 files changed, 215 insertions(+), 142 deletions(-) diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 0781dd3b7742f..9ab55620e0aec 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -73,6 +73,7 @@ use prelude::v1::*; +use marker; use mem; #[stable(feature = "rust1", since = "1.0.0")] @@ -190,6 +191,77 @@ pub trait Hasher { } } +/// A `BuildHasher` is typically used as a factory for instances of `Hasher` +/// which a `HashMap` can then use to hash keys independently. +/// +/// Note that for each instance of `BuildHasher` the create hashers should be +/// identical. That is if the same stream of bytes is fed into each hasher the +/// same output will also be generated. +#[stable(since = "1.7.0", feature = "build_hasher")] +pub trait BuildHasher { + /// Type of the hasher that will be created. + #[stable(since = "1.7.0", feature = "build_hasher")] + type Hasher: Hasher; + + /// Creates a new hasher. + #[stable(since = "1.7.0", feature = "build_hasher")] + fn build_hasher(&self) -> Self::Hasher; +} + +/// A structure which implements `BuildHasher` for all `Hasher` types which also +/// implement `Default`. +/// +/// This struct is 0-sized and does not need construction. +#[stable(since = "1.7.0", feature = "build_hasher")] +pub struct BuildHasherDefault<H>(marker::PhantomData<H>); + +#[stable(since = "1.7.0", feature = "build_hasher")] +impl<H: Default + Hasher> BuildHasher for BuildHasherDefault<H> { + type Hasher = H; + + fn build_hasher(&self) -> H { + H::default() + } +} + +#[stable(since = "1.7.0", feature = "build_hasher")] +impl<H> Clone for BuildHasherDefault<H> { + fn clone(&self) -> BuildHasherDefault<H> { + BuildHasherDefault(marker::PhantomData) + } +} + +#[stable(since = "1.7.0", feature = "build_hasher")] +impl<H> Default for BuildHasherDefault<H> { + fn default() -> BuildHasherDefault<H> { + BuildHasherDefault(marker::PhantomData) + } +} + +// The HashState trait is super deprecated, but it's here to have the blanket +// impl that goes from HashState -> BuildHasher + +/// Deprecated, renamed to `BuildHasher` +#[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", + issue = "27713")] +#[rustc_deprecated(since = "1.7.0", reason = "support moved to std::hash and \ + renamed to BuildHasher")] +pub trait HashState { + /// Type of the hasher that will be created. + type Hasher: Hasher; + + /// Creates a new hasher based on the given state of this object. + fn hasher(&self) -> Self::Hasher; +} + +#[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", + issue = "27713")] +#[allow(deprecated)] +impl<T: HashState> BuildHasher for T { + type Hasher = T::Hasher; + fn build_hasher(&self) -> T::Hasher { self.hasher() } +} + ////////////////////////////////////////////////////////////////////////////// mod impls { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 501a03f128664..2712ed2a19038 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,7 +29,6 @@ #![feature(collections)] #![feature(const_fn)] #![feature(enumset)] -#![feature(hashmap_hasher)] #![feature(iter_arith)] #![feature(libc)] #![feature(nonzero)] diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 2481cab78b4d6..9441e34cb9b1f 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -12,10 +12,9 @@ use std::cell::{RefCell, Cell}; use std::collections::HashMap; -use std::collections::hash_state::HashState; use std::ffi::CString; use std::fmt::Debug; -use std::hash::Hash; +use std::hash::{Hash, BuildHasher}; use std::iter::repeat; use std::path::Path; use std::time::Instant; @@ -217,7 +216,7 @@ pub trait MemoizationMap { } impl<K, V, S> MemoizationMap for RefCell<HashMap<K,V,S>> - where K: Hash+Eq+Clone, V: Clone, S: HashState + where K: Hash+Eq+Clone, V: Clone, S: BuildHasher { type Key = K; type Value = V; diff --git a/src/librustc_data_structures/fnv.rs b/src/librustc_data_structures/fnv.rs index 77baa84c0236d..6f4dc28e12221 100644 --- a/src/librustc_data_structures/fnv.rs +++ b/src/librustc_data_structures/fnv.rs @@ -9,21 +9,20 @@ // except according to those terms. use std::collections::{HashMap, HashSet}; -use std::collections::hash_state::DefaultState; use std::default::Default; -use std::hash::{Hasher, Hash}; +use std::hash::{Hasher, Hash, BuildHasherDefault}; -pub type FnvHashMap<K, V> = HashMap<K, V, DefaultState<FnvHasher>>; -pub type FnvHashSet<V> = HashSet<V, DefaultState<FnvHasher>>; +pub type FnvHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FnvHasher>>; +pub type FnvHashSet<V> = HashSet<V, BuildHasherDefault<FnvHasher>>; #[allow(non_snake_case)] pub fn FnvHashMap<K: Hash + Eq, V>() -> FnvHashMap<K, V> { - Default::default() + HashMap::default() } #[allow(non_snake_case)] pub fn FnvHashSet<V: Hash + Eq>() -> FnvHashSet<V> { - Default::default() + HashSet::default() } /// A speedy hash algorithm for node ids and def ids. The hashmap in diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 1fbbdf17455b2..20caf7dd0cfc1 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -24,7 +24,6 @@ html_favicon_url = "https://www.rust-lang.org/favicon.ico", html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(hashmap_hasher)] #![feature(nonzero)] #![feature(rustc_private)] #![feature(staged_api)] diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index e21307cc75292..804e1af19aba2 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -10,8 +10,7 @@ //! Implementations of serialization for structures found in libcollections -use std::hash::Hash; -use std::collections::hash_state::HashState; +use std::hash::{Hash, BuildHasher}; use std::mem; use {Decodable, Encodable, Decoder, Encoder}; @@ -159,7 +158,7 @@ impl< impl<K, V, S> Encodable for HashMap<K, V, S> where K: Encodable + Hash + Eq, V: Encodable, - S: HashState, + S: BuildHasher, { fn encode<E: Encoder>(&self, e: &mut E) -> Result<(), E::Error> { e.emit_map(self.len(), |e| { @@ -177,12 +176,12 @@ impl<K, V, S> Encodable for HashMap<K, V, S> impl<K, V, S> Decodable for HashMap<K, V, S> where K: Decodable + Hash + Eq, V: Decodable, - S: HashState + Default, + S: BuildHasher + Default, { fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> { d.read_map(|d, len| { let state = Default::default(); - let mut map = HashMap::with_capacity_and_hash_state(len, state); + let mut map = HashMap::with_capacity_and_hasher(len, state); for i in 0..len { let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d))); let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d))); @@ -195,7 +194,7 @@ impl<K, V, S> Decodable for HashMap<K, V, S> impl<T, S> Encodable for HashSet<T, S> where T: Encodable + Hash + Eq, - S: HashState, + S: BuildHasher, { fn encode<E: Encoder>(&self, s: &mut E) -> Result<(), E::Error> { s.emit_seq(self.len(), |s| { @@ -211,12 +210,12 @@ impl<T, S> Encodable for HashSet<T, S> impl<T, S> Decodable for HashSet<T, S> where T: Decodable + Hash + Eq, - S: HashState + Default, + S: BuildHasher + Default, { fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T, S>, D::Error> { d.read_seq(|d, len| { let state = Default::default(); - let mut set = HashSet::with_capacity_and_hash_state(len, state); + let mut set = HashSet::with_capacity_and_hasher(len, state); for i in 0..len { set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); } diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 910600d91e456..8bb596c8bb248 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -29,7 +29,6 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(collections)] #![feature(enumset)] -#![feature(hashmap_hasher)] #![feature(rustc_private)] #![feature(staged_api)] #![feature(str_char)] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index e43101b7c9d0d..509964cd29b88 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -13,16 +13,12 @@ use self::SearchResult::*; use self::VacantEntryState::*; use borrow::Borrow; -use clone::Clone; -use cmp::{max, Eq, PartialEq}; -use default::Default; +use cmp::max; use fmt::{self, Debug}; -use hash::{Hash, SipHasher}; -use iter::{self, Iterator, ExactSizeIterator, IntoIterator, FromIterator, Extend, Map}; -use marker::Sized; +use hash::{Hash, SipHasher, BuildHasher}; +use iter::{self, Map, FromIterator}; use mem::{self, replace}; -use ops::{Deref, FnMut, FnOnce, Index}; -use option::Option::{self, Some, None}; +use ops::{Deref, Index}; use rand::{self, Rng}; use super::table::{ @@ -39,7 +35,6 @@ use super::table::BucketState::{ Empty, Full, }; -use super::state::HashState; const INITIAL_LOG2_CAP: usize = 5; const INITIAL_CAPACITY: usize = 1 << INITIAL_LOG2_CAP; // 2^5 @@ -307,7 +302,7 @@ fn test_resize_policy() { #[stable(feature = "rust1", since = "1.0.0")] pub struct HashMap<K, V, S = RandomState> { // All hashes are keyed on these values, to prevent hash collision attacks. - hash_state: S, + hash_builder: S, table: RawTable<K, V>, @@ -455,10 +450,10 @@ impl<K, V, M> SearchResult<K, V, M> { } impl<K, V, S> HashMap<K, V, S> - where K: Eq + Hash, S: HashState + where K: Eq + Hash, S: BuildHasher { fn make_hash<X: ?Sized>(&self, x: &X) -> SafeHash where X: Hash { - table::make_hash(&self.hash_state, x) + table::make_hash(&self.hash_builder, x) } /// Search for a key, yielding the index if it's found in the hashtable. @@ -528,40 +523,52 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomState> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> HashMap<K, V, RandomState> { - HashMap::with_capacity_and_hash_state(capacity, Default::default()) + HashMap::with_capacity_and_hasher(capacity, Default::default()) } } impl<K, V, S> HashMap<K, V, S> - where K: Eq + Hash, S: HashState + where K: Eq + Hash, S: BuildHasher { - /// Creates an empty hashmap which will use the given hasher to hash keys. + /// 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 /// /// ``` - /// #![feature(hashmap_hasher)] - /// /// use std::collections::HashMap; /// use std::collections::hash_map::RandomState; /// /// let s = RandomState::new(); - /// let mut map = HashMap::with_hash_state(s); + /// let mut map = HashMap::with_hasher(s); /// map.insert(1, 2); /// ``` #[inline] - #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", - issue = "27713")] - pub fn with_hash_state(hash_state: S) -> HashMap<K, V, S> { + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> { HashMap { - hash_state: hash_state, + hash_builder: hash_builder, resize_policy: DefaultResizePolicy::new(), - table: RawTable::new(0), + table: RawTable::new(0), } } + /// Deprecated, renamed to `with_hasher` + #[inline] + #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", + issue = "27713")] + #[rustc_deprecated(since = "1.7.0", reason = "renamed to with_hasher")] + pub fn with_hash_state(hash_state: S) -> HashMap<K, V, S> { + HashMap::with_hasher(hash_state) + } + /// Creates an empty HashMap with space for at least `capacity` /// elements, using `hasher` to hash the keys. /// @@ -573,31 +580,39 @@ impl<K, V, S> HashMap<K, V, S> /// # Examples /// /// ``` - /// #![feature(hashmap_hasher)] - /// /// use std::collections::HashMap; /// use std::collections::hash_map::RandomState; /// /// let s = RandomState::new(); - /// let mut map = HashMap::with_capacity_and_hash_state(10, s); + /// let mut map = HashMap::with_capacity_and_hasher(10, s); /// map.insert(1, 2); /// ``` #[inline] - #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", - issue = "27713")] - pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S) - -> HashMap<K, V, S> { + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) + -> HashMap<K, V, S> { let resize_policy = DefaultResizePolicy::new(); let min_cap = max(INITIAL_CAPACITY, resize_policy.min_capacity(capacity)); let internal_cap = min_cap.checked_next_power_of_two().expect("capacity overflow"); assert!(internal_cap >= capacity, "capacity overflow"); HashMap { - hash_state: hash_state, + hash_builder: hash_builder, resize_policy: resize_policy, - table: RawTable::new(internal_cap), + table: RawTable::new(internal_cap), } } + /// Deprecated, renamed to `with_capacity_and_hasher` + #[inline] + #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", + issue = "27713")] + #[rustc_deprecated(since = "1.7.0", + reason = "renamed to with_capacity_and_hasher")] + pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S) + -> HashMap<K, V, S> { + HashMap::with_capacity_and_hasher(capacity, hash_state) + } + /// 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 @@ -1212,7 +1227,7 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHas #[stable(feature = "rust1", since = "1.0.0")] impl<K, V, S> PartialEq for HashMap<K, V, S> - where K: Eq + Hash, V: PartialEq, S: HashState + where K: Eq + Hash, V: PartialEq, S: BuildHasher { fn eq(&self, other: &HashMap<K, V, S>) -> bool { if self.len() != other.len() { return false; } @@ -1225,12 +1240,12 @@ impl<K, V, S> PartialEq for HashMap<K, V, S> #[stable(feature = "rust1", since = "1.0.0")] impl<K, V, S> Eq for HashMap<K, V, S> - where K: Eq + Hash, V: Eq, S: HashState + where K: Eq + Hash, V: Eq, S: BuildHasher {} #[stable(feature = "rust1", since = "1.0.0")] impl<K, V, S> Debug for HashMap<K, V, S> - where K: Eq + Hash + Debug, V: Debug, S: HashState + where K: Eq + Hash + Debug, V: Debug, S: BuildHasher { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_map().entries(self.iter()).finish() @@ -1240,10 +1255,10 @@ impl<K, V, S> Debug for HashMap<K, V, S> #[stable(feature = "rust1", since = "1.0.0")] impl<K, V, S> Default for HashMap<K, V, S> where K: Eq + Hash, - S: HashState + Default, + S: BuildHasher + Default, { fn default() -> HashMap<K, V, S> { - HashMap::with_hash_state(Default::default()) + HashMap::with_hasher(Default::default()) } } @@ -1251,7 +1266,7 @@ impl<K, V, S> Default for HashMap<K, V, S> impl<'a, K, Q: ?Sized, V, S> Index<&'a Q> for HashMap<K, V, S> where K: Eq + Hash + Borrow<Q>, Q: Eq + Hash, - S: HashState, + S: BuildHasher, { type Output = V; @@ -1368,7 +1383,7 @@ enum VacantEntryState<K, V, M> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> - where K: Eq + Hash, S: HashState + where K: Eq + Hash, S: BuildHasher { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1380,7 +1395,7 @@ impl<'a, K, V, S> IntoIterator for &'a HashMap<K, V, S> #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S> - where K: Eq + Hash, S: HashState + where K: Eq + Hash, S: BuildHasher { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -1392,7 +1407,7 @@ impl<'a, K, V, S> IntoIterator for &'a mut HashMap<K, V, S> #[stable(feature = "rust1", since = "1.0.0")] impl<K, V, S> IntoIterator for HashMap<K, V, S> - where K: Eq + Hash, S: HashState + where K: Eq + Hash, S: BuildHasher { type Item = (K, V); type IntoIter = IntoIter<K, V>; @@ -1571,13 +1586,12 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S> - where K: Eq + Hash, S: HashState + Default + where K: Eq + Hash, S: BuildHasher + Default { fn from_iter<T: IntoIterator<Item=(K, V)>>(iterable: T) -> HashMap<K, V, S> { let iter = iterable.into_iter(); let lower = iter.size_hint().0; - let mut map = HashMap::with_capacity_and_hash_state(lower, - Default::default()); + let mut map = HashMap::with_capacity_and_hasher(lower, Default::default()); map.extend(iter); map } @@ -1585,7 +1599,7 @@ impl<K, V, S> FromIterator<(K, V)> for HashMap<K, V, S> #[stable(feature = "rust1", since = "1.0.0")] impl<K, V, S> Extend<(K, V)> for HashMap<K, V, S> - where K: Eq + Hash, S: HashState + where K: Eq + Hash, S: BuildHasher { fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) { for (k, v) in iter { @@ -1596,7 +1610,7 @@ impl<K, V, S> Extend<(K, V)> for HashMap<K, V, S> #[stable(feature = "hash_extend_copy", since = "1.4.0")] impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S> - where K: Eq + Hash + Copy, V: Copy, S: HashState + where K: Eq + Hash + Copy, V: Copy, S: BuildHasher { fn extend<T: IntoIterator<Item=(&'a K, &'a V)>>(&mut self, iter: T) { self.extend(iter.into_iter().map(|(&key, &value)| (key, value))); @@ -1609,34 +1623,28 @@ impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap<K, V, S> /// `Hasher`, but the hashers created by two different `RandomState` /// instances are unlikely to produce the same result for the same values. #[derive(Clone)] -#[unstable(feature = "hashmap_hasher", - reason = "hashing an hash maps may be altered", - issue = "27713")] +#[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub struct RandomState { k0: u64, k1: u64, } -#[unstable(feature = "hashmap_hasher", - reason = "hashing an hash maps may be altered", - issue = "27713")] impl RandomState { /// Constructs a new `RandomState` that is initialized with random keys. #[inline] #[allow(deprecated)] // rand + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn new() -> RandomState { let mut r = rand::thread_rng(); RandomState { k0: r.gen(), k1: r.gen() } } } -#[unstable(feature = "hashmap_hasher", - reason = "hashing an hash maps may be altered", - issue = "27713")] -impl HashState for RandomState { +#[stable(feature = "hashmap_build_hasher", since = "1.7.0")] +impl BuildHasher for RandomState { type Hasher = SipHasher; #[inline] - fn hasher(&self) -> SipHasher { + fn build_hasher(&self) -> SipHasher { SipHasher::new_with_keys(self.k0, self.k1) } } @@ -1650,7 +1658,7 @@ impl Default for RandomState { } impl<K, S, Q: ?Sized> super::Recover<Q> for HashMap<K, (), S> - where K: Eq + Hash + Borrow<Q>, S: HashState, Q: Eq + Hash + where K: Eq + Hash + Borrow<Q>, S: BuildHasher, Q: Eq + Hash { type Key = K; diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 761709d41e77c..b5f47853afd4e 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -9,19 +9,13 @@ // except according to those terms. use borrow::Borrow; -use clone::Clone; -use cmp::{Eq, PartialEq}; -use core::marker::Sized; -use default::Default; use fmt; -use hash::Hash; -use iter::{Iterator, IntoIterator, ExactSizeIterator, FromIterator, Map, Chain, Extend}; +use hash::{Hash, BuildHasher}; +use iter::{Map, Chain, FromIterator}; use ops::{BitOr, BitAnd, BitXor, Sub}; -use option::Option::{Some, None, self}; use super::Recover; use super::map::{self, HashMap, Keys, RandomState}; -use super::state::HashState; const INITIAL_CAPACITY: usize = 32; @@ -144,30 +138,32 @@ impl<T: Hash + Eq> HashSet<T, RandomState> { } impl<T, S> HashSet<T, S> - where T: Eq + Hash, S: HashState + where T: Eq + Hash, S: BuildHasher { /// Creates a new empty hash set which will use the given hasher to hash /// keys. /// /// The hash set is also created with the default initial capacity. /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s 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 /// /// ``` - /// #![feature(hashmap_hasher)] - /// /// use std::collections::HashSet; /// use std::collections::hash_map::RandomState; /// /// let s = RandomState::new(); - /// let mut set = HashSet::with_hash_state(s); + /// let mut set = HashSet::with_hasher(s); /// set.insert(2); /// ``` #[inline] - #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", - issue = "27713")] - pub fn with_hash_state(hash_state: S) -> HashSet<T, S> { - HashSet::with_capacity_and_hash_state(INITIAL_CAPACITY, hash_state) + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_hasher(hasher: S) -> HashSet<T, S> { + HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher) } /// Creates an empty HashSet with space for at least `capacity` @@ -181,23 +177,40 @@ impl<T, S> HashSet<T, S> /// # Examples /// /// ``` - /// #![feature(hashmap_hasher)] - /// /// use std::collections::HashSet; /// use std::collections::hash_map::RandomState; /// /// let s = RandomState::new(); - /// let mut set = HashSet::with_capacity_and_hash_state(10, s); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); /// set.insert(1); /// ``` #[inline] + #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) + -> HashSet<T, S> { + HashSet { + map: HashMap::with_capacity_and_hasher(capacity, hasher), + } + } + + /// Deprecated, renamed to `with_hasher` + #[inline] #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", issue = "27713")] + #[rustc_deprecated(since = "1.7.0", reason = "renamed to with_hasher")] + pub fn with_hash_state(hash_state: S) -> HashSet<T, S> { + HashSet::with_hasher(hash_state) + } + + /// Deprecated, renamed to `with_capacity_and_hasher` + #[inline] + #[unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", + issue = "27713")] + #[rustc_deprecated(since = "1.7.0", + reason = "renamed to with_capacity_and_hasher")] pub fn with_capacity_and_hash_state(capacity: usize, hash_state: S) -> HashSet<T, S> { - HashSet { - map: HashMap::with_capacity_and_hash_state(capacity, hash_state), - } + HashSet::with_capacity_and_hasher(capacity, hash_state) } /// Returns the number of elements the set can hold without reallocating. @@ -604,7 +617,7 @@ impl<T, S> HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] impl<T, S> PartialEq for HashSet<T, S> - where T: Eq + Hash, S: HashState + where T: Eq + Hash, S: BuildHasher { fn eq(&self, other: &HashSet<T, S>) -> bool { if self.len() != other.len() { return false; } @@ -615,13 +628,13 @@ impl<T, S> PartialEq for HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] impl<T, S> Eq for HashSet<T, S> - where T: Eq + Hash, S: HashState + where T: Eq + Hash, S: BuildHasher {} #[stable(feature = "rust1", since = "1.0.0")] impl<T, S> fmt::Debug for HashSet<T, S> where T: Eq + Hash + fmt::Debug, - S: HashState + S: BuildHasher { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_set().entries(self.iter()).finish() @@ -631,12 +644,12 @@ impl<T, S> fmt::Debug for HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] impl<T, S> FromIterator<T> for HashSet<T, S> where T: Eq + Hash, - S: HashState + Default, + S: BuildHasher + Default, { fn from_iter<I: IntoIterator<Item=T>>(iterable: I) -> HashSet<T, S> { let iter = iterable.into_iter(); let lower = iter.size_hint().0; - let mut set = HashSet::with_capacity_and_hash_state(lower, Default::default()); + let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); set.extend(iter); set } @@ -645,7 +658,7 @@ impl<T, S> FromIterator<T> for HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] impl<T, S> Extend<T> for HashSet<T, S> where T: Eq + Hash, - S: HashState, + S: BuildHasher, { fn extend<I: IntoIterator<Item=T>>(&mut self, iter: I) { for k in iter { @@ -657,7 +670,7 @@ impl<T, S> Extend<T> for HashSet<T, S> #[stable(feature = "hash_extend_copy", since = "1.4.0")] impl<'a, T, S> Extend<&'a T> for HashSet<T, S> where T: 'a + Eq + Hash + Copy, - S: HashState, + S: BuildHasher, { fn extend<I: IntoIterator<Item=&'a T>>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); @@ -667,17 +680,17 @@ impl<'a, T, S> Extend<&'a T> for HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] impl<T, S> Default for HashSet<T, S> where T: Eq + Hash, - S: HashState + Default, + S: BuildHasher + Default, { fn default() -> HashSet<T, S> { - HashSet::with_hash_state(Default::default()) + HashSet::with_hasher(Default::default()) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, T, S> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S> where T: Eq + Hash + Clone, - S: HashState + Default, + S: BuildHasher + Default, { type Output = HashSet<T, S>; @@ -709,7 +722,7 @@ impl<'a, 'b, T, S> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, T, S> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S> where T: Eq + Hash + Clone, - S: HashState + Default, + S: BuildHasher + Default, { type Output = HashSet<T, S>; @@ -741,7 +754,7 @@ impl<'a, 'b, T, S> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, T, S> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S> where T: Eq + Hash + Clone, - S: HashState + Default, + S: BuildHasher + Default, { type Output = HashSet<T, S>; @@ -773,7 +786,7 @@ impl<'a, 'b, T, S> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b, T, S> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S> where T: Eq + Hash + Clone, - S: HashState + Default, + S: BuildHasher + Default, { type Output = HashSet<T, S>; @@ -852,7 +865,7 @@ pub struct Union<'a, T: 'a, S: 'a> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> IntoIterator for &'a HashSet<T, S> - where T: Eq + Hash, S: HashState + where T: Eq + Hash, S: BuildHasher { type Item = &'a T; type IntoIter = Iter<'a, T>; @@ -865,7 +878,7 @@ impl<'a, T, S> IntoIterator for &'a HashSet<T, S> #[stable(feature = "rust1", since = "1.0.0")] impl<T, S> IntoIterator for HashSet<T, S> where T: Eq + Hash, - S: HashState + S: BuildHasher { type Item = T; type IntoIter = IntoIter<T>; @@ -947,7 +960,7 @@ impl<'a, T, S> Clone for Intersection<'a, T, S> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for Intersection<'a, T, S> - where T: Eq + Hash, S: HashState + where T: Eq + Hash, S: BuildHasher { type Item = &'a T; @@ -977,7 +990,7 @@ impl<'a, T, S> Clone for Difference<'a, T, S> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for Difference<'a, T, S> - where T: Eq + Hash, S: HashState + where T: Eq + Hash, S: BuildHasher { type Item = &'a T; @@ -1007,7 +1020,7 @@ impl<'a, T, S> Clone for SymmetricDifference<'a, T, S> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S> - where T: Eq + Hash, S: HashState + where T: Eq + Hash, S: BuildHasher { type Item = &'a T; @@ -1022,7 +1035,7 @@ impl<'a, T, S> Clone for Union<'a, T, S> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T, S> Iterator for Union<'a, T, S> - where T: Eq + Hash, S: HashState + where T: Eq + Hash, S: BuildHasher { type Item = &'a T; diff --git a/src/libstd/collections/hash/state.rs b/src/libstd/collections/hash/state.rs index 1790eeb00b701..167aca083038e 100644 --- a/src/libstd/collections/hash/state.rs +++ b/src/libstd/collections/hash/state.rs @@ -10,31 +10,15 @@ #![unstable(feature = "hashmap_hasher", reason = "hasher stuff is unclear", issue = "27713")] +#![rustc_deprecated(since = "1.7.0", reason = "support moved to std::hash")] +#![allow(deprecated)] use clone::Clone; use default::Default; use hash; use marker; -/// A trait representing stateful hashes which can be used to hash keys in a -/// `HashMap`. -/// -/// A HashState is used as a factory for instances of `Hasher` which a `HashMap` -/// can then use to hash keys independently. A `HashMap` by default uses a state -/// which will create instances of a `SipHasher`, but a custom state factory can -/// be provided to the `with_hash_state` function. -/// -/// If a hashing algorithm has no initial state, then the `Hasher` type for that -/// algorithm can implement the `Default` trait and create hash maps with the -/// `DefaultState` structure. This state is 0-sized and will simply delegate -/// to `Default` when asked to create a hasher. -pub trait HashState { - /// Type of the hasher that will be created. - type Hasher: hash::Hasher; - - /// Creates a new hasher based on the given state of this object. - fn hasher(&self) -> Self::Hasher; -} +pub use hash::HashState; /// A structure which is a factory for instances of `Hasher` which implement the /// default trait. diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index f8550fd8842e1..316c75952667c 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -11,13 +11,12 @@ use alloc::heap::{allocate, deallocate, EMPTY}; use cmp; -use hash::{Hash, Hasher}; +use hash::{Hash, Hasher, BuildHasher}; use marker; use mem::{align_of, size_of}; use mem; use ops::{Deref, DerefMut}; use ptr::{self, Unique}; -use collections::hash_state::HashState; use self::BucketState::*; @@ -144,9 +143,9 @@ impl SafeHash { /// This function wraps up `hash_keyed` to be the only way outside this /// module to generate a SafeHash. pub fn make_hash<T: ?Sized, S>(hash_state: &S, t: &T) -> SafeHash - where T: Hash, S: HashState + where T: Hash, S: BuildHasher { - let mut state = hash_state.hasher(); + let mut state = hash_state.build_hasher(); t.hash(&mut state); // We need to avoid 0 in order to prevent collisions with // EMPTY_HASH. We can maintain our precious uniform distribution diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 07ddfe237be93..417261cf4c304 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -444,6 +444,8 @@ pub mod hash_set { /// HashSet. #[unstable(feature = "hashmap_hasher", reason = "module was recently added", issue = "27713")] +#[rustc_deprecated(since = "1.7.0", reason = "support moved to std::hash")] +#[allow(deprecated)] pub mod hash_state { pub use super::hash::state::*; } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9adea351e3d0e..e7bcdcc785f22 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -231,6 +231,7 @@ #![feature(float_from_str_radix)] #![feature(fnbox)] #![feature(heap_api)] +#![feature(hashmap_hasher)] #![feature(int_error_internals)] #![feature(into_cow)] #![feature(lang_items)] From 561e165f94274c1e56a5a1ec4e5fdfbf21585b13 Mon Sep 17 00:00:00 2001 From: Alex Crichton <alex@alexcrichton.com> Date: Fri, 22 Jan 2016 10:17:07 -0800 Subject: [PATCH 2/2] rustc_mir: Mark the crate as unstable Wouldn't want to be able to link to this on stable Rust! Conflicts: src/librustc_mir/lib.rs --- src/librustc_mir/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 9cc40bbc3838a..53609e65d075c 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -17,8 +17,10 @@ Rust MIR: a lowered representation of Rust. Also: an experiment! #![crate_name = "rustc_mir"] #![crate_type = "rlib"] #![crate_type = "dylib"] +#![unstable(feature = "rustc_private", issue = "27812")] #![feature(rustc_private)] +#![feature(staged_api)] #[macro_use] extern crate log; extern crate graphviz as dot;