urng 0.10.0

Universal Random Number Generator
Documentation
use ::wide::{u32x4, u32x8, u32x16};

use crate::wide::impl_methods;

macro_rules! impl_variants {
    ($size:expr) => {
        paste::paste! {
            #[doc = concat!("SplitMix32 producing ", stringify!($size), " values per call via `wide` SIMD vectors.")]
            #[doc = ""]
            #[doc = "Portable-SIMD counterpart of [`crate::rng32::SplitMix32`]. A fast finalizer-based"]
            #[doc = "generator, commonly used to seed the other `wide` generators. Each `nextu` call"]
            #[doc = "returns an array of `u32`, one per lane."]
            #[doc = ""]
            #[doc = "# Example"]
            #[doc = "```"]
            #[doc = concat!("use urng::wide::SplitMix32x", stringify!($size), ";")]
            #[doc = ""]
            #[doc = concat!("let mut rng = SplitMix32x", 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 [<SplitMix32x $size>] {
                state: [<u32x $size>],
            }

            #[allow(dead_code)]
            impl [<SplitMix32x $size>] {
                #[doc = "Creates a new generator, seeding every lane from `seed | 1` and advancing by the golden ratio."]
                pub fn new(seed: u32) -> Self {
                    let mut state = [0u32; $size];
                    state.iter_mut().fold(seed | 1, |s, x| {
                        *x = s;
                        s.wrapping_add(0x9E3779B9)
                    });

                    Self {
                        state: [<u32x $size>]::from(state),
                    }
                }

                #[inline(always)]
                pub(crate) fn compute(state: [<u32x $size>]) -> [<u32x $size>] {
                    let mut z = state;
                    z = (z ^ (z >> 16)) * [<u32x $size>]::splat(0x85EBCA6B);
                    z = (z ^ (z >> 13)) * [<u32x $size>]::splat(0xC2B2AE35);
                    z ^ (z >> 16)
                }

                #[doc = "Generates the next block of `u32` values, one per SIMD lane."]
                #[doc = ""]
                #[doc = "Advances the shared counter by `0x9E3779B9` and applies the two-multiply finalizer."]
                #[inline(always)]
                pub fn nextu(&mut self) -> [u32; $size] {
                    self.state += [<u32x $size>]::splat(0x9E3779B9);
                    let z = Self::compute(self.state);
                    bytemuck::cast(z)
                }

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

impl_variants!(4, 8, 16);

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

    crate::safe_test!(SplitMix32x4);
    crate::safe_test!(SplitMix32x8);
    crate::safe_test!(SplitMix32x16);
}