Skip to content

Commit 8bf3ee7

Browse files
committed
rollup merge of rust-lang#20654: alexcrichton/stabilize-hash
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]
2 parents b1c23f6 + 511f0b8 commit 8bf3ee7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1061
-1012
lines changed

src/compiletest/compiletest.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
#![crate_type = "bin"]
12-
#![feature(slicing_syntax, unboxed_closures)]
12+
#![feature(slicing_syntax)]
1313

1414
#![deny(warnings)]
1515

src/liballoc/arc.rs

+13-8
Original file line numberDiff line numberDiff line change
@@ -67,21 +67,20 @@
6767
//! }
6868
//! ```
6969
70+
use core::prelude::*;
71+
7072
use core::atomic;
7173
use core::atomic::Ordering::{Relaxed, Release, Acquire, SeqCst};
7274
use core::borrow::BorrowFrom;
73-
use core::clone::Clone;
7475
use core::fmt::{self, Show};
75-
use core::cmp::{Eq, Ord, PartialEq, PartialOrd, Ordering};
76+
use core::cmp::{Ordering};
7677
use core::default::Default;
77-
use core::marker::{Sync, Send};
78-
use core::mem::{min_align_of, size_of, drop};
78+
use core::mem::{min_align_of, size_of};
7979
use core::mem;
8080
use core::nonzero::NonZero;
81-
use core::ops::{Drop, Deref};
82-
use core::option::Option;
83-
use core::option::Option::{Some, None};
84-
use core::ptr::{self, PtrExt};
81+
use core::ops::Deref;
82+
use core::ptr;
83+
use core::hash::{Hash, Hasher};
8584
use heap::deallocate;
8685

8786
/// An atomically reference counted wrapper for shared state.
@@ -591,6 +590,12 @@ impl<T: Default + Sync + Send> Default for Arc<T> {
591590
fn default() -> Arc<T> { Arc::new(Default::default()) }
592591
}
593592

