std: Stabilize the hash module

This commit is an implementation of [RFC 823][rfc] which is another pass over
the `std::hash` module for stabilization. The contents of the module were not
entirely marked stable, but some portions which remained quite similar to the
previous incarnation are now marked `#[stable]`. Specifically:

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0823-hash-simplification.md

* `std::hash` is now stable (the name)
* `Hash` is now stable
* `Hash::hash` is now stable
* `Hasher` is now stable
* `SipHasher` is now stable
* `SipHasher::new` and `new_with_keys` are now stable
* `Hasher for SipHasher` is now stable
* Many `Hash` implementations are now stable

All other portions of the `hash` module remain `#[unstable]` as they are less
commonly used and were recently redesigned.

This commit is a breaking change due to the modifications to the `std::hash` API
and more details can be found on the [RFC][rfc].

Closes #22467
[breaking-change]
This commit is contained in:
Alex Crichton 2015-02-17 20:48:07 -08:00
parent dfc5c0f1e8
commit f83e23ad7c
54 changed files with 5004 additions and 372 deletions

View file

@ -17,7 +17,7 @@
use clone::Clone;
use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
use fmt;
use hash::{Hash, Hasher, self};
use hash::{Hash, self};
use iter::IntoIterator;
use marker::Copy;
use ops::Deref;
@ -35,11 +35,19 @@ macro_rules! array_impls {
}
}
impl<S: hash::Writer + Hasher, T: Hash<S>> Hash<S> for [T; $N] {
#[cfg(stage0)]
impl<S: hash::Writer + hash::Hasher, T: Hash<S>> Hash<S> for [T; $N] {
fn hash(&self, state: &mut S) {
Hash::hash(&self[], state)
}
}
#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for [T; $N] {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
Hash::hash(&self[], state)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug> fmt::Debug for [T; $N] {

View file

@ -35,7 +35,7 @@
//! the trait `Hash`:
//!
//! ```rust
//! use std::hash::{hash, Hash, Hasher, Writer, SipHasher};
//! use std::hash::{hash, Hash, Hasher, SipHasher};
//!
//! struct Person {
//! id: uint,
@ -43,8 +43,8 @@
//! phone: u64,
//! }
//!
//! impl<H: Hasher + Writer> Hash<H> for Person {
//! fn hash(&self, state: &mut H) {
//! impl Hash for Person {
//! fn hash<H: Hasher>(&self, state: &mut H) {
//! self.id.hash(state);
//! self.phone.hash(state);
//! }
@ -56,15 +56,11 @@
//! assert_eq!(hash::<_, SipHasher>(&person1), hash::<_, SipHasher>(&person2));
//! ```
#![unstable(feature = "hash",
reason = "module was recently redesigned")]
#![stable(feature = "rust1", since = "1.0.0")]
use prelude::*;
use borrow::{Cow, ToOwned};
use default::Default;
use marker::Sized;
use mem;
use num::Int;
pub use self::sip::SipHasher;
@ -76,22 +72,123 @@ mod sip;
/// 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))]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Hash {
/// Feeds this value into the state given, updating the hasher as necessary.
#[stable(feature = "rust1", since = "1.0.0")]
fn hash<H: Hasher>(&self, state: &mut H);
/// Feeds a slice of this type into the state provided.
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) where Self: Sized {
for piece in data {
piece.hash(state);
}
}
}
/// 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: 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.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Hasher {
/// Result type of one run of hashing generated by this hasher.
#[cfg(stage0)]
type Output;
/// Resets this hasher back to its initial state (as if it were just
/// created).
#[cfg(stage0)]
fn reset(&mut self);
/// Completes a round of hashing, producing the output hash generated.
#[cfg(stage0)]
fn finish(&self) -> Self::Output;
/// Completes a round of hashing, producing the output hash generated.
#[cfg(not(stage0))]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn finish(&self) -> u64;
/// Writes some data into this `Hasher`
#[cfg(not(stage0))]
#[stable(feature = "rust1", since = "1.0.0")]
fn write(&mut self, bytes: &[u8]);
/// Write a single `u8` into this hasher
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_u8(&mut self, i: u8) { self.write(&[i]) }
/// Write a single `u16` into this hasher.
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_u16(&mut self, i: u16) {
self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) })
}
/// Write a single `u32` into this hasher.
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_u32(&mut self, i: u32) {
self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) })
}
/// Write a single `u64` into this hasher.
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_u64(&mut self, i: u64) {
self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) })
}
/// Write a single `usize` into this hasher.
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_usize(&mut self, i: usize) {
if cfg!(target_pointer_size = "32") {
self.write_u32(i as u32)
} else {
self.write_u64(i as u64)
}
}
/// Write a single `i8` into this hasher.
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_i8(&mut self, i: i8) { self.write_u8(i as u8) }
/// Write a single `i16` into this hasher.
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_i16(&mut self, i: i16) { self.write_u16(i as u16) }
/// Write a single `i32` into this hasher.
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_i32(&mut self, i: i32) { self.write_u32(i as u32) }
/// Write a single `i64` into this hasher.
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) }
/// Write a single `isize` into this hasher.
#[cfg(not(stage0))]
#[inline]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
fn write_isize(&mut self, i: isize) { self.write_usize(i as usize) }
}
/// A common bound on the `Hasher` parameter to `Hash` implementations in order
@ -99,6 +196,7 @@ pub trait Hasher {
#[unstable(feature = "hash",
reason = "this trait will likely be replaced by io::Writer")]
#[allow(missing_docs)]
#[cfg(stage0)]
pub trait Writer {
fn write(&mut self, bytes: &[u8]);
}
@ -107,148 +205,312 @@ pub trait Writer {
///
/// The specified value will be hashed with this hasher and then the resulting
/// hash will be returned.
#[cfg(stage0)]
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()
}
/// 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.
#[cfg(not(stage0))]
#[unstable(feature = "hash", reason = "module was recently redesigned")]
pub fn hash<T: Hash, H: Hasher + Default>(value: &T) -> u64 {
let mut h: H = Default::default();
value.hash(&mut h);
h.finish()
}
//////////////////////////////////////////////////////////////////////////////
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)
}
}
}
}
#[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 mem;
use num::Int;
use super::*;
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);
)*
}
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)
}
}
}
);
}
}
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 + Hasher, T: Hash<S>> Hash<S> for [T] {
#[inline]
fn hash(&self, state: &mut S) {
self.len().hash(state);
for elt in self {
elt.hash(state);
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 {
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<'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)
}
}
}
#[cfg(not(stage0))]
mod impls {
use prelude::*;
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<'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)
use borrow::{Cow, ToOwned};
use slice;
use super::*;
macro_rules! impl_write {
($(($ty:ident, $meth:ident),)*) => {$(
#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for $ty {
fn hash<H: Hasher>(&self, state: &mut H) {
state.$meth(*self)
}
fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
let newlen = data.len() * ::$ty::BYTES;
let ptr = data.as_ptr() as *const u8;
state.write(unsafe { slice::from_raw_parts(ptr, newlen) })
}
}
)*}
}
impl_write! {
(u8, write_u8),
(u16, write_u16),
(u32, write_u32),
(u64, write_u64),
(usize, write_usize),
(i8, write_i8),
(i16, write_i16),
(i32, write_i32),
(i64, write_i64),
(isize, write_isize),
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for bool {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u8(*self as u8)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for char {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u32(*self as u32)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for str {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(self.as_bytes());
state.write_u8(0xff)
}
}
macro_rules! impl_hash_tuple {
() => (
#[stable(feature = "rust1", since = "1.0.0")]
impl Hash for () {
fn hash<H: Hasher>(&self, _state: &mut H) {}
}
);
( $($name:ident)+) => (
#[stable(feature = "rust1", since = "1.0.0")]
impl<$($name: Hash),*> Hash for ($($name,)*) {
#[allow(non_snake_case)]
fn hash<S: Hasher>(&self, state: &mut S) {
let ($(ref $name,)*) = *self;
$($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 }
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for [T] {
fn hash<H: Hasher>(&self, state: &mut H) {
self.len().hash(state);
Hash::hash_slice(self, state)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized + Hash> Hash for &'a T {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized + Hash> Hash for &'a mut T {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Hash for *const T {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_usize(*self as usize)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Hash for *mut T {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_usize(*self as usize)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T, B: ?Sized> Hash for Cow<'a, T, B>
where B: Hash + ToOwned<T>
{
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&**self, state)
}
}
}

View file

@ -15,7 +15,9 @@
use prelude::*;
use default::Default;
use super::{Hasher, Writer};
use super::Hasher;
#[cfg(stage0)]
use super::Writer;
/// An implementation of SipHash 2-4.
///
@ -30,6 +32,7 @@ use super::{Hasher, Writer};
/// strong, this implementation has not been reviewed for such purposes.
/// As such, all cryptographic uses of this implementation are strongly
/// discouraged.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SipHasher {
k0: u64,
k1: u64,
@ -88,12 +91,14 @@ macro_rules! compress {
impl SipHasher {
/// Creates a new `SipHasher` with the two initial keys set to 0.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> SipHasher {
SipHasher::new_with_keys(0, 0)
}
/// Creates a `SipHasher` that is keyed off the provided keys.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
let mut state = SipHasher {
k0: key0,
@ -114,10 +119,16 @@ impl SipHasher {
#[unstable(feature = "hash")]
#[deprecated(since = "1.0.0", reason = "renamed to finish")]
pub fn result(&self) -> u64 { self.finish() }
}
impl Writer for SipHasher {
#[inline]
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 write(&mut self, msg: &[u8]) {
let length = msg.len();
self.length += length;
@ -164,16 +175,28 @@ impl Writer for SipHasher {
}
}
#[cfg(stage0)]
impl Writer for SipHasher {
#[inline]
fn write(&mut self, msg: &[u8]) {
self.write(msg)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Hasher for SipHasher {
#[cfg(stage0)]
type Output = u64;
#[cfg(stage0)]
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;
self.reset();
}
#[inline]
#[cfg(not(stage0))]
fn write(&mut self, msg: &[u8]) {
self.write(msg)
}
fn finish(&self) -> u64 {
@ -199,6 +222,7 @@ impl Hasher for SipHasher {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Clone for SipHasher {
#[inline]
fn clone(&self) -> SipHasher {
@ -216,6 +240,7 @@ impl Clone for SipHasher {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Default for SipHasher {
fn default() -> SipHasher {
SipHasher::new()