1
Fork 0

Auto merge of #115694 - clarfonthey:std-hash-private, r=dtolnay

Add `std:#️⃣:{DefaultHasher, RandomState}` exports (needs FCP)

This implements rust-lang/libs-team#267 to move the libstd hasher types to `std::hash` where they belong, instead of `std::collections::hash_map`.

<details><summary>The below no longer applies, but is kept for clarity.</summary>
This is a small refactor for #27242, which moves the definitions of `RandomState` and `DefaultHasher` into `std::hash`, but in a way that won't be noticed in the public API.

I've opened rust-lang/libs-team#267 as a formal ACP to move these directly into the root of `std::hash`, but for now, they're at least separated out from the collections code in a way that will make moving that around easier.

I decided to simply copy the rustdoc for `std::hash` from `core::hash` since I think it would be ideal for the two to diverge longer-term, especially if the ACP is accepted. However, I would be willing to factor them out into a common markdown document if that's preferred.
</details>
This commit is contained in:
bors 2023-11-11 21:12:20 +00:00
commit 2c1b65ee14
27 changed files with 308 additions and 232 deletions

View file

@ -7,8 +7,7 @@ use rustc_hir::def_id::DefId;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_target::spec::abi; use rustc_target::spec::abi;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::hash_map::DefaultHasher; use std::hash::{DefaultHasher, Hash, Hasher};
use std::hash::{Hash, Hasher};
use std::path::PathBuf; use std::path::PathBuf;
#[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)] #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable)]

View file

