use std::collections::{HashMap, HashSet};
use crate::FxHasher;
pub type FxHashMapRand<K, V> = HashMap<K, V, FxRandomState>;
pub type FxHashSetRand<V> = HashSet<V, FxRandomState>;
#[derive(Clone)]
pub struct FxRandomState {
seed: usize,
}
impl FxRandomState {
pub fn new() -> FxRandomState {
use rand::Rng;
use std::{cell::Cell, thread_local};
thread_local!(static SEED: Cell<usize> = {
Cell::new(rand::thread_rng().gen())
});
SEED.with(|seed| {
let s = seed.get();
seed.set(s.wrapping_add(1));
FxRandomState { seed: s }
})
}
}
impl core::hash::BuildHasher for FxRandomState {
type Hasher = FxHasher;
fn build_hasher(&self) -> Self::Hasher {
FxHasher::with_seed(self.seed)
}
}
impl Default for FxRandomState {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use std::thread;
use crate::FxHashMapRand;
#[test]
fn cloned_random_states_are_equal() {
let a = FxHashMapRand::<&str, u32>::default();
let b = a.clone();
assert_eq!(a.hasher().seed, b.hasher().seed);
}
#[test]
fn random_states_are_different() {
let a = FxHashMapRand::<&str, u32>::default();
let b = FxHashMapRand::<&str, u32>::default();
assert_ne!(a.hasher().seed, b.hasher().seed);
}
#[test]
fn random_states_are_different_cross_thread() {
let a = FxHashMapRand::<&str, u32>::default();
let b = thread::spawn(|| FxHashMapRand::<&str, u32>::default())
.join()
.unwrap();
assert_ne!(a.hasher().seed, b.hasher().seed);
}
}