Skip to content

Commit

Permalink
std: Stabilize custom hasher support in HashMap
Browse files Browse the repository at this point in the history
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 rust-lang#27713
  • Loading branch information
alexcrichton committed Feb 3, 2016
1 parent 2bd875d commit eb8f43c
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 142 deletions.
72 changes: 72 additions & 0 deletions src/libcore/hash/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@

use prelude::v1::*;

use marker;
use mem;

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -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 {
Expand Down
1 change: 0 additions & 1 deletion src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#![feature(collections)]
#![feature(const_fn)]
#![feature(enumset)]
#![feature(hashmap_hasher)]
#![feature(iter_arith)]
#![feature(libc)]
#![feature(nonzero)]
Expand Down
5 changes: 2 additions & 3 deletions src/librustc/util/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
11 changes: 5 additions & 6 deletions src/librustc_data_structures/fnv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 0 additions & 1 deletion src/librustc_data_structures/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
15 changes: 7 additions & 8 deletions src/libserialize/collection_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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| {
Expand All @@ -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)));
Expand All @@ -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| {
Expand All @@ -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))));
}
Expand Down
1 change: 0 additions & 1 deletion src/libserialize/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
Loading

0 comments on commit eb8f43c

Please sign in to comment.