use crate::{
ConstInit, Infallible, InfallibleResult, RandQualities, RandSeedable, RandTry, Slice, slice,
};
#[doc = crate::_tags!(rand)]
#[doc = crate::_doc_meta!{location("num/prob/rand")}]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SplitMix64 {
state: u64,
}
impl Default for SplitMix64 {
fn default() -> Self {
Self::INIT
}
}
impl ConstInit for SplitMix64 {
const INIT: Self = Self::new(Self::DEFAULT_SEED);
}
impl SplitMix64 {
#[doc(hidden)]
pub const DEFAULT_SEED: u64 = 0xDEFA_0017_DEFA_0017;
pub const GOLDEN_GAMMA: u64 = 0x9E37_79B9_7F4A_7C15;
pub const MIX_A: u64 = 0xBF58_476D_1CE4_E5B9;
pub const MIX_B: u64 = 0x94D0_49BB_1331_11EB;
#[must_use]
#[inline(always)]
pub const fn new(seed: u64) -> Self {
Self { state: seed }
}
#[must_use]
#[inline(always)]
pub const fn mix64(mut x: u64) -> u64 {
x = (x ^ (x >> 30)).wrapping_mul(Self::MIX_A);
x = (x ^ (x >> 27)).wrapping_mul(Self::MIX_B);
x ^ (x >> 31)
}
#[must_use]
#[inline(always)]
pub const fn next_u64(&mut self) -> u64 {
self.state = self.state.wrapping_add(Self::GOLDEN_GAMMA);
Self::mix64(self.state)
}
pub const fn fill_bytes(&mut self, buffer: &mut [u8]) {
let mut i = 0;
while i < buffer.len() {
let r = self.next_u64();
let bytes = r.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;
}
}
}
}
#[rustfmt::skip]
impl RandTry for SplitMix64 {
type Error = Infallible;
const RAND_OUTPUT_BITS: u32 = 64;
const RAND_STATE_BITS: u32 = 64;
const RAND_QUALITIES: RandQualities = RandQualities::PRNG;
#[inline(always)]
fn rand_try_next_u64(&mut self) -> InfallibleResult<u64> {
Ok(self.next_u64())
}
#[inline(always)]
fn rand_try_fill_bytes(&mut self, buffer: &mut [u8]) -> InfallibleResult<()> {
self.fill_bytes(buffer);
Ok(())
}
}
impl RandSeedable for SplitMix64 {
type RandSeed = [u8; 8];
#[inline(always)]
fn rand_from_seed(seed: Self::RandSeed) -> Self {
Self::new(u64::from_le_bytes(seed))
}
}
crate::__impl_dep_rand_core!(SplitMix64);