use crate::{Cast, ConstInit, Own, Slice, slice};
use crate::{Infallible, InfallibleResult, RandQualities, RandSeedable, RandTry};
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_meta!{location("num/prob/rand")}]
#[must_use]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct XorShift128([u32; 4]);
impl Default for XorShift128 {
fn default() -> Self {
Self::INIT
}
}
impl ConstInit for XorShift128 {
const INIT: Self = Self::new_unchecked(Self::DEFAULT_SEED);
}
impl XorShift128 {
#[doc(hidden)]
pub const DEFAULT_SEED: [u32; 4] = [0xDEFA_0017; 4];
#[cold] #[allow(dead_code)] #[rustfmt::skip]
const fn cold_path_default() -> Self { Self::new_unchecked(Self::DEFAULT_SEED) }
}
impl XorShift128 {
pub const fn new(seeds: [u32; 4]) -> Self {
if (seeds[0] | seeds[1] | seeds[2] | seeds[3]) == 0 {
Self::cold_path_default()
} else {
Self([seeds[0], seeds[1], seeds[2], seeds[3]])
}
}
pub const fn new_unchecked(seeds: [u32; 4]) -> Self {
debug_assert![(seeds[0] | seeds[1] | seeds[2] | seeds[3]) != 0, "Seeds must be non-zero"];
Self(seeds)
}
#[must_use]
pub const fn inner_state(self) -> [u32; 4] {
self.0
}
pub const fn from_state(state: [u32; 4]) -> Self {
Self(state)
}
#[must_use]
pub const fn current_u64(&self) -> u64 {
((self.0[0] as u64) << 32) | (self.0[1] as u64)
}
#[must_use]
pub const fn next_u64(&mut self) -> u64 {
let t = self.0[3];
let mut s = self.0[0];
self.0[3] = self.0[2];
self.0[2] = self.0[1];
self.0[1] = s;
s ^= s << 11;
s ^= s >> 8;
self.0[0] = s ^ t ^ (t >> 19);
((self.0[0] as u64) << 32) | (self.0[1] as u64)
}
pub const fn peek_next_state(&self) -> Self {
let mut x = self.0;
let t = x[3];
let mut s = x[0];
x[3] = x[2];
x[2] = x[1];
x[1] = s;
s ^= s << 11;
s ^= s >> 8;
x[0] = s ^ t ^ (t >> 19);
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)
}
pub const fn fill_bytes(&mut self, buffer: &mut [u8]) {
let mut i = 0;
while i < buffer.len() {
let random_u64 = self.next_u64();
let bytes = random_u64.to_le_bytes();
let remaining = buffer.len() - i;
if remaining >= 8 {
Slice::copy(slice!(mut buffer, i, ..i + 8), &bytes);
i += 8;
} else {
Slice::copy(slice!(mut buffer, i, ..), slice!(&bytes, ..remaining));
break;
}
}
}
}
impl XorShift128 {
pub const fn new1_u128(seed: u128) -> Self {
Self::new(Cast(seed).into_u32_le())
}
pub const fn new2_u64(seeds: [u64; 2]) -> Self {
let [x, y] = Cast(seeds[0]).into_u32_le();
let [z, a] = Cast(seeds[1]).into_u32_le();
Self::new([x, y, z, a])
}
pub const fn new4_u32(seeds: [u32; 4]) -> Self {
Self::new(seeds)
}
pub const fn new8_u16(seeds: [u16; 8]) -> Self {
Self::new([
Cast::<u32>::from_u16_le([seeds[0], seeds[1]]),
Cast::<u32>::from_u16_le([seeds[2], seeds[3]]),
Cast::<u32>::from_u16_le([seeds[4], seeds[5]]),
Cast::<u32>::from_u16_le([seeds[6], seeds[7]]),
])
}
pub const fn new16_u8(seeds: [u8; 16]) -> Self {
Self::new([
u32::from_le_bytes([seeds[0], seeds[1], seeds[2], seeds[3]]),
u32::from_le_bytes([seeds[4], seeds[5], seeds[6], seeds[7]]),
u32::from_le_bytes([seeds[8], seeds[9], seeds[10], seeds[11]]),
u32::from_le_bytes([seeds[12], seeds[13], seeds[14], seeds[15]]),
])
}
}
crate::items! {
impl RandTry for XorShift128 {
type Error = Infallible;
const RAND_OUTPUT_BITS: u32 = 64;
const RAND_STATE_BITS: u32 = 128;
const RAND_QUALITIES: RandQualities = RandQualities::WEAK_PRNG;
fn rand_try_next_u64(&mut self) -> InfallibleResult<u64> { Ok(self.next_u64()) }
fn rand_try_fill_bytes(&mut self, buffer: &mut [u8]) -> InfallibleResult<()> {
self.fill_bytes(buffer); Ok(())
}
}
impl RandSeedable for XorShift128 {
type RandSeed = [u8; 16];
#[inline(always)]
fn rand_from_seed(seed: Self::RandSeed) -> Self { Self::new16_u8(seed) }
}
}
crate::__impl_dep_rand_core!(XorShift128);