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<H: Hasher> { 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]
This commit is contained in:
parent
9e4e524e0e
commit
511f0b8a3d
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
#![crate_type = "bin"]
|
||||
#![feature(slicing_syntax, unboxed_closures)]
|
||||
#![feature(slicing_syntax)]
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
|
@ -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<T: Default + Sync + Send> Default for Arc<T> {
|
||||
fn default() -> Arc<T> { Arc::new(Default::default()) }
|
||||
}
|
||||
|
||||
impl<H: Hasher, T: Hash<H>> Hash<H> for Arc<T> {
|
||||
fn hash(&self, state: &mut H) {
|
||||
(**self).hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(experimental)]
|
||||
mod tests {
|
||||
|
@ -106,12 +106,20 @@ impl<T: ?Sized + Ord> Ord for Box<T> {
|
||||
#[stable]}
|
||||
impl<T: ?Sized + Eq> Eq for Box<T> {}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<S: hash::Writer, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl<S: hash::Hasher, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
|
||||
#[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 \
|
||||
|
@ -10,23 +10,26 @@
|
||||
|
||||
//! Thread-local reference-counted boxes (the `Rc<T>` type).
|
||||
//!
|
||||
//! The `Rc<T>` 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<T>` 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<T>` pointer to the box. A
|
||||
//! `Weak<T>` pointer can be upgraded to an `Rc<T>` pointer, but will return `None` if the value
|
||||
//! has already been dropped.
|
||||
//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer
|
||||
//! to the box. A `Weak<T>` pointer can be upgraded to an `Rc<T>` 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<T>` pointers, and then storing the parent pointers as `Weak<T>` pointers.
|
||||
//! For example, a tree with parent pointers can be represented by putting the
|
||||
//! nodes behind strong `Rc<T>` pointers, and then storing the parent pointers
|
||||
//! as `Weak<T>` 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<T>` 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<T>` 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<T: Ord> Ord for Rc<T> {
|
||||
}
|
||||
|
||||
// FIXME (#18248) Make `T` `Sized?`
|
||||
#[cfg(stage0)]
|
||||
impl<S: hash::Writer, T: Hash<S>> Hash<S> for Rc<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl<S: hash::Hasher, T: Hash<S>> Hash<S> for Rc<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "Show is experimental."]
|
||||
impl<T: fmt::Show> fmt::Show for Rc<T> {
|
||||
|
@ -982,7 +982,7 @@ impl fmt::Show for Bitv {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<S: hash::Writer> hash::Hash<S> for Bitv {
|
||||
impl<S: hash::Writer + hash::Hasher> hash::Hash<S> 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<S: hash::Writer> hash::Hash<S> for BitvSet {
|
||||
impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for BitvSet {
|
||||
fn hash(&self, state: &mut S) {
|
||||
for pos in self.iter() {
|
||||
pos.hash(state);
|
||||
|
@ -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<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[cfg(stage0)]
|
||||
impl<S: Writer, K: Hash<S>, V: Hash<S>> Hash<S> for BTreeMap<K, V> {
|
||||
fn hash(&self, state: &mut S) {
|
||||
for elt in self.iter() {
|
||||
@ -827,6 +830,15 @@ impl<S: Writer, K: Hash<S>, V: Hash<S>> Hash<S> for BTreeMap<K, V> {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[stable]
|
||||
#[cfg(not(stage0))]
|
||||
impl<S: Hasher, K: Hash<S>, V: Hash<S>> Hash<S> for BTreeMap<K, V> {
|
||||
fn hash(&self, state: &mut S) {
|
||||
for elt in self.iter() {
|
||||
elt.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<K: Ord, V> Default for BTreeMap<K, V> {
|
||||
|
@ -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> {
|
||||
|
@ -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<A: fmt::Show> fmt::Show for DList<A> {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<S: Writer, A: Hash<S>> Hash<S> for DList<A> {
|
||||
impl<S: Writer + Hasher, A: Hash<S>> Hash<S> for DList<A> {
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.len().hash(state);
|
||||
for elt in self.iter() {
|
||||
@ -688,7 +688,7 @@ impl<S: Writer, A: Hash<S>> Hash<S> for DList<A> {
|
||||
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]
|
||||
|
@ -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]
|
||||
|
@ -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<A: Ord> Ord for RingBuf<A> {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl<S: Writer, A: Hash<S>> Hash<S> for RingBuf<A> {
|
||||
impl<S: Writer + Hasher, A: Hash<S>> Hash<S> for RingBuf<A> {
|
||||
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]
|
||||
|
@ -820,12 +820,21 @@ impl fmt::Show for String {
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Hash stabilization"]
|
||||
#[cfg(stage0)]
|
||||
impl<H: hash::Writer> hash::Hash<H> for String {
|
||||
#[inline]
|
||||
fn hash(&self, hasher: &mut H) {
|
||||
(**self).hash(hasher)
|
||||
}
|
||||
}
|
||||
#[experimental = "waiting on Hash stabilization"]
|
||||
#[cfg(not(stage0))]
|
||||
impl<H: hash::Writer + hash::Hasher> hash::Hash<H> 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 {
|
||||
|
@ -1183,12 +1183,20 @@ impl<T:Clone> Clone for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<S: hash::Writer, T: Hash<S>> Hash<S> for Vec<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.as_slice().hash(state);
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl<S: hash::Writer + hash::Hasher, T: Hash<S>> Hash<S> for Vec<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.as_slice().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[experimental = "waiting on Index stability"]
|
||||
impl<T> Index<uint> for Vec<T> {
|
||||
|
@ -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<V:Clone> Clone for VecMap<V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer, V: Hash<S>> Hash<S> for VecMap<V> {
|
||||
impl<S: Writer + Hasher, V: Hash<S>> Hash<S> for VecMap<V> {
|
||||
fn hash(&self, state: &mut S) {
|
||||
// In order to not traverse the `VecMap` twice, count the elements
|
||||
// during iteration.
|
||||
@ -712,7 +712,7 @@ impl<V> DoubleEndedIterator for IntoIter<V> {
|
||||
#[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]
|
||||
|
@ -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<H: Hasher + Writer> Hash<H> 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 `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<S = sip::SipState> {
|
||||
/// 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(stage0)]
|
||||
pub trait Hash<H> {
|
||||
/// 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<S> {
|
||||
/// Compute the hash of a value.
|
||||
fn hash<T: ?Sized + Hash<S>>(&self, value: &T) -> u64;
|
||||
/// 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<H: Hasher> {
|
||||
/// Feeds this value into the state given, updating the hasher as necessary.
|
||||
fn hash(&self, state: &mut H);
|
||||
}
|
||||
|
||||
/// 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<T: Hash<H>, 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<S: Writer> Hash<S> 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::*;
|
||||
|
||||
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 }
|
||||
use borrow::{Cow, ToOwned};
|
||||
use intrinsics::TypeId;
|
||||
use mem;
|
||||
use super::{Hash, Writer};
|
||||
use num::Int;
|
||||
|
||||
impl<S: Writer> Hash<S> for bool {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(*self as u8).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer> Hash<S> for char {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(*self as u32).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer> Hash<S> for str {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
state.write(self.as_bytes());
|
||||
0xffu8.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_hash_tuple {
|
||||
() => (
|
||||
impl<S: Writer> Hash<S> for () {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
state.write(&[]);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
( $($name:ident)+) => (
|
||||
impl<S: Writer, $($name: Hash<S>),*> Hash<S> for ($($name,)*) {
|
||||
#[inline]
|
||||
#[allow(non_snake_case)]
|
||||
fn hash(&self, state: &mut S) {
|
||||
match *self {
|
||||
($(ref $name,)*) => {
|
||||
$(
|
||||
$name.hash(state);
|
||||
)*
|
||||
}
|
||||
macro_rules! impl_hash {
|
||||
($ty:ident, $uty:ident) => {
|
||||
impl<S: Writer> Hash<S> 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_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! { 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<S: Writer, T: Hash<S>> Hash<S> for [T] {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.len().hash(state);
|
||||
for elt in self.iter() {
|
||||
elt.hash(state);
|
||||
impl<S: Writer> Hash<S> for bool {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(*self as u8).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer> Hash<S> for char {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(*self as u32).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer> Hash<S> for str {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
state.write(self.as_bytes());
|
||||
0xffu8.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_hash_tuple {
|
||||
() => (
|
||||
impl<S> Hash<S> for () {
|
||||
#[inline]
|
||||
fn hash(&self, _state: &mut S) {}
|
||||
}
|
||||
);
|
||||
|
||||
( $($name:ident)+) => (
|
||||
impl<S, $($name: Hash<S>),*> Hash<S> 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<S: Writer, T: Hash<S>> Hash<S> 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<S>> Hash<S> for &'a T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S, T: ?Sized + Hash<S>> Hash<S> for &'a mut T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer, T> Hash<S> 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<S: Writer, T> Hash<S> 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<S: Writer> Hash<S> for TypeId {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.hash().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, B: ?Sized, S> Hash<S> for Cow<'a, T, B>
|
||||
where B: Hash<S> + ToOwned<T>
|
||||
{
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
Hash::hash(&**self, state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
mod impls {
|
||||
use prelude::*;
|
||||
|
||||
impl<'a, S: Writer, T: ?Sized + Hash<S>> Hash<S> for &'a T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: Writer, T: ?Sized + Hash<S>> Hash<S> for &'a mut T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer, T> Hash<S> 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<S: Writer, T> Hash<S> 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<S: Writer> Hash<S> for TypeId {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.hash().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, B: ?Sized, S> Hash<S> for Cow<'a, T, B> where B: Hash<S> + ToOwned<T> {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
Hash::hash(&**self, state)
|
||||
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<S: Writer + Hasher> Hash<S> 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<S: Writer + Hasher> Hash<S> for bool {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(*self as u8).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer + Hasher> Hash<S> for char {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(*self as u32).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer + Hasher> Hash<S> for str {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
state.write(self.as_bytes());
|
||||
0xffu8.hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_hash_tuple {
|
||||
() => (
|
||||
impl<S: Hasher> Hash<S> for () {
|
||||
#[inline]
|
||||
fn hash(&self, _state: &mut S) {}
|
||||
}
|
||||
);
|
||||
|
||||
( $($name:ident)+) => (
|
||||
impl<S: Hasher, $($name: Hash<S>),*> Hash<S> 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<S: Writer + Hasher, T: Hash<S>> Hash<S> 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<S>> Hash<S> for &'a T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: Hasher, T: ?Sized + Hash<S>> Hash<S> for &'a mut T {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Writer + Hasher, T> Hash<S> 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<S: Writer + Hasher, T> Hash<S> 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<S: Writer + Hasher> Hash<S> for TypeId {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.hash().hash(state)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, B: ?Sized, S: Hasher> Hash<S> for Cow<'a, T, B>
|
||||
where B: Hash<S> + ToOwned<T>
|
||||
{
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
Hash::hash(&**self, state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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};
|
||||
use super::{Hasher, Writer};
|
||||
|
||||
/// `SipState` computes a SipHash 2-4 hash over a stream of bytes.
|
||||
#[derive(Copy)]
|
||||
pub struct SipState {
|
||||
/// 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
fn finish(&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
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl Default for SipState {
|
||||
impl Clone for SipHasher {
|
||||
#[inline]
|
||||
#[stable]
|
||||
fn default() -> SipState {
|
||||
SipState::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// `SipHasher` computes the SipHash algorithm from a stream of bytes.
|
||||
#[derive(Clone)]
|
||||
#[allow(missing_copy_implementations)]
|
||||
pub struct SipHasher {
|
||||
k0: u64,
|
||||
k1: u64,
|
||||
}
|
||||
|
||||
impl SipHasher {
|
||||
/// Creates a `Sip`.
|
||||
#[inline]
|
||||
pub fn new() -> SipHasher {
|
||||
SipHasher::new_with_keys(0, 0)
|
||||
}
|
||||
|
||||
/// Creates a `Sip` that is keyed off the provided keys.
|
||||
#[inline]
|
||||
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
|
||||
fn clone(&self) -> SipHasher {
|
||||
SipHasher {
|
||||
k0: key0,
|
||||
k1: key1,
|
||||
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 Hasher<SipState> for SipHasher {
|
||||
#[inline]
|
||||
fn hash<T: ?Sized + Hash<SipState>>(&self, value: &T) -> u64 {
|
||||
let mut state = SipState::new_with_keys(self.k0, self.k1);
|
||||
value.hash(&mut state);
|
||||
state.result()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SipHasher {
|
||||
#[inline]
|
||||
fn default() -> SipHasher {
|
||||
SipHasher::new()
|
||||
}
|
||||
}
|
||||
|
||||
/// Hashes a value using the SipHash algorithm.
|
||||
#[inline]
|
||||
pub fn hash<T: ?Sized + Hash<SipState>>(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<T: ?Sized + Hash<SipState>>(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<S> 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<u8> {
|
||||
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);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -7,27 +7,22 @@
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 std::hash::{Hash, Hasher, Writer};
|
||||
use std::default::Default;
|
||||
|
||||
use core::slice::SliceExt;
|
||||
use core::hash::{Hash, Hasher, Writer};
|
||||
|
||||
struct MyWriterHasher;
|
||||
|
||||
impl Hasher<MyWriter> for MyWriterHasher {
|
||||
fn hash<T: ?Sized + Hash<MyWriter>>(&self, value: &T) -> u64 {
|
||||
let mut state = MyWriter { hash: 0 };
|
||||
value.hash(&mut state);
|
||||
state.hash
|
||||
}
|
||||
}
|
||||
|
||||
struct MyWriter {
|
||||
struct MyHasher {
|
||||
hash: u64,
|
||||
}
|
||||
|
||||
impl Writer for MyWriter {
|
||||
impl Default for MyHasher {
|
||||
fn default() -> MyHasher {
|
||||
MyHasher { hash: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
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: Hash<MyHasher>>(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<str> = 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<str> 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 Hash<u64> for Custom {
|
||||
fn hash(&self, state: &mut u64) {
|
||||
*state = self.hash;
|
||||
impl Default for CustomHasher {
|
||||
fn default() -> CustomHasher {
|
||||
CustomHasher { output: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash<CustomHasher> for Custom {
|
||||
fn hash(&self, state: &mut CustomHasher) {
|
||||
state.output = self.hash;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_custom_state() {
|
||||
fn hash<T: Hash<CustomHasher>>(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);
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ impl PartialEq for LintId {
|
||||
|
||||
impl Eq for LintId { }
|
||||
|
||||
impl<S: hash::Writer> hash::Hash<S> for LintId {
|
||||
impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for LintId {
|
||||
fn hash(&self, state: &mut S) {
|
||||
let ptr = self.lint as *const Lint;
|
||||
ptr.hash(state);
|
||||
|
@ -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::<i64, SipHasher>(&(item_id as i64)))
|
||||
}
|
||||
|
||||
fn find_item<'a>(item_id: ast::NodeId, items: rbml::Doc<'a>) -> rbml::Doc<'a> {
|
||||
|
@ -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<T, F>(rbml_w: &mut Encoder, index: Vec<entry<T>>, mut write_fn: F) where
|
||||
F: FnMut(&mut SeekableMemWriter, &T),
|
||||
T: Hash,
|
||||
T: Hash<SipHasher>,
|
||||
{
|
||||
let mut buckets: Vec<Vec<entry<T>>> = 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);
|
||||
}
|
||||
|
||||
|
@ -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<S> for TyS<'tcx> {
|
||||
fn hash(&self, s: &mut S) {
|
||||
(self as *const _).hash(s)
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl<'tcx, S: Writer + Hasher> Hash<S> 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<S> for InternedTy<'tcx> {
|
||||
impl<'tcx, S: Writer + Hasher> Hash<S> 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<FnSig<'tcx>>| {
|
||||
let fn_sig = |&: state: &mut SipHasher, sig: &Binder<FnSig<'tcx>>| {
|
||||
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 {
|
||||
|
@ -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<P>(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<S,H:Hasher<S>,T:Eq+Clone+Hash<S>>(
|
||||
edges_map: &HashMap<T,Vec<T>,H>,
|
||||
source: T,
|
||||
destination: T)
|
||||
-> bool
|
||||
pub fn can_reach<T, S>(edges_map: &HashMap<T, Vec<T>, S>, source: T,
|
||||
destination: T) -> bool
|
||||
where S: HashState,
|
||||
<S as HashState>::Hasher: Hasher<Output=u64>,
|
||||
T: Hash< <S as HashState>::Hasher> + Eq + Clone,
|
||||
{
|
||||
if source == destination {
|
||||
return true;
|
||||
@ -202,11 +203,12 @@ pub fn can_reach<S,H:Hasher<S>,T:Eq+Clone+Hash<S>>(
|
||||
/// }
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn memoized<T, U, S, H, F>(cache: &RefCell<HashMap<T, U, H>>, arg: T, f: F) -> U where
|
||||
T: Clone + Hash<S> + Eq,
|
||||
U: Clone,
|
||||
H: Hasher<S>,
|
||||
F: FnOnce(T) -> U,
|
||||
pub fn memoized<T, U, S, F>(cache: &RefCell<HashMap<T, U, S>>, arg: T, f: F) -> U
|
||||
where T: Clone + Hash<<S as HashState>::Hasher> + Eq,
|
||||
U: Clone,
|
||||
S: HashState,
|
||||
<S as HashState>::Hasher: Hasher<Output=u64>,
|
||||
F: FnOnce(T) -> U,
|
||||
{
|
||||
let key = arg.clone();
|
||||
let result = cache.borrow().get(&key).map(|result| result.clone());
|
||||
|
@ -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<K, V> = HashMap<K, V, FnvHasher>;
|
||||
pub type FnvHashSet<V> = HashSet<V, FnvHasher>;
|
||||
pub type FnvHashMap<K, V> = HashMap<K, V, DefaultState<FnvHasher>>;
|
||||
pub type FnvHashSet<V> = HashSet<V, DefaultState<FnvHasher>>;
|
||||
|
||||
pub type NodeMap<T> = FnvHashMap<ast::NodeId, T>;
|
||||
pub type DefIdMap<T> = FnvHashMap<ast::DefId, T>;
|
||||
@ -28,16 +30,16 @@ pub type DefIdSet = FnvHashSet<ast::DefId>;
|
||||
// Hacks to get good names
|
||||
pub mod FnvHashMap {
|
||||
use std::hash::Hash;
|
||||
use std::collections::HashMap;
|
||||
pub fn new<K: Hash<super::FnvState> + Eq, V>() -> super::FnvHashMap<K, V> {
|
||||
HashMap::with_hasher(super::FnvHasher)
|
||||
use std::default::Default;
|
||||
pub fn new<K: Hash<super::FnvHasher> + Eq, V>() -> super::FnvHashMap<K, V> {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
pub mod FnvHashSet {
|
||||
use std::hash::Hash;
|
||||
use std::collections::HashSet;
|
||||
pub fn new<V: Hash<super::FnvState> + Eq>() -> super::FnvHashSet<V> {
|
||||
HashSet::with_hasher(super::FnvHasher)
|
||||
use std::default::Default;
|
||||
pub fn new<V: Hash<super::FnvHasher> + Eq>() -> super::FnvHashSet<V> {
|
||||
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<FnvState> for FnvHasher {
|
||||
fn hash<T: ?Sized + Hash<FnvState>>(&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 Writer for FnvState {
|
||||
impl Hasher for FnvHasher {
|
||||
type Output = u64;
|
||||
fn reset(&mut self) { *self = Default::default(); }
|
||||
fn finish(&self) -> u64 { self.0 }
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[old_impl_check]
|
||||
impl<'tcx, S, H, K, V> Repr<'tcx> for HashMap<K,V,H>
|
||||
where K : Hash<S> + Eq + Repr<'tcx>,
|
||||
V : Repr<'tcx>,
|
||||
H : Hasher<S>
|
||||
impl<'tcx, S, K, V> Repr<'tcx> for HashMap<K, V, S>
|
||||
where K: Hash<<S as HashState>::Hasher> + Eq + Repr<'tcx>,
|
||||
V: Repr<'tcx>,
|
||||
S: HashState,
|
||||
<S as HashState>::Hasher: Hasher<Output=u64>,
|
||||
{
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("HashMap({})",
|
||||
|
@ -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.
|
||||
//
|
||||
|
@ -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))
|
||||
})
|
||||
|
@ -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<X> + Eq,
|
||||
V: Encodable,
|
||||
X,
|
||||
H: Hasher<X>
|
||||
> Encodable for HashMap<K, V, H> {
|
||||
impl<K, V, S> Encodable for HashMap<K, V, S>
|
||||
where K: Encodable + Hash< <S as HashState>::Hasher> + Eq,
|
||||
V: Encodable,
|
||||
S: HashState,
|
||||
<S as HashState>::Hasher: Hasher<Output=u64>
|
||||
{
|
||||
fn encode<S: Encoder>(&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<S> + Eq,
|
||||
V: Decodable,
|
||||
S,
|
||||
H: Hasher<S> + Default
|
||||
> Decodable for HashMap<K, V, H> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, H>, D::Error> {
|
||||
impl<K, V, S> Decodable for HashMap<K, V, S>
|
||||
where K: Decodable + Hash< <S as HashState>::Hasher> + Eq,
|
||||
V: Decodable,
|
||||
S: HashState + Default,
|
||||
<S as HashState>::Hasher: Hasher<Output=u64>
|
||||
{
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, S>, 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<X> + Eq,
|
||||
X,
|
||||
H: Hasher<X>
|
||||
> Encodable for HashSet<T, H> {
|
||||
impl<T, S> Encodable for HashSet<T, S>
|
||||
where T: Encodable + Hash< <S as HashState>::Hasher> + Eq,
|
||||
S: HashState,
|
||||
<S as HashState>::Hasher: Hasher<Output=u64>
|
||||
{
|
||||
fn encode<S: Encoder>(&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<S> + Eq,
|
||||
S,
|
||||
H: Hasher<S> + Default
|
||||
> Decodable for HashSet<T, H> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T, H>, D::Error> {
|
||||
impl<T, S> Decodable for HashSet<T, S>
|
||||
where T: Decodable + Hash< <S as HashState>::Hasher> + Eq,
|
||||
S: HashState + Default,
|
||||
<S as HashState>::Hasher: Hasher<Output=u64>
|
||||
{
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T, S>, 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))));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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::<Flags, SipHasher>(&x) == hash::hash::<Flags, SipHasher>(&y));
|
||||
x = Flags::all();
|
||||
y = FlagABC;
|
||||
assert!(hash::hash(&x) == hash::hash(&y));
|
||||
assert!(hash::hash::<Flags, SipHasher>(&x) == hash::hash::<Flags, SipHasher>(&y));
|
||||
}
|
||||
}
|
||||
|
@ -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<K, V, H = RandomSipHasher> {
|
||||
pub struct HashMap<K, V, S = RandomState> {
|
||||
// All hashes are keyed on these values, to prevent hash collision attacks.
|
||||
hasher: H,
|
||||
hash_state: S,
|
||||
|
||||
table: RawTable<K, V>,
|
||||
|
||||
@ -439,17 +439,20 @@ impl<K, V, M> SearchResult<K, V, M> {
|
||||
}
|
||||
}
|
||||
|
||||
#[old_impl_check]
|
||||
impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
fn make_hash<X: ?Sized + Hash<S>>(&self, x: &X) -> SafeHash {
|
||||
table::make_hash(&self.hasher, x)
|
||||
impl<K, V, S, H> HashMap<K, V, S>
|
||||
where K: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn make_hash<X: ?Sized>(&self, x: &X) -> SafeHash where X: Hash<H> {
|
||||
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<FullBucketImm<'a, K, V>>
|
||||
where Q: BorrowFrom<K> + Eq + Hash<S>
|
||||
where Q: BorrowFrom<K> + Eq + Hash<H>
|
||||
{
|
||||
let hash = self.make_hash(q);
|
||||
search_hashed(&self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k)))
|
||||
@ -457,7 +460,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
}
|
||||
|
||||
fn search_mut<'a, Q: ?Sized>(&'a mut self, q: &Q) -> Option<FullBucketMut<'a, K, V>>
|
||||
where Q: BorrowFrom<K> + Eq + Hash<S>
|
||||
where Q: BorrowFrom<K> + Eq + Hash<H>
|
||||
{
|
||||
let hash = self.make_hash(q);
|
||||
search_hashed(&mut self.table, hash, |k| q.eq(BorrowFrom::borrow_from(k)))
|
||||
@ -486,7 +489,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Hash + Eq, V> HashMap<K, V, RandomSipHasher> {
|
||||
impl<K: Hash<Hasher> + Eq, V> HashMap<K, V, RandomState> {
|
||||
/// Create an empty HashMap.
|
||||
///
|
||||
/// # Example
|
||||
@ -497,9 +500,8 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomSipHasher> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn new() -> HashMap<K, V, RandomSipHasher> {
|
||||
let hasher = RandomSipHasher::new();
|
||||
HashMap::with_hasher(hasher)
|
||||
pub fn new() -> HashMap<K, V, RandomState> {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Creates an empty hash map with the given initial capacity.
|
||||
@ -512,14 +514,16 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomSipHasher> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn with_capacity(capacity: uint) -> HashMap<K, V, RandomSipHasher> {
|
||||
let hasher = RandomSipHasher::new();
|
||||
HashMap::with_capacity_and_hasher(capacity, hasher)
|
||||
pub fn with_capacity(capacity: uint) -> HashMap<K, V, RandomState> {
|
||||
HashMap::with_capacity_and_hash_state(capacity, Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[old_impl_check]
|
||||
impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
impl<K, V, S, H> HashMap<K, V, S>
|
||||
where K: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
/// 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<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
///
|
||||
/// ```
|
||||
/// 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<K, V, H> {
|
||||
pub fn with_hash_state(hash_state: S) -> HashMap<K, V, S> {
|
||||
HashMap {
|
||||
hasher: hasher,
|
||||
hash_state: hash_state,
|
||||
resize_policy: DefaultResizePolicy::new(),
|
||||
table: RawTable::new(0),
|
||||
}
|
||||
@ -556,21 +560,22 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
///
|
||||
/// ```
|
||||
/// 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<K, V, H> {
|
||||
pub fn with_capacity_and_hash_state(capacity: uint, hash_state: S)
|
||||
-> HashMap<K, V, S> {
|
||||
let resize_policy = DefaultResizePolicy::new();
|
||||
let min_cap = max(INITIAL_CAPACITY, resize_policy.min_capacity(capacity));
|
||||
let internal_cap = min_cap.checked_next_power_of_two().expect("capacity overflow");
|
||||
assert!(internal_cap >= capacity, "capacity overflow");
|
||||
HashMap {
|
||||
hasher: hasher,
|
||||
hash_state: hash_state,
|
||||
resize_policy: resize_policy,
|
||||
table: RawTable::new(internal_cap),
|
||||
}
|
||||
@ -1031,7 +1036,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||
where Q: Hash<S> + Eq + BorrowFrom<K>
|
||||
where Q: Hash<H> + Eq + BorrowFrom<K>
|
||||
{
|
||||
self.search(k).map(|bucket| bucket.into_refs().1)
|
||||
}
|
||||
@ -1054,7 +1059,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
|
||||
where Q: Hash<S> + Eq + BorrowFrom<K>
|
||||
where Q: Hash<H> + Eq + BorrowFrom<K>
|
||||
{
|
||||
self.search(k).is_some()
|
||||
}
|
||||
@ -1080,7 +1085,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
|
||||
where Q: Hash<S> + Eq + BorrowFrom<K>
|
||||
where Q: Hash<H> + Eq + BorrowFrom<K>
|
||||
{
|
||||
self.search_mut(k).map(|bucket| bucket.into_mut_refs().1)
|
||||
}
|
||||
@ -1132,7 +1137,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn remove<Q: ?Sized>(&mut self, k: &Q) -> Option<V>
|
||||
where Q: Hash<S> + Eq + BorrowFrom<K>
|
||||
where Q: Hash<H> + Eq + BorrowFrom<K>
|
||||
{
|
||||
if self.table.size() == 0 {
|
||||
return None
|
||||
@ -1189,10 +1194,12 @@ fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable<K,V>, hash: SafeHas
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<K: Eq + Hash<S>, V: PartialEq, S, H: Hasher<S>> PartialEq for HashMap<K, V, H> {
|
||||
fn eq(&self, other: &HashMap<K, V, H>) -> bool {
|
||||
impl<K, V, S, H> PartialEq for HashMap<K, V, S>
|
||||
where K: Eq + Hash<H>, V: PartialEq,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn eq(&self, other: &HashMap<K, V, S>) -> bool {
|
||||
if self.len() != other.len() { return false; }
|
||||
|
||||
self.iter().all(|(key, value)|
|
||||
@ -1202,12 +1209,18 @@ impl<K: Eq + Hash<S>, V: PartialEq, S, H: Hasher<S>> PartialEq for HashMap<K, V,
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<K: Eq + Hash<S>, V: Eq, S, H: Hasher<S>> Eq for HashMap<K, V, H> {}
|
||||
impl<K, V, S, H> Eq for HashMap<K, V, S>
|
||||
where K: Eq + Hash<H>, V: Eq,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<K: Eq + Hash<S> + Show, V: Show, S, H: Hasher<S>> Show for HashMap<K, V, H> {
|
||||
impl<K, V, S, H> Show for HashMap<K, V, S>
|
||||
where K: Eq + Hash<H> + Show, V: Show,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "HashMap {{"));
|
||||
|
||||
@ -1221,18 +1234,22 @@ impl<K: Eq + Hash<S> + Show, V: Show, S, H: Hasher<S>> Show for HashMap<K, V, H>
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> Default for HashMap<K, V, H> {
|
||||
#[stable]
|
||||
fn default() -> HashMap<K, V, H> {
|
||||
HashMap::with_hasher(Default::default())
|
||||
impl<K, V, S, H> Default for HashMap<K, V, S>
|
||||
where K: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H> + Default,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn default() -> HashMap<K, V, S> {
|
||||
HashMap::with_hash_state(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<K: Hash<S> + Eq, Q: ?Sized, V, S, H: Hasher<S>> Index<Q> for HashMap<K, V, H>
|
||||
where Q: BorrowFrom<K> + Hash<S> + Eq
|
||||
impl<K, Q: ?Sized, V, S, H> Index<Q> for HashMap<K, V, S>
|
||||
where K: Eq + Hash<H>,
|
||||
Q: Eq + Hash<H> + BorrowFrom<K>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
type Output = V;
|
||||
|
||||
@ -1243,9 +1260,11 @@ impl<K: Hash<S> + Eq, Q: ?Sized, V, S, H: Hasher<S>> Index<Q> for HashMap<K, V,
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<K: Hash<S> + Eq, Q: ?Sized, V, S, H: Hasher<S>> IndexMut<Q> for HashMap<K, V, H>
|
||||
where Q: BorrowFrom<K> + Hash<S> + Eq
|
||||
impl<K, V, S, H, Q: ?Sized> IndexMut<Q> for HashMap<K, V, S>
|
||||
where K: Eq + Hash<H>,
|
||||
Q: Eq + Hash<H> + BorrowFrom<K>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
type Output = V;
|
||||
|
||||
@ -1473,19 +1492,26 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> FromIterator<(K, V)> for HashMap<K, V, H> {
|
||||
fn from_iter<T: Iterator<Item=(K, V)>>(iter: T) -> HashMap<K, V, H> {
|
||||
impl<K, V, S, H> FromIterator<(K, V)> for HashMap<K, V, S>
|
||||
where K: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H> + Default,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn from_iter<T: Iterator<Item=(K, V)>>(iter: T) -> HashMap<K, V, S> {
|
||||
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<K: Eq + Hash<S>, V, S, H: Hasher<S>> Extend<(K, V)> for HashMap<K, V, H> {
|
||||
impl<K, V, S, H> Extend<(K, V)> for HashMap<K, V, S>
|
||||
where K: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn extend<T: Iterator<Item=(K, V)>>(&mut self, mut iter: T) {
|
||||
for (k, v) in iter {
|
||||
self.insert(k, v);
|
||||
@ -1493,6 +1519,64 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> Extend<(K, V)> for HashMap<K, V, H> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// `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::*;
|
||||
|
@ -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;
|
||||
|
@ -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<T, H = RandomSipHasher> {
|
||||
map: HashMap<T, (), H>
|
||||
pub struct HashSet<T, S = RandomState> {
|
||||
map: HashMap<T, (), S>
|
||||
}
|
||||
|
||||
impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
|
||||
impl<T: Hash<Hasher> + Eq> HashSet<T, RandomState> {
|
||||
/// Create an empty HashSet.
|
||||
///
|
||||
/// # Example
|
||||
@ -105,7 +106,7 @@ impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn new() -> HashSet<T, RandomSipHasher> {
|
||||
pub fn new() -> HashSet<T, RandomState> {
|
||||
HashSet::with_capacity(INITIAL_CAPACITY)
|
||||
}
|
||||
|
||||
@ -120,13 +121,16 @@ impl<T: Hash + Eq> HashSet<T, RandomSipHasher> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn with_capacity(capacity: uint) -> HashSet<T, RandomSipHasher> {
|
||||
pub fn with_capacity(capacity: uint) -> HashSet<T, RandomState> {
|
||||
HashSet { map: HashMap::with_capacity(capacity) }
|
||||
}
|
||||
}
|
||||
|
||||
#[old_impl_check]
|
||||
impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
impl<T, S, H> HashSet<T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
/// Creates a new empty hash set which will use the given hasher to hash
|
||||
/// keys.
|
||||
///
|
||||
@ -136,16 +140,16 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
///
|
||||
/// ```
|
||||
/// 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<T, H> {
|
||||
HashSet::with_capacity_and_hasher(INITIAL_CAPACITY, hasher)
|
||||
pub fn with_hash_state(hash_state: S) -> HashSet<T, S> {
|
||||
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<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
///
|
||||
/// ```
|
||||
/// 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<T, H> {
|
||||
HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) }
|
||||
pub fn with_capacity_and_hash_state(capacity: uint, hash_state: S)
|
||||
-> HashSet<T, S> {
|
||||
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<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
/// assert_eq!(diff, [4i].iter().map(|&x| x).collect());
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn difference<'a>(&'a self, other: &'a HashSet<T, H>) -> Difference<'a, T, H> {
|
||||
pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> {
|
||||
Difference {
|
||||
iter: self.iter(),
|
||||
other: other,
|
||||
@ -328,8 +335,8 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
/// assert_eq!(diff1, [1i, 4].iter().map(|&x| x).collect());
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, H>)
|
||||
-> SymmetricDifference<'a, T, H> {
|
||||
pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet<T, S>)
|
||||
-> SymmetricDifference<'a, T, S> {
|
||||
SymmetricDifference { iter: self.difference(other).chain(other.difference(self)) }
|
||||
}
|
||||
|
||||
@ -351,7 +358,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
/// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect());
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn intersection<'a>(&'a self, other: &'a HashSet<T, H>) -> Intersection<'a, T, H> {
|
||||
pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
|
||||
Intersection {
|
||||
iter: self.iter(),
|
||||
other: other,
|
||||
@ -376,7 +383,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
/// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect());
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn union<'a>(&'a self, other: &'a HashSet<T, H>) -> Union<'a, T, H> {
|
||||
pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
|
||||
Union { iter: self.iter().chain(other.difference(self)) }
|
||||
}
|
||||
|
||||
@ -452,7 +459,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
|
||||
where Q: BorrowFrom<T> + Hash<S> + Eq
|
||||
where Q: BorrowFrom<T> + Hash<H> + Eq
|
||||
{
|
||||
self.map.contains_key(value)
|
||||
}
|
||||
@ -475,7 +482,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
/// assert_eq!(a.is_disjoint(&b), false);
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn is_disjoint(&self, other: &HashSet<T, H>) -> bool {
|
||||
pub fn is_disjoint(&self, other: &HashSet<T, S>) -> bool {
|
||||
self.iter().all(|v| !other.contains(v))
|
||||
}
|
||||
|
||||
@ -496,7 +503,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
/// assert_eq!(set.is_subset(&sup), false);
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn is_subset(&self, other: &HashSet<T, H>) -> bool {
|
||||
pub fn is_subset(&self, other: &HashSet<T, S>) -> bool {
|
||||
self.iter().all(|v| other.contains(v))
|
||||
}
|
||||
|
||||
@ -521,7 +528,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn is_superset(&self, other: &HashSet<T, H>) -> bool {
|
||||
pub fn is_superset(&self, other: &HashSet<T, S>) -> bool {
|
||||
other.is_subset(self)
|
||||
}
|
||||
|
||||
@ -562,16 +569,19 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> HashSet<T, H> {
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn remove<Q: ?Sized>(&mut self, value: &Q) -> bool
|
||||
where Q: BorrowFrom<T> + Hash<S> + Eq
|
||||
where Q: BorrowFrom<T> + Hash<H> + Eq
|
||||
{
|
||||
self.map.remove(value).is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
|
||||
fn eq(&self, other: &HashSet<T, H>) -> bool {
|
||||
impl<T, S, H> PartialEq for HashSet<T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn eq(&self, other: &HashSet<T, S>) -> bool {
|
||||
if self.len() != other.len() { return false; }
|
||||
|
||||
self.iter().all(|key| other.contains(key))
|
||||
@ -579,12 +589,18 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> PartialEq for HashSet<T, H> {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<T: Eq + Hash<S>, S, H: Hasher<S>> Eq for HashSet<T, H> {}
|
||||
impl<T, S, H> Eq for HashSet<T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> {
|
||||
impl<T, S, H> fmt::Show for HashSet<T, S>
|
||||
where T: Eq + Hash<H> + fmt::Show,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(f, "HashSet {{"));
|
||||
|
||||
@ -598,19 +614,25 @@ impl<T: Eq + Hash<S> + fmt::Show, S, H: Hasher<S>> fmt::Show for HashSet<T, H> {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> FromIterator<T> for HashSet<T, H> {
|
||||
fn from_iter<I: Iterator<Item=T>>(iter: I) -> HashSet<T, H> {
|
||||
impl<T, S, H> FromIterator<T> for HashSet<T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H> + Default,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn from_iter<I: Iterator<Item=T>>(iter: I) -> HashSet<T, S> {
|
||||
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<T: Eq + Hash<S>, S, H: Hasher<S>> Extend<T> for HashSet<T, H> {
|
||||
impl<T, S, H> Extend<T> for HashSet<T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
fn extend<I: Iterator<Item=T>>(&mut self, mut iter: I) {
|
||||
for k in iter {
|
||||
self.insert(k);
|
||||
@ -619,21 +641,26 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S>> Extend<T> for HashSet<T, H> {
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> {
|
||||
impl<T, S, H> Default for HashSet<T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H> + Default,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
#[stable]
|
||||
fn default() -> HashSet<T, H> {
|
||||
HashSet::with_hasher(Default::default())
|
||||
fn default() -> HashSet<T, S> {
|
||||
HashSet::with_hash_state(Default::default())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default>
|
||||
BitOr<&'b HashSet<T, H>> for &'a HashSet<T, H> {
|
||||
type Output = HashSet<T, H>;
|
||||
impl<'a, 'b, T, S, H> BitOr<&'b HashSet<T, S>> for &'a HashSet<T, S>
|
||||
where T: Eq + Hash<H> + Clone,
|
||||
S: HashState<Hasher=H> + Default,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
type Output = HashSet<T, S>;
|
||||
|
||||
/// Returns the union of `self` and `rhs` as a new `HashSet<T, H>`.
|
||||
/// Returns the union of `self` and `rhs` as a new `HashSet<T, S>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -653,18 +680,20 @@ BitOr<&'b HashSet<T, H>> for &'a HashSet<T, H> {
|
||||
/// }
|
||||
/// assert_eq!(i, expected.len());
|
||||
/// ```
|
||||
fn bitor(self, rhs: &HashSet<T, H>) -> HashSet<T, H> {
|
||||
fn bitor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
|
||||
self.union(rhs).cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default>
|
||||
BitAnd<&'b HashSet<T, H>> for &'a HashSet<T, H> {
|
||||
type Output = HashSet<T, H>;
|
||||
impl<'a, 'b, T, S, H> BitAnd<&'b HashSet<T, S>> for &'a HashSet<T, S>
|
||||
where T: Eq + Hash<H> + Clone,
|
||||
S: HashState<Hasher=H> + Default,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
type Output = HashSet<T, S>;
|
||||
|
||||
/// Returns the intersection of `self` and `rhs` as a new `HashSet<T, H>`.
|
||||
/// Returns the intersection of `self` and `rhs` as a new `HashSet<T, S>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -684,18 +713,20 @@ BitAnd<&'b HashSet<T, H>> for &'a HashSet<T, H> {
|
||||
/// }
|
||||
/// assert_eq!(i, expected.len());
|
||||
/// ```
|
||||
fn bitand(self, rhs: &HashSet<T, H>) -> HashSet<T, H> {
|
||||
fn bitand(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
|
||||
self.intersection(rhs).cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default>
|
||||
BitXor<&'b HashSet<T, H>> for &'a HashSet<T, H> {
|
||||
type Output = HashSet<T, H>;
|
||||
impl<'a, 'b, T, S, H> BitXor<&'b HashSet<T, S>> for &'a HashSet<T, S>
|
||||
where T: Eq + Hash<H> + Clone,
|
||||
S: HashState<Hasher=H> + Default,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
type Output = HashSet<T, S>;
|
||||
|
||||
/// Returns the symmetric difference of `self` and `rhs` as a new `HashSet<T, H>`.
|
||||
/// Returns the symmetric difference of `self` and `rhs` as a new `HashSet<T, S>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -715,18 +746,20 @@ BitXor<&'b HashSet<T, H>> for &'a HashSet<T, H> {
|
||||
/// }
|
||||
/// assert_eq!(i, expected.len());
|
||||
/// ```
|
||||
fn bitxor(self, rhs: &HashSet<T, H>) -> HashSet<T, H> {
|
||||
fn bitxor(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
|
||||
self.symmetric_difference(rhs).cloned().collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
#[old_impl_check]
|
||||
impl<'a, 'b, T: Eq + Hash<S> + Clone, S, H: Hasher<S> + Default>
|
||||
Sub<&'b HashSet<T, H>> for &'a HashSet<T, H> {
|
||||
type Output = HashSet<T, H>;
|
||||
impl<'a, 'b, T, S, H> Sub<&'b HashSet<T, S>> for &'a HashSet<T, S>
|
||||
where T: Eq + Hash<H> + Clone,
|
||||
S: HashState<Hasher=H> + Default,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
type Output = HashSet<T, S>;
|
||||
|
||||
/// Returns the difference of `self` and `rhs` as a new `HashSet<T, H>`.
|
||||
/// Returns the difference of `self` and `rhs` as a new `HashSet<T, S>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -746,7 +779,7 @@ Sub<&'b HashSet<T, H>> for &'a HashSet<T, H> {
|
||||
/// }
|
||||
/// assert_eq!(i, expected.len());
|
||||
/// ```
|
||||
fn sub(self, rhs: &HashSet<T, H>) -> HashSet<T, H> {
|
||||
fn sub(self, rhs: &HashSet<T, S>) -> HashSet<T, S> {
|
||||
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<T, H>,
|
||||
other: &'a HashSet<T, S>,
|
||||
}
|
||||
|
||||
/// 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<T, H>,
|
||||
other: &'a HashSet<T, S>,
|
||||
}
|
||||
|
||||
/// Symmetric difference iterator.
|
||||
#[stable]
|
||||
pub struct SymmetricDifference<'a, T: 'a, H: 'a> {
|
||||
iter: Chain<Difference<'a, T, H>, Difference<'a, T, H>>
|
||||
pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
|
||||
iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>
|
||||
}
|
||||
|
||||
/// Set union iterator.
|
||||
#[stable]
|
||||
pub struct Union<'a, T: 'a, H: 'a> {
|
||||
iter: Chain<Iter<'a, T>, Difference<'a, T, H>>
|
||||
pub struct Union<'a, T: 'a, S: 'a> {
|
||||
iter: Chain<Iter<'a, T>, 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<S>, H: Hasher<S>
|
||||
impl<'a, T, S, H> Iterator for Intersection<'a, T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
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<S>, H: Hasher<S>
|
||||
impl<'a, T, S, H> Iterator for Difference<'a, T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
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<S>, H: Hasher<S>
|
||||
impl<'a, T, S, H> Iterator for SymmetricDifference<'a, T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
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<S>, H: Hasher<S>
|
||||
impl<'a, T, S, H> Iterator for Union<'a, T, S>
|
||||
where T: Eq + Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: hash::Hasher<Output=u64>
|
||||
{
|
||||
type Item = &'a T;
|
||||
|
||||
|
51
src/libstd/collections/hash/state.rs
Normal file
51
src/libstd/collections/hash/state.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<H>;
|
||||
|
||||
impl<H: Default + hash::Hasher> HashState for DefaultState<H> {
|
||||
type Hasher = H;
|
||||
fn hasher(&self) -> H { Default::default() }
|
||||
}
|
||||
|
||||
impl<H> Clone for DefaultState<H> {
|
||||
fn clone(&self) -> DefaultState<H> { DefaultState }
|
||||
}
|
||||
|
||||
impl<H> Default for DefaultState<H> {
|
||||
fn default() -> DefaultState<H> { DefaultState }
|
||||
}
|
@ -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<T: ?Sized + Hash<S>, S, H: Hasher<S>>(hasher: &H, t: &T) -> SafeHash {
|
||||
pub fn make_hash<T: ?Sized, S, H>(hash_state: &S, t: &T) -> SafeHash
|
||||
where T: Hash<H>,
|
||||
S: HashState<Hasher=H>,
|
||||
H: Hasher<Output=u64>
|
||||
{
|
||||
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
|
||||
|
@ -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::*;
|
||||
}
|
||||
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<sip::SipState> for RandomSipHasher {
|
||||
#[inline]
|
||||
fn hash<T: ?Sized + Hash<sip::SipState>>(&self, value: &T) -> u64 {
|
||||
self.hasher.hash(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable]
|
||||
impl Default for RandomSipHasher {
|
||||
#[stable]
|
||||
#[inline]
|
||||
fn default() -> RandomSipHasher {
|
||||
RandomSipHasher::new()
|
||||
}
|
||||
}
|
@ -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<H: hash::Writer + hash::Hasher> hash::Hash<H> 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() {
|
||||
|
@ -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!()
|
||||
|
@ -91,7 +91,7 @@ impl FromStr for Path {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: hash::Writer> hash::Hash<S> for Path {
|
||||
impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path {
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
self.repr.hash(state)
|
||||
|
@ -118,7 +118,7 @@ impl FromStr for Path {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: hash::Writer> hash::Hash<S> for Path {
|
||||
impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path {
|
||||
#[cfg(not(test))]
|
||||
#[inline]
|
||||
fn hash(&self, state: &mut S) {
|
||||
|
@ -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<P>, err_fd: Option<P>)
|
||||
-> IoResult<Process>
|
||||
where C: ProcessConfig<K, V>, P: AsInner<FileDesc>,
|
||||
K: BytesContainer + Eq + Hash, V: BytesContainer
|
||||
K: BytesContainer + Eq + Hash<Hasher>, V: BytesContainer
|
||||
{
|
||||
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
|
||||
use libc::funcs::bsd44::getdtablesize;
|
||||
@ -553,11 +554,11 @@ fn with_argv<T,F>(prog: &CString, args: &[CString],
|
||||
cb(ptrs.as_ptr())
|
||||
}
|
||||
|
||||
fn with_envp<K,V,T,F>(env: Option<&collections::HashMap<K, V>>,
|
||||
fn with_envp<K,V,T,F>(env: Option<&HashMap<K, V>>,
|
||||
cb: F)
|
||||
-> T
|
||||
where F : FnOnce(*const c_void) -> T,
|
||||
K : BytesContainer + Eq + Hash,
|
||||
K : BytesContainer + Eq + Hash<Hasher>,
|
||||
V : BytesContainer
|
||||
{
|
||||
// On posixy systems we can pass a char** for envp, which is a
|
||||
|
@ -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<P>, err_fd: Option<P>)
|
||||
-> IoResult<Process>
|
||||
where C: ProcessConfig<K, V>, P: AsInner<FileDesc>,
|
||||
K: BytesContainer + Eq + Hash, V: BytesContainer
|
||||
K: BytesContainer + Eq + Hash<Hasher>, 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<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T where
|
||||
K: BytesContainer + Eq + Hash, V: BytesContainer, F: FnOnce(*mut c_void) -> T,
|
||||
fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T
|
||||
where K: BytesContainer + Eq + Hash<Hasher>,
|
||||
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
|
||||
|
@ -30,7 +30,8 @@ pub fn expand_deriving_hash<F>(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"));
|
||||
|
@ -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<T: Show> Show for P<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S, T: Hash<S>> Hash<S> for P<T> {
|
||||
#[cfg(stage0)]
|
||||
impl<S: Writer, T: Hash<S>> Hash<S> for P<T> {
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl<S: Hasher, T: Hash<S>> Hash<S> for P<T> {
|
||||
fn hash(&self, state: &mut S) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
|
@ -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<T> {
|
||||
vect: RefCell<Vec<T> >,
|
||||
}
|
||||
|
||||
// when traits can extend traits, we should extend index<Name,T> to get .index(&FullRange)
|
||||
impl<T: Eq + Hash + Clone + 'static> Interner<T> {
|
||||
// when traits can extend traits, we should extend index<Name,T> to get []
|
||||
impl<T: Eq + Hash<Hasher> + Clone + 'static> Interner<T> {
|
||||
pub fn new() -> Interner<T> {
|
||||
Interner {
|
||||
map: RefCell::new(HashMap::new()),
|
||||
@ -78,7 +79,7 @@ impl<T: Eq + Hash + Clone + 'static> Interner<T> {
|
||||
}
|
||||
|
||||
pub fn find<Q: ?Sized>(&self, val: &Q) -> Option<Name>
|
||||
where Q: BorrowFrom<T> + Eq + Hash {
|
||||
where Q: BorrowFrom<T> + Eq + Hash<Hasher> {
|
||||
let map = self.map.borrow();
|
||||
match (*map).get(val) {
|
||||
Some(v) => Some(*v),
|
||||
@ -203,7 +204,7 @@ impl StrInterner {
|
||||
}
|
||||
|
||||
pub fn find<Q: ?Sized>(&self, val: &Q) -> Option<Name>
|
||||
where Q: BorrowFrom<RcStr> + Eq + Hash {
|
||||
where Q: BorrowFrom<RcStr> + Eq + Hash<Hasher> {
|
||||
match (*self.map.borrow()).get(val) {
|
||||
Some(v) => Some(*v),
|
||||
None => None,
|
||||
|
@ -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<W: Writer, T: Float + fmt::String + fmt::Show + FromPrimiti
|
||||
/// Returns a HashMap with the number of occurrences of every element in the
|
||||
/// sequence that the iterator exposes.
|
||||
pub fn freq_count<T, U>(mut iter: T) -> hash_map::HashMap<U, uint>
|
||||
where T: Iterator<Item=U>, U: Eq + Clone + Hash
|
||||
where T: Iterator<Item=U>, U: Eq + Clone + Hash<Hasher>
|
||||
{
|
||||
let mut map: hash_map::HashMap<U,uint> = hash_map::HashMap::new();
|
||||
for elem in iter {
|
||||
|
@ -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<T> {
|
||||
fn contains(&self, k: &T) -> bool;
|
||||
}
|
||||
|
||||
impl<T: Hash + Eq> MutableSet<T> for HashSet<T> {
|
||||
impl<T: Hash<Hasher> + Eq> MutableSet<T> for HashSet<T> {
|
||||
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) }
|
||||
|
@ -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: Hash<SipHasher>>(t: &T) -> u64 {
|
||||
std::hash::hash::<T, SipHasher>(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));
|
||||
}
|
||||
|
@ -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: Hash<SipHasher>>(_t: &T) {}
|
||||
|
||||
pub fn main() {
|
||||
let a = Foo {bar: 4, baz: -3};
|
||||
|
||||
|
@ -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: Hash<SipHasher>>(_t: &T) {}
|
||||
|
||||
pub fn main() {
|
||||
let a = Foo {bar: 4, baz: -3};
|
||||
|
||||
|
@ -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::<uint>(), TypeId::of::<uint>());
|
||||
|
||||
assert_eq!(hash::hash(&a), hash::hash(&b));
|
||||
assert_eq!(hash::hash::<TypeId, SipHasher>(&a),
|
||||
hash::hash::<TypeId, SipHasher>(&b));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user