urng 0.4.6

Universal Random Number Generator
use crate::{_internal::FSCALE32, wide::SplitMix32x4};
use ::wide::u32x8;

#[repr(C, align(64))]
pub struct Sfc32x8 {
    a: u32x8,
    b: u32x8,
    c: u32x8,
    counter: u32x8,
}

impl Sfc32x8 {
    #[target_feature(enable = "avx2")]
    pub fn new(seed: u32) -> Self {
        let mut seedgen = SplitMix32x4::new(seed);
        let mut a = [0u32; 8];
        let mut b = [0u32; 8];
        let mut c = [0u32; 8];
        let mut counter = [0u32; 8];
        for i in 0..a.len() {
            [a[i], b[i], c[i], counter[i]] = seedgen.nextu();
        }

        Self {
            a: u32x8::from(a),
            b: u32x8::from(b),
            c: u32x8::from(c),
            counter: u32x8::from(counter),
        }
    }

    #[target_feature(enable = "avx2")]
    #[inline]
    pub(crate) fn compute(
        tmp: u32x8,
        a: &mut u32x8,
        b: &mut u32x8,
        c: &mut u32x8,
        counter: &mut u32x8,
    ) -> u32x8 {
        *counter += u32x8::splat(1);
        *a = *b ^ (*b >> 9);
        *b = *c + (*c << 3);
        *c = (*c << 21) | (*c >> 11);
        *c += tmp;
        tmp
    }

    #[target_feature(enable = "avx2")]
    #[inline]
    pub fn nextu(&mut self) -> [u32; 8] {
        let tmp = self.a + self.b + self.counter;
        let result = Self::compute(
            tmp,
            &mut self.a,
            &mut self.b,
            &mut self.c,
            &mut self.counter,
        );
        bytemuck::cast(result)
    }

    #[target_feature(enable = "avx2")]
    #[inline]
    pub fn nextf(&mut self) -> [f32; 8] {
        self.nextu().map(|x| (x as f32) * FSCALE32)
    }
}

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

    unsafe_test!(Sfc32x8);
}