use crate::{Cast, ConstInit, Own, Rand, xorshift_basis};
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_location!("num/prob/rand")]
#[must_use]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct XorShift16<
const BASIS: usize = 0,
const A: usize = 7,
const B: usize = 9,
const C: usize = 8,
>(u16);
impl Default for XorShift16 {
fn default() -> Self {
Self::INIT
}
}
impl ConstInit for XorShift16 {
const INIT: Self = Self::new_unchecked(Self::DEFAULT_SEED);
}
impl<const BASIS: usize, const A: usize, const B: usize, const C: usize>
XorShift16<BASIS, A, B, C>
{
#[doc(hidden)]
pub const DEFAULT_SEED: u16 = 0xDEFA;
#[cold] #[allow(dead_code)] #[rustfmt::skip]
const fn cold_path_default() -> Self { Self::new_unchecked(Self::DEFAULT_SEED) }
}
impl<const BASIS: usize, const A: usize, const B: usize, const C: usize>
XorShift16<BASIS, A, B, C>
{
pub const fn new(seed: u16) -> Self {
if seed == 0 { Self::cold_path_default() } else { Self(seed) }
}
pub const fn new_unchecked(seed: u16) -> Self {
debug_assert![seed != 0, "Seed must be non-zero"];
Self(seed)
}
#[must_use]
pub const fn inner_state(self) -> u16 {
self.0
}
pub const fn from_state(state: u16) -> Self {
Self(state)
}
#[must_use]
pub const fn current_u16(&self) -> u16 {
self.0
}
#[must_use]
pub const fn next_u16(&mut self) -> u16 {
let mut x = self.0;
xorshift_basis!(x, BASIS, (A, B, C));
self.0 = x;
x
}
pub const fn peek_next_state(&self) -> Self {
let mut x = self.0;
xorshift_basis!(x, BASIS, (A, B, C));
Self(x)
}
pub const fn own_next_u16(self) -> Own<Self, u16> {
let s = self.peek_next_state();
let v = s.current_u16();
Own::new(s, v)
}
}
impl<const BASIS: usize, const A: usize, const B: usize, const C: usize>
XorShift16<BASIS, A, B, C>
{
pub const fn new1_u16(seed: u16) -> Self {
Self::new(seed)
}
pub const fn new2_u8(seeds: [u8; 2]) -> Self {
Self::new(u16::from_le_bytes(seeds))
}
}
impl<const BASIS: usize, const A: usize, const B: usize, const C: usize> Rand
for XorShift16<BASIS, A, B, C>
{
const RAND_OUTPUT_BITS: u32 = 16;
const RAND_STATE_BITS: u32 = 16;
fn rand_next_u32(&mut self) -> u32 {
Cast::<u32>::from_u16_le([self.next_u16(), self.next_u16()])
}
fn rand_next_u64(&mut self) -> u64 {
Cast::<u64>::from_u16_le([
self.next_u16(),
self.next_u16(),
self.next_u16(),
self.next_u16(),
])
}
fn rand_fill_bytes(&mut self, dest: &mut [u8]) {
let mut i = 0;
while i < dest.len() {
let random_u16 = self.next_u16();
let bytes = random_u16.to_le_bytes();
let remaining = dest.len() - i;
if remaining >= 2 {
dest[i] = bytes[0];
dest[i + 1] = bytes[1];
i += 2;
} else {
dest[i] = bytes[0];
i += 1;
}
}
}
}
#[cfg(feature = "dep_rand_core")]
#[cfg_attr(nightly_doc, doc(cfg(feature = "dep_rand_core")))]
mod impl_rand {
use crate::_dep::rand_core::{SeedableRng, TryRng};
use crate::{Rand, XorShift16};
impl<const BASIS: usize, const A: usize, const B: usize, const C: usize> TryRng
for XorShift16<BASIS, A, B, C>
{
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<const BASIS: usize, const A: usize, const B: usize, const C: usize> SeedableRng
for XorShift16<BASIS, A, B, C>
{
type Seed = [u8; 2];
fn from_seed(seed: Self::Seed) -> Self {
if seed == [0; 2] {
Self::cold_path_default()
} else {
Self::new_unchecked(u16::from_le_bytes(seed))
}
}
}
}
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_location!("num/prob/rand")]
#[doc(hidden)]
#[rustfmt::skip]
#[allow(dead_code)]
pub const XOROSHIFT_16_TRIPLETS: [(u8, u8, u8); 4] = [
(6, 7, 13), (7, 9, 8), (7, 9, 13), (9, 7, 13)
];