use crate::{Cast, ConstInit, Own, Rand};
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_location!("num/prob/rand")]
#[must_use]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct XorShift128p([u64; 2]);
impl Default for XorShift128p {
fn default() -> Self {
Self::INIT
}
}
impl ConstInit for XorShift128p {
const INIT: Self = Self::new_unchecked(Self::DEFAULT_SEED);
}
impl XorShift128p {
#[doc(hidden)]
pub const DEFAULT_SEED: [u64; 2] = [0xDEFA_0017_DEFA_0017; 2];
#[cold] #[allow(dead_code)] #[rustfmt::skip]
const fn cold_path_default() -> Self { Self::new_unchecked(Self::DEFAULT_SEED) }
}
impl XorShift128p {
pub const fn new(seeds: [u64; 2]) -> Self {
if (seeds[0] | seeds[1]) == 0 { Self::cold_path_default() } else { Self(seeds) }
}
pub const fn new_unchecked(seeds: [u64; 2]) -> Self {
debug_assert![(seeds[0] | seeds[1]) != 0, "Seeds must be non-zero"];
Self(seeds)
}
#[inline(never)]
pub fn from_stack() -> Self {
let (a, b) = (0, 0);
let seed: [u64; 2] = [&a as *const _ as u64, &b as *const _ as u64];
Self::new_unchecked(seed)
}
#[must_use]
pub const fn inner_state(self) -> [u64; 2] {
self.0
}
pub const fn from_state(state: [u64; 2]) -> Self {
Self(state)
}
#[must_use]
pub const fn current_u64(&self) -> u64 {
self.0[0].wrapping_add(self.0[1])
}
#[must_use]
pub const fn next_u64(&mut self) -> u64 {
let [s0, mut s1] = [self.0[0], self.0[1]];
let result = s0.wrapping_add(s1);
s1 ^= s0;
self.0[0] = s0.rotate_left(55) ^ s1 ^ (s1 << 14); self.0[1] = s1.rotate_left(36);
result
}
pub const fn peek_next_state(&self) -> Self {
let mut x = self.0;
let [s0, mut s1] = [x[0], x[1]];
s1 ^= s0;
x[0] = s0.rotate_left(55) ^ s1 ^ (s1 << 14); x[1] = s1.rotate_left(36);
Self(x)
}
pub const fn own_next_u64(self) -> Own<Self, u64> {
let s = self.peek_next_state();
let v = s.current_u64();
Own::new(s, v)
}
}
impl XorShift128p {
pub const fn new1_u128(seed: u128) -> Self {
Self::new(Cast(seed).into_u64_le())
}
pub const fn new2_u64(seeds: [u64; 2]) -> Self {
Self::new(seeds)
}
pub const fn new4_u32(seeds: [u32; 4]) -> Self {
Self::new([
Cast::<u64>::from_u32_le([seeds[0], seeds[1]]),
Cast::<u64>::from_u32_le([seeds[2], seeds[3]]),
])
}
pub const fn new8_u16(seeds: [u16; 8]) -> Self {
Self::new([
Cast::<u64>::from_u16_le([seeds[0], seeds[1], seeds[2], seeds[3]]),
Cast::<u64>::from_u16_le([seeds[4], seeds[5], seeds[6], seeds[7]]),
])
}
pub const fn new16_u8(seeds: [u8; 16]) -> Self {
let s = seeds;
Self::new([
u64::from_le_bytes([s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]]),
u64::from_le_bytes([s[8], s[9], s[10], s[11], s[12], s[13], s[14], s[15]]),
])
}
}
impl Rand for XorShift128p {
const RAND_OUTPUT_BITS: u32 = 64;
const RAND_STATE_BITS: u32 = 128;
fn rand_next_u32(&mut self) -> u32 {
self.next_u64() as u32
}
fn rand_next_u64(&mut self) -> u64 {
self.next_u64()
}
fn rand_fill_bytes(&mut self, dst: &mut [u8]) {
let mut i = 0;
while i < dst.len() {
let random_u64 = self.next_u64();
let bytes = random_u64.to_le_bytes();
let remaining = dst.len() - i;
if remaining >= 8 {
dst[i..i + 8].copy_from_slice(&bytes);
i += 8;
} else {
dst[i..].copy_from_slice(&bytes[..remaining]);
break;
}
}
}
}
#[cfg(feature = "dep_rand_core")]
#[cfg_attr(nightly_doc, doc(cfg(feature = "dep_rand_core")))]
mod impl_rand {
use super::{Rand, XorShift128p};
use crate::_dep::rand_core::{SeedableRng, TryRng};
impl TryRng for XorShift128p {
type Error = crate::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
Ok(self.rand_next_u32())
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
Ok(self.rand_next_u64())
}
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
self.rand_fill_bytes(dst);
Ok(())
}
}
impl SeedableRng for XorShift128p {
type Seed = [u8; 16];
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u64s = [0u64; 2];
if seed == [0; 16] {
Self::cold_path_default()
} else {
for i in 0..2 {
seed_u64s[i] = u64::from_le_bytes([
seed[i * 8],
seed[i * 8 + 1],
seed[i * 8 + 2],
seed[i * 8 + 3],
seed[i * 8 + 4],
seed[i * 8 + 5],
seed[i * 8 + 6],
seed[i * 8 + 7],
]);
}
Self::new_unchecked(seed_u64s)
}
}
}
}