use crate::chacha::{StdRng, Uniform};
use std::time::{SystemTime, UNIX_EPOCH};
fn uniform_usize_inclusive(rng: &mut StdRng, max: usize) -> usize {
let range = (max as u64).wrapping_add(1);
if range == 0 {
return rng.next_u64() as usize;
}
let ints_to_reject = (u64::MAX - range + 1) % range;
let zone = u64::MAX - ints_to_reject;
loop {
let v = rng.next_u64();
let m = (v as u128) * (range as u128);
let (hi, lo) = ((m >> 64) as u64, m as u64);
if lo <= zone {
return hi as usize;
}
}
}
fn gen_index(rng: &mut StdRng, ubound: usize) -> usize {
if ubound <= u32::MAX as usize {
let range = ubound as u32;
let zone = (range << range.leading_zeros()).wrapping_sub(1);
loop {
let v = rng.next_u32();
let m = (v as u64) * (range as u64);
let (hi, lo) = ((m >> 32) as u32, m as u32);
if lo <= zone {
return hi as usize;
}
}
} else {
let range = ubound as u64;
let zone = (range << range.leading_zeros()).wrapping_sub(1);
loop {
let v = rng.next_u64();
let m = (v as u128) * (range as u128);
let (hi, lo) = ((m >> 64) as u64, m as u64);
if lo <= zone {
return hi as usize;
}
}
}
}
fn clock_seed() -> u64 {
SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs()
}
pub struct CustomRNG {
gen: StdRng,
}
impl CustomRNG {
pub fn new(seed: Option<u64>) -> Self {
CustomRNG { gen: StdRng::seed_from_u64(seed.unwrap_or_else(clock_seed)) }
}
pub fn random_double(&mut self) -> f64 {
Uniform::new(0.0, 1.0).sample(&mut self.gen)
}
pub fn random_int(&mut self, max_int: usize) -> usize {
uniform_usize_inclusive(&mut self.gen, max_int)
}
}
#[derive(Clone, Debug)]
pub struct RandomListShuffle<T> {
generator: StdRng,
_marker: std::marker::PhantomData<T>,
}
impl Default for RandomListShuffle<usize> {
fn default() -> Self {
Self::new()
}
}
impl<T> RandomListShuffle<T> {
pub fn new() -> Self {
RandomListShuffle {
generator: StdRng::seed_from_u64(crate::mwpf::shim::random_u64()),
_marker: std::marker::PhantomData,
}
}
pub fn with_seed(seed: Option<u64>) -> Self {
RandomListShuffle {
generator: StdRng::seed_from_u64(seed.unwrap_or_else(clock_seed)),
_marker: std::marker::PhantomData,
}
}
pub fn seed(&mut self, seed: u64) {
self.generator = StdRng::seed_from_u64(seed);
}
pub fn shuffle(&mut self, data: &mut Vec<T>) {
for i in (1..data.len()).rev() {
let j = gen_index(&mut self.generator, i + 1);
data.swap(i, j);
}
}
}