From 511f0b8a3de5a166fc96aba5170782c9abf92101 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 prepare the `std::hash` module for alpha by formalizing its current interface whileholding off on adding `#[stable]` to the new APIs. The current usage with the `HashMap` and `HashSet` types is also reconciled by separating out composable parts of the design. 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 { type Output; fn reset(&mut self); fn finish(&self) -> Output; } This `Hasher` trait emphasizes that hashing algorithms may produce outputs other than a `u64`, so the output type is made generic. Other than that, however, very little is assumed about a particular hasher. It is left up to implementors to provide specific methods or trait implementations to feed data into a hasher. The corresponding `Hash` trait becomes: trait Hash { fn hash(&self, &mut H); } The old default of `SipState` was removed from this trait as it's not something that we're willing to stabilize until the end of time, but the type parameter is always required to implement `Hasher`. Note that the type parameter `H` remains on the trait to enable multidispatch for specialization of hashing for particular hashers. Note that `Writer` is not mentioned in either of `Hash` or `Hasher`, it is simply used as part `derive` and the implementations for all primitive types. With these definitions, the old `Hasher` trait is realized as a new `HashState` trait in the `collections::hash_state` module as an unstable addition for now. The current definition looks like: trait HashState { type Hasher: Hasher; fn hasher(&self) -> Hasher; } 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. The entire module and `HashState` infrastructure remains `#[unstable]` due to it being recently redesigned, but some other stability decision made for the `std::hash` module are: * 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. And finally, a few changes were made to the default parameters on `HashMap`. * The `RandomSipHasher` default type parameter was renamed to `RandomState`. This renaming emphasizes that it is not a hasher, but rather just state to generate hashers. It also moves away from the name "sip" as it may not always be implemented as `SipHasher`. This type lives in the `std::collections::hash_map` module as `#[unstable]` * The associated `Hasher` type of `RandomState` is creatively called... `Hasher`! This concrete structure lives next to `RandomState` as an implemenation of the "default hashing algorithm" used for a `HashMap`. Under the hood this is currently implemented as `SipHasher`, but it draws an explicit interface for now and allows us to modify the implementation over time if necessary. There are many breaking changes outlined above, and as a result this commit is a: [breaking-change] --- src/compiletest/compiletest.rs | 2 +- src/liballoc/arc.rs | 21 +- src/liballoc/boxed.rs | 8 + src/liballoc/rc.rs | 35 +- src/libcollections/bit.rs | 4 +- src/libcollections/btree/map.rs | 14 +- src/libcollections/btree/set.rs | 4 +- src/libcollections/dlist.rs | 10 +- src/libcollections/lib.rs | 2 +- src/libcollections/ring_buf.rs | 8 +- src/libcollections/string.rs | 9 + src/libcollections/vec.rs | 8 + src/libcollections/vec_map.rs | 12 +- src/libcore/hash/mod.rs | 473 ++++++++++++++------ src/libcore/hash/sip.rs | 460 +++---------------- src/libcoretest/hash/mod.rs | 103 +++-- src/librustc/lint/mod.rs | 2 +- src/librustc/metadata/decoder.rs | 5 +- src/librustc/metadata/encoder.rs | 9 +- src/librustc/middle/ty.rs | 26 +- src/librustc/util/common.rs | 22 +- src/librustc/util/nodemap.rs | 46 +- src/librustc/util/ppaux.rs | 11 +- src/librustc_back/svh.rs | 16 +- src/librustc_trans/trans/monomorphize.rs | 6 +- src/libserialize/collection_impls.rs | 60 ++- src/libserialize/lib.rs | 1 - src/libstd/bitflags.rs | 6 +- src/libstd/collections/hash/map.rs | 206 ++++++--- src/libstd/collections/hash/mod.rs | 3 +- src/libstd/collections/hash/set.rs | 217 +++++---- src/libstd/collections/hash/state.rs | 51 +++ src/libstd/collections/hash/table.rs | 11 +- src/libstd/collections/mod.rs | 7 + src/libstd/hash.rs | 105 ----- src/libstd/io/process.rs | 8 +- src/libstd/lib.rs | 3 +- src/libstd/path/posix.rs | 2 +- src/libstd/path/windows.rs | 2 +- src/libstd/sys/unix/process.rs | 9 +- src/libstd/sys/windows/process.rs | 9 +- src/libsyntax/ext/deriving/hash.rs | 3 +- src/libsyntax/ptr.rs | 13 +- src/libsyntax/util/interner.rs | 9 +- src/libtest/stats.rs | 4 +- src/test/bench/core-set.rs | 3 +- src/test/run-pass/deriving-hash.rs | 12 +- src/test/run-pass/deriving-meta-multiple.rs | 4 +- src/test/run-pass/deriving-meta.rs | 4 +- src/test/run-pass/typeid-intrinsic.rs | 5 +- 50 files changed, 1061 insertions(+), 1012 deletions(-) create mode 100644 src/libstd/collections/hash/state.rs delete mode 100644 src/libstd/hash.rs diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index e2420b0a22024..ac8cf543a423a 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -9,7 +9,7 @@ // except according to those terms. #![crate_type = "bin"] -#![feature(slicing_syntax, unboxed_closures)] +#![feature(slicing_syntax)] #![deny(warnings)] diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 8def8ad721528..38d6f4dad6ea9 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -67,21 +67,20 @@ //! } //! ``` +use core::prelude::*; + use core::atomic; use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst}; use core::borrow::BorrowFrom; -use core::clone::Clone; use core::fmt::{self, Show}; -use core::cmp::{Eq, Ord, PartialEq, PartialOrd, Ordering}; +use core::cmp::{Ordering}; use core::default::Default; -use core::marker::{Sync, Send}; -use core::mem::{min_align_of, size_of, drop}; +use core::mem::{min_align_of, size_of}; use core::mem; use core::nonzero::NonZero; -use core::ops::{Drop, Deref}; -use core::option::Option; -use core::option::Option::{Some, None}; -use core::ptr::{self, PtrExt}; +use core::ops::Deref; +use core::ptr; +use core::hash::{Hash, Hasher}; use heap::deallocate; /// An atomically reference counted wrapper for shared state. @@ -591,6 +590,12 @@ impl Default for Arc { fn default() -> Arc { Arc::new(Default::default()) } } +impl> Hash for Arc { + fn hash(&self, state: &mut H) { + (**self).hash(state) + } +} + #[cfg(test)] #[allow(experimental)] mod tests { diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index d46f18abf97b4..adca8b9cc4c27 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -106,12 +106,20 @@ impl Ord for Box { #[stable]} impl Eq for Box {} +#[cfg(stage0)] impl> Hash for Box { #[inline] fn hash(&self, state: &mut S) { (**self).hash(state); } } +#[cfg(not(stage0))] +impl> Hash for Box { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } +} /// Extension methods for an owning `Any` trait object. #[unstable = "post-DST and coherence changes, this will not be a trait but \ diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 67b2542771012..83eff71e2b80f 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -10,23 +10,26 @@ //! Thread-local reference-counted boxes (the `Rc` type). //! -//! The `Rc` type provides shared ownership of an immutable value. Destruction is deterministic, -//! and will occur as soon as the last owner is gone. It is marked as non-sendable because it -//! avoids the overhead of atomic reference counting. +//! The `Rc` type provides shared ownership of an immutable value. +//! Destruction is deterministic, and will occur as soon as the last owner is +//! gone. It is marked as non-sendable because it avoids the overhead of atomic +//! reference counting. //! -//! The `downgrade` method can be used to create a non-owning `Weak` pointer to the box. A -//! `Weak` pointer can be upgraded to an `Rc` pointer, but will return `None` if the value -//! has already been dropped. +//! The `downgrade` method can be used to create a non-owning `Weak` pointer +//! to the box. A `Weak` pointer can be upgraded to an `Rc` pointer, but +//! will return `None` if the value has already been dropped. //! -//! For example, a tree with parent pointers can be represented by putting the nodes behind strong -//! `Rc` pointers, and then storing the parent pointers as `Weak` pointers. +//! For example, a tree with parent pointers can be represented by putting the +//! nodes behind strong `Rc` pointers, and then storing the parent pointers +//! as `Weak` pointers. //! //! # Examples //! -//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. We want to have our -//! `Gadget`s point to their `Owner`. We can't do this with unique ownership, because more than one -//! gadget may belong to the same `Owner`. `Rc` allows us to share an `Owner` between multiple -//! `Gadget`s, and have the `Owner` remain allocated as long as any `Gadget` points at it. +//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. +//! We want to have our `Gadget`s point to their `Owner`. We can't do this with +//! unique ownership, because more than one gadget may belong to the same +//! `Owner`. `Rc` allows us to share an `Owner` between multiple `Gadget`s, +//! and have the `Owner` remain allocated as long as any `Gadget` points at it. //! //! ```rust //! use std::rc::Rc; @@ -597,12 +600,20 @@ impl Ord for Rc { } // FIXME (#18248) Make `T` `Sized?` +#[cfg(stage0)] impl> Hash for Rc { #[inline] fn hash(&self, state: &mut S) { (**self).hash(state); } } +#[cfg(not(stage0))] +impl> Hash for Rc { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } +} #[experimental = "Show is experimental."] impl fmt::Show for Rc { diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 2154d06377a19..f7277d4dfd8fc 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -982,7 +982,7 @@ impl fmt::Show for Bitv { } #[stable] -impl hash::Hash for Bitv { +impl hash::Hash for Bitv { fn hash(&self, state: &mut S) { self.nbits.hash(state); for elem in self.blocks() { @@ -1742,7 +1742,7 @@ impl fmt::Show for BitvSet { } } -impl hash::Hash for BitvSet { +impl hash::Hash for BitvSet { fn hash(&self, state: &mut S) { for pos in self.iter() { pos.hash(state); diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 4e44779810b29..3e1533dd35f59 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -23,7 +23,9 @@ use core::borrow::BorrowFrom; use core::cmp::Ordering; use core::default::Default; use core::fmt::Show; -use core::hash::{Writer, Hash}; +use core::hash::{Hash, Hasher}; +#[cfg(stage0)] +use core::hash::Writer; use core::iter::{Map, FromIterator}; use core::ops::{Index, IndexMut}; use core::{iter, fmt, mem}; @@ -820,6 +822,7 @@ impl Extend<(K, V)> for BTreeMap { } #[stable] +#[cfg(stage0)] impl, V: Hash> Hash for BTreeMap { fn hash(&self, state: &mut S) { for elt in self.iter() { @@ -827,6 +830,15 @@ impl, V: Hash> Hash for BTreeMap { } } } +#[stable] +#[cfg(not(stage0))] +impl, V: Hash> Hash for BTreeMap { + fn hash(&self, state: &mut S) { + for elt in self.iter() { + elt.hash(state); + } + } +} #[stable] impl Default for BTreeMap { diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 25df4a3cc2a6f..812cff6fab722 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -678,7 +678,7 @@ mod test { use prelude::*; use super::BTreeSet; - use std::hash; + use std::hash::{self, SipHasher}; #[test] fn test_clone_eq() { @@ -703,7 +703,7 @@ mod test { y.insert(2); y.insert(1); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y)); } struct Counter<'a, 'b> { diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index 63ea9f7cb4322..0b426f6016cb8 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -27,7 +27,7 @@ use alloc::boxed::Box; use core::cmp::Ordering; use core::default::Default; use core::fmt; -use core::hash::{Writer, Hash}; +use core::hash::{Writer, Hasher, Hash}; use core::iter::{self, FromIterator}; use core::mem; use core::ptr; @@ -675,7 +675,7 @@ impl fmt::Show for DList { } #[stable] -impl> Hash for DList { +impl> Hash for DList { fn hash(&self, state: &mut S) { self.len().hash(state); for elt in self.iter() { @@ -688,7 +688,7 @@ impl> Hash for DList { mod tests { use prelude::*; use std::rand; - use std::hash; + use std::hash::{self, SipHasher}; use std::thread::Thread; use test::Bencher; use test; @@ -951,7 +951,7 @@ mod tests { let mut x = DList::new(); let mut y = DList::new(); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y)); x.push_back(1i); x.push_back(2); @@ -961,7 +961,7 @@ mod tests { y.push_front(2); y.push_front(1); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y)); } #[test] diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs index 6eab36d8844df..84cd898a263fe 100644 --- a/src/libcollections/lib.rs +++ b/src/libcollections/lib.rs @@ -23,8 +23,8 @@ #![allow(unknown_features)] #![feature(unsafe_destructor, slicing_syntax)] -#![feature(old_impl_check)] #![feature(unboxed_closures)] +#![feature(old_impl_check)] #![no_std] #[macro_use] diff --git a/src/libcollections/ring_buf.rs b/src/libcollections/ring_buf.rs index 42c17136a0882..a35482aa5d3c2 100644 --- a/src/libcollections/ring_buf.rs +++ b/src/libcollections/ring_buf.rs @@ -27,7 +27,7 @@ use core::ops::{Index, IndexMut}; use core::ptr; use core::raw::Slice as RawSlice; -use std::hash::{Writer, Hash}; +use std::hash::{Writer, Hash, Hasher}; use std::cmp; use alloc::heap; @@ -1562,7 +1562,7 @@ impl Ord for RingBuf { } #[stable] -impl> Hash for RingBuf { +impl> Hash for RingBuf { fn hash(&self, state: &mut S) { self.len().hash(state); for elt in self.iter() { @@ -1631,7 +1631,7 @@ mod tests { use prelude::*; use core::iter; use std::fmt::Show; - use std::hash; + use std::hash::{self, SipHasher}; use test::Bencher; use test; @@ -2283,7 +2283,7 @@ mod tests { y.push_back(2); y.push_back(3); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y)); } #[test] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 59418f50e3c7d..0d91a5d4a643f 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -820,12 +820,21 @@ impl fmt::Show for String { } #[experimental = "waiting on Hash stabilization"] +#[cfg(stage0)] impl hash::Hash for String { #[inline] fn hash(&self, hasher: &mut H) { (**self).hash(hasher) } } +#[experimental = "waiting on Hash stabilization"] +#[cfg(not(stage0))] +impl hash::Hash for String { + #[inline] + fn hash(&self, hasher: &mut H) { + (**self).hash(hasher) + } +} #[unstable = "recent addition, needs more experience"] impl<'a> Add<&'a str> for String { diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 5fc3fafac9e22..ed86eaa308078 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1183,12 +1183,20 @@ impl Clone for Vec { } } +#[cfg(stage0)] impl> Hash for Vec { #[inline] fn hash(&self, state: &mut S) { self.as_slice().hash(state); } } +#[cfg(not(stage0))] +impl> Hash for Vec { + #[inline] + fn hash(&self, state: &mut S) { + self.as_slice().hash(state); + } +} #[experimental = "waiting on Index stability"] impl Index for Vec { diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 4399a6fec2274..d4ce266d3e211 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -18,7 +18,7 @@ use core::prelude::*; use core::cmp::Ordering; use core::default::Default; use core::fmt; -use core::hash::{Hash, Writer}; +use core::hash::{Hash, Writer, Hasher}; use core::iter::{Enumerate, FilterMap, Map, FromIterator}; use core::iter; use core::mem::replace; @@ -85,7 +85,7 @@ impl Clone for VecMap { } } -impl> Hash for VecMap { +impl> Hash for VecMap { fn hash(&self, state: &mut S) { // In order to not traverse the `VecMap` twice, count the elements // during iteration. @@ -712,7 +712,7 @@ impl DoubleEndedIterator for IntoIter { #[cfg(test)] mod test_map { use prelude::*; - use core::hash::hash; + use core::hash::{hash, SipHasher}; use super::VecMap; @@ -1004,7 +1004,7 @@ mod test_map { let mut x = VecMap::new(); let mut y = VecMap::new(); - assert!(hash(&x) == hash(&y)); + assert!(hash::<_, SipHasher>(&x) == hash::<_, SipHasher>(&y)); x.insert(1, 'a'); x.insert(2, 'b'); x.insert(3, 'c'); @@ -1013,12 +1013,12 @@ mod test_map { y.insert(2, 'b'); y.insert(1, 'a'); - assert!(hash(&x) == hash(&y)); + assert!(hash::<_, SipHasher>(&x) == hash::<_, SipHasher>(&y)); x.insert(1000, 'd'); x.remove(&1000); - assert!(hash(&x) == hash(&y)); + assert!(hash::<_, SipHasher>(&x) == hash::<_, SipHasher>(&y)); } #[test] diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index d8b9cf9594d6a..a82ea009e1361 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -16,8 +16,7 @@ //! # Examples //! //! ```rust -//! use std::hash; -//! use std::hash::Hash; +//! use std::hash::{hash, Hash, SipHasher}; //! //! #[derive(Hash)] //! struct Person { @@ -29,16 +28,14 @@ //! 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)); +//! assert!(hash::<_, SipHasher>(&person1) != hash::<_, SipHasher>(&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; +//! use std::hash::{hash, Hash, Hasher, Writer, SipHasher}; //! //! struct Person { //! id: uint, @@ -46,8 +43,8 @@ //! phone: u64, //! } //! -//! impl Hash for Person { -//! fn hash(&self, state: &mut SipState) { +//! impl Hash for Person { +//! fn hash(&self, state: &mut H) { //! self.id.hash(state); //! self.phone.hash(state); //! } @@ -56,186 +53,382 @@ //! 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)); +//! assert_eq!(hash::<_, SipHasher>(&person1), hash::<_, SipHasher>(&person2)); //! ``` -#![allow(unused_must_use)] +#![unstable = "module was recently redesigned"] -use prelude::*; +use default::Default; -use borrow::{Cow, ToOwned}; -use intrinsics::TypeId; -use mem; -use num::Int; +pub use self::sip::SipHasher; -/// Reexport the `sip::hash` function as our default hasher. -pub use self::sip::hash as hash; +mod sip; -pub mod sip; +/// A hashable type. +/// +/// The `H` type parameter is an abstract hash state that is used by the `Hash` +/// to compute the hash. Specific implementations of this trait may specialize +/// for particular instances of `H` in order to be able to optimize the hashing +/// behavior. +#[cfg(stage0)] +pub trait Hash { + /// Feeds this value into the state given, updating the hasher as necessary. + fn hash(&self, state: &mut H); +} -/// 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 { - /// Computes the hash of a value. - fn hash(&self, state: &mut S); +/// A hashable type. +/// +/// The `H` type parameter is an abstract hash state that is used by the `Hash` +/// to compute the hash. Specific implementations of this trait may specialize +/// for particular instances of `H` in order to be able to optimize the hashing +/// behavior. +#[cfg(not(stage0))] +pub trait Hash { + /// Feeds this value into the state given, updating the hasher as necessary. + fn hash(&self, state: &mut H); } -/// 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; +/// A trait which represents the ability to hash an arbitrary stream of bytes. +pub trait Hasher { + /// Result type of one run of hashing generated by this hasher. + type Output; + + /// Resets this hasher back to its initial state (as if it were just + /// created). + fn reset(&mut self); + + /// Completes a round of hashing, producing the output hash generated. + fn finish(&self) -> Self::Output; } +/// A common bound on the `Hasher` parameter to `Hash` implementations in order +/// to generically hash an aggregate. +#[experimental = "this trait will likely be replaced by io::Writer"] #[allow(missing_docs)] 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. +pub fn hash, H: Hasher + Default>(value: &T) -> H::Output { + let mut h: H = Default::default(); + value.hash(&mut h); + h.finish() +} + ////////////////////////////////////////////////////////////////////////////// -macro_rules! impl_hash { - ($ty:ident, $uty:ident) => { - impl Hash for $ty { - #[inline] - fn hash(&self, state: &mut S) { - let a: [u8; ::$ty::BYTES] = unsafe { - mem::transmute((*self as $uty).to_le() as $ty) - }; - state.write(a.as_slice()) +#[cfg(stage0)] +mod impls { + use prelude::*; + + use borrow::{Cow, ToOwned}; + use intrinsics::TypeId; + use mem; + use super::{Hash, Writer}; + use num::Int; + + macro_rules! impl_hash { + ($ty:ident, $uty:ident) => { + impl Hash for $ty { + #[inline] + fn hash(&self, state: &mut S) { + let a: [u8; ::$ty::BYTES] = unsafe { + mem::transmute((*self as $uty).to_le() as $ty) + }; + state.write(a.as_slice()) + } } } } -} -impl_hash! { u8, u8 } -impl_hash! { u16, u16 } -impl_hash! { u32, u32 } -impl_hash! { u64, u64 } -impl_hash! { uint, uint } -impl_hash! { i8, u8 } -impl_hash! { i16, u16 } -impl_hash! { i32, u32 } -impl_hash! { i64, u64 } -impl_hash! { int, uint } - -impl Hash for bool { - #[inline] - fn hash(&self, state: &mut S) { - (*self as u8).hash(state); + impl_hash! { u8, u8 } + impl_hash! { u16, u16 } + impl_hash! { u32, u32 } + impl_hash! { u64, u64 } + impl_hash! { uint, uint } + impl_hash! { i8, u8 } + impl_hash! { i16, u16 } + impl_hash! { i32, u32 } + impl_hash! { i64, u64 } + impl_hash! { int, uint } + + impl Hash for bool { + #[inline] + fn hash(&self, state: &mut S) { + (*self as u8).hash(state); + } } -} -impl Hash for char { - #[inline] - fn hash(&self, state: &mut S) { - (*self as u32).hash(state); + impl Hash for char { + #[inline] + fn hash(&self, state: &mut S) { + (*self as u32).hash(state); + } } -} -impl Hash for str { - #[inline] - fn hash(&self, state: &mut S) { - state.write(self.as_bytes()); - 0xffu8.hash(state) + impl Hash for str { + #[inline] + fn hash(&self, state: &mut S) { + state.write(self.as_bytes()); + 0xffu8.hash(state) + } } -} -macro_rules! impl_hash_tuple { - () => ( - impl Hash for () { - #[inline] - fn hash(&self, state: &mut S) { - state.write(&[]); + macro_rules! impl_hash_tuple { + () => ( + impl Hash for () { + #[inline] + fn hash(&self, _state: &mut S) {} } - } - ); - - ( $($name:ident)+) => ( - impl),*> Hash for ($($name,)*) { - #[inline] - #[allow(non_snake_case)] - fn hash(&self, state: &mut S) { - match *self { - ($(ref $name,)*) => { - $( - $name.hash(state); - )* + ); + + ( $($name:ident)+) => ( + impl),*> Hash for ($($name,)*) { + #[inline] + #[allow(non_snake_case)] + fn hash(&self, state: &mut S) { + match *self { + ($(ref $name,)*) => { + $( + $name.hash(state); + )* + } } } } + ); + } + + impl_hash_tuple! {} + impl_hash_tuple! { A } + impl_hash_tuple! { A B } + impl_hash_tuple! { A B C } + impl_hash_tuple! { A B C D } + impl_hash_tuple! { A B C D E } + impl_hash_tuple! { A B C D E F } + impl_hash_tuple! { A B C D E F G } + impl_hash_tuple! { A B C D E F G H } + impl_hash_tuple! { A B C D E F G H I } + impl_hash_tuple! { A B C D E F G H I J } + impl_hash_tuple! { A B C D E F G H I J K } + impl_hash_tuple! { A B C D E F G H I J K L } + + impl> Hash for [T] { + #[inline] + fn hash(&self, state: &mut S) { + self.len().hash(state); + for elt in self.iter() { + elt.hash(state); + } } - ); -} + } + -impl_hash_tuple! {} -impl_hash_tuple! { A } -impl_hash_tuple! { A B } -impl_hash_tuple! { A B C } -impl_hash_tuple! { A B C D } -impl_hash_tuple! { A B C D E } -impl_hash_tuple! { A B C D E F } -impl_hash_tuple! { A B C D E F G } -impl_hash_tuple! { A B C D E F G H } -impl_hash_tuple! { A B C D E F G H I } -impl_hash_tuple! { A B C D E F G H I J } -impl_hash_tuple! { A B C D E F G H I J K } -impl_hash_tuple! { A B C D E F G H I J K L } - -impl> Hash for [T] { - #[inline] - fn hash(&self, state: &mut S) { - self.len().hash(state); - for elt in self.iter() { - elt.hash(state); + impl<'a, S, T: ?Sized + Hash> Hash for &'a T { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); } } -} + impl<'a, S, T: ?Sized + Hash> Hash for &'a mut T { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } + } -impl<'a, S: Writer, T: ?Sized + Hash> Hash for &'a T { - #[inline] - fn hash(&self, state: &mut S) { - (**self).hash(state); + impl Hash for *const T { + #[inline] + fn hash(&self, state: &mut S) { + // NB: raw-pointer Hash does _not_ dereference + // to the target; it just gives you the pointer-bytes. + (*self as uint).hash(state); + } } -} -impl<'a, S: Writer, T: ?Sized + Hash> Hash for &'a mut T { - #[inline] - fn hash(&self, state: &mut S) { - (**self).hash(state); + impl Hash for *mut T { + #[inline] + fn hash(&self, state: &mut S) { + // NB: raw-pointer Hash does _not_ dereference + // to the target; it just gives you the pointer-bytes. + (*self as uint).hash(state); + } } -} -impl Hash for *const T { - #[inline] - fn hash(&self, state: &mut S) { - // NB: raw-pointer Hash does _not_ dereference - // to the target; it just gives you the pointer-bytes. - (*self as uint).hash(state); + impl Hash for TypeId { + #[inline] + fn hash(&self, state: &mut S) { + self.hash().hash(state) + } } -} -impl Hash for *mut T { - #[inline] - fn hash(&self, state: &mut S) { - // NB: raw-pointer Hash does _not_ dereference - // to the target; it just gives you the pointer-bytes. - (*self as uint).hash(state); + impl<'a, T, B: ?Sized, S> Hash for Cow<'a, T, B> + where B: Hash + ToOwned + { + #[inline] + fn hash(&self, state: &mut S) { + Hash::hash(&**self, state) + } } } -impl Hash for TypeId { - #[inline] - fn hash(&self, state: &mut S) { - self.hash().hash(state) +#[cfg(not(stage0))] +mod impls { + use prelude::*; + + use borrow::{Cow, ToOwned}; + use intrinsics::TypeId; + use mem; + use super::{Hash, Writer, Hasher}; + use num::Int; + + macro_rules! impl_hash { + ($ty:ident, $uty:ident) => { + impl Hash for $ty { + #[inline] + fn hash(&self, state: &mut S) { + let a: [u8; ::$ty::BYTES] = unsafe { + mem::transmute((*self as $uty).to_le() as $ty) + }; + state.write(a.as_slice()) + } + } + } + } + + impl_hash! { u8, u8 } + impl_hash! { u16, u16 } + impl_hash! { u32, u32 } + impl_hash! { u64, u64 } + impl_hash! { uint, uint } + impl_hash! { i8, u8 } + impl_hash! { i16, u16 } + impl_hash! { i32, u32 } + impl_hash! { i64, u64 } + impl_hash! { int, uint } + + impl Hash for bool { + #[inline] + fn hash(&self, state: &mut S) { + (*self as u8).hash(state); + } + } + + impl Hash for char { + #[inline] + fn hash(&self, state: &mut S) { + (*self as u32).hash(state); + } + } + + impl Hash for str { + #[inline] + fn hash(&self, state: &mut S) { + state.write(self.as_bytes()); + 0xffu8.hash(state) + } + } + + macro_rules! impl_hash_tuple { + () => ( + impl Hash for () { + #[inline] + fn hash(&self, _state: &mut S) {} + } + ); + + ( $($name:ident)+) => ( + impl),*> Hash for ($($name,)*) { + #[inline] + #[allow(non_snake_case)] + fn hash(&self, state: &mut S) { + match *self { + ($(ref $name,)*) => { + $( + $name.hash(state); + )* + } + } + } + } + ); + } + + impl_hash_tuple! {} + impl_hash_tuple! { A } + impl_hash_tuple! { A B } + impl_hash_tuple! { A B C } + impl_hash_tuple! { A B C D } + impl_hash_tuple! { A B C D E } + impl_hash_tuple! { A B C D E F } + impl_hash_tuple! { A B C D E F G } + impl_hash_tuple! { A B C D E F G H } + impl_hash_tuple! { A B C D E F G H I } + impl_hash_tuple! { A B C D E F G H I J } + impl_hash_tuple! { A B C D E F G H I J K } + impl_hash_tuple! { A B C D E F G H I J K L } + + impl> Hash for [T] { + #[inline] + fn hash(&self, state: &mut S) { + self.len().hash(state); + for elt in self.iter() { + elt.hash(state); + } + } + } + + + impl<'a, S: Hasher, T: ?Sized + Hash> Hash for &'a T { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } + } + + impl<'a, S: Hasher, T: ?Sized + Hash> Hash for &'a mut T { + #[inline] + fn hash(&self, state: &mut S) { + (**self).hash(state); + } } -} -impl<'a, T, B: ?Sized, S> Hash for Cow<'a, T, B> where B: Hash + ToOwned { - #[inline] - fn hash(&self, state: &mut S) { - Hash::hash(&**self, state) + impl Hash for *const T { + #[inline] + fn hash(&self, state: &mut S) { + // NB: raw-pointer Hash does _not_ dereference + // to the target; it just gives you the pointer-bytes. + (*self as uint).hash(state); + } + } + + impl Hash for *mut T { + #[inline] + fn hash(&self, state: &mut S) { + // NB: raw-pointer Hash does _not_ dereference + // to the target; it just gives you the pointer-bytes. + (*self as uint).hash(state); + } + } + + impl Hash for TypeId { + #[inline] + fn hash(&self, state: &mut S) { + self.hash().hash(state) + } + } + + impl<'a, T, B: ?Sized, S: Hasher> Hash for Cow<'a, T, B> + where B: Hash + ToOwned + { + #[inline] + fn hash(&self, state: &mut S) { + Hash::hash(&**self, state) + } } } diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index c4d45e9c2c804..c20fb8457d26e 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -11,27 +11,27 @@ // 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 prelude::*; use default::Default; -use super::{Hash, Hasher, Writer}; - -/// `SipState` computes a SipHash 2-4 hash over a stream of bytes. -#[derive(Copy)] -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 @@ -86,17 +86,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, @@ -111,43 +111,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(); @@ -195,355 +164,60 @@ impl Writer for SipState { } } -#[stable] -impl Clone for SipState { - #[inline] - fn clone(&self) -> SipState { - *self - } -} +impl Hasher for SipHasher { + type Output = u64; -#[stable] -impl Default for SipState { - #[inline] - #[stable] - fn default() -> SipState { - SipState::new() + 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; } -} -/// `SipHasher` computes the SipHash algorithm from a stream of bytes. -#[derive(Clone)] -#[allow(missing_copy_implementations)] -pub struct SipHasher { - k0: u64, - k1: u64, -} + fn finish(&self) -> u64 { + let mut v0 = self.v0; + let mut v1 = self.v1; + let mut v2 = self.v2; + let mut v3 = self.v3; -impl SipHasher { - /// Creates a `Sip`. - #[inline] - pub fn new() -> SipHasher { - SipHasher::new_with_keys(0, 0) - } + let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail; - /// 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, - } + 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 } } -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; - use prelude::*; - use std::fmt; - - use super::super::{Hash, Writer}; - use super::{SipState, hash, hash_with_keys}; - - // Hash just the bytes of the slice, without length prefix - struct Bytes<'a>(&'a [u8]); - - impl<'a, S: Writer> Hash for Bytes<'a> { - #[allow(unused_must_use)] - fn hash(&self, state: &mut S) { - let Bytes(v) = *self; - state.write(v); - } - } - - #[test] - #[allow(unused_must_use)] - fn test_siphash() { - let vecs : [[u8; 8]; 64] = [ - [ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ], - [ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ], - [ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ], - [ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ], - [ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ], - [ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ], - [ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ], - [ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ], - [ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ], - [ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ], - [ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ], - [ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ], - [ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ], - [ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ], - [ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ], - [ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ], - [ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ], - [ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ], - [ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ], - [ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ], - [ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ], - [ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ], - [ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ], - [ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ], - [ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ], - [ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ], - [ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ], - [ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ], - [ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ], - [ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ], - [ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ], - [ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ], - [ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ], - [ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ], - [ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ], - [ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ], - [ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ], - [ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ], - [ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ], - [ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ], - [ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ], - [ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ], - [ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ], - [ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ], - [ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ], - [ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ], - [ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ], - [ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ], - [ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ], - [ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ], - [ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ], - [ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ], - [ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ], - [ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ], - [ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ], - [ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ], - [ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ], - [ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ], - [ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ], - [ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ], - [ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ], - [ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ], - [ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ], - [ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ] - ]; - - let k0 = 0x_07_06_05_04_03_02_01_00_u64; - 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); - - fn to_hex_str(r: &[u8; 8]) -> String { - let mut s = String::new(); - for b in r.iter() { - s.push_str(format!("{}", fmt::radix(*b, 16)).as_slice()); - } - s - } - - fn result_bytes(h: u64) -> Vec { - vec![(h >> 0) as u8, - (h >> 8) as u8, - (h >> 16) as u8, - (h >> 24) as u8, - (h >> 32) as u8, - (h >> 40) as u8, - (h >> 48) as u8, - (h >> 56) as u8, - ] - } - - fn result_str(h: u64) -> String { - let r = result_bytes(h); - let mut s = String::new(); - for b in r.iter() { - s.push_str(format!("{}", fmt::radix(*b, 16)).as_slice()); - } - s - } - - while t < 64 { - debug!("siphash test {}: {}", t, buf); - let vec = u8to64_le!(vecs[t], 0); - let out = hash_with_keys(k0, k1, &Bytes(buf.as_slice())); - debug!("got {}, expected {}", out, vec); - assert_eq!(vec, out); - - state_full.reset(); - state_full.write(buf.as_slice()); - let f = result_str(state_full.result()); - let i = result_str(state_inc.result()); - let v = to_hex_str(&vecs[t]); - debug!("{}: ({}) => inc={} full={}", t, v, i, f); - - assert_eq!(f, i); - assert_eq!(f, v); - - buf.push(t as u8); - state_inc.write(&[t as u8]); - - t += 1; - } - } - - #[test] #[cfg(target_arch = "aarch64")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as uint))); - assert!(hash(&(val as u32)) != hash(&(val as uint))); - } - #[test] #[cfg(target_arch = "arm")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); - } - #[test] #[cfg(target_arch = "x86_64")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as uint))); - assert!(hash(&(val as u32)) != hash(&(val as uint))); - } - #[test] #[cfg(target_arch = "x86")] - fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); - } - - #[test] - fn test_hash_idempotent() { - let val64 = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&val64), hash(&val64)); - let val32 = 0xdeadbeef_u32; - assert_eq!(hash(&val32), hash(&val32)); - } - - #[test] - fn test_hash_no_bytes_dropped_64() { - let val = 0xdeadbeef_deadbeef_u64; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - assert!(hash(&val) != hash(&zero_byte(val, 4))); - assert!(hash(&val) != hash(&zero_byte(val, 5))); - assert!(hash(&val) != hash(&zero_byte(val, 6))); - assert!(hash(&val) != hash(&zero_byte(val, 7))); - - fn zero_byte(val: u64, byte: uint) -> u64 { - assert!(byte < 8); - val & !(0xff << (byte * 8)) - } - } - - #[test] - fn test_hash_no_bytes_dropped_32() { - let val = 0xdeadbeef_u32; - - assert!(hash(&val) != hash(&zero_byte(val, 0))); - assert!(hash(&val) != hash(&zero_byte(val, 1))); - assert!(hash(&val) != hash(&zero_byte(val, 2))); - assert!(hash(&val) != hash(&zero_byte(val, 3))); - - fn zero_byte(val: u32, byte: uint) -> u32 { - assert!(byte < 4); - val & !(0xff << (byte * 8)) - } - } - - #[test] - fn test_hash_no_concat_alias() { - let s = ("aa", "bb"); - let t = ("aabb", ""); - let u = ("a", "abb"); - - assert!(s != t && t != u); - assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - - let v: (&[u8], &[u8], &[u8]) = (&[1u8], &[0u8, 0], &[0u8]); - let w: (&[u8], &[u8], &[u8]) = (&[1u8, 0, 0, 0], &[], &[]); - - assert!(v != w); - assert!(hash(&v) != hash(&w)); - } - - #[bench] - fn bench_str_under_8_bytes(b: &mut Bencher) { - let s = "foo"; - b.iter(|| { - assert_eq!(hash(&s), 16262950014981195938); - }) - } - - #[bench] - fn bench_str_of_8_bytes(b: &mut Bencher) { - let s = "foobar78"; - b.iter(|| { - assert_eq!(hash(&s), 4898293253460910787); - }) - } - - #[bench] - fn bench_str_over_8_bytes(b: &mut Bencher) { - let s = "foobarbaz0"; - b.iter(|| { - assert_eq!(hash(&s), 10581415515220175264); - }) - } - - #[bench] - fn bench_long_str(b: &mut Bencher) { - let s = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor \ -incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud \ -exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute \ -irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla \ -pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui \ -officia deserunt mollit anim id est laborum."; - b.iter(|| { - assert_eq!(hash(&s), 17717065544121360093); - }) - } - - #[bench] - fn bench_u64(b: &mut Bencher) { - let u = 16262950014981195938u64; - b.iter(|| { - assert_eq!(hash(&u), 5254097107239593357); - }) - } -} diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 63bf9ec331454..63935894bf514 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -7,27 +7,22 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::marker::Sized; -use std::mem; - -use core::slice::SliceExt; -use core::hash::{Hash, Hasher, Writer}; -struct MyWriterHasher; +use std::mem; +use std::hash::{Hash, Hasher, Writer}; +use std::default::Default; -impl Hasher for MyWriterHasher { - fn hash>(&self, value: &T) -> u64 { - let mut state = MyWriter { hash: 0 }; - value.hash(&mut state); - state.hash - } +struct MyHasher { + hash: u64, } -struct MyWriter { - hash: u64, +impl Default for MyHasher { + fn default() -> MyHasher { + MyHasher { hash: 0 } + } } -impl Writer for MyWriter { +impl Writer for MyHasher { // Most things we'll just add up the bytes. fn write(&mut self, buf: &[u8]) { for byte in buf.iter() { @@ -36,66 +31,88 @@ impl Writer for MyWriter { } } +impl Hasher for MyHasher { + type Output = u64; + fn reset(&mut self) { self.hash = 0; } + fn finish(&self) -> u64 { self.hash } +} + + #[test] fn test_writer_hasher() { - let hasher = MyWriterHasher; + fn hash>(t: &T) -> u64 { + ::std::hash::hash::<_, MyHasher>(t) + } - 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); + assert_eq!(hash(&ptr), 5); } unsafe { let ptr: *mut int = mem::transmute(5i); - assert_eq!(hasher.hash(&ptr), 5); + assert_eq!(hash(&ptr), 5); } } -struct Custom { - hash: u64 +struct Custom { hash: u64 } +struct CustomHasher { output: u64 } + +impl Hasher for CustomHasher { + type Output = u64; + fn reset(&mut self) { self.output = 0; } + fn finish(&self) -> u64 { self.output } +} + +impl Default for CustomHasher { + fn default() -> CustomHasher { + CustomHasher { output: 0 } + } } -impl Hash for Custom { - fn hash(&self, state: &mut u64) { - *state = self.hash; +impl Hash for Custom { + fn hash(&self, state: &mut CustomHasher) { + state.output = self.hash; } } #[test] fn test_custom_state() { + fn hash>(t: &T) -> u64 { + ::std::hash::hash::<_, CustomHasher>(t) + } + let custom = Custom { hash: 5 }; - let mut state = 0; - custom.hash(&mut state); - assert_eq!(state, 5); + assert_eq!(hash(&Custom { hash: 5 }), 5); } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index e9778fa05ff17..7043ea89c7d79 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -186,7 +186,7 @@ impl PartialEq for LintId { impl Eq for LintId { } -impl hash::Hash for LintId { +impl hash::Hash for LintId { fn hash(&self, state: &mut S) { let ptr = self.lint as *const Lint; ptr.hash(state); diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 9e71c867efa09..750f8a2985608 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -33,8 +33,7 @@ use middle::ty::{self, Ty}; use middle::astencode::vtable_decoder_helpers; use std::collections::HashMap; -use std::hash::Hash; -use std::hash; +use std::hash::{self, Hash, SipHasher}; use std::io::extensions::u64_from_be_bytes; use std::io; use std::num::FromPrimitive; @@ -94,7 +93,7 @@ pub fn maybe_find_item<'a>(item_id: ast::NodeId, } lookup_hash(items, |a| eq_item(a, item_id), - hash::hash(&(item_id as i64))) + hash::hash::(&(item_id as i64))) } fn find_item<'a>(item_id: ast::NodeId, items: rbml::Doc<'a>) -> rbml::Doc<'a> { diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 28ad36194ef9a..af1b27afa39c6 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -29,8 +29,7 @@ use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; use serialize::Encodable; use std::cell::RefCell; -use std::hash::Hash; -use std::hash; +use std::hash::{Hash, Hasher, SipHasher}; use syntax::abi; use syntax::ast::{self, DefId, NodeId}; use syntax::ast_map::{PathElem, PathElems}; @@ -1598,11 +1597,13 @@ fn encode_info_for_items(ecx: &EncodeContext, fn encode_index(rbml_w: &mut Encoder, index: Vec>, mut write_fn: F) where F: FnMut(&mut SeekableMemWriter, &T), - T: Hash, + T: Hash, { let mut buckets: Vec>> = range(0, 256u16).map(|_| Vec::new()).collect(); for elt in index.into_iter() { - let h = hash::hash(&elt.val) as uint; + let mut s = SipHasher::new(); + elt.val.hash(&mut s); + let h = s.finish() as uint; (&mut buckets[h % 256]).push(elt); } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 90716844fbe80..edf132dec3d1e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -72,7 +72,7 @@ use std::borrow::BorrowFrom; use std::cell::{Cell, RefCell}; use std::cmp::{self, Ordering}; use std::fmt::{self, Show}; -use std::hash::{Hash, sip, Writer}; +use std::hash::{Hash, Writer, SipHasher, Hasher}; use std::mem; use std::ops; use std::rc::Rc; @@ -946,11 +946,18 @@ impl<'tcx> PartialEq for TyS<'tcx> { } impl<'tcx> Eq for TyS<'tcx> {} +#[cfg(stage0)] impl<'tcx, S: Writer> Hash for TyS<'tcx> { fn hash(&self, s: &mut S) { (self as *const _).hash(s) } } +#[cfg(not(stage0))] +impl<'tcx, S: Writer + Hasher> Hash for TyS<'tcx> { + fn hash(&self, s: &mut S) { + (self as *const _).hash(s) + } +} pub type Ty<'tcx> = &'tcx TyS<'tcx>; @@ -968,7 +975,7 @@ impl<'tcx> PartialEq for InternedTy<'tcx> { impl<'tcx> Eq for InternedTy<'tcx> {} -impl<'tcx, S: Writer> Hash for InternedTy<'tcx> { +impl<'tcx, S: Writer + Hasher> Hash for InternedTy<'tcx> { fn hash(&self, s: &mut S) { self.ty.sty.hash(s) } @@ -6164,15 +6171,16 @@ 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>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) -> u64 { - let mut state = sip::SipState::new(); + let mut state = SipHasher::new(); helper(tcx, ty, svh, &mut state); - return state.result(); + return state.finish(); - fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, state: &mut sip::SipState) { + fn helper<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh, + state: &mut SipHasher) { macro_rules! byte { ($b:expr) => { ($b as u8).hash(state) } } macro_rules! hash { ($e:expr) => { $e.hash(state) } } - let region = |&: state: &mut sip::SipState, r: Region| { + let region = |&: state: &mut SipHasher, r: Region| { match r { ReStatic => {} ReLateBound(db, BrAnon(i)) => { @@ -6189,7 +6197,7 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - } } }; - 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 { @@ -6198,10 +6206,10 @@ pub fn hash_crate_independent<'tcx>(tcx: &ctxt<'tcx>, ty: Ty<'tcx>, svh: &Svh) - 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); }; - let fn_sig = |&: state: &mut sip::SipState, sig: &Binder>| { + let fn_sig = |&: state: &mut SipHasher, sig: &Binder>| { let sig = anonymize_late_bound_regions(tcx, sig).0; for a in sig.inputs.iter() { helper(tcx, *a, svh, state); } if let ty::FnConverging(output) = sig.output { diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 26f98e28a8d95..c505e9e311256 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -16,6 +16,7 @@ use std::fmt::Show; use std::hash::{Hash, Hasher}; use std::iter::repeat; use std::time::Duration; +use std::collections::hash_state::HashState; use syntax::ast; use syntax::visit; @@ -140,11 +141,11 @@ pub fn block_query

