From 085838c5c7699196d995a62747edd563d5543e2a Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 9 Dec 2014 12:37:23 -0800 Subject: [PATCH] std: Stabilize the std::hash module This commit aims to stabilize the `std::hash` module by standardizing on its hashing interface while rationalizing the current usage with the `HashMap` and `HashSet` types. The primary goal of this slight redesign is to separate the concepts of a hasher's state from a hashing algorithm itself. The primary change of this commit is to separate the `Hasher` trait into a `Hasher` and a `HashState` trait. Conceptually the old `Hasher` trait was actually just a factory for various states, but hashing had very little control over how these states were used. Additionally the old `Hasher` trait was actually fairly unrelated to hashing. This commit redesigns the existing `Hasher` trait to match what the notion of a `Hasher` normally implies with the following definition: trait Hasher: Writer { type Output; fn reset(&mut self); fn finish(&self) -> Output; } Note that the `Output` associated type is currently a type parameter due to associated types not being fully implemented yet. This new `Hasher` trait emphasizes that all hashers are sinks for bytes, and hashing algorithms may produce outputs other than a `u64`, so a the output type is made generic. With this definition, the old `Hasher` trait is realized as a new `HashState` trait in the `collections::hash_state` module as an experimental addition for now. The current definition looks like: trait HashState { type H: Hasher; fn hasher(&self) -> H; } Note that the `H` associated type (along with its `O` output) are both type parameters on the `HashState` trait due to the current limitations of associated types. The purpose of this trait is to emphasize that the one piece of functionality for implementors is that new instances of `Hasher` can be created. This conceptually represents the two keys from which more instances of a `SipHasher` can be created, and a `HashState` is what's stored in a `HashMap`, not a `Hasher`. Implementors of custom hash algorithms should implement the `Hasher` trait, and only hash algorithms intended for use in hash maps need to implement or worry about the `HashState` trait. Some other stability decision made for the `std::hash` module are: * The name of the module, hash, is `#![stable]` * The `Hash` and `Hasher` traits are `#[unstable]` due to type parameters that want to be associated types. * The `Writer` trait remains `#[experimental]` as it's intended to be replaced with an `io::Writer` (more details soon). * The top-level `hash` function is `#[unstable]` as it is intended to be generic over the hashing algorithm instead of hardwired to `SipHasher` * The inner `sip` module is now private as its one export, `SipHasher` is reexported in the `hash` module. There are many breaking changes outlined above, and as a result this commit is a: [breaking-change] --- src/libcollections/hash/mod.rs | 127 +++++++++------ src/libcollections/hash/sip.rs | 192 +++++++++-------------- src/libcollections/lib.rs | 2 +- src/libflate/lib.rs | 2 +- src/librustc/middle/ty.rs | 12 +- src/librustc/util/common.rs | 10 +- src/librustc/util/nodemap.rs | 47 +++--- src/librustc_back/lib.rs | 2 +- src/librustc_back/svh.rs | 16 +- src/librustc_llvm/lib.rs | 2 +- src/librustc_trans/trans/monomorphize.rs | 6 +- src/libserialize/collection_impls.rs | 44 +++--- src/libstd/collections/hash/map.rs | 153 +++++++++++------- src/libstd/collections/hash/mod.rs | 3 +- src/libstd/collections/hash/set.rs | 120 ++++++++------ src/libstd/collections/hash/state.rs | 82 ++++++++++ src/libstd/collections/hash/table.rs | 9 +- src/libstd/collections/lru_cache.rs | 4 +- src/libstd/collections/mod.rs | 7 + src/libstd/hash.rs | 103 ------------ src/libstd/lib.rs | 3 +- src/libsyntax/ext/deriving/hash.rs | 2 +- src/libsyntax/ptr.rs | 4 +- 23 files changed, 503 insertions(+), 449 deletions(-) create mode 100644 src/libstd/collections/hash/state.rs delete mode 100644 src/libstd/hash.rs diff --git a/src/libcollections/hash/mod.rs b/src/libcollections/hash/mod.rs index 637541a8fd654..b6c20a18a62d9 100644 --- a/src/libcollections/hash/mod.rs +++ b/src/libcollections/hash/mod.rs @@ -38,7 +38,7 @@ //! ```rust //! use std::hash; //! use std::hash::Hash; -//! use std::hash::sip::SipState; +//! use std::hash::SipHasher; //! //! struct Person { //! id: uint, @@ -47,7 +47,7 @@ //! } //! //! impl Hash for Person { -//! fn hash(&self, state: &mut SipState) { +//! fn hash(&self, state: &mut SipHasher) { //! self.id.hash(state); //! self.phone.hash(state); //! } @@ -60,42 +60,63 @@ //! ``` #![allow(unused_must_use)] +#![stable] use core::prelude::*; use alloc::boxed::Box; use alloc::rc::Rc; use core::borrow::{Cow, ToOwned}; +use core::default::Default; use core::intrinsics::TypeId; use core::mem; use core::num::Int; - use vec::Vec; -/// Reexport the `sip::hash` function as our default hasher. -pub use self::sip::hash as hash; +pub use self::sip::SipHasher; -pub mod sip; +mod sip; /// A hashable type. The `S` type parameter is an abstract hash state that is /// used by the `Hash` to compute the hash. It defaults to /// `std::hash::sip::SipState`. -pub trait Hash for Sized? { +#[unstable = "waiting for std::hash dust to settle"] +pub trait Hash for Sized? { /// Computes the hash of a value. fn hash(&self, state: &mut S); } /// A trait that computes a hash for a value. The main users of this trait are /// containers like `HashMap`, which need a generic way hash multiple types. -pub trait Hasher { - /// Compute the hash of a value. - fn hash>(&self, value: &T) -> u64; +// FIXME(#17307) Output should be an associated type +#[unstable = "the Output type parameter should be an associated type"] +pub trait Hasher: Writer { + /// Resets this hasher back to its initial state (as if it were just + /// created). + #[stable] + fn reset(&mut self); + + /// Completes a round of hashing, producing the output hash generated. + #[unstable = "may be renamed or may take some extra bytes"] + fn finish(&self) -> Output; } +#[experimental = "this trait will likely be replaced by io::Writer"] pub trait Writer { fn write(&mut self, bytes: &[u8]); } +/// Hash a value with the default SipHasher algorithm (two initial keys of 0). +/// +/// The specified value will be hashed with this hasher and then the resulting +/// hash will be returned. +#[unstable = "the hashing algorithm used will likely become generic soon"] +pub fn hash>(value: &T) -> u64 { + let mut h: SipHasher = Default::default(); + value.hash(&mut h); + h.finish() +} + ////////////////////////////////////////////////////////////////////////////// macro_rules! impl_hash { @@ -283,7 +304,8 @@ impl, U: Hash> Hash for Result { } } -impl<'a, T, Sized? B, S> Hash for Cow<'a, T, B> where B: Hash + ToOwned { +impl<'a, T, Sized? B, S> Hash for Cow<'a, T, B> + where B: Hash + ToOwned, S: Writer { #[inline] fn hash(&self, state: &mut S) { Hash::hash(&**self, state) @@ -300,16 +322,6 @@ mod tests { use slice::SlicePrelude; use super::{Hash, Hasher, Writer}; - struct MyWriterHasher; - - impl Hasher for MyWriterHasher { - fn hash>(&self, value: &T) -> u64 { - let mut state = MyWriter { hash: 0 }; - value.hash(&mut state); - state.hash - } - } - struct MyWriter { hash: u64, } @@ -323,69 +335,80 @@ mod tests { } } + impl Hasher for MyWriter { + fn reset(&mut self) { self.hash = 0; } + fn finish(&self) -> u64 { self.hash } + } + #[test] fn test_writer_hasher() { use alloc::boxed::Box; - let hasher = MyWriterHasher; + fn hash>(t: &T) -> u64 { + let mut hasher = MyWriter { hash: 0 }; + t.hash(&mut hasher); + hasher.finish() + } - assert_eq!(hasher.hash(&()), 0); + assert_eq!(hash(&()), 0); - assert_eq!(hasher.hash(&5u8), 5); - assert_eq!(hasher.hash(&5u16), 5); - assert_eq!(hasher.hash(&5u32), 5); - assert_eq!(hasher.hash(&5u64), 5); - assert_eq!(hasher.hash(&5u), 5); + assert_eq!(hash(&5u8), 5); + assert_eq!(hash(&5u16), 5); + assert_eq!(hash(&5u32), 5); + assert_eq!(hash(&5u64), 5); + assert_eq!(hash(&5u), 5); - assert_eq!(hasher.hash(&5i8), 5); - assert_eq!(hasher.hash(&5i16), 5); - assert_eq!(hasher.hash(&5i32), 5); - assert_eq!(hasher.hash(&5i64), 5); - assert_eq!(hasher.hash(&5i), 5); + assert_eq!(hash(&5i8), 5); + assert_eq!(hash(&5i16), 5); + assert_eq!(hash(&5i32), 5); + assert_eq!(hash(&5i64), 5); + assert_eq!(hash(&5i), 5); - assert_eq!(hasher.hash(&false), 0); - assert_eq!(hasher.hash(&true), 1); + assert_eq!(hash(&false), 0); + assert_eq!(hash(&true), 1); - assert_eq!(hasher.hash(&'a'), 97); + assert_eq!(hash(&'a'), 97); let s: &str = "a"; - assert_eq!(hasher.hash(& s), 97 + 0xFF); + assert_eq!(hash(& s), 97 + 0xFF); // FIXME (#18283) Enable test //let s: Box = box "a"; //assert_eq!(hasher.hash(& s), 97 + 0xFF); let cs: &[u8] = &[1u8, 2u8, 3u8]; - assert_eq!(hasher.hash(& cs), 9); + assert_eq!(hash(& cs), 9); let cs: Box<[u8]> = box [1u8, 2u8, 3u8]; - assert_eq!(hasher.hash(& cs), 9); + assert_eq!(hash(& cs), 9); // FIXME (#18248) Add tests for hashing Rc and Rc<[T]> - unsafe { - let ptr: *const int = mem::transmute(5i); - assert_eq!(hasher.hash(&ptr), 5); - } + let ptr = 5i as *const int; + assert_eq!(hash(&ptr), 5); - unsafe { - let ptr: *mut int = mem::transmute(5i); - assert_eq!(hasher.hash(&ptr), 5); - } + let ptr = 5i as *mut int; + assert_eq!(hash(&ptr), 5); } struct Custom { hash: u64 } - impl Hash for Custom { - fn hash(&self, state: &mut u64) { - *state = self.hash; + struct CustomHasher { state: u64 } + + impl Writer for CustomHasher { + fn write(&mut self, _data: &[u8]) {} + } + + impl Hash for Custom { + fn hash(&self, state: &mut CustomHasher) { + state.state = self.hash; } } #[test] fn test_custom_state() { let custom = Custom { hash: 5 }; - let mut state = 0; + let mut state = CustomHasher { state: 0 }; custom.hash(&mut state); - assert_eq!(state, 5); + assert_eq!(state.state, 5); } } diff --git a/src/libcollections/hash/sip.rs b/src/libcollections/hash/sip.rs index 9a7aa8c20d3a1..90de06cef850e 100644 --- a/src/libcollections/hash/sip.rs +++ b/src/libcollections/hash/sip.rs @@ -11,27 +11,28 @@ // ignore-lexer-test FIXME #15883 //! An implementation of SipHash 2-4. -//! -//! See: http://131002.net/siphash/ -//! -//! Consider this as a main "general-purpose" hash for all hashtables: it -//! runs at good speed (competitive with spooky and city) and permits -//! strong _keyed_ hashing. Key your hashtables from a strong RNG, -//! such as `rand::Rng`. -//! -//! Although the SipHash algorithm is considered to be cryptographically -//! strong, this implementation has not been reviewed for such purposes. -//! As such, all cryptographic uses of this implementation are strongly -//! discouraged. use core::prelude::*; use core::default::Default; -use super::{Hash, Hasher, Writer}; - -/// `SipState` computes a SipHash 2-4 hash over a stream of bytes. -pub struct SipState { +use super::{Hasher, Writer}; + +/// An implementation of SipHash 2-4. +/// +/// See: http://131002.net/siphash/ +/// +/// Consider this as a main "general-purpose" hash for all hashtables: it +/// runs at good speed (competitive with spooky and city) and permits +/// strong _keyed_ hashing. Key your hashtables from a strong RNG, +/// such as `rand::Rng`. +/// +/// Although the SipHash algorithm is considered to be cryptographically +/// strong, this implementation has not been reviewed for such purposes. +/// As such, all cryptographic uses of this implementation are strongly +/// discouraged. +#[allow(missing_copy_implementations)] +pub struct SipHasher { k0: u64, k1: u64, length: uint, // how many bytes we've processed @@ -43,8 +44,6 @@ pub struct SipState { ntail: uint, // how many bytes in tail are valid } -impl Copy for SipState {} - // sadly, these macro definitions can't appear later, // because they're needed in the following defs; // this design could be improved. @@ -88,17 +87,17 @@ macro_rules! compress ( }) ) -impl SipState { - /// Creates a `SipState` that is keyed off the provided keys. +impl SipHasher { + /// Creates a new `SipHasher` with the two initial keys set to 0. #[inline] - pub fn new() -> SipState { - SipState::new_with_keys(0, 0) + pub fn new() -> SipHasher { + SipHasher::new_with_keys(0, 0) } - /// Creates a `SipState` that is keyed off the provided keys. + /// Creates a `SipHasher` that is keyed off the provided keys. #[inline] - pub fn new_with_keys(key0: u64, key1: u64) -> SipState { - let mut state = SipState { + pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { + let mut state = SipHasher { k0: key0, k1: key1, length: 0, @@ -113,43 +112,12 @@ impl SipState { state } - /// Resets the state to its initial state. - #[inline] - pub fn reset(&mut self) { - self.length = 0; - self.v0 = self.k0 ^ 0x736f6d6570736575; - self.v1 = self.k1 ^ 0x646f72616e646f6d; - self.v2 = self.k0 ^ 0x6c7967656e657261; - self.v3 = self.k1 ^ 0x7465646279746573; - self.ntail = 0; - } - /// Returns the computed hash. - #[inline] - pub fn result(&self) -> u64 { - let mut v0 = self.v0; - let mut v1 = self.v1; - let mut v2 = self.v2; - let mut v3 = self.v3; - - let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail; - - v3 ^= b; - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - v0 ^= b; - - v2 ^= 0xff; - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - compress!(v0, v1, v2, v3); - - v0 ^ v1 ^ v2 ^ v3 - } + #[deprecated = "renamed to finish"] + pub fn result(&self) -> u64 { self.finish() } } -impl Writer for SipState { +impl Writer for SipHasher { #[inline] fn write(&mut self, msg: &[u8]) { let length = msg.len(); @@ -197,77 +165,62 @@ impl Writer for SipState { } } -impl Clone for SipState { - #[inline] - fn clone(&self) -> SipState { - *self +impl Hasher for SipHasher { + fn reset(&mut self) { + self.length = 0; + self.v0 = self.k0 ^ 0x736f6d6570736575; + self.v1 = self.k1 ^ 0x646f72616e646f6d; + self.v2 = self.k0 ^ 0x6c7967656e657261; + self.v3 = self.k1 ^ 0x7465646279746573; + self.ntail = 0; } -} -impl Default for SipState { - #[inline] - fn default() -> SipState { - SipState::new() - } -} + fn finish(&self) -> u64 { + let mut v0 = self.v0; + let mut v1 = self.v1; + let mut v2 = self.v2; + let mut v3 = self.v3; -/// `SipHasher` computes the SipHash algorithm from a stream of bytes. -#[deriving(Clone)] -#[allow(missing_copy_implementations)] -pub struct SipHasher { - k0: u64, - k1: u64, -} + let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail; -impl SipHasher { - /// Creates a `Sip`. - #[inline] - pub fn new() -> SipHasher { - SipHasher::new_with_keys(0, 0) - } + v3 ^= b; + compress!(v0, v1, v2, v3); + compress!(v0, v1, v2, v3); + v0 ^= b; - /// Creates a `Sip` that is keyed off the provided keys. - #[inline] - pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher { - SipHasher { - k0: key0, - k1: key1, - } + v2 ^= 0xff; + compress!(v0, v1, v2, v3); + compress!(v0, v1, v2, v3); + compress!(v0, v1, v2, v3); + compress!(v0, v1, v2, v3); + + v0 ^ v1 ^ v2 ^ v3 } } -impl Hasher for SipHasher { +impl Clone for SipHasher { #[inline] - fn hash>(&self, value: &T) -> u64 { - let mut state = SipState::new_with_keys(self.k0, self.k1); - value.hash(&mut state); - state.result() + fn clone(&self) -> SipHasher { + SipHasher { + k0: self.k0, + k1: self.k1, + length: self.length, + v0: self.v0, + v1: self.v1, + v2: self.v2, + v3: self.v3, + tail: self.tail, + ntail: self.ntail, + } } } impl Default for SipHasher { - #[inline] fn default() -> SipHasher { SipHasher::new() } } -/// Hashes a value using the SipHash algorithm. -#[inline] -pub fn hash>(value: &T) -> u64 { - let mut state = SipState::new(); - value.hash(&mut state); - state.result() -} - -/// Hashes a value with the SipHash algorithm with the provided keys. -#[inline] -pub fn hash_with_keys>(k0: u64, k1: u64, value: &T) -> u64 { - let mut state = SipState::new_with_keys(k0, k1); - value.hash(&mut state); - state.result() -} - #[cfg(test)] mod tests { use test::Bencher; @@ -279,8 +232,15 @@ mod tests { use slice::{AsSlice, SlicePrelude}; use vec::Vec; - use super::super::{Hash, Writer}; - use super::{SipState, hash, hash_with_keys}; + use hash::hash; + use super::super::{Hash, Writer, Hasher}; + use super::SipHasher; + + fn hash_with_keys>(k1: u64, k2: u64, t: &T) -> u64 { + let mut s = SipHasher::new_with_keys(k1, k2); + t.hash(&mut s); + s.finish() + } // Hash just the bytes of the slice, without length prefix struct Bytes<'a>(&'a [u8]); @@ -367,8 +327,8 @@ mod tests { let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64; let mut buf = Vec::new(); let mut t = 0; - let mut state_inc = SipState::new_with_keys(k0, k1); - let mut state_full = SipState::new_with_keys(k0, k1); + let mut state_inc = SipHasher::new_with_keys(k0, k1); + let mut state_full = SipHasher::new_with_keys(k0, k1); fn to_hex_str(r: &[u8, ..8]) -> String { let mut s = String::new(); diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 039bbcd2b7020..999359e9d4f54 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -24,7 +24,7 @@ #![allow(unknown_features)] #![feature(macro_rules, default_type_params, phase, globs)] #![feature(unsafe_destructor, import_shadowing, slicing_syntax)] -#![feature(tuple_indexing, unboxed_closures)] +#![feature(associated_types, unboxed_closures)] #![no_std] #[phase(plugin, link)] extern crate core; diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs index cc36c2eef4552..0078eab562a2e 100644 --- a/src/libflate/lib.rs +++ b/src/libflate/lib.rs @@ -21,7 +21,7 @@ #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_root_url = "http://doc.rust-lang.org/nightly/")] -#![feature(phase)] +#![feature(phase, default_type_params)] #[cfg(test)] #[phase(plugin, link)] extern crate log; diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3f555ec5c4cbe..f32c6eba3f51b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -71,7 +71,7 @@ use std::borrow::BorrowFrom; use std::cell::{Cell, RefCell}; use std::cmp; use std::fmt::{mod, Show}; -use std::hash::{Hash, sip, Writer}; +use std::hash::{Hash, Writer, SipHasher, Hasher}; use std::mem; use std::ops; use std::rc::Rc; @@ -5697,11 +5697,11 @@ pub fn trait_item_of_item(tcx: &ctxt, def_id: ast::DefId) /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { - let mut state = sip::SipState::new(); + let mut state = SipHasher::new(); macro_rules! byte( ($b:expr) => { ($b as u8).hash(&mut state) } ); macro_rules! hash( ($e:expr) => { $e.hash(&mut state) } ); - let region = |_state: &mut sip::SipState, r: Region| { + let region = |_state: &mut SipHasher, r: Region| { match r { ReStatic => {} @@ -5715,7 +5715,7 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { } } }; - let did = |state: &mut sip::SipState, did: DefId| { + let did = |state: &mut SipHasher, did: DefId| { let h = if ast_util::is_local(did) { svh.clone() } else { @@ -5724,7 +5724,7 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { h.as_str().hash(state); did.node.hash(state); }; - let mt = |state: &mut sip::SipState, mt: mt| { + let mt = |state: &mut SipHasher, mt: mt| { mt.mutbl.hash(state); }; ty::walk_ty(ty, |ty| { @@ -5817,7 +5817,7 @@ pub fn hash_crate_independent(tcx: &ctxt, ty: Ty, svh: &Svh) -> u64 { } }); - state.result() + state.finish() } impl Variance { diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 30318cc129cac..c53ba7b2bf52d 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -15,6 +15,7 @@ use std::collections::HashMap; use std::fmt::Show; use std::hash::{Hash, Hasher}; use std::time::Duration; +use std::collections::hash_state::HashState; use syntax::ast; use syntax::visit; @@ -132,8 +133,8 @@ pub fn block_query(b: &ast::Block, p: |&ast::Expr| -> bool) -> bool { /// Efficiency note: This is implemented in an inefficient way because it is typically invoked on /// very small graphs. If the graphs become larger, a more efficient graph representation and /// algorithm would probably be advised. -pub fn can_reach,T:Eq+Clone+Hash>( - edges_map: &HashMap,H>, +pub fn can_reach, H: Hasher, T: Eq + Clone + Hash>( + edges_map: &HashMap, S>, source: T, destination: T) -> bool @@ -194,8 +195,9 @@ pub fn can_reach,T:Eq+Clone+Hash>( /// } /// ``` #[inline(always)] -pub fn memoized + Eq, U: Clone, S, H: Hasher>( - cache: &RefCell>, +pub fn memoized + Eq, U: Clone, H: Hasher, + S: HashState>( + cache: &RefCell>, arg: T, f: |T| -> U ) -> U { diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs index d1816c655fa5f..c6215a4629131 100644 --- a/src/librustc/util/nodemap.rs +++ b/src/librustc/util/nodemap.rs @@ -12,12 +12,14 @@ #![allow(non_snake_case)] +use std::collections::hash_state::{DefaultState}; use std::collections::{HashMap, HashSet}; -use std::hash::{Hasher, Hash, Writer}; +use std::default::Default; +use std::hash::{Hasher, Writer}; use syntax::ast; -pub type FnvHashMap = HashMap; -pub type FnvHashSet = HashSet; +pub type FnvHashMap = HashMap>; +pub type FnvHashSet = HashSet>; pub type NodeMap = FnvHashMap; pub type DefIdMap = FnvHashMap; @@ -28,16 +30,16 @@ pub type DefIdSet = FnvHashSet; // Hacks to get good names pub mod FnvHashMap { use std::hash::Hash; - use std::collections::HashMap; - pub fn new + Eq, V>() -> super::FnvHashMap { - HashMap::with_hasher(super::FnvHasher) + use std::default::Default; + pub fn new + Eq, V>() -> super::FnvHashMap { + Default::default() } } pub mod FnvHashSet { use std::hash::Hash; - use std::collections::HashSet; - pub fn new + Eq>() -> super::FnvHashSet { - HashSet::with_hasher(super::FnvHasher) + use std::default::Default; + pub fn new + Eq>() -> super::FnvHashSet { + Default::default() } } pub mod NodeMap { @@ -68,30 +70,25 @@ pub mod DefIdSet { /// /// This uses FNV hashing, as described here: /// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function -#[deriving(Clone, Default)] -pub struct FnvHasher; - -impl Copy for FnvHasher {} - #[allow(missing_copy_implementations)] -pub struct FnvState(u64); +pub struct FnvHasher(u64); -impl Hasher for FnvHasher { - fn hash>(&self, t: &T) -> u64 { - let mut state = FnvState(0xcbf29ce484222325); - t.hash(&mut state); - let FnvState(ret) = state; - return ret; - } +impl Default for FnvHasher { + fn default() -> FnvHasher { FnvHasher(0xcbf29ce484222325) } +} + +impl Hasher for FnvHasher { + fn reset(&mut self) { *self = Default::default(); } + fn finish(&self) -> u64 { self.0 } } -impl Writer for FnvState { +impl Writer for FnvHasher { fn write(&mut self, bytes: &[u8]) { - let FnvState(mut hash) = *self; + let FnvHasher(mut hash) = *self; for byte in bytes.iter() { hash = hash ^ (*byte as u64); hash = hash * 0x100000001b3; } - *self = FnvState(hash); + *self = FnvHasher(hash); } } diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index fc98a5cd6b559..6004ba71f9477 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -30,7 +30,7 @@ html_root_url = "http://doc.rust-lang.org/nightly/")] #![allow(unknown_features)] -#![feature(globs, phase, macro_rules, slicing_syntax)] +#![feature(globs, phase, macro_rules, slicing_syntax, default_type_params)] #[phase(plugin, link)] extern crate log; diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 549d636e8cb56..97054f06d4e74 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -47,8 +47,7 @@ //! Original issue: https://github.com/rust-lang/rust/issues/10207 use std::fmt; -use std::hash::Hash; -use std::hash::sip::SipState; +use std::hash::{Hash, SipHasher, Hasher}; use std::iter::range_step; use syntax::ast; use syntax::visit; @@ -78,7 +77,7 @@ impl Svh { // FIXME: this should use SHA1, not SipHash. SipHash is not built to // avoid collisions. - let mut state = SipState::new(); + let mut state = SipHasher::new(); for data in metadata.iter() { data.hash(&mut state); @@ -102,7 +101,7 @@ impl Svh { attr.node.value.hash(&mut state); } - let hash = state.result(); + let hash = state.finish(); return Svh { hash: range_step(0u, 64u, 4u).map(|i| hex(hash >> i)).collect() }; @@ -141,14 +140,13 @@ mod svh_visitor { use syntax::visit; use syntax::visit::{Visitor, FnKind}; - use std::hash::Hash; - use std::hash::sip::SipState; + use std::hash::{Hash, SipHasher}; pub struct StrictVersionHashVisitor<'a> { - pub st: &'a mut SipState, + pub st: &'a mut SipHasher, } - pub fn make<'a>(st: &'a mut SipState) -> StrictVersionHashVisitor<'a> { + pub fn make<'a>(st: &'a mut SipHasher) -> StrictVersionHashVisitor<'a> { StrictVersionHashVisitor { st: st } } @@ -391,7 +389,7 @@ mod svh_visitor { } // All of the remaining methods just record (in the hash - // SipState) that the visitor saw that particular variant + // SipHasher) that the visitor saw that particular variant // (with its payload), and continue walking as the default // visitor would. // diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 23dad21e5303f..d8d4ee41270f5 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -22,7 +22,7 @@ html_root_url = "http://doc.rust-lang.org/nightly/")] #![feature(globs)] -#![feature(link_args)] +#![feature(link_args, default_type_params)] extern crate libc; diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index cb3c56ad2778e..956fffe907ef5 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -28,7 +28,7 @@ use syntax::ast; use syntax::ast_map; use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::attr; -use std::hash::{sip, Hash}; +use std::hash::{Hasher, Hash, SipHasher}; pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_id: ast::DefId, @@ -116,11 +116,11 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let hash; let s = { - let mut state = sip::SipState::new(); + let mut state = SipHasher::new(); hash_id.hash(&mut state); mono_ty.hash(&mut state); - hash = format!("h{}", state.result()); + hash = format!("h{}", state.finish()); ccx.tcx().map.with_path(fn_id.node, |path| { exported_name(path, hash.as_slice()) }) diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index ffeb190ddf87c..6b19134ac8d86 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -13,6 +13,7 @@ use std::uint; use std::default::Default; use std::hash::{Hash, Hasher}; +use std::collections::hash_state::HashState; use {Decodable, Encodable, Decoder, Encoder}; use std::collections::{DList, RingBuf, TreeMap, TreeSet, HashMap, HashSet, @@ -178,11 +179,11 @@ impl< impl< E, S: Encoder, - K: Encodable + Hash + Eq, + K: Encodable + Hash + Eq, V: Encodable, - X, - H: Hasher -> Encodable for HashMap { + H: Hasher, + HS: HashState +> Encodable for HashMap { fn encode(&self, e: &mut S) -> Result<(), E> { e.emit_map(self.len(), |e| { let mut i = 0; @@ -199,15 +200,15 @@ impl< impl< E, D: Decoder, - K: Decodable + Hash + Eq, + K: Decodable + Hash + Eq, V: Decodable, - S, - H: Hasher + Default -> Decodable for HashMap { - fn decode(d: &mut D) -> Result, E> { + H: Hasher, + S: HashState + Default +> Decodable for HashMap { + fn decode(d: &mut D) -> Result, E> { d.read_map(|d, len| { - let hasher = Default::default(); - let mut map = HashMap::with_capacity_and_hasher(len, hasher); + let state = Default::default(); + let mut map = HashMap::with_capacity_and_hash_state(len, state); for i in range(0u, 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))); @@ -221,10 +222,10 @@ impl< impl< E, S: Encoder, - T: Encodable + Hash + Eq, - X, - H: Hasher -> Encodable for HashSet { + T: Encodable + Hash + Eq, + H: Hasher, + HS: HashState, +> Encodable for HashSet { fn encode(&self, s: &mut S) -> Result<(), E> { s.emit_seq(self.len(), |s| { let mut i = 0; @@ -240,13 +241,14 @@ impl< impl< E, D: Decoder, - T: Decodable + Hash + Eq, - S, - H: Hasher + Default -> Decodable for HashSet { - fn decode(d: &mut D) -> Result, E> { + T: Decodable + Hash + Eq, + H: Hasher, + S: HashState + Default, +> Decodable for HashSet { + fn decode(d: &mut D) -> Result, E> { d.read_seq(|d, len| { - let mut set = HashSet::with_capacity_and_hasher(len, Default::default()); + let state = Default::default(); + let mut set = HashSet::with_capacity_and_hash_state(len, state); for i in range(0u, len) { set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d)))); } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a8dce232d26d5..ff1ca5246138c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -17,18 +17,19 @@ use self::VacantEntryState::*; use borrow::BorrowFrom; use clone::Clone; use cmp::{max, Eq, Equiv, PartialEq}; +use collections::hash_state::{HashState, RandomSipState}; use default::Default; use fmt::{mod, Show}; -use hash::{Hash, Hasher, RandomSipHasher}; +use hash::{Hash, Hasher}; use iter::{mod, Iterator, IteratorExt, FromIterator, Extend}; use kinds::Sized; use mem::{mod, replace}; use num::{Int, UnsignedInt}; use ops::{Deref, Index, IndexMut}; -use option::Option; use option::Option::{Some, None}; -use result::Result; +use option::Option; use result::Result::{Ok, Err}; +use result::Result; use super::table; use super::table::{ @@ -286,9 +287,9 @@ fn test_resize_policy() { /// } /// ``` #[deriving(Clone)] -pub struct HashMap { +pub struct HashMap { // All hashes are keyed on these values, to prevent hash collision attacks. - hasher: H, + hash_state: S, table: RawTable, @@ -429,20 +430,22 @@ impl SearchResult { } } -impl, V, S, H: Hasher> HashMap { - fn make_hash>(&self, x: &X) -> SafeHash { - table::make_hash(&self.hasher, x) +impl HashMap + where K: Eq + Hash, H: Hasher, S: HashState +{ + fn make_hash>(&self, x: &X) -> SafeHash { + table::make_hash(&self.hash_state, x) } #[allow(deprecated)] - fn search_equiv<'a, Sized? Q: Hash + Equiv>(&'a self, q: &Q) + fn search_equiv<'a, Sized? Q: Hash + Equiv>(&'a self, q: &Q) -> Option> { let hash = self.make_hash(q); search_hashed(&self.table, &hash, |k| q.equiv(k)).into_option() } #[allow(deprecated)] - fn search_equiv_mut<'a, Sized? Q: Hash + Equiv>(&'a mut self, q: &Q) + fn search_equiv_mut<'a, Sized? Q: Hash + Equiv>(&'a mut self, q: &Q) -> Option> { let hash = self.make_hash(q); search_hashed(&mut self.table, &hash, |k| q.equiv(k)).into_option() @@ -452,7 +455,7 @@ impl, V, S, H: Hasher> HashMap { /// If you already have the hash for the key lying around, use /// search_hashed. fn search<'a, Sized? Q>(&'a self, q: &Q) -> Option> - where Q: BorrowFrom + Eq + Hash + where Q: BorrowFrom + Eq + Hash { let hash = self.make_hash(q); search_hashed(&self.table, &hash, |k| q.eq(BorrowFrom::borrow_from(k))) @@ -460,7 +463,7 @@ impl, V, S, H: Hasher> HashMap { } fn search_mut<'a, Sized? Q>(&'a mut self, q: &Q) -> Option> - where Q: BorrowFrom + Eq + Hash + where Q: BorrowFrom + Eq + Hash { let hash = self.make_hash(q); search_hashed(&mut self.table, &hash, |k| q.eq(BorrowFrom::borrow_from(k))) @@ -489,7 +492,7 @@ impl, V, S, H: Hasher> HashMap { } } -impl HashMap { +impl HashMap { /// Create an empty HashMap. /// /// # Example @@ -500,9 +503,8 @@ impl HashMap { /// ``` #[inline] #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn new() -> HashMap { - let hasher = RandomSipHasher::new(); - HashMap::with_hasher(hasher) + pub fn new() -> HashMap { + Default::default() } /// Creates an empty hash map with the given initial capacity. @@ -515,13 +517,14 @@ impl HashMap { /// ``` #[inline] #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn with_capacity(capacity: uint) -> HashMap { - let hasher = RandomSipHasher::new(); - HashMap::with_capacity_and_hasher(capacity, hasher) + pub fn with_capacity(capacity: uint) -> HashMap { + HashMap::with_capacity_and_hash_state(capacity, Default::default()) } } -impl, V, S, H: Hasher> HashMap { +impl HashMap + where K: Eq + Hash, H: Hasher, S: HashState +{ /// Creates an empty hashmap which will use the given hasher to hash keys. /// /// The creates map has the default initial capacity. @@ -530,21 +533,28 @@ impl, V, S, H: Hasher> HashMap { /// /// ``` /// use std::collections::HashMap; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_state::RandomSipState; /// - /// let h = SipHasher::new(); - /// let mut map = HashMap::with_hasher(h); + /// let s = RandomSipState::new(); + /// let mut map = HashMap::with_hash_state(s); /// map.insert(1i, 2u); /// ``` #[inline] - pub fn with_hasher(hasher: H) -> HashMap { + pub fn with_hash_state(hash_state: S) -> HashMap { HashMap { - hasher: hasher, + hash_state: hash_state, resize_policy: DefaultResizePolicy::new(), table: RawTable::new(0), } } + /// Renamed to `with_hash_state`. + #[inline] + #[deprecated = "renamed to with_hash_state"] + pub fn with_hasher(hash_state: S) -> HashMap { + HashMap::with_hash_state(hash_state) + } + /// Create an empty HashMap with space for at least `capacity` /// elements, using `hasher` to hash the keys. /// @@ -557,25 +567,34 @@ impl, V, S, H: Hasher> HashMap { /// /// ``` /// use std::collections::HashMap; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_state::RandomSipState; /// - /// let h = SipHasher::new(); - /// let mut map = HashMap::with_capacity_and_hasher(10, h); + /// let s = RandomSipState::new(); + /// let mut map = HashMap::with_capacity_and_hash_state(10, s); /// map.insert(1i, 2u); /// ``` #[inline] - pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashMap { + pub fn with_capacity_and_hash_state(capacity: uint, hash_state: S) + -> HashMap { 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 { - hasher: hasher, + hash_state: hash_state, resize_policy: resize_policy, table: RawTable::new(internal_cap), } } + /// Renamed to with_capacity_and_hash_state + #[inline] + #[deprecated = "renamed to with_capacity_and_hash_state"] + pub fn with_capacity_and_hasher(capacity: uint, hash_state: S) + -> HashMap { + HashMap::with_capacity_and_hash_state(capacity, hash_state) + } + /// Returns the number of elements the map can hold without reallocating. /// /// # Example @@ -799,13 +818,17 @@ impl, V, S, H: Hasher> HashMap { /// Deprecated: use `contains_key` and `BorrowFrom` instead. #[deprecated = "use contains_key and BorrowFrom instead"] - pub fn contains_key_equiv + Equiv>(&self, key: &Q) -> bool { + pub fn contains_key_equiv(&self, key: &Q) -> bool + where Q: Hash + Equiv + { self.search_equiv(key).is_some() } /// Deprecated: use `get` and `BorrowFrom` instead. #[deprecated = "use get and BorrowFrom instead"] - pub fn find_equiv<'a, Sized? Q: Hash + Equiv>(&'a self, k: &Q) -> Option<&'a V> { + pub fn find_equiv<'a, Sized? Q>(&'a self, k: &Q) -> Option<&'a V> + where Q: Hash + Equiv + { match self.search_equiv(k) { None => None, Some(bucket) => { @@ -817,7 +840,9 @@ impl, V, S, H: Hasher> HashMap { /// Deprecated: use `remove` and `BorrowFrom` instead. #[deprecated = "use remove and BorrowFrom instead"] - pub fn pop_equiv + Equiv>(&mut self, k: &Q) -> Option { + pub fn pop_equiv(&mut self, k: &Q) -> Option + where Q: Hash + Equiv + { if self.table.size() == 0 { return None } @@ -1044,7 +1069,7 @@ impl, V, S, H: Hasher> HashMap { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn get(&self, k: &Q) -> Option<&V> - where Q: Hash + Eq + BorrowFrom + where Q: Hash + Eq + BorrowFrom { self.search(k).map(|bucket| { let (_, v) = bucket.into_refs(); @@ -1070,7 +1095,7 @@ impl, V, S, H: Hasher> HashMap { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn contains_key(&self, k: &Q) -> bool - where Q: Hash + Eq + BorrowFrom + where Q: Hash + Eq + BorrowFrom { self.search(k).is_some() } @@ -1102,7 +1127,7 @@ impl, V, S, H: Hasher> HashMap { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where Q: Hash + Eq + BorrowFrom + where Q: Hash + Eq + BorrowFrom { match self.search_mut(k) { Some(bucket) => { @@ -1172,7 +1197,7 @@ impl, V, S, H: Hasher> HashMap { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn remove(&mut self, k: &Q) -> Option - where Q: Hash + Eq + BorrowFrom + where Q: Hash + Eq + BorrowFrom { if self.table.size() == 0 { return None @@ -1234,7 +1259,9 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable, hash: SafeHas } } -impl, V: Clone, S, H: Hasher> HashMap { +impl HashMap + where K: Eq + Hash, V: Clone, H: Hasher, S: HashState +{ /// Deprecated: Use `map.get(k).cloned()`. /// /// Return a copy of the value corresponding to the key. @@ -1252,8 +1279,10 @@ impl, V: Clone, S, H: Hasher> HashMap { } } -impl, V: PartialEq, S, H: Hasher> PartialEq for HashMap { - fn eq(&self, other: &HashMap) -> bool { +impl PartialEq for HashMap + where K: Eq + Hash, V: PartialEq, H: Hasher, S: HashState +{ + fn eq(&self, other: &HashMap) -> bool { if self.len() != other.len() { return false; } self.iter().all(|(key, value)| @@ -1262,9 +1291,12 @@ impl, V: PartialEq, S, H: Hasher> PartialEq for HashMap, V: Eq, S, H: Hasher> Eq for HashMap {} +impl Eq for HashMap + where K: Eq + Hash, V: Eq, H: Hasher, S: HashState {} -impl + Show, V: Show, S, H: Hasher> Show for HashMap { +impl Show for HashMap + where K: Eq + Hash + Show, V: Show, H: Hasher, S: HashState +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{")); @@ -1277,14 +1309,19 @@ impl + Show, V: Show, S, H: Hasher> Show for HashMap } } -impl, V, S, H: Hasher + Default> Default for HashMap { - fn default() -> HashMap { - HashMap::with_hasher(Default::default()) +impl Default for HashMap + where K: Eq + Hash, H: Hasher, S: HashState + Default +{ + fn default() -> HashMap { + HashMap::with_hash_state(Default::default()) } } -impl + Eq, Sized? Q, V, S, H: Hasher> Index for HashMap - where Q: BorrowFrom + Hash + Eq +impl Index for HashMap + where K: Eq + Hash, + Q: BorrowFrom + Hash + Eq, + H: Hasher, + S: HashState { #[inline] fn index<'a>(&'a self, index: &Q) -> &'a V { @@ -1292,8 +1329,11 @@ impl + Eq, Sized? Q, V, S, H: Hasher> Index for HashMap + Eq, Sized? Q, V, S, H: Hasher> IndexMut for HashMap - where Q: BorrowFrom + Hash + Eq +impl IndexMut for HashMap + where K: Eq + Hash, + Q: BorrowFrom + Hash + Eq, + H: Hasher, + S: HashState { #[inline] fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V { @@ -1440,16 +1480,23 @@ pub type Keys<'a, K, V> = pub type Values<'a, K, V> = iter::Map<'static, (&'a K, &'a V), &'a V, Entries<'a, K, V>>; -impl, V, S, H: Hasher + Default> FromIterator<(K, V)> for HashMap { - fn from_iter>(iter: T) -> HashMap { +impl FromIterator<(K, V)> for HashMap + where K: Eq + Hash, H: Hasher, + S: HashState + Default +{ + fn from_iter>(iter: T) -> HashMap { let (lower, _) = iter.size_hint(); - let mut map = HashMap::with_capacity_and_hasher(lower, Default::default()); + let state = Default::default(); + let mut map = HashMap::with_capacity_and_hash_state(lower, state); map.extend(iter); map } } -impl, V, S, H: Hasher + Default> Extend<(K, V)> for HashMap { +impl Extend<(K, V)> for HashMap + where K: Eq + Hash, H: Hasher, + S: HashState + Default +{ fn extend>(&mut self, mut iter: T) { for (k, v) in iter { self.insert(k, v); diff --git a/src/libstd/collections/hash/mod.rs b/src/libstd/collections/hash/mod.rs index ee3fc1e6ac362..47e300af26981 100644 --- a/src/libstd/collections/hash/mod.rs +++ b/src/libstd/collections/hash/mod.rs @@ -11,6 +11,7 @@ //! Unordered containers, implemented as hash-tables mod bench; +mod table; pub mod map; pub mod set; -mod table; +pub mod state; diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index b3ccfdbb47cce..cd5b02453fa50 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -16,7 +16,8 @@ use core::kinds::Sized; use default::Default; use fmt::Show; use fmt; -use hash::{Hash, Hasher, RandomSipHasher}; +use hash::{Hash, Hasher}; +use collections::hash_state::{HashState, RandomSipState}; use iter::{Iterator, IteratorExt, FromIterator, FilterMap, Chain, Repeat, Zip, Extend, repeat}; use iter; use option::Option::{Some, None}; @@ -92,11 +93,11 @@ use super::map::{HashMap, Entries, MoveEntries, INITIAL_CAPACITY}; /// } /// ``` #[deriving(Clone)] -pub struct HashSet { - map: HashMap +pub struct HashSet { + map: HashMap } -impl HashSet { +impl HashSet { /// Create an empty HashSet. /// /// # Example @@ -107,7 +108,7 @@ impl HashSet { /// ``` #[inline] #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn new() -> HashSet { + pub fn new() -> HashSet { HashSet::with_capacity(INITIAL_CAPACITY) } @@ -122,12 +123,12 @@ impl HashSet { /// ``` #[inline] #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn with_capacity(capacity: uint) -> HashSet { + pub fn with_capacity(capacity: uint) -> HashSet { HashSet { map: HashMap::with_capacity(capacity) } } } -impl, S, H: Hasher> HashSet { +impl, H: Hasher, S: HashState> HashSet { /// Creates a new empty hash set which will use the given hasher to hash /// keys. /// @@ -137,15 +138,22 @@ impl, S, H: Hasher> HashSet { /// /// ``` /// use std::collections::HashSet; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_state::RandomSipState; /// - /// let h = SipHasher::new(); - /// let mut set = HashSet::with_hasher(h); + /// let s = RandomSipState::new(); + /// let mut set = HashSet::with_hash_state(s); /// set.insert(2u); /// ``` #[inline] - pub fn with_hasher(hasher: H) -> HashSet { - HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher) + pub fn with_hash_state(hash_state: S) -> HashSet { + HashSet::with_capacity_and_hash_state(INITIAL_CAPACITY, hash_state) + } + + /// Deprecated in favor of `with_hash_state` + #[inline] + #[deprecated = "renamed to with_hash_state"] + pub fn with_hasher(hash_state: S) -> HashSet { + HashSet::with_hash_state(hash_state) } /// Create an empty HashSet with space for at least `capacity` @@ -160,15 +168,26 @@ impl, S, H: Hasher> HashSet { /// /// ``` /// use std::collections::HashSet; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_state::RandomSipState; /// - /// let h = SipHasher::new(); - /// let mut set = HashSet::with_capacity_and_hasher(10u, h); + /// let s = RandomSipState::new(); + /// let mut set = HashSet::with_capacity_and_hash_state(10u, s); /// set.insert(1i); /// ``` #[inline] - pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet { - HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } + pub fn with_capacity_and_hash_state(capacity: uint, hash_state: S) + -> HashSet { + HashSet { + map: HashMap::with_capacity_and_hash_state(capacity, hash_state), + } + } + + /// Deprecated in favor of `with_capacity_and_hash_state` + #[inline] + #[deprecated = "renamed to with_capacity_and_hash_state"] + pub fn with_capacity_and_hasher(capacity: uint, hash_state: S) + -> HashSet { + HashSet::with_capacity_and_hash_state(capacity, hash_state) } /// Returns the number of elements the set can hold without reallocating. @@ -230,7 +249,7 @@ impl, S, H: Hasher> HashSet { /// Deprecated: use `contains` and `BorrowFrom`. #[deprecated = "use contains and BorrowFrom"] #[allow(deprecated)] - pub fn contains_equiv + Equiv>(&self, value: &Q) -> bool { + pub fn contains_equiv + Equiv>(&self, value: &Q) -> bool { self.map.contains_key_equiv(value) } @@ -303,7 +322,7 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(diff, [4i].iter().map(|&x| x).collect()); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn difference<'a>(&'a self, other: &'a HashSet) -> SetAlgebraItems<'a, T, H> { + pub fn difference<'a>(&'a self, other: &'a HashSet) -> SetAlgebraItems<'a, T, S> { repeat(other).zip(self.iter()) .filter_map(|(other, elt)| { if !other.contains(elt) { Some(elt) } else { None } @@ -331,8 +350,8 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(diff1, [1i, 4].iter().map(|&x| x).collect()); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) - -> Chain, SetAlgebraItems<'a, T, H>> { + pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) + -> Chain, SetAlgebraItems<'a, T, S>> { self.difference(other).chain(other.difference(self)) } @@ -354,8 +373,8 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect()); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn intersection<'a>(&'a self, other: &'a HashSet) - -> SetAlgebraItems<'a, T, H> { + pub fn intersection<'a>(&'a self, other: &'a HashSet) + -> SetAlgebraItems<'a, T, S> { repeat(other).zip(self.iter()) .filter_map(|(other, elt)| { if other.contains(elt) { Some(elt) } else { None } @@ -380,8 +399,8 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect()); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn union<'a>(&'a self, other: &'a HashSet) - -> Chain, SetAlgebraItems<'a, T, H>> { + pub fn union<'a>(&'a self, other: &'a HashSet) + -> Chain, SetAlgebraItems<'a, T, S>> { self.iter().chain(other.difference(self)) } @@ -447,7 +466,7 @@ impl, S, H: Hasher> HashSet { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn contains(&self, value: &Q) -> bool - where Q: BorrowFrom + Hash + Eq + where Q: BorrowFrom + Hash + Eq { self.map.contains_key(value) } @@ -470,7 +489,7 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(a.is_disjoint(&b), false); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn is_disjoint(&self, other: &HashSet) -> bool { + pub fn is_disjoint(&self, other: &HashSet) -> bool { self.iter().all(|v| !other.contains(v)) } @@ -491,7 +510,7 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(set.is_subset(&sup), false); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn is_subset(&self, other: &HashSet) -> bool { + pub fn is_subset(&self, other: &HashSet) -> bool { self.iter().all(|v| other.contains(v)) } @@ -516,7 +535,7 @@ impl, S, H: Hasher> HashSet { /// ``` #[inline] #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn is_superset(&self, other: &HashSet) -> bool { + pub fn is_superset(&self, other: &HashSet) -> bool { other.is_subset(self) } @@ -557,23 +576,29 @@ impl, S, H: Hasher> HashSet { /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn remove(&mut self, value: &Q) -> bool - where Q: BorrowFrom + Hash + Eq + where Q: BorrowFrom + Hash + Eq { self.map.remove(value).is_some() } } -impl, S, H: Hasher> PartialEq for HashSet { - fn eq(&self, other: &HashSet) -> bool { +impl PartialEq for HashSet + where T: Eq + Hash, H: Hasher, S: HashState +{ + fn eq(&self, other: &HashSet) -> bool { if self.len() != other.len() { return false; } self.iter().all(|key| other.contains(key)) } } -impl, S, H: Hasher> Eq for HashSet {} +impl Eq for HashSet + where T: Eq + Hash, H: Hasher, S: HashState +{} -impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { +impl fmt::Show for HashSet + where T: Eq + Hash, H: Hasher, S: HashState +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "{{")); @@ -586,16 +611,21 @@ impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { } } -impl, S, H: Hasher + Default> FromIterator for HashSet { - fn from_iter>(iter: I) -> HashSet { +impl FromIterator for HashSet + where T: Eq + Hash, H: Hasher, S: HashState + Default +{ + fn from_iter>(iter: I) -> HashSet { let (lower, _) = iter.size_hint(); - let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); + let state = Default::default(); + let mut set = HashSet::with_capacity_and_hash_state(lower, state); set.extend(iter); set } } -impl, S, H: Hasher + Default> Extend for HashSet { +impl Extend for HashSet + where T: Eq + Hash, H: Hasher, S: HashState +{ fn extend>(&mut self, mut iter: I) { for k in iter { self.insert(k); @@ -603,9 +633,11 @@ impl, S, H: Hasher + Default> Extend for HashSet { } } -impl, S, H: Hasher + Default> Default for HashSet { - fn default() -> HashSet { - HashSet::with_hasher(Default::default()) +impl Default for HashSet + where T: Eq + Hash, H: Hasher, S: HashState + Default +{ + fn default() -> HashSet { + HashSet::with_hash_state(Default::default()) } } @@ -620,9 +652,9 @@ pub type SetMoveItems = // `Repeat` is used to feed the filter closure an explicit capture // of a reference to the other set /// Set operations iterator -pub type SetAlgebraItems<'a, T, H> = - FilterMap<'static, (&'a HashSet, &'a T), &'a T, - Zip>, SetItems<'a, T>>>; +pub type SetAlgebraItems<'a, T, S> = + FilterMap<'static, (&'a HashSet, &'a T), &'a T, + Zip>, SetItems<'a, T>>>; #[cfg(test)] mod test_set { diff --git a/src/libstd/collections/hash/state.rs b/src/libstd/collections/hash/state.rs new file mode 100644 index 0000000000000..d498f7d49ea58 --- /dev/null +++ b/src/libstd/collections/hash/state.rs @@ -0,0 +1,82 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use clone::Clone; +use default::Default; +use hash::{Hasher, SipHasher}; +use rand::{mod, Rng}; + +/// 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. +// FIXME(#17307) the `H` type parameter should be an associated type +#[unstable = "interface may become more general in the future"] +pub trait HashState> { + /// Creates a new hasher based on the given state of this object. + fn hasher(&self) -> H; +} + +/// A structure which is a factory for instances of `Hasher` which implement the +/// default trait. +/// +/// This struct has is 0-sized and does not need construction. +pub struct DefaultState; + +impl> HashState for DefaultState { + fn hasher(&self) -> T { Default::default() } +} + +impl Clone for DefaultState { + fn clone(&self) -> DefaultState { DefaultState } +} + +impl Default for DefaultState { + fn default() -> DefaultState { DefaultState } +} + +/// `RandomSipState` is a factory for instances of `SipHasher` which is created +/// with random keys. +#[deriving(Clone)] +#[unstable = "this structure may not make it through to stability at 1.0"] +#[allow(missing_copy_implementations)] +pub struct RandomSipState { + k0: u64, + k1: u64, +} + +impl RandomSipState { + /// Construct a new `RandomSipState` that is initialized with random keys. + #[inline] + pub fn new() -> RandomSipState { + let mut r = rand::task_rng(); + RandomSipState { k0: r.gen(), k1: r.gen() } + } +} + +impl HashState for RandomSipState { + fn hasher(&self) -> SipHasher { SipHasher::new_with_keys(self.k0, self.k1) } +} + +#[stable] +impl Default for RandomSipState { + #[inline] + fn default() -> RandomSipState { + RandomSipState::new() + } +} diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index ef4cabedc474e..f0e39da51868b 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -26,6 +26,7 @@ use option::Option::{Some, None}; use ptr::{RawPtr, copy_nonoverlapping_memory, zero_memory}; use ptr; use rt::heap::{allocate, deallocate}; +use collections::hash_state::HashState; const EMPTY_BUCKET: u64 = 0u64; @@ -138,8 +139,12 @@ impl SafeHash { /// We need to remove hashes of 0. That's reserved for empty buckets. /// This function wraps up `hash_keyed` to be the only way outside this /// module to generate a SafeHash. -pub fn make_hash, S, H: Hasher>(hasher: &H, t: &T) -> SafeHash { - match hasher.hash(t) { +pub fn make_hash(hash_state: &S, t: &T) -> SafeHash + where T: Hash, H: Hasher, S: HashState +{ + let mut state = hash_state.hasher(); + t.hash(&mut state); + match state.finish() { // This constant is exceedingly likely to hash to the same // bucket, but it won't be counted as empty! Just so we can maintain // our precious uniform distribution of initial indexes. diff --git a/src/libstd/collections/lru_cache.rs b/src/libstd/collections/lru_cache.rs index 6caa2f7b4da6a..beab5875194ad 100644 --- a/src/libstd/collections/lru_cache.rs +++ b/src/libstd/collections/lru_cache.rs @@ -40,7 +40,7 @@ use cmp::{PartialEq, Eq}; use collections::HashMap; use fmt; -use hash::Hash; +use hash::{Hash, Writer}; use iter::{range, Iterator, Extend}; use mem; use ops::Drop; @@ -69,7 +69,7 @@ pub struct LruCache { head: *mut LruEntry, } -impl> Hash for KeyRef { +impl> Hash for KeyRef { fn hash(&self, state: &mut S) { unsafe { (*self.k).hash(state) } } diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 3419a3d98a154..e38c9b349db39 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -351,4 +351,11 @@ pub mod hash_set { pub use super::hash::set::*; } +/// Experimental support for providing custom hash algorithms to a HashMap and +/// HashSet. +#[unstable] +pub mod hash_state { + pub use super::hash::state::*; +} + pub mod lru_cache; diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs deleted file mode 100644 index ac68e1ef121fb..0000000000000 --- a/src/libstd/hash.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Generic hashing support. -//! -//! This module provides a generic way to compute the hash of a value. The -//! simplest way to make a type hashable is to use `#[deriving(Hash)]`: -//! -//! # Example -//! -//! ```rust -//! use std::hash; -//! use std::hash::Hash; -//! -//! #[deriving(Hash)] -//! struct Person { -//! id: uint, -//! name: String, -//! phone: u64, -//! } -//! -//! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; -//! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; -//! -//! assert!(hash::hash(&person1) != hash::hash(&person2)); -//! ``` -//! -//! If you need more control over how a value is hashed, you need to implement -//! the trait `Hash`: -//! -//! ```rust -//! use std::hash; -//! use std::hash::Hash; -//! use std::hash::sip::SipState; -//! -//! struct Person { -//! id: uint, -//! name: String, -//! phone: u64, -//! } -//! -//! impl Hash for Person { -//! fn hash(&self, state: &mut SipState) { -//! self.id.hash(state); -//! self.phone.hash(state); -//! } -//! } -//! -//! let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; -//! let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; -//! -//! assert!(hash::hash(&person1) == hash::hash(&person2)); -//! ``` - -#![experimental] - -pub use core_collections::hash::{Hash, Hasher, Writer, hash, sip}; - -use core::kinds::Sized; -use default::Default; -use rand::Rng; -use rand; - -/// `RandomSipHasher` computes the SipHash algorithm from a stream of bytes -/// initialized with random keys. -#[deriving(Clone)] -pub struct RandomSipHasher { - hasher: sip::SipHasher, -} - -impl RandomSipHasher { - /// Construct a new `RandomSipHasher` that is initialized with random keys. - #[inline] - pub fn new() -> RandomSipHasher { - let mut r = rand::task_rng(); - let r0 = r.gen(); - let r1 = r.gen(); - RandomSipHasher { - hasher: sip::SipHasher::new_with_keys(r0, r1), - } - } -} - -impl Hasher for RandomSipHasher { - #[inline] - fn hash>(&self, value: &T) -> u64 { - self.hasher.hash(value) - } -} - -impl Default for RandomSipHasher { - #[inline] - fn default() -> RandomSipHasher { - RandomSipHasher::new() - } -} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f6b73f037f25b..f68f5cc527aba 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -161,6 +161,7 @@ pub use core::option; pub use alloc::boxed; pub use alloc::rc; +pub use core_collections::hash; pub use core_collections::slice; pub use core_collections::str; pub use core_collections::string; @@ -225,7 +226,6 @@ pub mod time; /* Common data structures */ pub mod collections; -pub mod hash; /* Tasks and communication */ @@ -252,6 +252,7 @@ mod std { pub use clone; pub use cmp; pub use hash; + pub use default; pub use comm; // used for select!() pub use error; // used for try!() diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index b7f11c2582548..849f2404ce787 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -35,7 +35,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, } else { (Path::new(vec!("std", "hash", "Hash")), LifetimeBounds::empty(), - Path::new(vec!("std", "hash", "sip", "SipState"))) + Path::new(vec!("std", "hash", "SipHasher"))) }; let inline = cx.meta_word(span, InternedString::new("inline")); let attrs = vec!(cx.attribute(span, inline)); diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 1b231ed861b89..9e74064070a81 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -36,7 +36,7 @@ use std::fmt; use std::fmt::Show; -use std::hash::Hash; +use std::hash::{Hash, Writer}; use std::ptr; use serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -97,7 +97,7 @@ impl Show for P { } } -impl> Hash for P { +impl> Hash for P { fn hash(&self, state: &mut S) { (**self).hash(state); }