Auto merge of #31081 - alexcrichton:stabilize-hasher, r=aturon
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:#️⃣:BuildHasher` * `BuildHasher::Hasher` * `BuildHasher::build_hasher` * `std:#️⃣: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
This commit is contained in:
commit
a9e139b66c
@ -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 {
|
||||
|
@ -29,7 +29,6 @@
|
||||
#![feature(collections)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(enumset)]
|
||||
#![feature(hashmap_hasher)]
|
||||
#![feature(iter_arith)]
|
||||
#![feature(libc)]
|
||||
#![feature(nonzero)]
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)]
|
||||
|
@ -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))));
|
||||
}
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
@ -336,7 +331,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>,
|
||||
|
||||
@ -484,10 +479,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.
|
||||
@ -557,38 +552,50 @@ 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]
|
||||
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
|
||||
pub fn with_hasher(hash_builder: S) -> HashMap<K, V, S> {
|
||||
HashMap {
|
||||
hash_builder: hash_builder,
|
||||
resize_policy: DefaultResizePolicy::new(),
|
||||
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 {
|
||||
hash_state: hash_state,
|
||||
resize_policy: DefaultResizePolicy::new(),
|
||||
table: RawTable::new(0),
|
||||
}
|
||||
HashMap::with_hasher(hash_state)
|
||||
}
|
||||
|
||||
/// Creates an empty HashMap with space for at least `capacity`
|
||||
@ -602,31 +609,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
|
||||
@ -1241,7 +1256,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; }
|
||||
@ -1254,12 +1269,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()
|
||||
@ -1269,10 +1284,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())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1280,7 +1295,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;
|
||||
|
||||
@ -1397,7 +1412,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>;
|
||||
@ -1409,7 +1424,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>;
|
||||
@ -1421,7 +1436,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>;
|
||||
@ -1600,13 +1615,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
|
||||
}
|
||||
@ -1614,7 +1628,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 {
|
||||
@ -1625,7 +1639,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)));
|
||||
@ -1638,34 +1652,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)
|
||||
}
|
||||
}
|
||||
@ -1679,7 +1687,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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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::*;
|
||||
}
|
||||
|
@ -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)]
|
||||
|
Loading…
Reference in New Issue
Block a user