(b: &ast::Block, p: P) -> bool where P: FnMut(&ast::Expr) - /// 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>, - source: T, - destination: T) - -> bool +pub fn can_reach(edges_map: &HashMap, S>, source: T, + destination: T) -> bool + where S: HashState, + ::Hasher: Hasher, + T: Hash< ::Hasher> + Eq + Clone, { if source == destination { return true; @@ -202,11 +203,12 @@ pub fn can_reach,T:Eq+Clone+Hash>( /// } /// ``` #[inline(always)] -pub fn memoized(cache: &RefCell>, arg: T, f: F) -> U where - T: Clone + Hash + Eq, - U: Clone, - H: Hasher, - F: FnOnce(T) -> U, +pub fn memoized(cache: &RefCell>, arg: T, f: F) -> U + where T: Clone + Hash<::Hasher> + Eq, + U: Clone, + S: HashState, + ::Hasher: Hasher, + F: FnOnce(T) -> U, { let key = arg.clone(); let result = cache.borrow().get(&key).map(|result| result.clone()); diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs index ee224d1ec80fe..044534ae85236 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,28 +70,26 @@ pub mod DefIdSet { /// /// This uses FNV hashing, as described here: /// http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function -#[derive(Clone, Copy, Default)] -pub struct 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 { + type Output = u64; + 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/util/ppaux.rs b/src/librustc/util/ppaux.rs index 2d433369366eb..edd1bc873be92 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -26,6 +26,7 @@ use middle::ty; use middle::ty_fold::TypeFoldable; use std::collections::HashMap; +use std::collections::hash_state::HashState; use std::hash::{Hash, Hasher}; use std::rc::Rc; use syntax::abi; @@ -1350,11 +1351,11 @@ impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for ty::Binder { } } -#[old_impl_check] -impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap - where K : Hash + Eq + Repr<'tcx>, - V : Repr<'tcx>, - H : Hasher +impl<'tcx, S, K, V> Repr<'tcx> for HashMap + where K: Hash<::Hasher> + Eq + Repr<'tcx>, + V: Repr<'tcx>, + S: HashState, + ::Hasher: Hasher, { fn repr(&self, tcx: &ctxt<'tcx>) -> String { format!("HashMap({})", diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 863c1a7c865f3..2dcf08cee9265 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() }; @@ -149,14 +148,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 } } @@ -400,7 +398,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_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index e2594765f4fda..cc98ee9592b0f 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -32,7 +32,7 @@ use syntax::ast_map; use syntax::ast_util::{local_def, PostExpansionMethod}; use syntax::attr; use syntax::codemap::DUMMY_SP; -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, @@ -125,11 +125,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.index(&FullRange)) }) diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index d89a4754d2efe..42498328ff6cb 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, BTreeMap, BTreeSet, HashMap, HashSet, VecMap}; @@ -156,13 +157,12 @@ impl< } } -#[old_impl_check] -impl< - K: Encodable + Hash + Eq, - V: Encodable, - X, - H: Hasher -> Encodable for HashMap { +impl Encodable for HashMap + where K: Encodable + Hash< ::Hasher> + Eq, + V: Encodable, + S: HashState, + ::Hasher: Hasher +{ fn encode(&self, e: &mut S) -> Result<(), S::Error> { e.emit_map(self.len(), |e| { let mut i = 0; @@ -176,17 +176,16 @@ impl< } } -#[old_impl_check] -impl< - K: Decodable + Hash + Eq, - V: Decodable, - S, - H: Hasher + Default -> Decodable for HashMap { - fn decode(d: &mut D) -> Result, D::Error> { +impl Decodable for HashMap + where K: Decodable + Hash< ::Hasher> + Eq, + V: Decodable, + S: HashState + Default, + ::Hasher: Hasher +{ + fn decode(d: &mut D) -> Result, D::Error> { 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))); @@ -197,12 +196,11 @@ impl< } } -#[old_impl_check] -impl< - T: Encodable + Hash + Eq, - X, - H: Hasher -> Encodable for HashSet { +impl Encodable for HashSet + where T: Encodable + Hash< ::Hasher> + Eq, + S: HashState, + ::Hasher: Hasher +{ fn encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_seq(self.len(), |s| { let mut i = 0; @@ -215,15 +213,15 @@ impl< } } -#[old_impl_check] -impl< - T: Decodable + Hash + Eq, - S, - H: Hasher + Default -> Decodable for HashSet { - fn decode(d: &mut D) -> Result, D::Error> { +impl Decodable for HashSet + where T: Decodable + Hash< ::Hasher> + Eq, + S: HashState + Default, + ::Hasher: Hasher +{ + fn decode(d: &mut D) -> Result, D::Error> { 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/libserialize/lib.rs b/src/libserialize/lib.rs index 139170fc012cb..fd15526193456 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -24,7 +24,6 @@ Core encoding and decoding interfaces. html_playground_url = "http://play.rust-lang.org/")] #![allow(unknown_features)] #![feature(slicing_syntax)] -#![feature(old_impl_check)] #![cfg_attr(stage0, allow(unused_attributes))] // test harness access diff --git a/src/libstd/bitflags.rs b/src/libstd/bitflags.rs index 5764962b51b02..8dc41368e7f92 100644 --- a/src/libstd/bitflags.rs +++ b/src/libstd/bitflags.rs @@ -273,7 +273,7 @@ macro_rules! bitflags { #[cfg(test)] #[allow(non_upper_case_globals)] mod tests { - use hash; + use hash::{self, SipHasher}; use option::Option::{Some, None}; bitflags! { @@ -467,9 +467,9 @@ mod tests { fn test_hash() { let mut x = Flags::empty(); let mut y = Flags::empty(); - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::(&x) == hash::hash::(&y)); x = Flags::all(); y = FlagABC; - assert!(hash::hash(&x) == hash::hash(&y)); + assert!(hash::hash::(&x) == hash::hash::(&y)); } } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 2011c03c773d2..bf3b48645154c 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -19,16 +19,15 @@ use clone::Clone; use cmp::{max, Eq, PartialEq}; use default::Default; use fmt::{self, Show}; -use hash::{Hash, Hasher, RandomSipHasher}; +use hash::{self, Hash, SipHasher}; use iter::{self, Iterator, IteratorExt, FromIterator, Extend, Map}; use marker::Sized; use mem::{self, replace}; use num::{Int, UnsignedInt}; use ops::{Deref, FnMut, Index, IndexMut}; -use option::Option; -use option::Option::{Some, None}; -use result::Result; -use result::Result::{Ok, Err}; +use option::Option::{self, Some, None}; +use rand::{self, Rng}; +use result::Result::{self, Ok, Err}; use super::table::{ self, @@ -44,6 +43,7 @@ use super::table::BucketState::{ Empty, Full, }; +use super::state::HashState; const INITIAL_LOG2_CAP: uint = 5; pub const INITIAL_CAPACITY: uint = 1 << INITIAL_LOG2_CAP; // 2^5 @@ -297,9 +297,9 @@ fn test_resize_policy() { /// ``` #[derive(Clone)] #[stable] -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, @@ -439,17 +439,20 @@ impl SearchResult { } } -#[old_impl_check] -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, + S: HashState, + H: hash::Hasher +{ + fn make_hash(&self, x: &X) -> SafeHash where X: Hash { + table::make_hash(&self.hash_state, x) } /// Search for a key, yielding the index if it's found in the hashtable. /// If you already have the hash for the key lying around, use /// search_hashed. fn search<'a, Q: ?Sized>(&'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))) @@ -457,7 +460,7 @@ impl, V, S, H: Hasher> HashMap { } fn search_mut<'a, Q: ?Sized>(&'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))) @@ -486,7 +489,7 @@ impl, V, S, H: Hasher> HashMap { } } -impl HashMap { +impl + Eq, V> HashMap { /// Create an empty HashMap. /// /// # Example @@ -497,9 +500,8 @@ impl HashMap { /// ``` #[inline] #[stable] - 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. @@ -512,14 +514,16 @@ impl HashMap { /// ``` #[inline] #[stable] - 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()) } } -#[old_impl_check] -impl, V, S, H: Hasher> HashMap { +impl HashMap + where K: Eq + Hash, + S: HashState, + H: hash::Hasher +{ /// Creates an empty hashmap which will use the given hasher to hash keys. /// /// The creates map has the default initial capacity. @@ -528,17 +532,17 @@ impl, V, S, H: Hasher> HashMap { /// /// ``` /// use std::collections::HashMap; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_map::RandomState; /// - /// let h = SipHasher::new(); - /// let mut map = HashMap::with_hasher(h); + /// let s = RandomState::new(); + /// let mut map = HashMap::with_hash_state(s); /// map.insert(1i, 2u); /// ``` #[inline] #[unstable = "hasher stuff is unclear"] - 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), } @@ -556,21 +560,22 @@ impl, V, S, H: Hasher> HashMap { /// /// ``` /// use std::collections::HashMap; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_map::RandomState; /// - /// let h = SipHasher::new(); - /// let mut map = HashMap::with_capacity_and_hasher(10, h); + /// let s = RandomState::new(); + /// let mut map = HashMap::with_capacity_and_hash_state(10, s); /// map.insert(1i, 2u); /// ``` #[inline] #[unstable = "hasher stuff is unclear"] - 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), } @@ -1031,7 +1036,7 @@ impl, V, S, H: Hasher> HashMap { /// ``` #[stable] pub fn get(&self, k: &Q) -> Option<&V> - where Q: Hash + Eq + BorrowFrom + where Q: Hash + Eq + BorrowFrom { self.search(k).map(|bucket| bucket.into_refs().1) } @@ -1054,7 +1059,7 @@ impl, V, S, H: Hasher> HashMap { /// ``` #[stable] pub fn contains_key(&self, k: &Q) -> bool - where Q: Hash + Eq + BorrowFrom + where Q: Hash + Eq + BorrowFrom { self.search(k).is_some() } @@ -1080,7 +1085,7 @@ impl, V, S, H: Hasher> HashMap { /// ``` #[stable] pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where Q: Hash + Eq + BorrowFrom + where Q: Hash + Eq + BorrowFrom { self.search_mut(k).map(|bucket| bucket.into_mut_refs().1) } @@ -1132,7 +1137,7 @@ impl, V, S, H: Hasher> HashMap { /// ``` #[stable] 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 @@ -1189,10 +1194,12 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable, hash: SafeHas } } -#[stable] -#[old_impl_check] -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, + S: HashState, + H: hash::Hasher +{ + fn eq(&self, other: &HashMap) -> bool { if self.len() != other.len() { return false; } self.iter().all(|(key, value)| @@ -1202,12 +1209,18 @@ 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, + S: HashState, + H: hash::Hasher +{} #[stable] -#[old_impl_check] -impl + Show, V: Show, S, H: Hasher> Show for HashMap { +impl Show for HashMap + where K: Eq + Hash + Show, V: Show, + S: HashState, + H: hash::Hasher +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "HashMap {{")); @@ -1221,18 +1234,22 @@ impl + Show, V: Show, S, H: Hasher> Show for HashMap } #[stable] -#[old_impl_check] -impl, V, S, H: Hasher + Default> Default for HashMap { - #[stable] - fn default() -> HashMap { - HashMap::with_hasher(Default::default()) +impl Default for HashMap + where K: Eq + Hash, + S: HashState + Default, + H: hash::Hasher +{ + fn default() -> HashMap { + HashMap::with_hash_state(Default::default()) } } #[stable] -#[old_impl_check] -impl + Eq, Q: ?Sized, V, S, H: Hasher> Index for HashMap - where Q: BorrowFrom + Hash + Eq +impl Index for HashMap + where K: Eq + Hash, + Q: Eq + Hash + BorrowFrom, + S: HashState, + H: hash::Hasher { type Output = V; @@ -1243,9 +1260,11 @@ impl + Eq, Q: ?Sized, V, S, H: Hasher> Index for HashMap + Eq, Q: ?Sized, V, S, H: Hasher> IndexMut for HashMap - where Q: BorrowFrom + Hash + Eq +impl IndexMut for HashMap + where K: Eq + Hash, + Q: Eq + Hash + BorrowFrom, + S: HashState, + H: hash::Hasher { type Output = V; @@ -1473,19 +1492,26 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { } #[stable] -#[old_impl_check] -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, + S: HashState + Default, + H: hash::Hasher +{ + fn from_iter>(iter: T) -> HashMap { let lower = iter.size_hint().0; - let mut map = HashMap::with_capacity_and_hasher(lower, Default::default()); + let mut map = HashMap::with_capacity_and_hash_state(lower, + Default::default()); map.extend(iter); map } } #[stable] -#[old_impl_check] -impl, V, S, H: Hasher> Extend<(K, V)> for HashMap { +impl Extend<(K, V)> for HashMap + where K: Eq + Hash, + S: HashState, + H: hash::Hasher +{ fn extend>(&mut self, mut iter: T) { for (k, v) in iter { self.insert(k, v); @@ -1493,6 +1519,64 @@ impl, V, S, H: Hasher> Extend<(K, V)> for HashMap { } } + +/// `RandomState` is the default state for `HashMap` types. +/// +/// A particular instance `RandomState` will create the same instances of +/// `Hasher`, but the hashers created by two different `RandomState` +/// instances are unlikely to produce the same result for the same values. +#[derive(Clone)] +#[allow(missing_copy_implementations)] +#[unstable = "hashing an hash maps may be altered"] +pub struct RandomState { + k0: u64, + k1: u64, +} + +#[unstable = "hashing an hash maps may be altered"] +impl RandomState { + /// Construct a new `RandomState` that is initialized with random keys. + #[inline] + pub fn new() -> RandomState { + let mut r = rand::thread_rng(); + RandomState { k0: r.gen(), k1: r.gen() } + } +} + +#[unstable = "hashing an hash maps may be altered"] +impl HashState for RandomState { + type Hasher = Hasher; + fn hasher(&self) -> Hasher { + Hasher { inner: SipHasher::new_with_keys(self.k0, self.k1) } + } +} + +#[unstable = "hashing an hash maps may be altered"] +impl Default for RandomState { + #[inline] + fn default() -> RandomState { + RandomState::new() + } +} + +/// A hasher implementation which is generated from `RandomState` instances. +/// +/// This is the default hasher used in a `HashMap` to hash keys. Types do not +/// typically declare an ability to explicitly hash into this particular type, +/// but rather in a `H: hash::Writer` type parameter. +#[allow(missing_copy_implementations)] +pub struct Hasher { inner: SipHasher } + +impl hash::Writer for Hasher { + fn write(&mut self, data: &[u8]) { self.inner.write(data) } +} + +impl hash::Hasher for Hasher { + type Output = u64; + fn reset(&mut self) { self.inner.reset() } + fn finish(&self) -> u64 { self.inner.finish() } +} + #[cfg(test)] mod test_map { use prelude::v1::*; 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 f66e538494248..4003d3addf139 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -17,12 +17,13 @@ use core::marker::Sized; use default::Default; use fmt::Show; use fmt; -use hash::{Hash, Hasher, RandomSipHasher}; +use hash::{self, Hash}; use iter::{Iterator, IteratorExt, FromIterator, Map, Chain, Extend}; use ops::{BitOr, BitAnd, BitXor, Sub}; use option::Option::{Some, None, self}; -use super::map::{self, HashMap, Keys, INITIAL_CAPACITY}; +use super::map::{self, HashMap, Keys, INITIAL_CAPACITY, RandomState, Hasher}; +use super::state::HashState; // Future Optimization (FIXME!) // ============================= @@ -90,11 +91,11 @@ use super::map::{self, HashMap, Keys, INITIAL_CAPACITY}; /// ``` #[derive(Clone)] #[stable] -pub struct HashSet { - map: HashMap +pub struct HashSet { + map: HashMap } -impl HashSet { +impl + Eq> HashSet { /// Create an empty HashSet. /// /// # Example @@ -105,7 +106,7 @@ impl HashSet { /// ``` #[inline] #[stable] - pub fn new() -> HashSet { + pub fn new() -> HashSet { HashSet::with_capacity(INITIAL_CAPACITY) } @@ -120,13 +121,16 @@ impl HashSet { /// ``` #[inline] #[stable] - pub fn with_capacity(capacity: uint) -> HashSet { + pub fn with_capacity(capacity: uint) -> HashSet { HashSet { map: HashMap::with_capacity(capacity) } } } -#[old_impl_check] -impl, S, H: Hasher> HashSet { +impl HashSet + where T: Eq + Hash, + S: HashState, + H: hash::Hasher +{ /// Creates a new empty hash set which will use the given hasher to hash /// keys. /// @@ -136,16 +140,16 @@ impl, S, H: Hasher> HashSet { /// /// ``` /// use std::collections::HashSet; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_map::RandomState; /// - /// let h = SipHasher::new(); - /// let mut set = HashSet::with_hasher(h); + /// let s = RandomState::new(); + /// let mut set = HashSet::with_hash_state(s); /// set.insert(2u); /// ``` #[inline] #[unstable = "hasher stuff is unclear"] - 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) } /// Create an empty HashSet with space for at least `capacity` @@ -160,16 +164,19 @@ impl, S, H: Hasher> HashSet { /// /// ``` /// use std::collections::HashSet; - /// use std::hash::sip::SipHasher; + /// use std::collections::hash_map::RandomState; /// - /// let h = SipHasher::new(); - /// let mut set = HashSet::with_capacity_and_hasher(10u, h); + /// let s = RandomState::new(); + /// let mut set = HashSet::with_capacity_and_hash_state(10u, s); /// set.insert(1i); /// ``` #[inline] #[unstable = "hasher stuff is unclear"] - 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), + } } /// Returns the number of elements the set can hold without reallocating. @@ -300,7 +307,7 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(diff, [4i].iter().map(|&x| x).collect()); /// ``` #[stable] - pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, H> { + pub fn difference<'a>(&'a self, other: &'a HashSet) -> Difference<'a, T, S> { Difference { iter: self.iter(), other: other, @@ -328,8 +335,8 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(diff1, [1i, 4].iter().map(|&x| x).collect()); /// ``` #[stable] - pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) - -> SymmetricDifference<'a, T, H> { + pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) + -> SymmetricDifference<'a, T, S> { SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) } } @@ -351,7 +358,7 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect()); /// ``` #[stable] - pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, H> { + pub fn intersection<'a>(&'a self, other: &'a HashSet) -> Intersection<'a, T, S> { Intersection { iter: self.iter(), other: other, @@ -376,7 +383,7 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect()); /// ``` #[stable] - pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, H> { + pub fn union<'a>(&'a self, other: &'a HashSet) -> Union<'a, T, S> { Union { iter: self.iter().chain(other.difference(self)) } } @@ -452,7 +459,7 @@ impl, S, H: Hasher> HashSet { /// ``` #[stable] pub fn contains(&self, value: &Q) -> bool - where Q: BorrowFrom + Hash + Eq + where Q: BorrowFrom + Hash + Eq { self.map.contains_key(value) } @@ -475,7 +482,7 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(a.is_disjoint(&b), false); /// ``` #[stable] - pub fn is_disjoint(&self, other: &HashSet) -> bool { + pub fn is_disjoint(&self, other: &HashSet) -> bool { self.iter().all(|v| !other.contains(v)) } @@ -496,7 +503,7 @@ impl, S, H: Hasher> HashSet { /// assert_eq!(set.is_subset(&sup), false); /// ``` #[stable] - pub fn is_subset(&self, other: &HashSet) -> bool { + pub fn is_subset(&self, other: &HashSet) -> bool { self.iter().all(|v| other.contains(v)) } @@ -521,7 +528,7 @@ impl, S, H: Hasher> HashSet { /// ``` #[inline] #[stable] - pub fn is_superset(&self, other: &HashSet) -> bool { + pub fn is_superset(&self, other: &HashSet) -> bool { other.is_subset(self) } @@ -562,16 +569,19 @@ impl, S, H: Hasher> HashSet { /// ``` #[stable] pub fn remove(&mut self, value: &Q) -> bool - where Q: BorrowFrom + Hash + Eq + where Q: BorrowFrom + Hash + Eq { self.map.remove(value).is_some() } } #[stable] -#[old_impl_check] -impl, S, H: Hasher> PartialEq for HashSet { - fn eq(&self, other: &HashSet) -> bool { +impl PartialEq for HashSet + where T: Eq + Hash, + S: HashState, + H: hash::Hasher +{ + fn eq(&self, other: &HashSet) -> bool { if self.len() != other.len() { return false; } self.iter().all(|key| other.contains(key)) @@ -579,12 +589,18 @@ impl, S, H: Hasher> PartialEq for HashSet { } #[stable] -#[old_impl_check] -impl, S, H: Hasher> Eq for HashSet {} +impl Eq for HashSet + where T: Eq + Hash, + S: HashState, + H: hash::Hasher +{} #[stable] -#[old_impl_check] -impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { +impl fmt::Show for HashSet + where T: Eq + Hash + fmt::Show, + S: HashState, + H: hash::Hasher +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { try!(write!(f, "HashSet {{")); @@ -598,19 +614,25 @@ impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { } #[stable] -#[old_impl_check] -impl, S, H: Hasher + Default> FromIterator for HashSet { - fn from_iter>(iter: I) -> HashSet { +impl FromIterator for HashSet + where T: Eq + Hash, + S: HashState + Default, + H: hash::Hasher +{ + fn from_iter>(iter: I) -> HashSet { let lower = iter.size_hint().0; - let mut set = HashSet::with_capacity_and_hasher(lower, Default::default()); + let mut set = HashSet::with_capacity_and_hash_state(lower, Default::default()); set.extend(iter); set } } #[stable] -#[old_impl_check] -impl, S, H: Hasher> Extend for HashSet { +impl Extend for HashSet + where T: Eq + Hash, + S: HashState, + H: hash::Hasher +{ fn extend>(&mut self, mut iter: I) { for k in iter { self.insert(k); @@ -619,21 +641,26 @@ impl, S, H: Hasher> Extend for HashSet { } #[stable] -#[old_impl_check] -impl, S, H: Hasher + Default> Default for HashSet { +impl Default for HashSet + where T: Eq + Hash, + S: HashState + Default, + H: hash::Hasher +{ #[stable] - fn default() -> HashSet { - HashSet::with_hasher(Default::default()) + fn default() -> HashSet { + HashSet::with_hash_state(Default::default()) } } #[stable] -#[old_impl_check] -impl<'a, 'b, T: Eq + Hash + Clone, S, H: Hasher + Default> -BitOr<&'b HashSet> for &'a HashSet { - type Output = HashSet; +impl<'a, 'b, T, S, H> BitOr<&'b HashSet> for &'a HashSet + where T: Eq + Hash + Clone, + S: HashState + Default, + H: hash::Hasher +{ + type Output = HashSet; - /// Returns the union of `self` and `rhs` as a new `HashSet`. + /// Returns the union of `self` and `rhs` as a new `HashSet`. /// /// # Examples /// @@ -653,18 +680,20 @@ BitOr<&'b HashSet> for &'a HashSet { /// } /// assert_eq!(i, expected.len()); /// ``` - fn bitor(self, rhs: &HashSet) -> HashSet { + fn bitor(self, rhs: &HashSet) -> HashSet { self.union(rhs).cloned().collect() } } #[stable] -#[old_impl_check] -impl<'a, 'b, T: Eq + Hash + Clone, S, H: Hasher + Default> -BitAnd<&'b HashSet> for &'a HashSet { - type Output = HashSet; +impl<'a, 'b, T, S, H> BitAnd<&'b HashSet> for &'a HashSet + where T: Eq + Hash + Clone, + S: HashState + Default, + H: hash::Hasher +{ + type Output = HashSet; - /// Returns the intersection of `self` and `rhs` as a new `HashSet`. + /// Returns the intersection of `self` and `rhs` as a new `HashSet`. /// /// # Examples /// @@ -684,18 +713,20 @@ BitAnd<&'b HashSet> for &'a HashSet { /// } /// assert_eq!(i, expected.len()); /// ``` - fn bitand(self, rhs: &HashSet) -> HashSet { + fn bitand(self, rhs: &HashSet) -> HashSet { self.intersection(rhs).cloned().collect() } } #[stable] -#[old_impl_check] -impl<'a, 'b, T: Eq + Hash + Clone, S, H: Hasher + Default> -BitXor<&'b HashSet> for &'a HashSet { - type Output = HashSet; +impl<'a, 'b, T, S, H> BitXor<&'b HashSet> for &'a HashSet + where T: Eq + Hash + Clone, + S: HashState + Default, + H: hash::Hasher +{ + type Output = HashSet; - /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet`. + /// Returns the symmetric difference of `self` and `rhs` as a new `HashSet`. /// /// # Examples /// @@ -715,18 +746,20 @@ BitXor<&'b HashSet> for &'a HashSet { /// } /// assert_eq!(i, expected.len()); /// ``` - fn bitxor(self, rhs: &HashSet) -> HashSet { + fn bitxor(self, rhs: &HashSet) -> HashSet { self.symmetric_difference(rhs).cloned().collect() } } #[stable] -#[old_impl_check] -impl<'a, 'b, T: Eq + Hash + Clone, S, H: Hasher + Default> -Sub<&'b HashSet> for &'a HashSet { - type Output = HashSet; +impl<'a, 'b, T, S, H> Sub<&'b HashSet> for &'a HashSet + where T: Eq + Hash + Clone, + S: HashState + Default, + H: hash::Hasher +{ + type Output = HashSet; - /// Returns the difference of `self` and `rhs` as a new `HashSet`. + /// Returns the difference of `self` and `rhs` as a new `HashSet`. /// /// # Examples /// @@ -746,7 +779,7 @@ Sub<&'b HashSet> for &'a HashSet { /// } /// assert_eq!(i, expected.len()); /// ``` - fn sub(self, rhs: &HashSet) -> HashSet { + fn sub(self, rhs: &HashSet) -> HashSet { self.difference(rhs).cloned().collect() } } @@ -771,32 +804,32 @@ pub struct Drain<'a, K: 'a> { /// Intersection iterator #[stable] -pub struct Intersection<'a, T: 'a, H: 'a> { +pub struct Intersection<'a, T: 'a, S: 'a> { // iterator of the first set iter: Iter<'a, T>, // the second set - other: &'a HashSet, + other: &'a HashSet, } /// Difference iterator #[stable] -pub struct Difference<'a, T: 'a, H: 'a> { +pub struct Difference<'a, T: 'a, S: 'a> { // iterator of the first set iter: Iter<'a, T>, // the second set - other: &'a HashSet, + other: &'a HashSet, } /// Symmetric difference iterator. #[stable] -pub struct SymmetricDifference<'a, T: 'a, H: 'a> { - iter: Chain, Difference<'a, T, H>> +pub struct SymmetricDifference<'a, T: 'a, S: 'a> { + iter: Chain, Difference<'a, T, S>> } /// Set union iterator. #[stable] -pub struct Union<'a, T: 'a, H: 'a> { - iter: Chain, Difference<'a, T, H>> +pub struct Union<'a, T: 'a, S: 'a> { + iter: Chain, Difference<'a, T, S>> } #[stable] @@ -824,9 +857,10 @@ impl<'a, K: 'a> Iterator for Drain<'a, K> { } #[stable] -#[old_impl_check] -impl<'a, T, S, H> Iterator for Intersection<'a, T, H> - where T: Eq + Hash, H: Hasher +impl<'a, T, S, H> Iterator for Intersection<'a, T, S> + where T: Eq + Hash, + S: HashState, + H: hash::Hasher { type Item = &'a T; @@ -848,9 +882,10 @@ impl<'a, T, S, H> Iterator for Intersection<'a, T, H> } #[stable] -#[old_impl_check] -impl<'a, T, S, H> Iterator for Difference<'a, T, H> - where T: Eq + Hash, H: Hasher +impl<'a, T, S, H> Iterator for Difference<'a, T, S> + where T: Eq + Hash, + S: HashState, + H: hash::Hasher { type Item = &'a T; @@ -872,9 +907,10 @@ impl<'a, T, S, H> Iterator for Difference<'a, T, H> } #[stable] -#[old_impl_check] -impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, H> - where T: Eq + Hash, H: Hasher +impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, S> + where T: Eq + Hash, + S: HashState, + H: hash::Hasher { type Item = &'a T; @@ -883,9 +919,10 @@ impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, H> } #[stable] -#[old_impl_check] -impl<'a, T, S, H> Iterator for Union<'a, T, H> - where T: Eq + Hash, H: Hasher +impl<'a, T, S, H> Iterator for Union<'a, T, S> + where T: Eq + Hash, + S: HashState, + H: hash::Hasher { type Item = &'a T; diff --git a/src/libstd/collections/hash/state.rs b/src/libstd/collections/hash/state.rs new file mode 100644 index 0000000000000..ffbc958f179f5 --- /dev/null +++ b/src/libstd/collections/hash/state.rs @@ -0,0 +1,51 @@ +// 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; + +/// 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 Hasher: hash::Hasher; + + /// Creates a new hasher based on the given state of this object. + fn hasher(&self) -> Self::Hasher; +} + +/// 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 { + type Hasher = H; + fn hasher(&self) -> H { Default::default() } +} + +impl Clone for DefaultState { + fn clone(&self) -> DefaultState { DefaultState } +} + +impl Default for DefaultState { + fn default() -> DefaultState { DefaultState } +} diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 6eb98da4da46e..e43cc053ba079 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::{Unique, PtrExt, copy_nonoverlapping_memory, zero_memory}; use ptr; use rt::heap::{allocate, deallocate}; +use collections::hash_state::HashState; const EMPTY_BUCKET: u64 = 0u64; @@ -138,12 +139,18 @@ 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 { +pub fn make_hash(hash_state: &S, t: &T) -> SafeHash + where T: Hash, + S: HashState, + H: Hasher +{ + let mut state = hash_state.hasher(); + t.hash(&mut state); // We need to avoid 0u64 in order to prevent collisions with // EMPTY_HASH. We can maintain our precious uniform distribution // of initial indexes by unconditionally setting the MSB, // effectively reducing 64-bits hashes to 63 bits. - SafeHash { hash: 0x8000_0000_0000_0000 | hasher.hash(t) } + SafeHash { hash: 0x8000_0000_0000_0000 | state.finish() } } // `replace` casts a `*u64` to a `*SafeHash`. Since we statically diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 9b2a4926bcb92..71ab89027ff4c 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -333,3 +333,10 @@ pub mod hash_set { //! A hashset pub use super::hash::set::*; } + +/// Experimental support for providing custom hash algorithms to a HashMap and +/// HashSet. +#[unstable = "module was recently added"] +pub mod hash_state { + pub use super::hash::state::*; +} diff --git a/src/libstd/hash.rs b/src/libstd/hash.rs deleted file mode 100644 index 69e7e429d07da..0000000000000 --- a/src/libstd/hash.rs +++ /dev/null @@ -1,105 +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 `#[derive(Hash)]`: -//! -//! # Example -//! -//! ```rust -//! use std::hash; -//! use std::hash::Hash; -//! -//! #[derive(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::hash::{Hash, Hasher, Writer, hash, sip}; - -use core::marker::Sized; -use default::Default; -use rand::Rng; -use rand; - -/// `RandomSipHasher` computes the SipHash algorithm from a stream of bytes -/// initialized with random keys. -#[derive(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::thread_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) - } -} - -#[stable] -impl Default for RandomSipHasher { - #[stable] - #[inline] - fn default() -> RandomSipHasher { - RandomSipHasher::new() - } -} diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 55df6330dd33c..ed29d3b2c7fff 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -34,7 +34,7 @@ use sys::process::Process as ProcessImp; use sys; use thread::Thread; -#[cfg(windows)] use std::hash::sip::SipState; +#[cfg(windows)] use hash; #[cfg(windows)] use str; /// Signal a process to exit, without forcibly killing it. Corresponds to @@ -98,7 +98,7 @@ pub struct Process { /// A representation of environment variable name /// It compares case-insensitive on Windows and case-sensitive everywhere else. #[cfg(not(windows))] -#[derive(PartialEq, Eq, Hash, Clone, Show)] +#[derive(Hash, PartialEq, Eq, Clone, Show)] struct EnvKey(CString); #[doc(hidden)] @@ -107,8 +107,8 @@ struct EnvKey(CString); struct EnvKey(CString); #[cfg(windows)] -impl Hash for EnvKey { - fn hash(&self, state: &mut SipState) { +impl hash::Hash for EnvKey { + fn hash(&self, state: &mut H) { let &EnvKey(ref x) = self; match str::from_utf8(x.as_bytes()) { Ok(s) => for ch in s.chars() { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index eef5bdb60eeaa..6950a6cf8d04f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -150,6 +150,7 @@ pub use core::clone; #[cfg(not(test))] pub use core::cmp; pub use core::default; pub use core::finally; +pub use core::hash; pub use core::intrinsics; pub use core::iter; #[cfg(stage0)] #[cfg(not(test))] pub use core::marker as kinds; @@ -242,7 +243,6 @@ pub mod time; /* Common data structures */ pub mod collections; -pub mod hash; /* Threads and communication */ @@ -274,6 +274,7 @@ mod std { pub use clone; pub use cmp; pub use hash; + pub use default; pub use sync; // used for select!() pub use error; // used for try!() diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index 0b7dc19fcab4e..b13278205b4eb 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -91,7 +91,7 @@ impl FromStr for Path { } } -impl hash::Hash for Path { +impl hash::Hash for Path { #[inline] fn hash(&self, state: &mut S) { self.repr.hash(state) diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index 5c4e7aa9ac27b..0a43c7b5140e8 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -118,7 +118,7 @@ impl FromStr for Path { } } -impl hash::Hash for Path { +impl hash::Hash for Path { #[cfg(not(test))] #[inline] fn hash(&self, state: &mut S) { diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 1357bbdd5a371..36bf696dba550 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -11,7 +11,8 @@ use prelude::v1::*; use self::Req::*; -use collections; +use collections::HashMap; +use collections::hash_map::Hasher; use ffi::CString; use hash::Hash; use io::process::{ProcessExit, ExitStatus, ExitSignal}; @@ -60,7 +61,7 @@ impl Process { out_fd: Option

