diff options
| author | bors <bors@rust-lang.org> | 2021-06-25 06:47:30 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2021-06-25 06:47:30 +0000 |
| commit | 50e0cc59ffcacda5b48f4edb95e5a5c353624fb0 (patch) | |
| tree | e439eaa42d3072e2b5882ca004fb696aa8742583 | |
| parent | 50a908121620edbef02d124e8d7d94943c50d4a1 (diff) | |
| parent | 579d19bc6ac91548e8b256656ca1d7fbceb53197 (diff) | |
| download | rust-50e0cc59ffcacda5b48f4edb95e5a5c353624fb0.tar.gz rust-50e0cc59ffcacda5b48f4edb95e5a5c353624fb0.zip | |
Auto merge of #86151 - scottmcm:simple-hash-of, r=joshtriplett
Add `BuildHasher::hash_one` as unstable Inspired by https://github.com/rust-lang/rust/pull/86140/files#diff-246941135168fbc44fce120385ee9c3156e08a1c3e2697985b56dcb8d728eedeR2416, where I wanted to write a quick test for a `Hash` implementation and it took more of a dance than I'd hoped. It looks like this would be handy in hashtable implementations, too -- a quick look at hashbrown found two places where it needs to do the same dance: https://github.com/rust-lang/hashbrown/blob/6302512a8a514fe5bd442464ebcd78139c82e1e2/src/map.rs#L247-L270 I wanted to get a "seems plausible" from a libs member before making a tracking issue, so random-sampling the intersection of highfive and governance gave me... r? `@joshtriplett` (As always, bikeshed away! And let me know if I missed something obvious again that I should have used instead.)
| -rw-r--r-- | library/alloc/src/vec/mod.rs | 11 | ||||
| -rw-r--r-- | library/core/src/array/mod.rs | 11 | ||||
| -rw-r--r-- | library/core/src/hash/mod.rs | 44 |
3 files changed, 50 insertions, 16 deletions
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index f3a47cba759..4ac28b8308e 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2411,18 +2411,13 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> { /// as required by the `core::borrow::Borrow` implementation. /// /// ``` -/// use std::hash::{BuildHasher, Hash, Hasher}; -/// -/// fn hash_of(x: impl Hash, b: &impl BuildHasher) -> u64 { -/// let mut h = b.build_hasher(); -/// x.hash(&mut h); -/// h.finish() -/// } +/// #![feature(build_hasher_simple_hash_one)] +/// use std::hash::BuildHasher; /// /// let b = std::collections::hash_map::RandomState::new(); /// let v: Vec<u8> = vec![0xa8, 0x3c, 0x09]; /// let s: &[u8] = &[0xa8, 0x3c, 0x09]; -/// assert_eq!(hash_of(v, &b), hash_of(s, &b)); +/// assert_eq!(b.hash_one(v), b.hash_one(s)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] impl<T: Hash, A: Allocator> Hash for Vec<T, A> { diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index f44e22b3dbd..030b42a53d0 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -143,18 +143,13 @@ impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] { /// as required by the `Borrow` implementation. /// /// ``` -/// use std::hash::{BuildHasher, Hash, Hasher}; -/// -/// fn hash_of(x: impl Hash, b: &impl BuildHasher) -> u64 { -/// let mut h = b.build_hasher(); -/// x.hash(&mut h); -/// h.finish() -/// } +/// #![feature(build_hasher_simple_hash_one)] +/// use std::hash::BuildHasher; /// /// let b = std::collections::hash_map::RandomState::new(); /// let a: [u8; 3] = [0xa8, 0x3c, 0x09]; /// let s: &[u8] = &[0xa8, 0x3c, 0x09]; -/// assert_eq!(hash_of(a, &b), hash_of(s, &b)); +/// assert_eq!(b.hash_one(a), b.hash_one(s)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] impl<T: Hash, const N: usize> Hash for [T; N] { diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 77d3a35b268..9dbefe0822e 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -481,6 +481,50 @@ pub trait BuildHasher { /// ``` #[stable(since = "1.7.0", feature = "build_hasher")] fn build_hasher(&self) -> Self::Hasher; + + /// Calculates the hash of a single value. + /// + /// This is intended as a convenience for code which *consumes* hashes, such + /// as the implementation of a hash table or in unit tests that check + /// whether a custom [`Hash`] implementation behaves as expected. + /// + /// This must not be used in any code which *creates* hashes, such as in an + /// implementation of [`Hash`]. The way to create a combined hash of + /// multiple values is to call [`Hash::hash`] multiple times using the same + /// [`Hasher`], not to call this method repeatedly and combine the results. + /// + /// # Example + /// + /// ``` + /// #![feature(build_hasher_simple_hash_one)] + /// + /// use std::cmp::{max, min}; + /// use std::hash::{BuildHasher, Hash, Hasher}; + /// struct OrderAmbivalentPair<T: Ord>(T, T); + /// impl<T: Ord + Hash> Hash for OrderAmbivalentPair<T> { + /// fn hash<H: Hasher>(&self, hasher: &mut H) { + /// min(&self.0, &self.1).hash(hasher); + /// max(&self.0, &self.1).hash(hasher); + /// } + /// } + /// + /// // Then later, in a `#[test]` for the type... + /// let bh = std::collections::hash_map::RandomState::new(); + /// assert_eq!( + /// bh.hash_one(OrderAmbivalentPair(1, 2)), + /// bh.hash_one(OrderAmbivalentPair(2, 1)) + /// ); + /// assert_eq!( + /// bh.hash_one(OrderAmbivalentPair(10, 2)), + /// bh.hash_one(&OrderAmbivalentPair(2, 10)) + /// ); + /// ``` + #[unstable(feature = "build_hasher_simple_hash_one", issue = "86161")] + fn hash_one<T: Hash>(&self, x: T) -> u64 { + let mut hasher = self.build_hasher(); + x.hash(&mut hasher); + hasher.finish() + } } /// Used to create a default [`BuildHasher`] instance for types that implement |