@ -3178,9 +3178,8 @@ pub(crate) mod dep_tracking {
use rustc_target::spec::{ use rustc_target::spec::{
RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
}; };
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::hash::Hash; use std::hash::{DefaultHasher, Hash};
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use std::path::PathBuf; use std::path::PathBuf;

View file

@ -19,8 +19,7 @@ use rustc_span::SourceFileHashAlgorithm;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::hash_map::DefaultHasher; use std::hash::{DefaultHasher, Hasher};
use std::hash::Hasher;
use std::num::{IntErrorKind, NonZeroUsize}; use std::num::{IntErrorKind, NonZeroUsize};
use std::path::PathBuf; use std::path::PathBuf;
use std::str; use std::str;

View file

@ -3503,7 +3503,7 @@ impl TargetTriple {
/// If this target is a path, a hash of the path is appended to the triple returned /// If this target is a path, a hash of the path is appended to the triple returned
/// by `triple()`. /// by `triple()`.
pub fn debug_triple(&self) -> String { pub fn debug_triple(&self) -> String {
use std::collections::hash_map::DefaultHasher; use std::hash::DefaultHasher;
match self { match self {
TargetTriple::TargetTriple(triple) => triple.to_owned(), TargetTriple::TargetTriple(triple) => triple.to_owned(),

View file

@ -270,7 +270,7 @@ pub(crate) mod test_helpers {
/// seed not being the same for every RNG invocation too. /// seed not being the same for every RNG invocation too.
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
use std::hash::{BuildHasher, Hash, Hasher}; use std::hash::{BuildHasher, Hash, Hasher};
let mut hasher = std::collections::hash_map::RandomState::new().build_hasher(); let mut hasher = std::hash::RandomState::new().build_hasher();
std::panic::Location::caller().hash(&mut hasher); std::panic::Location::caller().hash(&mut hasher);
let hc64 = hasher.finish(); let hc64 = hasher.finish();
let seed_vec = let seed_vec =

View file

@ -2706,7 +2706,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for Vec<T, A> {
/// ``` /// ```
/// use std::hash::BuildHasher; /// use std::hash::BuildHasher;
/// ///
/// let b = std::collections::hash_map::RandomState::new(); /// let b = std::hash::RandomState::new();
/// let v: Vec<u8> = vec![0xa8, 0x3c, 0x09]; /// let v: Vec<u8> = vec![0xa8, 0x3c, 0x09];
/// let s: &[u8] = &[0xa8, 0x3c, 0x09]; /// let s: &[u8] = &[0xa8, 0x3c, 0x09];
/// assert_eq!(b.hash_one(v), b.hash_one(s)); /// assert_eq!(b.hash_one(v), b.hash_one(s));

View file

@ -43,8 +43,7 @@
#![deny(fuzzy_provenance_casts)] #![deny(fuzzy_provenance_casts)]
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
use std::collections::hash_map::DefaultHasher; use std::hash::{DefaultHasher, Hash, Hasher};
use std::hash::{Hash, Hasher};
mod arc; mod arc;
mod autotraits; mod autotraits;

View file

@ -297,7 +297,7 @@ impl<'a, T, const N: usize> TryFrom<&'a mut [T]> for &'a mut [T; N] {
/// ``` /// ```
/// use std::hash::BuildHasher; /// use std::hash::BuildHasher;
/// ///
/// let b = std::collections::hash_map::RandomState::new(); /// let b = std::hash::RandomState::new();
/// let a: [u8; 3] = [0xa8, 0x3c, 0x09]; /// let a: [u8; 3] = [0xa8, 0x3c, 0x09];
/// let s: &[u8] = &[0xa8, 0x3c, 0x09]; /// let s: &[u8] = &[0xa8, 0x3c, 0x09];
/// assert_eq!(b.hash_one(a), b.hash_one(s)); /// assert_eq!(b.hash_one(a), b.hash_one(s));

View file

@ -12,8 +12,7 @@
//! # Examples //! # Examples
//! //!
//! ```rust //! ```rust
//! use std::collections::hash_map::DefaultHasher; //! use std::hash::{DefaultHasher, Hash, Hasher};
//! use std::hash::{Hash, Hasher};
//! //!
//! #[derive(Hash)] //! #[derive(Hash)]
//! struct Person { //! struct Person {
@ -46,8 +45,7 @@
//! the [`Hash`] trait: //! the [`Hash`] trait:
//! //!
//! ```rust //! ```rust
//! use std::collections::hash_map::DefaultHasher; //! use std::hash::{DefaultHasher, Hash, Hasher};
//! use std::hash::{Hash, Hasher};
//! //!
//! struct Person { //! struct Person {
//! id: u32, //! id: u32,
@ -194,8 +192,7 @@ pub trait Hash {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::collections::hash_map::DefaultHasher; /// use std::hash::{DefaultHasher, Hash, Hasher};
/// use std::hash::{Hash, Hasher};
/// ///
/// let mut hasher = DefaultHasher::new(); /// let mut hasher = DefaultHasher::new();
/// 7920.hash(&mut hasher); /// 7920.hash(&mut hasher);
@ -224,8 +221,7 @@ pub trait Hash {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::collections::hash_map::DefaultHasher; /// use std::hash::{DefaultHasher, Hash, Hasher};
/// use std::hash::{Hash, Hasher};
/// ///
/// let mut hasher = DefaultHasher::new(); /// let mut hasher = DefaultHasher::new();
/// let numbers = [6, 28, 496, 8128]; /// let numbers = [6, 28, 496, 8128];
@ -300,8 +296,7 @@ pub use macros::Hash;
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::collections::hash_map::DefaultHasher; /// use std::hash::{DefaultHasher, Hasher};
/// use std::hash::Hasher;
/// ///
/// let mut hasher = DefaultHasher::new(); /// let mut hasher = DefaultHasher::new();
/// ///
@ -329,8 +324,7 @@ pub trait Hasher {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::collections::hash_map::DefaultHasher; /// use std::hash::{DefaultHasher, Hasher};
/// use std::hash::Hasher;
/// ///
/// let mut hasher = DefaultHasher::new(); /// let mut hasher = DefaultHasher::new();
/// hasher.write(b"Cool!"); /// hasher.write(b"Cool!");
@ -347,8 +341,7 @@ pub trait Hasher {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::collections::hash_map::DefaultHasher; /// use std::hash::{DefaultHasher, Hasher};
/// use std::hash::Hasher;
/// ///
/// let mut hasher = DefaultHasher::new(); /// let mut hasher = DefaultHasher::new();
/// let data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; /// let data = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];
@ -627,8 +620,7 @@ impl<H: Hasher + ?Sized> Hasher for &mut H {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::collections::hash_map::RandomState; /// use std::hash::{BuildHasher, Hasher, RandomState};
/// use std::hash::{BuildHasher, Hasher};
/// ///
/// let s = RandomState::new(); /// let s = RandomState::new();
/// let mut hasher_1 = s.build_hasher(); /// let mut hasher_1 = s.build_hasher();
@ -656,8 +648,7 @@ pub trait BuildHasher {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::collections::hash_map::RandomState; /// use std::hash::{BuildHasher, RandomState};
/// use std::hash::BuildHasher;
/// ///
/// let s = RandomState::new(); /// let s = RandomState::new();
/// let new_s = s.build_hasher(); /// let new_s = s.build_hasher();
@ -690,7 +681,7 @@ pub trait BuildHasher {
/// } /// }
/// ///
/// // Then later, in a `#[test]` for the type... /// // Then later, in a `#[test]` for the type...
/// let bh = std::collections::hash_map::RandomState::new(); /// let bh = std::hash::RandomState::new();
/// assert_eq!( /// assert_eq!(
/// bh.hash_one(OrderAmbivalentPair(1, 2)), /// bh.hash_one(OrderAmbivalentPair(1, 2)),
/// bh.hash_one(OrderAmbivalentPair(2, 1)) /// bh.hash_one(OrderAmbivalentPair(2, 1))

View file

@ -14,7 +14,7 @@ use crate::ptr;
/// ///
/// See: <https://131002.net/siphash> /// See: <https://131002.net/siphash>
#[unstable(feature = "hashmap_internals", issue = "none")] #[unstable(feature = "hashmap_internals", issue = "none")]
#[deprecated(since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
#[doc(hidden)] #[doc(hidden)]
pub struct SipHasher13 { pub struct SipHasher13 {
@ -25,7 +25,7 @@ pub struct SipHasher13 {
/// ///
/// See: <https://131002.net/siphash/> /// See: <https://131002.net/siphash/>
#[unstable(feature = "hashmap_internals", issue = "none")] #[unstable(feature = "hashmap_internals", issue = "none")]
#[deprecated(since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
struct SipHasher24 { struct SipHasher24 {
hasher: Hasher<Sip24Rounds>, hasher: Hasher<Sip24Rounds>,
@ -44,7 +44,7 @@ struct SipHasher24 {
/// it is not intended for cryptographic purposes. As such, all /// it is not intended for cryptographic purposes. As such, all
/// cryptographic uses of this implementation are _strongly discouraged_. /// cryptographic uses of this implementation are _strongly discouraged_.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[deprecated(since = "1.13.0", note = "use `std::collections::hash_map::DefaultHasher` instead")] #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct SipHasher(SipHasher24); pub struct SipHasher(SipHasher24);
@ -147,10 +147,7 @@ impl SipHasher {
/// Creates a new `SipHasher` with the two initial keys set to 0. /// Creates a new `SipHasher` with the two initial keys set to 0.
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[deprecated( #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
since = "1.13.0",
note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
#[must_use] #[must_use]
pub const fn new() -> SipHasher { pub const fn new() -> SipHasher {
@ -160,10 +157,7 @@ impl SipHasher {
/// Creates a `SipHasher` that is keyed off the provided keys. /// Creates a `SipHasher` that is keyed off the provided keys.
#[inline] #[inline]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[deprecated( #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
since = "1.13.0",
note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
#[must_use] #[must_use]
pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher { pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
@ -175,10 +169,7 @@ impl SipHasher13 {
/// Creates a new `SipHasher13` with the two initial keys set to 0. /// Creates a new `SipHasher13` with the two initial keys set to 0.
#[inline] #[inline]
#[unstable(feature = "hashmap_internals", issue = "none")] #[unstable(feature = "hashmap_internals", issue = "none")]
#[deprecated( #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
since = "1.13.0",
note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
pub const fn new() -> SipHasher13 { pub const fn new() -> SipHasher13 {
SipHasher13::new_with_keys(0, 0) SipHasher13::new_with_keys(0, 0)
@ -187,10 +178,7 @@ impl SipHasher13 {
/// Creates a `SipHasher13` that is keyed off the provided keys. /// Creates a `SipHasher13` that is keyed off the provided keys.
#[inline] #[inline]
#[unstable(feature = "hashmap_internals", issue = "none")] #[unstable(feature = "hashmap_internals", issue = "none")]
#[deprecated( #[deprecated(since = "1.13.0", note = "use `std::hash::DefaultHasher` instead")]
since = "1.13.0",
note = "use `std::collections::hash_map::DefaultHasher` instead"
)]
#[rustc_const_unstable(feature = "const_hash", issue = "104061")] #[rustc_const_unstable(feature = "const_hash", issue = "104061")]
pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 { pub const fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) } SipHasher13 { hasher: Hasher::new_with_keys(key0, key1) }

View file

@ -1921,8 +1921,7 @@ pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::collections::hash_map::DefaultHasher; /// use std::hash::{DefaultHasher, Hash, Hasher};
/// use std::hash::{Hash, Hasher};
/// use std::ptr; /// use std::ptr;
/// ///
/// let five = 5; /// let five = 5;

View file

@ -167,7 +167,7 @@ fn test_indirect_hasher() {
#[test] #[test]
fn test_build_hasher_object_safe() { fn test_build_hasher_object_safe() {
use std::collections::hash_map::{DefaultHasher, RandomState}; use std::hash::{DefaultHasher, RandomState};
let _: &dyn BuildHasher<Hasher = DefaultHasher> = &RandomState::new(); let _: &dyn BuildHasher<Hasher = DefaultHasher> = &RandomState::new();
} }

View file

@ -169,7 +169,7 @@ mod waker;
#[allow(dead_code)] // Not used in all configurations. #[allow(dead_code)] // Not used in all configurations.
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
use core::hash::{BuildHasher, Hash, Hasher}; use core::hash::{BuildHasher, Hash, Hasher};
let mut hasher = std::collections::hash_map::RandomState::new().build_hasher(); let mut hasher = std::hash::RandomState::new().build_hasher();
core::panic::Location::caller().hash(&mut hasher); core::panic::Location::caller().hash(&mut hasher);
let hc64 = hasher.finish(); let hc64 = hasher.finish();
let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>(); let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();

View file

@ -6,16 +6,13 @@ use self::Entry::*;
use hashbrown::hash_map as base; use hashbrown::hash_map as base;
use crate::borrow::Borrow; use crate::borrow::Borrow;
use crate::cell::Cell;
use crate::collections::TryReserveError; use crate::collections::TryReserveError;
use crate::collections::TryReserveErrorKind; use crate::collections::TryReserveErrorKind;
use crate::error::Error; use crate::error::Error;
use crate::fmt::{self, Debug}; use crate::fmt::{self, Debug};
#[allow(deprecated)] use crate::hash::{BuildHasher, Hash, RandomState};
use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13};
use crate::iter::FusedIterator; use crate::iter::FusedIterator;
use crate::ops::Index; use crate::ops::Index;
use crate::sys;
/// A [hash map] implemented with quadratic probing and SIMD lookup. /// A [hash map] implemented with quadratic probing and SIMD lookup.
/// ///
@ -274,7 +271,7 @@ impl<K, V, S> HashMap<K, V, S> {
/// ///
/// ``` /// ```
/// use std::collections::HashMap; /// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState; /// use std::hash::RandomState;
/// ///
/// let s = RandomState::new(); /// let s = RandomState::new();
/// let mut map = HashMap::with_hasher(s); /// let mut map = HashMap::with_hasher(s);
@ -306,7 +303,7 @@ impl<K, V, S> HashMap<K, V, S> {
/// ///
/// ``` /// ```
/// use std::collections::HashMap; /// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState; /// use std::hash::RandomState;
/// ///
/// let s = RandomState::new(); /// let s = RandomState::new();
/// let mut map = HashMap::with_capacity_and_hasher(10, s); /// let mut map = HashMap::with_capacity_and_hasher(10, s);
@ -717,7 +714,7 @@ impl<K, V, S> HashMap<K, V, S> {
/// ///
/// ``` /// ```
/// use std::collections::HashMap; /// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState; /// use std::hash::RandomState;
/// ///
/// let hasher = RandomState::new(); /// let hasher = RandomState::new();
/// let map: HashMap<i32, i32> = HashMap::with_hasher(hasher); /// let map: HashMap<i32, i32> = HashMap::with_hasher(hasher);
@ -3072,152 +3069,6 @@ where
} }
} }
/// `RandomState` is the default state for [`HashMap`] types.
///
/// A particular instance `RandomState` will create the same instances of
/// [`Hasher`], but the hashers created by two different `RandomState`
/// instances are unlikely to produce the same result for the same values.
///
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
/// let mut map = HashMap::with_hasher(s);
/// map.insert(1, 2);
/// ```
#[derive(Clone)]
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub struct RandomState {
k0: u64,
k1: u64,
}
impl RandomState {
/// Constructs a new `RandomState` that is initialized with random keys.
///
/// # Examples
///
/// ```
/// use std::collections::hash_map::RandomState;
///
/// let s = RandomState::new();
/// ```
#[inline]
#[allow(deprecated)]
// rand
#[must_use]
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub fn new() -> RandomState {
// Historically this function did not cache keys from the OS and instead
// simply always called `rand::thread_rng().gen()` twice. In #31356 it
// was discovered, however, that because we re-seed the thread-local RNG
// from the OS periodically that this can cause excessive slowdown when
// many hash maps are created on a thread. To solve this performance
// trap we cache the first set of randomly generated keys per-thread.
//
// Later in #36481 it was discovered that exposing a deterministic
// iteration order allows a form of DOS attack. To counter that we
// increment one of the seeds on every RandomState creation, giving
// every corresponding HashMap a different iteration order.
thread_local!(static KEYS: Cell<(u64, u64)> = {
Cell::new(sys::hashmap_random_keys())
});
KEYS.with(|keys| {
let (k0, k1) = keys.get();
keys.set((k0.wrapping_add(1), k1));
RandomState { k0, k1 }
})
}
}
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
impl BuildHasher for RandomState {
type Hasher = DefaultHasher;
#[inline]
#[allow(deprecated)]
fn build_hasher(&self) -> DefaultHasher {
DefaultHasher(SipHasher13::new_with_keys(self.k0, self.k1))
}
}
/// The default [`Hasher`] used by [`RandomState`].
///
/// The internal algorithm is not specified, and so it and its hashes should
/// not be relied upon over releases.
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
#[allow(deprecated)]
#[derive(Clone, Debug)]
pub struct DefaultHasher(SipHasher13);
impl DefaultHasher {
/// Creates a new `DefaultHasher`.
///
/// This hasher is not guaranteed to be the same as all other
/// `DefaultHasher` instances, but is the same as all other `DefaultHasher`
/// instances created through `new` or `default`.
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
#[inline]
#[allow(deprecated)]
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
#[must_use]
pub const fn new() -> DefaultHasher {
DefaultHasher(SipHasher13::new_with_keys(0, 0))
}
}
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
impl Default for DefaultHasher {
/// Creates a new `DefaultHasher` using [`new`].
/// See its documentation for more.
///
/// [`new`]: DefaultHasher::new
#[inline]
fn default() -> DefaultHasher {
DefaultHasher::new()
}
}
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
impl Hasher for DefaultHasher {
// The underlying `SipHasher13` doesn't override the other
// `write_*` methods, so it's ok not to forward them here.
#[inline]
fn write(&mut self, msg: &[u8]) {
self.0.write(msg)
}
#[inline]
fn write_str(&mut self, s: &str) {
self.0.write_str(s);
}
#[inline]
fn finish(&self) -> u64 {
self.0.finish()
}
}
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
impl Default for RandomState {
/// Constructs a new `RandomState`.
#[inline]
fn default() -> RandomState {
RandomState::new()
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for RandomState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RandomState").finish_non_exhaustive()
}
}
#[inline] #[inline]
fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, V> { fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, V> {
match raw { match raw {

View file

@ -1,8 +1,8 @@
use super::Entry::{Occupied, Vacant}; use super::Entry::{Occupied, Vacant};
use super::HashMap; use super::HashMap;
use super::RandomState;
use crate::assert_matches::assert_matches; use crate::assert_matches::assert_matches;
use crate::cell::RefCell; use crate::cell::RefCell;
use crate::hash::RandomState;
use crate::test_helpers::test_rng; use crate::test_helpers::test_rng;
use rand::Rng; use rand::Rng;
use realstd::collections::TryReserveErrorKind::*; use realstd::collections::TryReserveErrorKind::*;

View file

@ -6,11 +6,11 @@ use hashbrown::hash_set as base;
use crate::borrow::Borrow; use crate::borrow::Borrow;
use crate::collections::TryReserveError; use crate::collections::TryReserveError;
use crate::fmt; use crate::fmt;
use crate::hash::{BuildHasher, Hash}; use crate::hash::{BuildHasher, Hash, RandomState};
use crate::iter::{Chain, FusedIterator}; use crate::iter::{Chain, FusedIterator};
use crate::ops::{BitAnd, BitOr, BitXor, Sub}; use crate::ops::{BitAnd, BitOr, BitXor, Sub};
use super::map::{map_try_reserve_error, RandomState}; use super::map::map_try_reserve_error;
/// A [hash set] implemented as a `HashMap` where the value is `()`. /// A [hash set] implemented as a `HashMap` where the value is `()`.
/// ///
@ -361,7 +361,7 @@ impl<T, S> HashSet<T, S> {
/// ///
/// ``` /// ```
/// use std::collections::HashSet; /// use std::collections::HashSet;
/// use std::collections::hash_map::RandomState; /// use std::hash::RandomState;
/// ///
/// let s = RandomState::new(); /// let s = RandomState::new();
/// let mut set = HashSet::with_hasher(s); /// let mut set = HashSet::with_hasher(s);
@ -393,7 +393,7 @@ impl<T, S> HashSet<T, S> {
/// ///
/// ``` /// ```
/// use std::collections::HashSet; /// use std::collections::HashSet;
/// use std::collections::hash_map::RandomState; /// use std::hash::RandomState;
/// ///
/// let s = RandomState::new(); /// let s = RandomState::new();
/// let mut set = HashSet::with_capacity_and_hasher(10, s); /// let mut set = HashSet::with_capacity_and_hasher(10, s);
@ -411,7 +411,7 @@ impl<T, S> HashSet<T, S> {
/// ///
/// ``` /// ```
/// use std::collections::HashSet; /// use std::collections::HashSet;
/// use std::collections::hash_map::RandomState; /// use std::hash::RandomState;
/// ///
/// let hasher = RandomState::new(); /// let hasher = RandomState::new();
/// let set: HashSet<i32> = HashSet::with_hasher(hasher); /// let set: HashSet<i32> = HashSet::with_hasher(hasher);

View file

@ -1,6 +1,6 @@
use super::super::map::RandomState;
use super::HashSet; use super::HashSet;
use crate::hash::RandomState;
use crate::panic::{catch_unwind, AssertUnwindSafe}; use crate::panic::{catch_unwind, AssertUnwindSafe};
use crate::sync::atomic::{AtomicU32, Ordering}; use crate::sync::atomic::{AtomicU32, Ordering};
use crate::sync::Arc; use crate::sync::Arc;

View file

@ -439,6 +439,11 @@ pub mod hash_map {
//! A hash map implemented with quadratic probing and SIMD lookup. //! A hash map implemented with quadratic probing and SIMD lookup.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::hash::map::*; pub use super::hash::map::*;
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub use crate::hash::random::DefaultHasher;
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub use crate::hash::random::RandomState;
} }
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]

View file

@ -0,0 +1,91 @@
//! Generic hashing support.
//!
//! This module provides a generic way to compute the [hash] of a value.
//! Hashes are most commonly used with [`HashMap`] and [`HashSet`].
//!
//! [hash]: https://en.wikipedia.org/wiki/Hash_function
//! [`HashMap`]: ../../std/collections/struct.HashMap.html
//! [`HashSet`]: ../../std/collections/struct.HashSet.html
//!
//! The simplest way to make a type hashable is to use `#[derive(Hash)]`:
//!
//! # Examples
//!
//! ```rust
//! use std::hash::{DefaultHasher, Hash, Hasher};
//!
//! #[derive(Hash)]
//! struct Person {
//! id: u32,
//! name: String,
//! phone: u64,
//! }
//!
//! let person1 = Person {
//! id: 5,
//! name: "Janet".to_string(),
//! phone: 555_666_7777,
//! };
//! let person2 = Person {
//! id: 5,
//! name: "Bob".to_string(),
//! phone: 555_666_7777,
//! };
//!
//! assert!(calculate_hash(&person1) != calculate_hash(&person2));
//!
//! fn calculate_hash<T: Hash>(t: &T) -> u64 {
//! let mut s = DefaultHasher::new();
//! t.hash(&mut s);
//! s.finish()
//! }
//! ```
//!
//! If you need more control over how a value is hashed, you need to implement
//! the [`Hash`] trait:
//!
//! ```rust
//! use std::hash::{DefaultHasher, Hash, Hasher};
//!
//! struct Person {
//! id: u32,
//! # #[allow(dead_code)]
//! name: String,
//! phone: u64,
//! }
//!
//! impl Hash for Person {
//! fn hash<H: Hasher>(&self, state: &mut H) {
//! self.id.hash(state);
//! self.phone.hash(state);
//! }
//! }
//!
//! let person1 = Person {
//! id: 5,
//! name: "Janet".to_string(),
//! phone: 555_666_7777,
//! };
//! let person2 = Person {
//! id: 5,
//! name: "Bob".to_string(),
//! phone: 555_666_7777,
//! };
//!
//! assert_eq!(calculate_hash(&person1), calculate_hash(&person2));
//!
//! fn calculate_hash<T: Hash>(t: &T) -> u64 {
//! let mut s = DefaultHasher::new();
//! t.hash(&mut s);
//! s.finish()
//! }
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
pub(crate) mod random;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::hash::*;
#[stable(feature = "std_hash_exports", since = "CURRENT_RUSTC_VERSION")]
pub use self::random::{DefaultHasher, RandomState};

View file

@ -0,0 +1,161 @@
//! This module exists to isolate [`RandomState`] and [`DefaultHasher`] outside of the
//! [`collections`] module without actually publicly exporting them, so that parts of that
//! implementation can more easily be moved to the [`alloc`] crate.
//!
//! Although its items are public and contain stability attributes, they can't actually be accessed
//! outside this crate.
//!
//! [`collections`]: crate::collections
#[allow(deprecated)]
use super::{BuildHasher, Hasher, SipHasher13};
use crate::cell::Cell;
use crate::fmt;
use crate::sys;
/// `RandomState` is the default state for [`HashMap`] types.
///
/// A particular instance `RandomState` will create the same instances of
/// [`Hasher`], but the hashers created by two different `RandomState`
/// instances are unlikely to produce the same result for the same values.
///
/// [`HashMap`]: crate::collections::HashMap
///
/// # Examples
///
/// ```
/// use std::collections::HashMap;
/// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// let mut map = HashMap::with_hasher(s);
/// map.insert(1, 2);
/// ```
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
#[derive(Clone)]
pub struct RandomState {
k0: u64,
k1: u64,
}
impl RandomState {
/// Constructs a new `RandomState` that is initialized with random keys.
///
/// # Examples
///
/// ```
/// use std::hash::RandomState;
///
/// let s = RandomState::new();
/// ```
#[inline]
#[allow(deprecated)]
// rand
#[must_use]
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub fn new() -> RandomState {
// Historically this function did not cache keys from the OS and instead
// simply always called `rand::thread_rng().gen()` twice. In #31356 it
// was discovered, however, that because we re-seed the thread-local RNG
// from the OS periodically that this can cause excessive slowdown when
// many hash maps are created on a thread. To solve this performance
// trap we cache the first set of randomly generated keys per-thread.
//
// Later in #36481 it was discovered that exposing a deterministic
// iteration order allows a form of DOS attack. To counter that we
// increment one of the seeds on every RandomState creation, giving
// every corresponding HashMap a different iteration order.
thread_local!(static KEYS: Cell<(u64, u64)> = {
Cell::new(sys::hashmap_random_keys())
});
KEYS.with(|keys| {
let (k0, k1) = keys.get();
keys.set((k0.wrapping_add(1), k1));
RandomState { k0, k1 }
})
}
}
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
impl BuildHasher for RandomState {
type Hasher = DefaultHasher;
#[inline]
#[allow(deprecated)]
fn build_hasher(&self) -> DefaultHasher {
DefaultHasher(SipHasher13::new_with_keys(self.k0, self.k1))
}
}
/// The default [`Hasher`] used by [`RandomState`].
///
/// The internal algorithm is not specified, and so it and its hashes should
/// not be relied upon over releases.
#[allow(deprecated)]
#[derive(Clone, Debug)]
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
pub struct DefaultHasher(SipHasher13);
impl DefaultHasher {
/// Creates a new `DefaultHasher`.
///
/// This hasher is not guaranteed to be the same as all other
/// `DefaultHasher` instances, but is the same as all other `DefaultHasher`
/// instances created through `new` or `default`.
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
#[inline]
#[allow(deprecated)]
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
#[must_use]
pub const fn new() -> DefaultHasher {
DefaultHasher(SipHasher13::new_with_keys(0, 0))
}
}
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
impl Default for DefaultHasher {
/// Creates a new `DefaultHasher` using [`new`].
/// See its documentation for more.
///
/// [`new`]: DefaultHasher::new
#[inline]
fn default() -> DefaultHasher {
DefaultHasher::new()
}
}
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
impl Hasher for DefaultHasher {
// The underlying `SipHasher13` doesn't override the other
// `write_*` methods, so it's ok not to forward them here.
#[inline]
fn write(&mut self, msg: &[u8]) {
self.0.write(msg)
}
#[inline]
fn write_str(&mut self, s: &str) {
self.0.write_str(s);
}
#[inline]
fn finish(&self) -> u64 {
self.0.finish()
}
}
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
impl Default for RandomState {
/// Constructs a new `RandomState`.
#[inline]
fn default() -> RandomState {
RandomState::new()
}
}
#[stable(feature = "std_debug", since = "1.16.0")]
impl fmt::Debug for RandomState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RandomState").finish_non_exhaustive()
}
}

View file

@ -494,8 +494,6 @@ pub use core::convert;
pub use core::default; pub use core::default;
#[stable(feature = "futures_api", since = "1.36.0")] #[stable(feature = "futures_api", since = "1.36.0")]
pub use core::future; pub use core::future;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::hash;
#[stable(feature = "core_hint", since = "1.27.0")] #[stable(feature = "core_hint", since = "1.27.0")]
pub use core::hint; pub use core::hint;
#[stable(feature = "i128", since = "1.26.0")] #[stable(feature = "i128", since = "1.26.0")]
@ -565,6 +563,7 @@ pub mod env;
pub mod error; pub mod error;
pub mod ffi; pub mod ffi;
pub mod fs; pub mod fs;
pub mod hash;
pub mod io; pub mod io;
pub mod net; pub mod net;
pub mod num; pub mod num;
@ -716,7 +715,7 @@ pub(crate) mod test_helpers {
#[track_caller] #[track_caller]
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
use core::hash::{BuildHasher, Hash, Hasher}; use core::hash::{BuildHasher, Hash, Hasher};
let mut hasher = crate::collections::hash_map::RandomState::new().build_hasher(); let mut hasher = crate::hash::RandomState::new().build_hasher();
core::panic::Location::caller().hash(&mut hasher); core::panic::Location::caller().hash(&mut hasher);
let hc64 = hasher.finish(); let hc64 = hasher.finish();
let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>(); let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();

View file

@ -1,8 +1,7 @@
use super::*; use super::*;
use crate::collections::hash_map::DefaultHasher;
use crate::collections::{BTreeSet, HashSet}; use crate::collections::{BTreeSet, HashSet};
use crate::hash::Hasher; use crate::hash::{DefaultHasher, Hasher};
use crate::rc::Rc; use crate::rc::Rc;
use crate::sync::Arc; use crate::sync::Arc;
use core::hint::black_box; use core::hint::black_box;
@ -1461,8 +1460,7 @@ fn test_eq_receivers() {
#[test] #[test]
pub fn test_compare() { pub fn test_compare() {
use crate::collections::hash_map::DefaultHasher; use crate::hash::{DefaultHasher, Hash, Hasher};
use crate::hash::{Hash, Hasher};
fn hash<T: Hash>(t: T) -> u64 { fn hash<T: Hash>(t: T) -> u64 {
let mut s = DefaultHasher::new(); let mut s = DefaultHasher::new();

View file

@ -1,17 +1,17 @@
#![allow(unused)] #![allow(unused)]
use rand::RngCore;
use std::env; use std::env;
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::thread; use std::thread;
use rand::RngCore;
/// Copied from `std::test_helpers::test_rng`, since these tests rely on the /// Copied from `std::test_helpers::test_rng`, since these tests rely on the
/// seed not being the same for every RNG invocation too. /// seed not being the same for every RNG invocation too.
#[track_caller] #[track_caller]
pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng {
use core::hash::{BuildHasher, Hash, Hasher}; use core::hash::{BuildHasher, Hash, Hasher};
let mut hasher = std::collections::hash_map::RandomState::new().build_hasher(); let mut hasher = std::hash::RandomState::new().build_hasher();
core::panic::Location::caller().hash(&mut hasher); core::panic::Location::caller().hash(&mut hasher);
let hc64 = hasher.finish(); let hc64 = hasher.finish();
let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>(); let seed_vec = hc64.to_le_bytes().into_iter().chain(0u8..8).collect::<Vec<u8>>();

View file

@ -1,7 +1,6 @@
use crate::cli::TestOpts; use crate::cli::TestOpts;
use crate::types::{TestDescAndFn, TestId, TestName}; use crate::types::{TestDescAndFn, TestId, TestName};
use std::collections::hash_map::DefaultHasher; use std::hash::{DefaultHasher, Hasher};
use std::hash::Hasher;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
pub fn get_shuffle_seed(opts: &TestOpts) -> Option<u64> { pub fn get_shuffle_seed(opts: &TestOpts) -> Option<u64> {

View file

@ -264,8 +264,8 @@ pub fn run_tests<F>(
where where
F: FnMut(TestEvent) -> io::Result<()>, F: FnMut(TestEvent) -> io::Result<()>,
{ {
use std::collections::{self, HashMap}; use std::collections::HashMap;
use std::hash::BuildHasherDefault; use std::hash::{BuildHasherDefault, DefaultHasher};
use std::sync::mpsc::RecvTimeoutError; use std::sync::mpsc::RecvTimeoutError;
struct RunningTest { struct RunningTest {
@ -286,8 +286,7 @@ where
} }
// Use a deterministic hasher // Use a deterministic hasher
type TestMap = type TestMap = HashMap<TestId, RunningTest, BuildHasherDefault<DefaultHasher>>;
HashMap<TestId, RunningTest, BuildHasherDefault<collections::hash_map::DefaultHasher>>;
struct TimeoutEntry { struct TimeoutEntry {
id: TestId, id: TestId,

View file

@ -20,12 +20,11 @@ use regex::{Captures, Regex};
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter}; use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::hash_map::DefaultHasher;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::env; use std::env;
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::fs::{self, create_dir_all, File, OpenOptions}; use std::fs::{self, create_dir_all, File, OpenOptions};
use std::hash::{Hash, Hasher}; use std::hash::{DefaultHasher, Hash, Hasher};
use std::io::prelude::*; use std::io::prelude::*;
use std::io::{self, BufReader}; use std::io::{self, BufReader};
use std::iter; use std::iter;

View file

@ -1,7 +1,7 @@
use std::hash::BuildHasher; use std::hash::BuildHasher;
fn next_u64() -> u64 { fn next_u64() -> u64 {
let bh = std::collections::hash_map::RandomState::new(); let bh = std::hash::RandomState::new();
let h = bh.build_hasher(); let h = bh.build_hasher();
h.finish() //~ ERROR no method named `finish` found for struct `DefaultHasher` h.finish() //~ ERROR no method named `finish` found for struct `DefaultHasher`
} }