urng 0.12.0

Universal Random Number Generator
Documentation
use crate::wide::{impl_methods, wide_rotate_left};
use crate::{Rng32, SplitMix32};
use ::wide::{u32x4, u32x8, u32x16};

macro_rules! impl_variants {
    ($size:expr) => {
        ::pastey::paste! {
            #[doc = concat!("Xoroshiro64** producing ", stringify!($size), " values per call via `wide` SIMD vectors.")]
            #[doc = ""]
            #[doc = "Portable-SIMD counterpart of [`crate::rng32::Xoroshiro64Ss`]. A 64-bit state (two"]
            #[doc = "32-bit words) per lane; each `nextu` call returns an array of `u32`, one per lane."]
            #[doc = ""]
            #[doc = "# Example"]
            #[doc = "```"]
            #[doc = concat!("use urng::wide::Xoroshiro64Ssx", stringify!($size), ";")]
            #[doc = ""]
            #[doc = concat!("let mut rng = Xoroshiro64Ssx", stringify!($size), "::new(1);")]
            #[doc = concat!("let v = rng.nextu();")]
            #[doc = concat!("assert_eq!(v.len(), ", stringify!($size), ");")]
            #[doc = "```"]
            #[allow(dead_code)]
            #[repr(C, align(64))]
            pub struct [<Xoroshiro64Ssx $size>] {
                s0: [<u32x $size>],
                s1: [<u32x $size>],
            }

            #[allow(dead_code)]
            impl [<Xoroshiro64Ssx $size>] {
                #[doc = "Creates a new generator, seeding the two state words of every lane from `seed`."]
                pub fn new(seed: u32) -> Self {
                    let mut seedgen = SplitMix32::new(seed);
                    Self {
                        s0: [<u32x $size>]::from([0u32; $size].map(|_| seedgen.nextu())),
                        s1: [<u32x $size>]::from([0u32; $size].map(|_| seedgen.nextu())),
                    }
                }

                #[doc = "Generates the next block of `u32` values, one per SIMD lane."]
                #[doc = ""]
                #[doc = "Applies the Xoroshiro64** scramble: `rotl(s0 * 0x9E3779BB, 5) * 5`."]
                #[inline(always)]
                pub fn nextu(&mut self) -> [u32; $size] {
                    let s0 = self.s0;
                    let mut s1 = self.s1;
                    let result = wide_rotate_left!(32 (s0 * 0x9E3779BBu32), 5) * 5u32;

                    s1 ^= s0;
                    self.s0 = wide_rotate_left!(32 s0, 26) ^ s1 ^ (s1 << 9);
                    self.s1 = wide_rotate_left!(32 s1, 13);

                    bytemuck::cast(result)
                }

                impl_methods!($size, 32);
            }
        }
    };
    ($($size:expr),+ $(,)*) => {
        $(impl_variants!($size);)+
    };
}

impl_variants!(4, 8, 16);

#[cfg(test)]
mod tests {
    use super::*;

    crate::safe_test!(Xoroshiro64Ssx4);
    crate::safe_test!(Xoroshiro64Ssx8);
    crate::safe_test!(Xoroshiro64Ssx16);
}