593+
impl<H: Hasher, T: Hash<H>> Hash<H> for Arc<T> {
594+
fn hash(&self, state: &mut H) {
595+
(**self).hash(state)
596+
}
597+
}
598+
594599
#[cfg(test)]
595600
#[allow(experimental)]
596601
mod tests {

src/liballoc/boxed.rs

+8
Original file line numberDiff line numberDiff line change
@@ -106,12 +106,20 @@ impl<T: ?Sized + Ord> Ord for Box<T> {
106106
#[stable]}
107107
impl<T: ?Sized + Eq> Eq for Box<T> {}
108108

109+
#[cfg(stage0)]
109110
impl<S: hash::Writer, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
110111
#[inline]
111112
fn hash(&self, state: &mut S) {
112113
(**self).hash(state);
113114
}
114115
}
116+
#[cfg(not(stage0))]
117+
impl<S: hash::Hasher, T: ?Sized + Hash<S>> Hash<S> for Box<T> {
118+
#[inline]
119+
fn hash(&self, state: &mut S) {
120+
(**self).hash(state);
121+
}
122+
}
115123

116124
/// Extension methods for an owning `Any` trait object.
117125
#[unstable = "post-DST and coherence changes, this will not be a trait but \

src/liballoc/rc.rs

+23-12
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,26 @@
1010

1111
//! Thread-local reference-counted boxes (the `Rc<T>` type).
1212
//!
13-
//! The `Rc<T>` type provides shared ownership of an immutable value. Destruction is deterministic,
14-
//! and will occur as soon as the last owner is gone. It is marked as non-sendable because it
15-
//! avoids the overhead of atomic reference counting.
13+
//! The `Rc<T>` type provides shared ownership of an immutable value.
14+
//! Destruction is deterministic, and will occur as soon as the last owner is
15+
//! gone. It is marked as non-sendable because it avoids the overhead of atomic
16+
//! reference counting.
1617
//!
17-
//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer to the box. A
18-
//! `Weak<T>` pointer can be upgraded to an `Rc<T>` pointer, but will return `None` if the value
19-
//! has already been dropped.
18+
//! The `downgrade` method can be used to create a non-owning `Weak<T>` pointer
19+
//! to the box. A `Weak<T>` pointer can be upgraded to an `Rc<T>` pointer, but
20+
//! will return `None` if the value has already been dropped.
2021
//!
21-
//! For example, a tree with parent pointers can be represented by putting the nodes behind strong
22-
//! `Rc<T>` pointers, and then storing the parent pointers as `Weak<T>` pointers.
22+
//! For example, a tree with parent pointers can be represented by putting the
23+
//! nodes behind strong `Rc<T>` pointers, and then storing the parent pointers
24+
//! as `Weak<T>` pointers.
2325
//!
2426
//! # Examples
2527
//!
26-
//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`. We want to have our
27-
//! `Gadget`s point to their `Owner`. We can't do this with unique ownership, because more than one
28-
//! gadget may belong to the same `Owner`. `Rc<T>` allows us to share an `Owner` between multiple
29-
//! `Gadget`s, and have the `Owner` remain allocated as long as any `Gadget` points at it.
28+
//! Consider a scenario where a set of `Gadget`s are owned by a given `Owner`.
29+
//! We want to have our `Gadget`s point to their `Owner`. We can't do this with
30+
//! unique ownership, because more than one gadget may belong to the same
31+
//! `Owner`. `Rc<T>` allows us to share an `Owner` between multiple `Gadget`s,
32+
//! and have the `Owner` remain allocated as long as any `Gadget` points at it.
3033
//!
3134
//! ```rust
3235
//! use std::rc::Rc;
@@ -597,12 +600,20 @@ impl<T: Ord> Ord for Rc<T> {
597600
}
598601

599602
// FIXME (#18248) Make `T` `Sized?`
603+
#[cfg(stage0)]
600604
impl<S: hash::Writer, T: Hash<S>> Hash<S> for Rc<T> {
601605
#[inline]
602606
fn hash(&self, state: &mut S) {
603607
(**self).hash(state);
604608
}
605609
}
610+
#[cfg(not(stage0))]
611+
impl<S: hash::Hasher, T: Hash<S>> Hash<S> for Rc<T> {
612+
#[inline]
613+
fn hash(&self, state: &mut S) {
614+
(**self).hash(state);
615+
}
616+
}
606617

607618
#[experimental = "Show is experimental."]
608619
impl<T: fmt::Show> fmt::Show for Rc<T> {

src/libcollections/bit.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,7 @@ impl fmt::Show for Bitv {
982982
}
983983

984984
#[stable]
985-
impl<S: hash::Writer> hash::Hash<S> for Bitv {
985+
impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Bitv {
986986
fn hash(&self, state: &mut S) {
987987
self.nbits.hash(state);
988988
for elem in self.blocks() {
@@ -1742,7 +1742,7 @@ impl fmt::Show for BitvSet {
17421742
}
17431743
}
17441744

1745-
impl<S: hash::Writer> hash::Hash<S> for BitvSet {
1745+
impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for BitvSet {
17461746
fn hash(&self, state: &mut S) {
17471747
for pos in self.iter() {
17481748
pos.hash(state);

src/libcollections/btree/map.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use core::borrow::BorrowFrom;
2323
use core::cmp::Ordering;
2424
use core::default::Default;
2525
use core::fmt::Show;
26-
use core::hash::{Writer, Hash};
26+
use core::hash::{Hash, Hasher};
27+
#[cfg(stage0)]
28+
use core::hash::Writer;
2729
use core::iter::{Map, FromIterator};
2830
use core::ops::{Index, IndexMut};
2931
use core::{iter, fmt, mem};
@@ -820,13 +822,23 @@ impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
820822
}
821823

822824
#[stable]
825+
#[cfg(stage0)]
823826
impl<S: Writer, K: Hash<S>, V: Hash<S>> Hash<S> for BTreeMap<K, V> {
824827
fn hash(&self, state: &mut S) {
825828
for elt in self.iter() {
826829
elt.hash(state);
827830
}
828831
}
829832
}
833+
#[stable]
834+
#[cfg(not(stage0))]
835+
impl<S: Hasher, K: Hash<S>, V: Hash<S>> Hash<S> for BTreeMap<K, V> {
836+
fn hash(&self, state: &mut S) {
837+
for elt in self.iter() {
838+
elt.hash(state);
839+
}
840+
}
841+
}
830842

831843
#[stable]
832844
impl<K: Ord, V> Default for BTreeMap<K, V> {

src/libcollections/btree/set.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ mod test {
678678
use prelude::*;
679679

680680
use super::BTreeSet;
681-
use std::hash;
681+
use std::hash::{self, SipHasher};
682682

683683
#[test]
684684
fn test_clone_eq() {
@@ -703,7 +703,7 @@ mod test {
703703
y.insert(2);
704704
y.insert(1);
705705

706-
assert!(hash::hash(&x) == hash::hash(&y));
706+
assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y));
707707
}
708708

709709
struct Counter<'a, 'b> {

src/libcollections/dlist.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use alloc::boxed::Box;
2727
use core::cmp::Ordering;
2828
use core::default::Default;
2929
use core::fmt;
30-
use core::hash::{Writer, Hash};
30+
use core::hash::{Writer, Hasher, Hash};
3131
use core::iter::{self, FromIterator};
3232
use core::mem;
3333
use core::ptr;
@@ -675,7 +675,7 @@ impl<A: fmt::Show> fmt::Show for DList<A> {
675675
}
676676

677677
#[stable]
678-
impl<S: Writer, A: Hash<S>> Hash<S> for DList<A> {
678+
impl<S: Writer + Hasher, A: Hash<S>> Hash<S> for DList<A> {
679679
fn hash(&self, state: &mut S) {
680680
self.len().hash(state);
681681
for elt in self.iter() {
@@ -688,7 +688,7 @@ impl<S: Writer, A: Hash<S>> Hash<S> for DList<A> {
688688
mod tests {
689689
use prelude::*;
690690
use std::rand;
691-
use std::hash;
691+
use std::hash::{self, SipHasher};
692692
use std::thread::Thread;
693693
use test::Bencher;
694694
use test;
@@ -951,7 +951,7 @@ mod tests {
951951
let mut x = DList::new();
952952
let mut y = DList::new();
953953

954-
assert!(hash::hash(&x) == hash::hash(&y));
954+
assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y));
955955

956956
x.push_back(1i);
957957
x.push_back(2);
@@ -961,7 +961,7 @@ mod tests {
961961
y.push_front(2);
962962
y.push_front(1);
963963

964-
assert!(hash::hash(&x) == hash::hash(&y));
964+
assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y));
965965
}
966966

967967
#[test]

src/libcollections/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323

2424
#![allow(unknown_features)]
2525
#![feature(unsafe_destructor, slicing_syntax)]
26-
#![feature(old_impl_check)]
2726
#![feature(unboxed_closures)]
27+
#![feature(old_impl_check)]
2828
#![no_std]
2929

3030
#[macro_use]

src/libcollections/ring_buf.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use core::ops::{Index, IndexMut};
2727
use core::ptr;
2828
use core::raw::Slice as RawSlice;
2929

30-
use std::hash::{Writer, Hash};
30+
use std::hash::{Writer, Hash, Hasher};
3131
use std::cmp;
3232

3333
use alloc::heap;
@@ -1562,7 +1562,7 @@ impl<A: Ord> Ord for RingBuf<A> {
15621562
}
15631563

15641564
#[stable]
1565-
impl<S: Writer, A: Hash<S>> Hash<S> for RingBuf<A> {
1565+
impl<S: Writer + Hasher, A: Hash<S>> Hash<S> for RingBuf<A> {
15661566
fn hash(&self, state: &mut S) {
15671567
self.len().hash(state);
15681568
for elt in self.iter() {
@@ -1631,7 +1631,7 @@ mod tests {
16311631
use prelude::*;
16321632
use core::iter;
16331633
use std::fmt::Show;
1634-
use std::hash;
1634+
use std::hash::{self, SipHasher};
16351635
use test::Bencher;
16361636
use test;
16371637

@@ -2283,7 +2283,7 @@ mod tests {
22832283
y.push_back(2);
22842284
y.push_back(3);
22852285

2286-
assert!(hash::hash(&x) == hash::hash(&y));
2286+
assert!(hash::hash::<_, SipHasher>(&x) == hash::hash::<_, SipHasher>(&y));
22872287
}
22882288

22892289
#[test]

src/libcollections/string.rs

+9
Original file line numberDiff line numberDiff line change
@@ -820,12 +820,21 @@ impl fmt::Show for String {
820820
}
821821

822822
#[experimental = "waiting on Hash stabilization"]
823+
#[cfg(stage0)]
823824
impl<H: hash::Writer> hash::Hash<H> for String {
824825
#[inline]
825826
fn hash(&self, hasher: &mut H) {
826827
(**self).hash(hasher)
827828
}
828829
}
830+
#[experimental = "waiting on Hash stabilization"]
831+
#[cfg(not(stage0))]
832+
impl<H: hash::Writer + hash::Hasher> hash::Hash<H> for String {
833+
#[inline]
834+
fn hash(&self, hasher: &mut H) {
835+
(**self).hash(hasher)
836+
}
837+
}
829838

830839
#[unstable = "recent addition, needs more experience"]
831840
impl<'a> Add<&'a str> for String {

src/libcollections/vec.rs

+8
Original file line numberDiff line numberDiff line change
@@ -1183,12 +1183,20 @@ impl<T:Clone> Clone for Vec<T> {
11831183
}
11841184
}
11851185

1186+
#[cfg(stage0)]
11861187
impl<S: hash::Writer, T: Hash<S>> Hash<S> for Vec<T> {
11871188
#[inline]
11881189
fn hash(&self, state: &mut S) {
11891190
self.as_slice().hash(state);
11901191
}
11911192
}
1193+
#[cfg(not(stage0))]
1194+
impl<S: hash::Writer + hash::Hasher, T: Hash<S>> Hash<S> for Vec<T> {
1195+
#[inline]
1196+
fn hash(&self, state: &mut S) {
1197+
self.as_slice().hash(state);
1198+
}
1199+
}
11921200

11931201
#[experimental = "waiting on Index stability"]
11941202
impl<T> Index<uint> for Vec<T> {

src/libcollections/vec_map.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use core::prelude::*;
1818
use core::cmp::Ordering;
1919
use core::default::Default;
2020
use core::fmt;
21-
use core::hash::{Hash, Writer};
21+
use core::hash::{Hash, Writer, Hasher};
2222
use core::iter::{Enumerate, FilterMap, Map, FromIterator};
2323
use core::iter;
2424
use core::mem::replace;
@@ -85,7 +85,7 @@ impl<V:Clone> Clone for VecMap<V> {
8585
}
8686
}
8787

88-
impl<S: Writer, V: Hash<S>> Hash<S> for VecMap<V> {
88+
impl<S: Writer + Hasher, V: Hash<S>> Hash<S> for VecMap<V> {
8989
fn hash(&self, state: &mut S) {
9090
// In order to not traverse the `VecMap` twice, count the elements
9191
// during iteration.
@@ -712,7 +712,7 @@ impl<V> DoubleEndedIterator for IntoIter<V> {
712712
#[cfg(test)]
713713
mod test_map {
714714
use prelude::*;
715-
use core::hash::hash;
715+
use core::hash::{hash, SipHasher};
716716

717717
use super::VecMap;
718718

@@ -1004,7 +1004,7 @@ mod test_map {
10041004
let mut x = VecMap::new();
10051005
let mut y = VecMap::new();
10061006

1007-
assert!(hash(&x) == hash(&y));
1007+
assert!(hash::<_, SipHasher>(&x) == hash::<_, SipHasher>(&y));
10081008
x.insert(1, 'a');
10091009
x.insert(2, 'b');
10101010
x.insert(3, 'c');
@@ -1013,12 +1013,12 @@ mod test_map {
10131013
y.insert(2, 'b');
10141014
y.insert(1, 'a');
10151015

1016-
assert!(hash(&x) == hash(&y));
1016+
assert!(hash::<_, SipHasher>(&x) == hash::<_, SipHasher>(&y));
10171017

10181018
x.insert(1000, 'd');
10191019
x.remove(&1000);
10201020

1021-
assert!(hash(&x) == hash(&y));
1021+
assert!(hash::<_, SipHasher>(&x) == hash::<_, SipHasher>(&y));
10221022
}
10231023

10241024
#[test]

0 commit comments

Comments
 (0)