Skip to content

Commit

Permalink
auto merge of #18440 : japaric/rust/hash, r=alexcrichton
Browse files Browse the repository at this point in the history
- The signature of the `*_equiv` methods of `HashMap` and similar structures have changed, and now require one less level of indirection. Change your code from:

``` rust
hashmap.find_equiv(&"Hello");
hashmap.find_equiv(&&[0u8, 1, 2]);
```

to:

``` rust
hashmap.find_equiv("Hello");
hashmap.find_equiv(&[0u8, 1, 2]);
```

- The generic parameter `T` of the `Hasher::hash<T>` method have become `Sized?`. Downstream code must add `Sized?` to that method in their implementations. For example:

``` rust
impl Hasher<FnvState> for FnvHasher {
    fn hash<T: Hash<FnvState>>(&self, t: &T) -> u64 { /* .. */ }
}
```

must be changed to:

``` rust
impl Hasher<FnvState> for FnvHasher {
    fn hash<Sized? T: Hash<FnvState>>(&self, t: &T) -> u64 { /* .. */ }
    //      ^^^^^^
}
```

[breaking-change]

---

After review I'll squash the commits and update the commit message with the above paragraph.

r? @aturon 
cc #16918
  • Loading branch information
bors committed Oct 31, 2014
2 parents 7e66231 + 1384a43 commit 5e83424
Show file tree
Hide file tree
Showing 26 changed files with 83 additions and 74 deletions.
37 changes: 21 additions & 16 deletions src/libcollections/hash/mod.rs
Expand Up @@ -80,7 +80,7 @@ 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> {
pub trait Hash<S = sip::SipState> for Sized? {
/// Computes the hash of a value.
fn hash(&self, state: &mut S);
}
Expand All @@ -89,7 +89,7 @@ pub trait Hash<S = sip::SipState> {
/// containers like `HashMap`, which need a generic way hash multiple types.
pub trait Hasher<S> {
/// Compute the hash of a value.
fn hash<T: Hash<S>>(&self, value: &T) -> u64;
fn hash<Sized? T: Hash<S>>(&self, value: &T) -> u64;
}

pub trait Writer {
Expand Down Expand Up @@ -137,7 +137,7 @@ impl<S: Writer> Hash<S> for char {
}
}

impl<'a, S: Writer> Hash<S> for &'a str {
impl<S: Writer> Hash<S> for str {
#[inline]
fn hash(&self, state: &mut S) {
state.write(self.as_bytes());
Expand Down Expand Up @@ -186,7 +186,7 @@ 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<'a, S: Writer, T: Hash<S>> Hash<S> for &'a [T] {
impl<S: Writer, T: Hash<S>> Hash<S> for [T] {
#[inline]
fn hash(&self, state: &mut S) {
self.len().hash(state);
Expand All @@ -197,41 +197,35 @@ impl<'a, S: Writer, T: Hash<S>> Hash<S> for &'a [T] {
}


impl<'a, S: Writer, T: Hash<S>> Hash<S> for &'a mut [T] {
#[inline]
fn hash(&self, state: &mut S) {
self.as_slice().hash(state);
}
}

impl<S: Writer, T: Hash<S>> Hash<S> for Vec<T> {
#[inline]
fn hash(&self, state: &mut S) {
self.as_slice().hash(state);
}
}

impl<'a, S: Writer, T: Hash<S>> Hash<S> for &'a T {
impl<'a, S: Writer, Sized? T: Hash<S>> Hash<S> for &'a T {
#[inline]
fn hash(&self, state: &mut S) {
(**self).hash(state);
}
}

impl<'a, S: Writer, T: Hash<S>> Hash<S> for &'a mut T {
impl<'a, S: Writer, Sized? T: Hash<S>> Hash<S> for &'a mut T {
#[inline]
fn hash(&self, state: &mut S) {
(**self).hash(state);
}
}

impl<S: Writer, T: Hash<S>> Hash<S> for Box<T> {
impl<S: Writer, Sized? T: Hash<S>> Hash<S> for Box<T> {
#[inline]
fn hash(&self, state: &mut S) {
(**self).hash(state);
}
}

// FIXME (#18248) Make `T` `Sized?`
impl<S: Writer, T: Hash<S>> Hash<S> for Rc<T> {
#[inline]
fn hash(&self, state: &mut S) {
Expand Down Expand Up @@ -293,6 +287,7 @@ impl<S: Writer, T: Hash<S>, U: Hash<S>> Hash<S> for Result<T, U> {

#[cfg(test)]
mod tests {
use core::kinds::Sized;
use std::mem;

use slice::ImmutableSlice;
Expand All @@ -301,7 +296,7 @@ mod tests {
struct MyWriterHasher;

impl Hasher<MyWriter> for MyWriterHasher {
fn hash<T: Hash<MyWriter>>(&self, value: &T) -> u64 {
fn hash<Sized? T: Hash<MyWriter>>(&self, value: &T) -> u64 {
let mut state = MyWriter { hash: 0 };
value.hash(&mut state);
state.hash
Expand All @@ -323,6 +318,8 @@ mod tests {

#[test]
fn test_writer_hasher() {
use alloc::boxed::Box;

let hasher = MyWriterHasher;

assert_eq!(hasher.hash(&()), 0);
Expand All @@ -344,9 +341,17 @@ mod tests {

assert_eq!(hasher.hash(&'a'), 97);

assert_eq!(hasher.hash(&("a")), 97 + 0xFF);
let s: &str = "a";
assert_eq!(hasher.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);
let cs: Box<[u8]> = box [1u8, 2u8, 3u8];
assert_eq!(hasher.hash(& cs), 9);

// FIXME (#18248) Add tests for hashing Rc<str> and Rc<[T]>

unsafe {
let ptr: *const int = mem::transmute(5i);
Expand Down
2 changes: 1 addition & 1 deletion src/libcollections/hash/sip.rs
Expand Up @@ -235,7 +235,7 @@ impl SipHasher {

impl Hasher<SipState> for SipHasher {
#[inline]
fn hash<T: Hash<SipState>>(&self, value: &T) -> u64 {
fn hash<Sized? T: Hash<SipState>>(&self, value: &T) -> u64 {
let mut state = SipState::new_with_keys(self.k0, self.k1);
value.hash(&mut state);
state.result()
Expand Down
3 changes: 2 additions & 1 deletion src/libcore/cmp.rs
Expand Up @@ -39,6 +39,7 @@

#![stable]

use kinds::Sized;
use option::{Option, Some, None};

/// Trait for values that can be compared for equality and inequality.
Expand Down Expand Up @@ -236,7 +237,7 @@ pub trait PartialOrd: PartialEq {
/// container types; e.g. it is often desirable to be able to use `&str`
/// values to look up entries in a container with `String` keys.
#[experimental = "Better solutions may be discovered."]
pub trait Equiv<T> {
pub trait Equiv<T> for Sized? {
/// Implement this function to decide equivalent values.
fn equiv(&self, other: &T) -> bool;
}
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/slice.rs
Expand Up @@ -1565,7 +1565,7 @@ impl<'a,T:PartialEq> PartialEq for &'a [T] {
impl<'a,T:Eq> Eq for &'a [T] {}

#[unstable = "waiting for DST"]
impl<'a,T:PartialEq, V: AsSlice<T>> Equiv<V> for &'a [T] {
impl<T: PartialEq, V: AsSlice<T>> Equiv<V> for [T] {
#[inline]
fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
}
Expand Down
4 changes: 2 additions & 2 deletions src/libcore/str.rs
Expand Up @@ -1160,9 +1160,9 @@ pub mod traits {
}
}

impl<'a, S: Str> Equiv<S> for &'a str {
impl<S: Str> Equiv<S> for str {
#[inline]
fn equiv(&self, other: &S) -> bool { eq_slice(*self, other.as_slice()) }
fn equiv(&self, other: &S) -> bool { eq_slice(self, other.as_slice()) }
}

impl ops::Slice<uint, str> for str {
Expand Down
2 changes: 1 addition & 1 deletion src/libregex/re.rs
Expand Up @@ -724,7 +724,7 @@ impl<'t> Captures<'t> {
match self.named {
None => "",
Some(ref h) => {
match h.find_equiv(&name) {
match h.find_equiv(name) {
None => "",
Some(i) => self.at(*i),
}
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/lint/context.rs
Expand Up @@ -164,7 +164,7 @@ impl LintStore {
}

fn register_renamed(&mut self, old_name: &str, new_name: &str) {
let target = match self.by_name.find_equiv(&new_name) {
let target = match self.by_name.find_equiv(new_name) {
Some(&Id(lint_id)) => lint_id.clone(),
_ => panic!("invalid lint renaming of {} to {}", old_name, new_name)
};
Expand Down Expand Up @@ -258,7 +258,7 @@ impl LintStore {
fn find_lint(&self, lint_name: &str, sess: &Session, span: Option<Span>)
-> Option<LintId>
{
match self.by_name.find_equiv(&lint_name) {
match self.by_name.find_equiv(lint_name) {
Some(&Id(lint_id)) => Some(lint_id),
Some(&Renamed(ref new_name, lint_id)) => {
let warning = format!("lint {} has been renamed to {}",
Expand All @@ -280,7 +280,7 @@ impl LintStore {
None => {
match self.lint_groups.iter().map(|(&x, pair)| (x, pair.ref0().clone()))
.collect::<HashMap<&'static str, Vec<LintId>>>()
.find_equiv(&lint_name.as_slice()) {
.find_equiv(lint_name.as_slice()) {
Some(v) => {
v.iter()
.map(|lint_id: &LintId|
Expand Down Expand Up @@ -487,7 +487,7 @@ impl<'a, 'tcx> Context<'a, 'tcx> {
match self.lints.find_lint(lint_name.get(), &self.tcx.sess, Some(span)) {
Some(lint_id) => vec![(lint_id, level, span)],
None => {
match self.lints.lint_groups.find_equiv(&lint_name.get()) {
match self.lints.lint_groups.find_equiv(lint_name.get()) {
Some(&(ref v, _)) => v.iter()
.map(|lint_id: &LintId|
(*lint_id, level, span))
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/metadata/creader.rs
Expand Up @@ -303,7 +303,7 @@ fn existing_match(e: &Env, name: &str,
// `source` stores paths which are normalized which may be different
// from the strings on the command line.
let source = e.sess.cstore.get_used_crate_source(cnum).unwrap();
match e.sess.opts.externs.find_equiv(&name) {
match e.sess.opts.externs.find_equiv(name) {
Some(locs) => {
let found = locs.iter().any(|l| {
let l = fs::realpath(&Path::new(l.as_slice())).ok();
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/metadata/decoder.rs
Expand Up @@ -295,7 +295,7 @@ fn item_path(item_doc: rbml::Doc) -> Vec<ast_map::PathElem> {
fn item_name(intr: &IdentInterner, item: rbml::Doc) -> ast::Name {
let name = reader::get_doc(item, tag_paths_data_name);
let string = name.as_str_slice();
match intr.find_equiv(&string) {
match intr.find_equiv(string) {
None => token::intern(string),
Some(val) => val,
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/metadata/filesearch.rs
Expand Up @@ -52,7 +52,7 @@ impl<'a> FileSearch<'a> {
debug!("filesearch: searching lib path");
let tlib_path = make_target_lib_path(self.sysroot,
self.triple);
if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
if !visited_dirs.contains_equiv(tlib_path.as_vec()) {
match f(&tlib_path) {
FileMatches => found = true,
FileDoesntMatch => ()
Expand All @@ -69,7 +69,7 @@ impl<'a> FileSearch<'a> {
debug!("is {} in visited_dirs? {}", tlib_path.display(),
visited_dirs.contains_equiv(&tlib_path.as_vec().to_vec()));

if !visited_dirs.contains_equiv(&tlib_path.as_vec()) {
if !visited_dirs.contains_equiv(tlib_path.as_vec()) {
visited_dirs.insert(tlib_path.as_vec().to_vec());
// Don't keep searching the RUST_PATH if one match turns up --
// if we did, we'd get a "multiple matching crates" error
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/metadata/loader.rs
Expand Up @@ -631,7 +631,7 @@ impl<'a> Context<'a> {
}

fn find_commandline_library(&mut self) -> Option<Library> {
let locs = match self.sess.opts.externs.find_equiv(&self.crate_name) {
let locs = match self.sess.opts.externs.find_equiv(self.crate_name) {
Some(s) => s,
None => return None,
};
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/trans/base.rs
Expand Up @@ -224,7 +224,7 @@ pub fn get_extern_fn(ccx: &CrateContext,
ty: Type,
output: ty::t)
-> ValueRef {
match externs.find_equiv(&name) {
match externs.find_equiv(name) {
Some(n) => return *n,
None => {}
}
Expand All @@ -234,7 +234,7 @@ pub fn get_extern_fn(ccx: &CrateContext,
}

fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::DefId) -> ValueRef {
match ccx.externs().borrow().find_equiv(&name) {
match ccx.externs().borrow().find_equiv(name) {
Some(n) => return *n,
None => ()
}
Expand Down Expand Up @@ -3006,7 +3006,7 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<String>) {

let name = CString::new(llvm::LLVMGetValueName(val), false);
if !declared.contains(&name) &&
!reachable.contains_equiv(&name.as_str().unwrap()) {
!reachable.contains_equiv(name.as_str().unwrap()) {
llvm::SetLinkage(val, llvm::InternalLinkage);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/debuginfo.rs
Expand Up @@ -1670,7 +1670,7 @@ fn declare_local(bcx: Block,
}

fn file_metadata(cx: &CrateContext, full_path: &str) -> DIFile {
match debug_context(cx).created_files.borrow().find_equiv(&full_path) {
match debug_context(cx).created_files.borrow().find_equiv(full_path) {
Some(file_metadata) => return *file_metadata,
None => ()
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/type_.rs
Expand Up @@ -333,7 +333,7 @@ impl TypeNames {
}

pub fn find_type(&self, s: &str) -> Option<Type> {
self.named_types.borrow().find_equiv(&s).map(|x| Type::from_ref(*x))
self.named_types.borrow().find_equiv(s).map(|x| Type::from_ref(*x))
}

pub fn type_to_string(&self, ty: Type) -> String {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/util/nodemap.rs
Expand Up @@ -74,7 +74,7 @@ pub struct FnvHasher;
pub struct FnvState(u64);

impl Hasher<FnvState> for FnvHasher {
fn hash<T: Hash<FnvState>>(&self, t: &T) -> u64 {
fn hash<Sized? T: Hash<FnvState>>(&self, t: &T) -> u64 {
let mut state = FnvState(0xcbf29ce484222325);
t.hash(&mut state);
let FnvState(ret) = state;
Expand Down
2 changes: 1 addition & 1 deletion src/librustdoc/html/render.rs
Expand Up @@ -2123,7 +2123,7 @@ impl<'a> fmt::Show for Sidebar<'a> {

fn block(w: &mut fmt::Formatter, short: &str, longty: &str,
cur: &clean::Item, cx: &Context) -> fmt::Result {
let items = match cx.sidebar.find_equiv(&short) {
let items = match cx.sidebar.find_equiv(short) {
Some(items) => items.as_slice(),
None => return Ok(())
};
Expand Down
21 changes: 11 additions & 10 deletions src/libstd/collections/hashmap/map.rs
Expand Up @@ -17,6 +17,7 @@ use default::Default;
use fmt::{mod, Show};
use hash::{Hash, Hasher, RandomSipHasher};
use iter::{mod, Iterator, FromIterator, Extendable};
use kinds::Sized;
use mem::{mod, replace};
use num;
use ops::{Deref, Index, IndexMut};
Expand Down Expand Up @@ -419,17 +420,17 @@ impl<K, V, M> SearchResult<K, V, M> {
}

impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
fn make_hash<X: Hash<S>>(&self, x: &X) -> SafeHash {
fn make_hash<Sized? X: Hash<S>>(&self, x: &X) -> SafeHash {
table::make_hash(&self.hasher, x)
}

fn search_equiv<'a, Q: Hash<S> + Equiv<K>>(&'a self, q: &Q)
fn search_equiv<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a self, q: &Q)
-> Option<FullBucketImm<'a, K, V>> {
let hash = self.make_hash(q);
search_hashed_generic(&self.table, &hash, |k| q.equiv(k)).into_option()
}

fn search_equiv_mut<'a, Q: Hash<S> + Equiv<K>>(&'a mut self, q: &Q)
fn search_equiv_mut<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a mut self, q: &Q)
-> Option<FullBucketMut<'a, K, V>> {
let hash = self.make_hash(q);
search_hashed_generic(&mut self.table, &hash, |k| q.equiv(k)).into_option()
Expand Down Expand Up @@ -857,15 +858,15 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
/// using equivalence.
///
/// See [pop_equiv](#method.pop_equiv) for an extended example.
pub fn contains_key_equiv<Q: Hash<S> + Equiv<K>>(&self, key: &Q) -> bool {
pub fn contains_key_equiv<Sized? Q: Hash<S> + Equiv<K>>(&self, key: &Q) -> bool {
self.search_equiv(key).is_some()
}

/// Return the value corresponding to the key in the map, using
/// equivalence.
///
/// See [pop_equiv](#method.pop_equiv) for an extended example.
pub fn find_equiv<'a, Q: Hash<S> + Equiv<K>>(&'a self, k: &Q) -> Option<&'a V> {
pub fn find_equiv<'a, Sized? Q: Hash<S> + Equiv<K>>(&'a self, k: &Q) -> Option<&'a V> {
match self.search_equiv(k) {
None => None,
Some(bucket) => {
Expand Down Expand Up @@ -921,7 +922,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
///
/// ```
#[experimental]
pub fn pop_equiv<Q:Hash<S> + Equiv<K>>(&mut self, k: &Q) -> Option<V> {
pub fn pop_equiv<Sized? Q:Hash<S> + Equiv<K>>(&mut self, k: &Q) -> Option<V> {
if self.table.size() == 0 {
return None
}
Expand Down Expand Up @@ -1879,11 +1880,11 @@ mod test_map {
m.insert("baz".to_string(), baz);


assert_eq!(m.find_equiv(&("foo")), Some(&foo));
assert_eq!(m.find_equiv(&("bar")), Some(&bar));
assert_eq!(m.find_equiv(&("baz")), Some(&baz));
assert_eq!(m.find_equiv("foo"), Some(&foo));
assert_eq!(m.find_equiv("bar"), Some(&bar));
assert_eq!(m.find_equiv("baz"), Some(&baz));

assert_eq!(m.find_equiv(&("qux")), None);
assert_eq!(m.find_equiv("qux"), None);
}

#[test]
Expand Down

0 comments on commit 5e83424

Please sign in to comment.