use core::{convert::Infallible, fmt};
use rand_core::{SeedableRng, TryRng, utils};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
const MULTIPLIER: u64 = 6364136223846793005;
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Lcg64Xsh32 {
state: u64,
increment: u64,
}
pub type Pcg32 = Lcg64Xsh32;
impl Lcg64Xsh32 {
#[inline]
pub fn advance(&mut self, delta: u64) {
let mut acc_mult: u64 = 1;
let mut acc_plus: u64 = 0;
let mut cur_mult = MULTIPLIER;
let mut cur_plus = self.increment;
let mut mdelta = delta;
while mdelta > 0 {
if (mdelta & 1) != 0 {
acc_mult = acc_mult.wrapping_mul(cur_mult);
acc_plus = acc_plus.wrapping_mul(cur_mult).wrapping_add(cur_plus);
}
cur_plus = cur_mult.wrapping_add(1).wrapping_mul(cur_plus);
cur_mult = cur_mult.wrapping_mul(cur_mult);
mdelta /= 2;
}
self.state = acc_mult.wrapping_mul(self.state).wrapping_add(acc_plus);
}
pub fn new(state: u64, stream: u64) -> Self {
let increment = (stream << 1) | 1;
Lcg64Xsh32::from_state_incr(state, increment)
}
#[inline]
fn from_state_incr(state: u64, increment: u64) -> Self {
let mut pcg = Lcg64Xsh32 { state, increment };
pcg.state = pcg.state.wrapping_add(pcg.increment);
pcg.step();
pcg
}
#[inline]
fn step(&mut self) {
self.state = self
.state
.wrapping_mul(MULTIPLIER)
.wrapping_add(self.increment);
}
}
crate::macros::impl_state_stream!(Lcg64Xsh32, u64);
impl fmt::Debug for Lcg64Xsh32 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Lcg64Xsh32 {{}}")
}
}
impl SeedableRng for Lcg64Xsh32 {
type Seed = [u8; 16];
fn from_seed(seed: Self::Seed) -> Self {
let seed_u64: [u64; 2] = utils::read_words(&seed);
Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1)
}
}
impl TryRng for Lcg64Xsh32 {
type Error = Infallible;
#[inline]
fn try_next_u32(&mut self) -> Result<u32, Infallible> {
let state = self.state;
self.step();
const ROTATE: u32 = 59; const XSHIFT: u32 = 18; const SPARE: u32 = 27;
let rot = (state >> ROTATE) as u32;
let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32;
Ok(xsh.rotate_right(rot))
}
#[inline]
fn try_next_u64(&mut self) -> Result<u64, Infallible> {
utils::next_u64_via_u32(self)
}
#[inline]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Infallible> {
utils::fill_bytes_via_next_word(dest, || self.try_next_u32());
Ok(())
}
}