, err_fd: Option

) -> IoResult where C: ProcessConfig, P: AsInner, - K: BytesContainer + Eq + Hash, V: BytesContainer + K: BytesContainer + Eq + Hash, V: BytesContainer { use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; use libc::funcs::bsd44::getdtablesize; @@ -553,11 +554,11 @@ fn with_argv(prog: &CString, args: &[CString], cb(ptrs.as_ptr()) } -fn with_envp(env: Option<&collections::HashMap>, +fn with_envp(env: Option<&HashMap>, cb: F) -> T where F : FnOnce(*const c_void) -> T, - K : BytesContainer + Eq + Hash, + K : BytesContainer + Eq + Hash, V : BytesContainer { // On posixy systems we can pass a char** for envp, which is a diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 8e1f169b5cdcc..1b837385d1eb6 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -13,6 +13,7 @@ use prelude::v1::*; use collections; use ffi::CString; use hash::Hash; +use collections::hash_map::Hasher; use io::fs::PathExtensions; use io::process::{ProcessExit, ExitStatus, ExitSignal}; use io::{IoResult, IoError}; @@ -109,7 +110,7 @@ impl Process { out_fd: Option

, err_fd: Option

) -> IoResult where C: ProcessConfig, P: AsInner, - K: BytesContainer + Eq + Hash, V: BytesContainer + K: BytesContainer + Eq + Hash, V: BytesContainer { use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; use libc::consts::os::extra::{ @@ -424,8 +425,10 @@ fn make_command_line(prog: &CString, args: &[CString]) -> String { } } -fn with_envp(env: Option<&collections::HashMap>, cb: F) -> T where - K: BytesContainer + Eq + Hash, V: BytesContainer, F: FnOnce(*mut c_void) -> T, +fn with_envp(env: Option<&collections::HashMap>, cb: F) -> T + where K: BytesContainer + Eq + Hash, + V: BytesContainer, + F: FnOnce(*mut c_void) -> T, { // On Windows we pass an "environment block" which is not a char**, but // rather a concatenation of null-terminated k=v\0 sequences, with a final diff --git a/src/libsyntax/ext/deriving/hash.rs b/src/libsyntax/ext/deriving/hash.rs index 844bd80d1610a..db99c14244324 100644 --- a/src/libsyntax/ext/deriving/hash.rs +++ b/src/libsyntax/ext/deriving/hash.rs @@ -30,7 +30,8 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, let generics = LifetimeBounds { lifetimes: Vec::new(), bounds: vec!(("__S", - vec!(Path::new(vec!("std", "hash", "Writer"))))), + vec!(Path::new(vec!("std", "hash", "Writer")), + Path::new(vec!("std", "hash", "Hasher"))))), }; let args = Path::new_local("__S"); let inline = cx.meta_word(span, InternedString::new("inline")); diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index 8abb46011e65c..13a14d069d705 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -37,9 +37,11 @@ //! Moreover, a switch to, e.g. `P<'a, T>` would be easy and mostly automated. use std::fmt::{self, Show}; -use std::hash::Hash; +use std::hash::{Hash, Hasher}; +#[cfg(stage0)] use std::hash::Writer; use std::ops::Deref; use std::ptr; + use serialize::{Encodable, Decodable, Encoder, Decoder}; /// An owned smart pointer. @@ -105,7 +107,14 @@ impl Show for P { } } -impl> Hash for P { +#[cfg(stage0)] +impl> Hash for P { + fn hash(&self, state: &mut S) { + (**self).hash(state); + } +} +#[cfg(not(stage0))] +impl> Hash for P { fn hash(&self, state: &mut S) { (**self).hash(state); } diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 93de342d487dc..7058fa64811c0 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -20,6 +20,7 @@ use std::cmp::Ordering; use std::collections::HashMap; use std::fmt; use std::hash::Hash; +use std::collections::hash_map::Hasher; use std::ops::Deref; use std::rc::Rc; @@ -28,8 +29,8 @@ pub struct Interner { vect: RefCell >, } -// when traits can extend traits, we should extend index to get .index(&FullRange) -impl Interner { +// when traits can extend traits, we should extend index to get [] +impl + Clone + 'static> Interner { pub fn new() -> Interner { Interner { map: RefCell::new(HashMap::new()), @@ -78,7 +79,7 @@ impl Interner { } pub fn find(&self, val: &Q) -> Option - where Q: BorrowFrom + Eq + Hash { + where Q: BorrowFrom + Eq + Hash { let map = self.map.borrow(); match (*map).get(val) { Some(v) => Some(*v), @@ -203,7 +204,7 @@ impl StrInterner { } pub fn find(&self, val: &Q) -> Option - where Q: BorrowFrom + Eq + Hash { + where Q: BorrowFrom + Eq + Hash { match (*self.map.borrow()).get(val) { Some(v) => Some(*v), None => None, diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs index 1abb52459e493..6061c4fd1d3d3 100644 --- a/src/libtest/stats.rs +++ b/src/libtest/stats.rs @@ -12,7 +12,7 @@ use std::cmp::Ordering::{self, Less, Greater, Equal}; use std::collections::hash_map::Entry::{Occupied, Vacant}; -use std::collections::hash_map; +use std::collections::hash_map::{self, Hasher}; use std::fmt; use std::hash::Hash; use std::io; @@ -440,7 +440,7 @@ pub fn write_boxplot(mut iter: T) -> hash_map::HashMap - where T: Iterator, U: Eq + Clone + Hash + where T: Iterator, U: Eq + Clone + Hash { let mut map: hash_map::HashMap = hash_map::HashMap::new(); for elem in iter { diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 1dcac9fe0742d..edeb07c960e7e 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -18,6 +18,7 @@ extern crate rand; use std::collections::BTreeSet; use std::collections::BitvSet; use std::collections::HashSet; +use std::collections::hash_map::Hasher; use std::hash::Hash; use std::os; use std::time::Duration; @@ -43,7 +44,7 @@ trait MutableSet { fn contains(&self, k: &T) -> bool; } -impl MutableSet for HashSet { +impl + Eq> MutableSet for HashSet { fn insert(&mut self, k: T) { self.insert(k); } fn remove(&mut self, k: &T) -> bool { self.remove(k) } fn contains(&self, k: &T) -> bool { self.contains(k) } diff --git a/src/test/run-pass/deriving-hash.rs b/src/test/run-pass/deriving-hash.rs index ddad703d7dfdb..02ab7e5db5b89 100644 --- a/src/test/run-pass/deriving-hash.rs +++ b/src/test/run-pass/deriving-hash.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -use std::hash; -use std::hash::Hash; +use std::hash::{Hash, SipHasher}; #[derive(Hash)] struct Person { @@ -19,6 +17,10 @@ struct Person { phone: uint, } +fn hash>(t: &T) -> u64 { + std::hash::hash::(t) +} + fn main() { let person1 = Person { id: 5, @@ -30,6 +32,6 @@ fn main() { name: "Bob".to_string(), phone: 555_666_7777 }; - assert!(hash::hash(&person1) == hash::hash(&person1)); - assert!(hash::hash(&person1) != hash::hash(&person2)); + assert!(hash(&person1) == hash(&person1)); + assert!(hash(&person1) != hash(&person2)); } diff --git a/src/test/run-pass/deriving-meta-multiple.rs b/src/test/run-pass/deriving-meta-multiple.rs index c435a1f344d3d..f45dce9da632e 100644 --- a/src/test/run-pass/deriving-meta-multiple.rs +++ b/src/test/run-pass/deriving-meta-multiple.rs @@ -9,7 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::hash::hash; +use std::hash::{Hash, SipHasher}; // testing multiple separate deriving attributes #[derive(PartialEq)] @@ -20,6 +20,8 @@ struct Foo { baz: int } +fn hash>(_t: &T) {} + pub fn main() { let a = Foo {bar: 4, baz: -3}; diff --git a/src/test/run-pass/deriving-meta.rs b/src/test/run-pass/deriving-meta.rs index 54dc2b97b77f3..d6a2fad08ed88 100644 --- a/src/test/run-pass/deriving-meta.rs +++ b/src/test/run-pass/deriving-meta.rs @@ -9,7 +9,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::hash::hash; +use std::hash::{Hash, SipHasher}; #[derive(PartialEq, Clone, Hash)] struct Foo { @@ -17,6 +17,8 @@ struct Foo { baz: int } +fn hash>(_t: &T) {} + pub fn main() { let a = Foo {bar: 4, baz: -3}; diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs index bba043ea8f8ac..e346c4ff3495e 100644 --- a/src/test/run-pass/typeid-intrinsic.rs +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -14,7 +14,7 @@ extern crate "typeid-intrinsic" as other1; extern crate "typeid-intrinsic2" as other2; -use std::hash; +use std::hash::{self, SipHasher}; use std::intrinsics; use std::intrinsics::TypeId; @@ -70,5 +70,6 @@ pub fn main() { // check it has a hash let (a, b) = (TypeId::of::(), TypeId::of::()); - assert_eq!(hash::hash(&a), hash::hash(&b)); + assert_eq!(hash::hash::(&a), + hash::hash::(&b)); }