From e6350e0e36e900517df8cfa22165def4a31d20bd Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Feb 2018 06:28:42 +0100 Subject: [PATCH 1/4] HashMap, HashSet: impl Hash --- src/libstd/collections/hash/map.rs | 31 ++++++++++++++++++++++++++++++ src/libstd/collections/hash/set.rs | 10 ++++++++++ 2 files changed, 41 insertions(+) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index a82ff915093c6..97300624130e7 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1370,6 +1370,37 @@ impl Eq for HashMap { } +#[unstable(feature = "hashmap_hash", issue = "0")] +impl Hash for HashMap + where K: Eq + Hash, + V: Hash, + S: BuildHasher +{ + fn hash(&self, hasher: &mut H) { + // We must preserve: x == y -> hash(x) == hash(y). + // HashMaps have no order, so we must use a commutative operation + // (.wrapping_add) so that the order does not matter. + // + // For this to hold, we must also ensure that the hashing of + // individual elements does not depend on the state of the given Hasher. + // So we ensure that hashing each individual element starts with the + // same state. + // + // Unfortunately, we can't .clone() the hasher since we can't add more + // constraints than H being a Hasher. With some sort of ConstraintKinds + // we might be able do so in the future. + hasher.write_u64( + self.iter() + .map(|(k, v)| { + let mut h = DefaultHasher::new(); + (k, v).hash(&mut h); + h.finish() + }) + .fold(0, u64::wrapping_add) + ); + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Debug for HashMap where K: Eq + Hash + Debug, diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index e9427fb40a016..562abe1d92bd2 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -757,6 +757,16 @@ impl Eq for HashSet { } +#[unstable(feature = "hashmap_hash", issue = "0")] +impl Hash for HashSet + where T: Eq + Hash, + S: BuildHasher +{ + fn hash(&self, hasher: &mut H) { + self.map.hash(hasher); + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for HashSet where T: Eq + Hash + fmt::Debug, From 8c200ad6166867e207adeb751d91b99423acc812 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Feb 2018 06:54:05 +0100 Subject: [PATCH 2/4] HashMap, HashSet: impl Hash - fix import --- src/libstd/collections/hash/set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 562abe1d92bd2..cdbf4e2ec21c1 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -10,7 +10,7 @@ use borrow::Borrow; use fmt; -use hash::{Hash, BuildHasher}; +use hash::{Hash, Hasher, BuildHasher}; use iter::{Chain, FromIterator, FusedIterator}; use ops::{BitOr, BitAnd, BitXor, Sub}; From 6f92790264b9e2a43e88fc0004569540fe39d4f0 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Feb 2018 09:14:16 +0100 Subject: [PATCH 3/4] HashMap, HashSet: impl Hash - don't destructure/restructure kv-pair --- src/libstd/collections/hash/map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 97300624130e7..fd6a55decae07 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1391,9 +1391,9 @@ impl Hash for HashMap // we might be able do so in the future. hasher.write_u64( self.iter() - .map(|(k, v)| { + .map(|kv| { let mut h = DefaultHasher::new(); - (k, v).hash(&mut h); + kv.hash(&mut h); h.finish() }) .fold(0, u64::wrapping_add) From e4dcd822395d54111f052a38120aecd4667cc0e6 Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Tue, 20 Feb 2018 12:29:50 +0100 Subject: [PATCH 4/4] HashMap, HashSet: impl Hash - note on commutative monoid --- src/libstd/collections/hash/map.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index fd6a55decae07..bc664fb7e5cc8 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1378,13 +1378,14 @@ impl Hash for HashMap { fn hash(&self, hasher: &mut H) { // We must preserve: x == y -> hash(x) == hash(y). - // HashMaps have no order, so we must use a commutative operation - // (.wrapping_add) so that the order does not matter. + // HashMaps have no order, so we must combine the elements with an + // associative and commutative operation • so that the order does not + // matter. In other words, (u64, •, 0) must form a commutative monoid. + // This is satisfied by • = u64::wrapping_add. // - // For this to hold, we must also ensure that the hashing of - // individual elements does not depend on the state of the given Hasher. - // So we ensure that hashing each individual element starts with the - // same state. + // We must further ensure that the hashing of individual elements does + // not depend on the state of the given Hasher. So we ensure that + // hashing each individual element starts with the same state. // // Unfortunately, we can't .clone() the hasher since we can't add more // constraints than H being a Hasher. With some sort of ConstraintKinds