Skip to content

Commit c4b514b

Browse files
committed
Move RandomState and DefaultHasher into std::hash, but in a sneaky way
1 parent 2bbb619 commit c4b514b

File tree

8 files changed

+262
-155
lines changed

8 files changed

+262
-155
lines changed

Diff for: library/std/src/collections/hash/map.rs

+1-149
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,14 @@ use self::Entry::*;
66
use hashbrown::hash_map as base;
77

88
use crate::borrow::Borrow;
9-
use crate::cell::Cell;
109
use crate::collections::TryReserveError;
1110
use crate::collections::TryReserveErrorKind;
1211
use crate::error::Error;
1312
use crate::fmt::{self, Debug};
1413
#[allow(deprecated)]
15-
use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13};
14+
use crate::hash::{private::RandomState, BuildHasher, Hash};
1615
use crate::iter::FusedIterator;
1716
use crate::ops::Index;
18-
use crate::sys;
1917

2018
/// A [hash map] implemented with quadratic probing and SIMD lookup.
2119
///
@@ -3072,152 +3070,6 @@ where
30723070
}
30733071
}
30743072

3075-
/// `RandomState` is the default state for [`HashMap`] types.
3076-
///
3077-
/// A particular instance `RandomState` will create the same instances of
3078-
/// [`Hasher`], but the hashers created by two different `RandomState`
3079-
/// instances are unlikely to produce the same result for the same values.
3080-
///
3081-
/// # Examples
3082-
///
3083-
/// ```
3084-
/// use std::collections::HashMap;
3085-
/// use std::collections::hash_map::RandomState;
3086-
///
3087-
/// let s = RandomState::new();
3088-
/// let mut map = HashMap::with_hasher(s);
3089-
/// map.insert(1, 2);
3090-
/// ```
3091-
#[derive(Clone)]
3092-
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
3093-
pub struct RandomState {
3094-
k0: u64,
3095-
k1: u64,
3096-
}
3097-
3098-
impl RandomState {
3099-
/// Constructs a new `RandomState` that is initialized with random keys.
3100-
///
3101-
/// # Examples
3102-
///
3103-
/// ```
3104-
/// use std::collections::hash_map::RandomState;
3105-
///
3106-
/// let s = RandomState::new();
3107-
/// ```
3108-
#[inline]
3109-
#[allow(deprecated)]
3110-
// rand
3111-
#[must_use]
3112-
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
3113-
pub fn new() -> RandomState {
3114-
// Historically this function did not cache keys from the OS and instead
3115-
// simply always called `rand::thread_rng().gen()` twice. In #31356 it
3116-
// was discovered, however, that because we re-seed the thread-local RNG
3117-
// from the OS periodically that this can cause excessive slowdown when
3118-
// many hash maps are created on a thread. To solve this performance
3119-
// trap we cache the first set of randomly generated keys per-thread.
3120-
//
3121-
// Later in #36481 it was discovered that exposing a deterministic
3122-
// iteration order allows a form of DOS attack. To counter that we
3123-
// increment one of the seeds on every RandomState creation, giving
3124-
// every corresponding HashMap a different iteration order.
3125-
thread_local!(static KEYS: Cell<(u64, u64)> = {
3126-
Cell::new(sys::hashmap_random_keys())
3127-
});
3128-
3129-
KEYS.with(|keys| {
3130-
let (k0, k1) = keys.get();
3131-
keys.set((k0.wrapping_add(1), k1));
3132-
RandomState { k0, k1 }
3133-
})
3134-
}
3135-
}
3136-
3137-
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
3138-
impl BuildHasher for RandomState {
3139-
type Hasher = DefaultHasher;
3140-
#[inline]
3141-
#[allow(deprecated)]
3142-
fn build_hasher(&self) -> DefaultHasher {
3143-
DefaultHasher(SipHasher13::new_with_keys(self.k0, self.k1))
3144-
}
3145-
}
3146-
3147-
/// The default [`Hasher`] used by [`RandomState`].
3148-
///
3149-
/// The internal algorithm is not specified, and so it and its hashes should
3150-
/// not be relied upon over releases.
3151-
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
3152-
#[allow(deprecated)]
3153-
#[derive(Clone, Debug)]
3154-
pub struct DefaultHasher(SipHasher13);
3155-
3156-
impl DefaultHasher {
3157-
/// Creates a new `DefaultHasher`.
3158-
///
3159-
/// This hasher is not guaranteed to be the same as all other
3160-
/// `DefaultHasher` instances, but is the same as all other `DefaultHasher`
3161-
/// instances created through `new` or `default`.
3162-
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
3163-
#[inline]
3164-
#[allow(deprecated)]
3165-
#[rustc_const_unstable(feature = "const_hash", issue = "104061")]
3166-
#[must_use]
3167-
pub const fn new() -> DefaultHasher {
3168-
DefaultHasher(SipHasher13::new_with_keys(0, 0))
3169-
}
3170-
}
3171-
3172-
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
3173-
impl Default for DefaultHasher {
3174-
/// Creates a new `DefaultHasher` using [`new`].
3175-
/// See its documentation for more.
3176-
///
3177-
/// [`new`]: DefaultHasher::new
3178-
#[inline]
3179-
fn default() -> DefaultHasher {
3180-
DefaultHasher::new()
3181-
}
3182-
}
3183-
3184-
#[stable(feature = "hashmap_default_hasher", since = "1.13.0")]
3185-
impl Hasher for DefaultHasher {
3186-
// The underlying `SipHasher13` doesn't override the other
3187-
// `write_*` methods, so it's ok not to forward them here.
3188-
3189-
#[inline]
3190-
fn write(&mut self, msg: &[u8]) {
3191-
self.0.write(msg)
3192-
}
3193-
3194-
#[inline]
3195-
fn write_str(&mut self, s: &str) {
3196-
self.0.write_str(s);
3197-
}
3198-
3199-
#[inline]
3200-
fn finish(&self) -> u64 {
3201-
self.0.finish()
3202-
}
3203-
}
3204-
3205-
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
3206-
impl Default for RandomState {
3207-
/// Constructs a new `RandomState`.
3208-
#[inline]
3209-
fn default() -> RandomState {
3210-
RandomState::new()
3211-
}
3212-
}
3213-
3214-
#[stable(feature = "std_debug", since = "1.16.0")]
3215-
impl fmt::Debug for RandomState {
3216-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3217-
f.debug_struct("RandomState").finish_non_exhaustive()
3218-
}
3219-
}
3220-
32213073
#[inline]
32223074
fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, V> {
32233075
match raw {

Diff for: library/std/src/collections/hash/map/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use super::Entry::{Occupied, Vacant};
22
use super::HashMap;
3-
use super::RandomState;
43
use crate::assert_matches::assert_matches;
54
use crate::cell::RefCell;
5+
use crate::hash::private::RandomState;
66
use crate::test_helpers::test_rng;
77
use rand::Rng;
88
use realstd::collections::TryReserveErrorKind::*;

Diff for: library/std/src/collections/hash/set.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ use hashbrown::hash_set as base;
66
use crate::borrow::Borrow;
77
use crate::collections::TryReserveError;
88
use crate::fmt;
9-
use crate::hash::{BuildHasher, Hash};
9+
use crate::hash::{private::RandomState, BuildHasher, Hash};
1010
use crate::iter::{Chain, FusedIterator};
1111
use crate::ops::{BitAnd, BitOr, BitXor, Sub};
1212

13-
use super::map::{map_try_reserve_error, RandomState};
13+
use super::map::map_try_reserve_error;
1414

1515
/// A [hash set] implemented as a `HashMap` where the value is `()`.
1616
///

Diff for: library/std/src/collections/hash/set/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use super::super::map::RandomState;
21
use super::HashSet;
32

3+
use crate::hash::private::RandomState;
44
use crate::panic::{catch_unwind, AssertUnwindSafe};
55
use crate::sync::atomic::{AtomicU32, Ordering};
66
use crate::sync::Arc;

Diff for: library/std/src/collections/mod.rs

+5
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,11 @@ pub mod hash_map {
439439
//! A hash map implemented with quadratic probing and SIMD lookup.
440440
#[stable(feature = "rust1", since = "1.0.0")]
441441
pub use super::hash::map::*;
442+
443+
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
444+
pub use crate::hash::private::DefaultHasher;
445+
#[stable(feature = "hashmap_build_hasher", since = "1.7.0")]
446+
pub use crate::hash::private::RandomState;
442447
}
443448

444449
#[stable(feature = "rust1", since = "1.0.0")]

Diff for: library/std/src/hash/mod.rs

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//! Generic hashing support.
2+
//!
3+
//! This module provides a generic way to compute the [hash] of a value.
4+
//! Hashes are most commonly used with [`HashMap`] and [`HashSet`].
5+
//!
6+
//! [hash]: https://en.wikipedia.org/wiki/Hash_function
7+
//! [`HashMap`]: ../../std/collections/struct.HashMap.html
8+
//! [`HashSet`]: ../../std/collections/struct.HashSet.html
9+
//!
10+
//! The simplest way to make a type hashable is to use `#[derive(Hash)]`:
11+
//!
12+
//! # Examples
13+
//!
14+
//! ```rust
15+
//! use std::collections::hash_map::DefaultHasher;
16+
//! use std::hash::{Hash, Hasher};
17+
//!
18+
//! #[derive(Hash)]
19+
//! struct Person {
20+
//! id: u32,
21+
//! name: String,
22+
//! phone: u64,
23+
//! }
24+
//!
25+
//! let person1 = Person {
26+
//! id: 5,
27+
//! name: "Janet".to_string(),
28+
//! phone: 555_666_7777,
29+
//! };
30+
//! let person2 = Person {
31+
//! id: 5,
32+
//! name: "Bob".to_string(),
33+
//! phone: 555_666_7777,
34+
//! };
35+
//!
36+
//! assert!(calculate_hash(&person1) != calculate_hash(&person2));
37+
//!
38+
//! fn calculate_hash<T: Hash>(t: &T) -> u64 {
39+
//! let mut s = DefaultHasher::new();
40+
//! t.hash(&mut s);
41+
//! s.finish()
42+
//! }
43+
//! ```
44+
//!
45+
//! If you need more control over how a value is hashed, you need to implement
46+
//! the [`Hash`] trait:
47+
//!
48+
//! ```rust
49+
//! use std::collections::hash_map::DefaultHasher;
50+
//! use std::hash::{Hash, Hasher};
51+
//!
52+
//! struct Person {
53+
//! id: u32,
54+
//! # #[allow(dead_code)]
55+
//! name: String,
56+
//! phone: u64,
57+
//! }
58+
//!
59+
//! impl Hash for Person {
60+
//! fn hash<H: Hasher>(&self, state: &mut H) {
61+
//! self.id.hash(state);
62+
//! self.phone.hash(state);
63+
//! }
64+
//! }
65+
//!
66+
//! let person1 = Person {
67+
//! id: 5,
68+
//! name: "Janet".to_string(),
69+
//! phone: 555_666_7777,
70+
//! };
71+
//! let person2 = Person {
72+
//! id: 5,
73+
//! name: "Bob".to_string(),
74+
//! phone: 555_666_7777,
75+
//! };
76+
//!
77+
//! assert_eq!(calculate_hash(&person1), calculate_hash(&person2));
78+
//!
79+
//! fn calculate_hash<T: Hash>(t: &T) -> u64 {
80+
//! let mut s = DefaultHasher::new();
81+
//! t.hash(&mut s);
82+
//! s.finish()
83+
//! }
84+
//! ```
85+
#![stable(feature = "rust1", since = "1.0.0")]
86+
87+
pub(crate) mod private;
88+
89+
#[stable(feature = "rust1", since = "1.0.0")]
90+
pub use core::hash::*;

0 commit comments

Comments
 (0)