28
28
#[ cfg( feature = "std" ) ]
29
29
extern crate std;
30
30
31
+ #[ cfg( feature = "rand" ) ]
32
+ extern crate rand;
33
+
31
34
use core:: convert:: TryInto ;
32
35
use core:: default:: Default ;
33
36
#[ cfg( feature = "std" ) ]
@@ -46,6 +49,14 @@ pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
46
49
#[ cfg( feature = "std" ) ]
47
50
pub type FxHashSet < V > = HashSet < V , BuildHasherDefault < FxHasher > > ;
48
51
52
+ /// Type alias for a hashmap using the `fx` hash algorithm with [`FxRandomState`].
53
+ #[ cfg( feature = "rand" ) ]
54
+ pub type FxHashMapRand < K , V > = HashMap < K , V , FxRandomState > ;
55
+
56
+ /// Type alias for a hashmap using the `fx` hash algorithm with [`FxRandomState`].
57
+ #[ cfg( feature = "rand" ) ]
58
+ pub type FxHashSetRand < V > = HashSet < V , FxRandomState > ;
59
+
49
60
/// A speedy hash algorithm for use within rustc. The hashmap in liballoc
50
61
/// by default uses SipHash which isn't quite as speedy as we want. In the
51
62
/// compiler we're not really worried about DOS attempts, so we use a fast
@@ -62,6 +73,16 @@ pub struct FxHasher {
62
73
hash : usize ,
63
74
}
64
75
76
+ /// `FxRandomState` is an alternative state for `HashMap` types.
77
+ ///
78
+ /// A particular instance `FxRandomState` will create the same instances of
79
+ /// [`Hasher`], but the hashers created by two different `FxRandomState`
80
+ /// instances are unlikely to produce the same result for the same values.
81
+ #[ cfg( feature = "rand" ) ]
82
+ pub struct FxRandomState {
83
+ seed : usize ,
84
+ }
85
+
65
86
#[ cfg( target_pointer_width = "32" ) ]
66
87
const K : usize = 0x9e3779b9 ;
67
88
#[ cfg( target_pointer_width = "64" ) ]
@@ -155,6 +176,41 @@ impl Hasher for FxHasher {
155
176
}
156
177
}
157
178
179
+ #[ cfg( feature = "rand" ) ]
180
+ impl FxRandomState {
181
+ /// Constructs a new `FxRandomState` that is initialized with random seed.
182
+ pub fn new ( ) -> FxRandomState {
183
+ use rand:: Rng ;
184
+ use std:: { cell:: Cell , thread_local} ;
185
+
186
+ // This mirrors what `std::collections::hash_map::RandomState` does, as of 2024-01-14.
187
+ //
188
+ // Basically
189
+ // 1. Cache result of the rng in a thread local, so repeatedly
190
+ // creating maps is cheaper
191
+ // 2. Change the cached result on every creation, so maps created
192
+ // on the same thread don't have the same iteration order
193
+ thread_local ! ( static SEED : Cell <usize > = {
194
+ Cell :: new( rand:: thread_rng( ) . gen ( ) )
195
+ } ) ;
196
+
197
+ SEED . with ( |seed| {
198
+ let s = seed. get ( ) ;
199
+ seed. set ( s. wrapping_add ( 1 ) ) ;
200
+ FxRandomState { seed : s }
201
+ } )
202
+ }
203
+ }
204
+
205
+ #[ cfg( feature = "rand" ) ]
206
+ impl core:: hash:: BuildHasher for FxRandomState {
207
+ type Hasher = FxHasher ;
208
+
209
+ fn build_hasher ( & self ) -> Self :: Hasher {
210
+ FxHasher { hash : self . seed }
211
+ }
212
+ }
213
+
158
214
#[ cfg( test) ]
159
215
mod tests {
160
216
#[ cfg( not( any( target_pointer_width = "64" , target_pointer_width = "32" ) ) ) ]
0 commit comments