use super::*;
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(transparent)]
pub struct Xoshiro256 {
state: [u64; 4],
}
impl Xoshiro256 {
#[inline]
pub fn new() -> Random<Xoshiro256> {
let state = util::getrandom();
Random::wrap(Xoshiro256 { state })
}
#[inline]
pub fn from_rng<R: Rng + ?Sized>(rand: &mut Random<R>) -> Random<Xoshiro256> {
let state = rand.random_bytes();
Random::wrap(Xoshiro256 { state })
}
pub fn from_seed(seed: u64) -> Random<Xoshiro256> {
let mut master = SplitMix64::from_seed(seed);
let state = [master.next_u64(), master.next_u64(), master.next_u64(), master.next_u64()];
Random::wrap(Xoshiro256 { state })
}
}
impl Rng for Xoshiro256 {
#[inline]
fn next_u32(&mut self) -> u32 {
(next_plus(&mut self.state) >> 32) as u32
}
#[inline]
fn next_u64(&mut self) -> u64 {
next_plusplus(&mut self.state)
}
#[inline]
fn next_f32(&mut self) -> f32 {
util::rng_f32((next_plus(&mut self.state) >> 32) as u32)
}
#[inline]
fn next_f64(&mut self) -> f64 {
util::rng_f64(next_plus(&mut self.state))
}
#[inline(never)]
fn fill_bytes(&mut self, buf: &mut [MaybeUninit<u8>]) {
let mut rng = self.clone();
util::rng_fill_bytes(&mut rng, buf);
*self = rng;
}
#[inline(never)]
fn jump(&mut self) {
jump(&mut self.state)
}
}
#[test]
fn fill_bytes() {
crate::rng::tests::check_fill_bytes(&mut Xoshiro256::new());
}
#[cfg(feature = "serde")]
#[test]
fn serde() {
tests::check_serde_initial_state(Xoshiro256::new());
tests::check_serde_middle_state(Xoshiro256::new());
}
#[inline]
fn advance(s: &mut [u64; 4]) {
let t = s[1] << 17;
s[2] ^= s[0];
s[3] ^= s[1];
s[1] ^= s[2];
s[0] ^= s[3];
s[2] ^= t;
s[3] = s[3].rotate_left(45);
}
#[inline]
fn next_plusplus(s: &mut [u64; 4]) -> u64 {
let result = u64::wrapping_add(u64::wrapping_add(s[0], s[3]).rotate_left(23), s[0]);
advance(s);
return result;
}
#[inline]
fn next_plus(s: &mut [u64; 4]) -> u64 {
let result = u64::wrapping_add(s[0], s[3]);
advance(s);
return result;
}
#[inline(always)]
fn jump(s: &mut [u64; 4]) {
static JUMP: [u64; 4] = [0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c];
let mut s0 = 0;
let mut s1 = 0;
let mut s2 = 0;
let mut s3 = 0;
for i in 0..4 {
for b in 0..64 {
if (JUMP[i] & (1 << b)) != 0 {
s0 ^= s[0];
s1 ^= s[1];
s2 ^= s[2];
s3 ^= s[3];
}
advance(s);
}
}
s[0] = s0;
s[1] = s1;
s[2] = s2;
s[3] = s3;
}