use crate::hash::wyhash::WYP;
use std::cell::Cell;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::ops::{Bound, Div, RangeBounds};
use std::stringify;
#[inline(always)]
#[allow(unused)]
fn mul_u32(a: u32, b: u32) -> u32 {
((a as u64).wrapping_mul(b as u64) >> 32) as u32
}
#[inline(always)]
#[allow(unused)]
fn mul_u64(a: u64, b: u64) -> u64 {
((a as u128).wrapping_mul(b as u128) >> 64) as u64
}
macro_rules! mod_impl {
($fname:tt,$typ:tt, $next_random:tt,$mul:ident) => {
#[inline(always)]
#[allow(unused)]
#[cfg(feature = "rand_nobias")]
pub(crate) fn $fname(&self, n: $typ) -> $typ {
let mut v = self.$next_random();
let mut res = $mul(v, n);
let mut low = v.wrapping_mul(n);
if low < n {
let t = n.wrapping_neg() % n;
while low < t {
v = self.$next_random();
res = $mul(v, n);
low = v.wrapping_mul(n);
}
}
res
}
#[inline(always)]
#[allow(unused)]
#[cfg(not(feature = "rand_nobias"))]
pub(crate) fn $fname(&self, n: $typ) -> $typ {
$mul(self.$next_random(), n)
}
};
}
macro_rules! size_impl {
($fname:tt,$typ:tt) => {
#[inline(always)]
#[allow(unused)]
fn $fname(&self) -> $typ {
self.next_u64() as $typ
}
};
}
macro_rules! range_impl {
($typ:tt, $unsigned_typ:tt, $next_random:tt, $mod:tt) => {
#[doc = "Returns a random `"]
#[doc = stringify!($typ)]
#[doc = "` in the given range."]
#[inline(always)]
pub fn $typ(&self, range: impl RangeBounds<$typ>) -> $typ {
let panic_invalid_range = || {
panic!(
"invalid range: {:?}..{:?}",
range.start_bound(),
range.end_bound()
)
};
let lo = match range.start_bound() {
Bound::Unbounded => std::$typ::MIN,
Bound::Included(&x) => x,
Bound::Excluded(&x) => x.checked_add(1).unwrap_or_else(panic_invalid_range),
};
let hi = match range.end_bound() {
Bound::Unbounded => std::$typ::MAX,
Bound::Included(&x) => x,
Bound::Excluded(&x) => x.checked_sub(1).unwrap_or_else(panic_invalid_range),
};
if lo > hi {
panic_invalid_range();
}
if lo == std::$typ::MIN && hi == std::$typ::MAX {
self.$next_random() as $typ
} else {
let len = hi.wrapping_sub(lo).wrapping_add(1);
lo.wrapping_add(self.$mod(len as $unsigned_typ as _) as $typ)
}
}
};
}
#[derive(Debug, PartialEq, Eq)]
pub struct WyRng(Cell<u64>);
impl WyRng {
size_impl!(next_u32, u32);
size_impl!(next_i32, i32);
size_impl!(next_i64, i64);
size_impl!(next_usize, usize);
size_impl!(next_isize, isize);
mod_impl!(next_u32_mod, u32, next_u32, mul_u32);
mod_impl!(next_u64_mod, u64, next_u64, mul_u64);
range_impl!(u32, u32, next_u64, next_u64_mod);
range_impl!(i32, u32, next_u64, next_u64_mod);
range_impl!(u64, u64, next_u64, next_u64_mod);
range_impl!(i64, u64, next_u64, next_u64_mod);
range_impl!(usize, usize, next_u64, next_u64_mod);
range_impl!(isize, usize, next_u64, next_u64_mod);
#[inline]
#[allow(unused)]
pub fn new() -> Self {
WyRng::from_seed_u64(
THREAD_WYRAND
.try_with(|rng| rng.next_u64())
.unwrap_or(WYP[3]),
)
}
pub fn seed(&self) -> u64 {
self.0.get()
}
#[inline]
#[allow(unused)]
pub fn from_seed_u64(seed: u64) -> Self {
let rng = WyRng(Cell::new(seed));
rng
}
#[inline(always)]
#[allow(unused)]
fn next_u64(&self) -> u64 {
let v = self.0.get().wrapping_add(WYP[0]);
self.0.set(v);
let t = (v as u128).wrapping_mul((v ^ WYP[1]) as u128);
(t as u64) ^ (t >> 64) as u64
}
#[inline(always)]
pub fn f64(&self) -> f64 {
((self.next_u64() >> 11) as f64).div(((1 as u64) << 53) as f64)
}
#[inline(always)]
pub fn f32(&self) -> f32 {
self.f64() as f32
}
#[inline(always)]
#[allow(unused)]
fn next_u128(&self) -> u128 {
(self.next_u64() as u128) << 64 + (self.next_u64() as u128)
}
}
thread_local! {
pub(crate) static THREAD_WYRAND: WyRng = WyRng::from_seed_u64({
let mut hasher = DefaultHasher::new();
std::time::Instant::now().hash(&mut hasher);
std::thread::current().id().hash(&mut hasher);
let wyrand = WyRng::from_seed_u64(hasher.finish());
wyrand.next_u64()
});
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use std::ops::Mul;
use super::WyRng;
const TEST_SEED: u64 = 123;
#[test]
fn simple_test() {
let r = WyRng::from_seed_u64(TEST_SEED);
let mut m = HashMap::new();
let times = 1000000;
let mod_num = 100;
for _ in 0..times {
let rad = r.next_u64_mod(mod_num);
let pv = m.get(&rad);
match pv {
Some(v) => {
m.insert(rad, *v + 1);
}
_ => {
m.insert(rad, 1);
}
}
}
let avg_count = times / mod_num;
let max_thres = (avg_count as f64 * 0.1) as u64;
let num_range = avg_count - max_thres..avg_count + max_thres;
for (k, v) in m.iter() {
assert!(
num_range.contains(v),
"({},{}) not in range({}..{}).",
k,
v,
num_range.start,
num_range.end
)
}
}
#[test]
fn range_test() {
let r = WyRng::from_seed_u64(TEST_SEED);
let mut m = HashMap::new();
let test_range = -30..70;
for _ in 0..10000 {
m.insert(r.i32(test_range.clone()), 1);
}
for i in test_range.clone() {
match m.get(&i) {
Some(_) => {}
None => {
assert!(false, "{} doesn't exist.", i)
}
}
}
}
#[test]
fn float_test() {
let r = WyRng::from_seed_u64(TEST_SEED);
let mut m = HashMap::new();
for _ in 0..100 {
let random = r.f32().mul(10.0 as f32) as i32;
m.insert(random, 1);
}
assert!(m.len() == 10)
}
}