urng 0.12.0

Universal Random Number Generator
Documentation
use crate::wide::{SplitMix32x4, SplitMix32x8, SplitMix32x16, impl_methods, wide_rotate_left};
use ::wide::{u32x4, u32x8, u32x16};

macro_rules! impl_variants {
    ($size:expr) => {
        ::pastey::paste! {
            #[doc = concat!("JSF (Jenkins Small Fast) 32-bit RNG producing ", stringify!($size), " values per call via `wide` SIMD vectors.")]
            #[doc = ""]
            #[doc = "Portable-SIMD counterpart of [`crate::rng32::Jsf32`]. Each `nextu` call returns an"]
            #[doc = "array of `u32`; `nextf`, `randi` and `randf` return the same number of `f32`/`i32`"]
            #[doc = "values in parallel."]
            #[doc = ""]
            #[doc = "# Example"]
            #[doc = "```"]
            #[doc = concat!("use urng::wide::Jsf32x", stringify!($size), ";")]
            #[doc = ""]
            #[doc = concat!("let mut rng = Jsf32x", stringify!($size), "::new(12345);")]
            #[doc = concat!("let v = rng.nextu();")]
            #[doc = concat!("assert_eq!(v.len(), ", stringify!($size), ");")]
            #[doc = "```"]
            #[repr(C, align(64))]
            pub struct [<Jsf32x $size>] {
                pub(crate) a: [<u32x $size>],
                pub(crate) b: [<u32x $size>],
                pub(crate) c: [<u32x $size>],
                pub(crate) d: [<u32x $size>],
            }

            impl [<Jsf32x $size>] {
                #[doc = "Creates a new generator, seeding every SIMD lane from `seed` using a `SplitMix32` stream."]
                pub fn new(seed: u32) -> Self {
                    let mut seedgen = [<SplitMix32x $size>]::new(seed);
                    Self {
                        a: [<u32x $size>]::splat(0xf1ea5eed),
                        b: bytemuck::cast(seedgen.nextu()),
                        c: bytemuck::cast(seedgen.nextu()),
                        d: bytemuck::cast(seedgen.nextu()),
                    }
                }

                #[doc = "Generates the next block of `u32` values, one per SIMD lane."]
                #[doc = ""]
                #[doc = "Applies one round of the JSF scramble and returns the rotated `d` word from each lane."]
                #[inline(always)]
                pub fn nextu(&mut self) -> [u32; $size] {
                    let e = self.a - wide_rotate_left!(32 self.b, 27);
                    self.a = self.b ^ wide_rotate_left!(32 self.c, 17);
                    self.b = self.c + self.d;
                    self.c = self.d + e;
                    self.d = e + self.a;
                    bytemuck::cast(self.d)
                }

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

impl_variants!(4, 8, 16);

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

    crate::safe_test!(Jsf32x4);
    crate::safe_test!(Jsf32x8);
    crate::safe_test!(Jsf32x16);
}