devela/num/rand/xoroshiro/
u128.rs#[cfg(feature = "alloc")]
use crate::Box;
#[cfg(any(feature = "join", feature = "split"))]
use crate::Cast;
use crate::{ConstDefault, Own};
#[cfg(feature = "std")]
use crate::{Hasher, HasherBuild, RandomState};
#[must_use]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Xoroshiro128pp([u32; 4]);
impl Xoroshiro128pp {
#[must_use]
pub const fn new(seed: [u32; 4]) -> Option<Self> {
if (seed[0] | seed[1] | seed[2] | seed[3]) == 0 {
Self::cold_path_result()
} else {
Some(Self(seed))
}
}
pub const fn new_unchecked(seed: [u32; 4]) -> Self {
debug_assert!((seed[0] | seed[1] | seed[2] | seed[3]) != 0, "Seed must be non-zero");
Self(seed)
}
#[inline(never)]
pub fn from_stack() -> Self {
let (a, b, c, d) = (0, 0, 0, 0);
let seed: [u32; 4] = [
&a as *const _ as u32,
&b as *const _ as u32,
&c as *const _ as u32,
&d as *const _ as u32,
];
Self::new_unchecked(seed)
}
#[inline(never)]
#[cfg(feature = "alloc")]
pub fn from_heap() -> Self {
let (a, b, c, d) = (0, Box::new(0), Box::new(0), 0);
let seed: [u32; 4] = [
&a as *const _ as u32,
&b as *const _ as u32,
&c as *const _ as u32,
&d as *const _ as u32,
];
Self::new_unchecked(seed)
}
#[inline(never)]
#[cfg(feature = "std")]
pub fn from_randomstate() -> Self {
let h = RandomState::new();
let (mut hasher1, mut hasher2) = (h.build_hasher(), h.build_hasher());
hasher1.write_u32(Self::DEFAULT_SEED[0]);
hasher2.write_u32(Self::DEFAULT_SEED[0]);
let (hash1, hash2) = (hasher1.finish(), hasher2.finish());
let seed = [(hash1 >> 32) as u32, hash1 as u32, (hash2 >> 32) as u32, hash2 as u32];
Self::new_unchecked(seed)
}
}
impl Xoroshiro128pp {
pub fn jump(&mut self) {
self.jump_with_constant(Self::JUMP);
}
pub fn long_jump(&mut self) {
self.jump_with_constant(Self::LONG_JUMP);
}
#[must_use]
pub fn next_u32(&mut self) -> u32 {
let result = self.current_u32();
let t = self.0[1] << 9;
self.0[2] ^= self.0[0];
self.0[3] ^= self.0[1];
self.0[1] ^= self.0[2];
self.0[0] ^= self.0[3];
self.0[2] ^= t;
self.0[3] = Self::rotl(self.0[3], 11);
result
}
#[must_use]
pub fn next2(&mut self) -> [u32; 2] {
[self.next_u32(), self.next_u32()]
}
#[must_use]
pub fn next4(&mut self) -> [u32; 4] {
[self.next_u32(), self.next_u32(), self.next_u32(), self.next_u32()]
}
#[must_use]
pub fn next4_u8(&mut self) -> [u8; 4] {
self.next_u32().to_ne_bytes()
}
#[must_use]
#[cfg(feature = "split")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "split")))]
pub fn next2_u16(&mut self) -> [u16; 2] {
Cast(self.next_u32()).into_u16_ne()
}
#[must_use]
#[cfg(feature = "join")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "join")))]
pub fn next_u64(&mut self) -> u64 {
Cast::<u64>::from_u32_ne(self.next2())
}
#[must_use]
#[cfg(feature = "join")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "join")))]
pub fn next_u128(&mut self) -> u128 {
Cast::<u128>::from_u32_ne(self.next4())
}
}
impl Xoroshiro128pp {
#[must_use]
pub const fn current_u32(self) -> u32 {
Self::rotl(self.0[0].wrapping_add(self.0[3]), 7).wrapping_add(self.0[0])
}
pub const fn copy_next_state(self) -> Self {
let mut x = self.0;
let t = x[1] << 9;
x[2] ^= x[0];
x[3] ^= x[1];
x[1] ^= x[2];
x[0] ^= x[3];
x[2] ^= t;
x[3] = Self::rotl(x[3], 11);
Self(x)
}
pub const fn own_next_u32(self) -> Own<Self, u32> {
let next_state = self.copy_next_state();
let next_value = next_state.current_u32();
Own::new(next_state, next_value)
}
pub const fn copy_jump(self) -> Self {
self.copy_jump_with_constant(Self::JUMP)
}
pub const fn copy_long_jump(self) -> Self {
self.copy_jump_with_constant(Self::LONG_JUMP)
}
}
impl Xoroshiro128pp {
#[cfg(feature = "split")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "split")))]
pub const fn new1_u128(seed: u128) -> Option<Self> {
Self::new(Cast(seed).into_u32_le())
}
#[cfg(feature = "split")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "split")))]
pub const fn new2_u64(seeds: [u64; 2]) -> Option<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]) -> Option<Self> {
Self::new(seeds)
}
#[cfg(feature = "join")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "join")))]
pub const fn new8_u16(seeds: [u16; 8]) -> Option<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]) -> Option<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]]),
])
}
}
impl Default for Xoroshiro128pp {
fn default() -> Self {
Self::new_unchecked(Self::DEFAULT_SEED)
}
}
impl ConstDefault for Xoroshiro128pp {
const DEFAULT: Self = Self::new_unchecked(Self::DEFAULT_SEED);
}
#[cfg(feature = "dep_rand_core")]
#[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "dep_rand_core")))]
mod impl_rand {
use super::{Cast, Xoroshiro128pp};
use crate::_dep::rand_core::{Error, RngCore, SeedableRng};
impl RngCore for Xoroshiro128pp {
fn next_u32(&mut self) -> u32 {
self.next_u32()
}
fn next_u64(&mut self) -> u64 {
Cast::<u64>::from_u32_le([self.next_u32(), self.next_u32()])
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut i = 0;
while i < dest.len() {
let random_u32 = self.next_u32();
let bytes = random_u32.to_le_bytes();
let remaining = dest.len() - i;
if remaining >= 4 {
dest[i..i + 4].copy_from_slice(&bytes);
i += 4;
} else {
dest[i..].copy_from_slice(&bytes[..remaining]);
break;
}
}
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}
impl SeedableRng for Xoroshiro128pp {
type Seed = [u8; 16];
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u32s = [0u32; 4];
if seed == [0; 16] {
Self::cold_path_default()
} else {
for i in 0..4 {
seed_u32s[i] = u32::from_le_bytes([
seed[i * 4],
seed[i * 4 + 1],
seed[i * 4 + 2],
seed[i * 4 + 3],
]);
}
Self::new_unchecked(seed_u32s)
}
}
}
}
impl Xoroshiro128pp {
const DEFAULT_SEED: [u32; 4] = [0xDEFA_0017; 4];
const JUMP: [u32; 4] = [0x8764_000b, 0xf542_d2d3, 0x6fa0_35c3, 0x77f2_db5b];
const LONG_JUMP: [u32; 4] = [0xb523_952e, 0x0b6f_099f, 0xccf_5a0ef, 0x1c58_0662];
#[cold] #[rustfmt::skip]
const fn cold_path_result() -> Option<Self> { None }
#[cold] #[allow(dead_code)] #[rustfmt::skip]
const fn cold_path_default() -> Self { Self::new_unchecked(Self::DEFAULT_SEED) }
const fn rotl(x: u32, k: i32) -> u32 {
(x << k) | (x >> (32 - k))
}
fn jump_with_constant(&mut self, jump: [u32; 4]) {
let (mut s0, mut s1, mut s2, mut s3) = (0, 0, 0, 0);
for &j in jump.iter() {
for b in 0..32 {
if (j & (1 << b)) != 0 {
s0 ^= self.0[0];
s1 ^= self.0[1];
s2 ^= self.0[2];
s3 ^= self.0[3];
}
let _ = self.next_u32();
}
}
self.0 = [s0, s1, s2, s3];
}
const fn copy_jump_with_constant(self, jump: [u32; 4]) -> Self {
let (mut s0, mut s1, mut s2, mut s3) = (0, 0, 0, 0);
let mut state = self;
let mut i = 0;
while i < jump.len() {
let mut b = 0;
while b < 32 {
if (jump[i] & (1 << b)) != 0 {
s0 ^= state.0[0];
s1 ^= state.0[1];
s2 ^= state.0[2];
s3 ^= state.0[3];
}
state = state.copy_next_state();
b += 1;
}
i += 1;
}
Self([s0, s1, s2, s3])
}
}