devela 0.27.0

A development layer of coherence.
Documentation
// devela::num::prob::rand::prng::shift::macros
//
//! Defines [`define_xorshift!`],  ([`xorshift_basis!`]).
//

#[cfg(doc)]
use crate::{XorShift16, XorShift32, XorShift64};

#[doc = crate::_tags!(construction rand)]
/// Constructs a *XorShift* prng with custom bits, basis, triplet and seed.
#[doc = crate::_doc_location!("num/prob/rand")]
///
/// It can construct custom instances of [`XorShift16`], [`XorShift32`] and [`XorShift64`].
///
/// The given `$triplet` is an index for an array of good triples with a maximum of:
/// - 3 for 16-bit,
/// - 80 for 32-bit
/// - 274 for 64-bit
///
/// ## Usage:
/// `xorshift_with![bits: 32, basis: 1, triplet: 40, seed: 5334];`
///
/// Valid argument values:
/// - `$bits`:    `16`, `32` or `64`.
/// - `$basis`:   in range `0..=7`.
/// - `$triplet`: `0..=3` for 16-bit; `0..=80` for 32-bit; `0..=274` for 64-bit.
/// - `$seed`:    any value. If `0` is given the default seed will be used.
///
/// # Panics
/// If the `$basis` is outside range `0..=7`.
//
// The reason for this macro is that is not possible to operate with const-generics,
// so we can't make a method using an INDEX const-generic to index in a const array.
// Also: Inner items do not inherit the generic parameters from the items they are embedded in.
// WAIT: [generic_const_expr](https://github.com/rust-lang/rust/issues/76560)
#[doc(hidden)]
#[macro_export]
#[rustfmt::skip]
#[cfg_attr(nightly_doc, doc(cfg(feature = "rand")))]
macro_rules! _define_xorshift {
    (bits:$bits:literal, basis:$basis:expr, triplet:$triplet:expr, seed:$seed:expr) => {{
        $crate::paste! {
            const T: (u8, u8, u8) = $crate::[<XOROSHIFT_ $bits _TRIPLETS>][{ $triplet }];
                $crate::[<XorShift $bits>]
                    ::<{$basis}, {T.0 as usize}, {T.1 as usize}, {T.2 as usize}>
                    ::new($seed)
        }
    }};
}
#[doc = crate::_tags!(rand)]
#[doc(inline)]
pub use _define_xorshift as define_xorshift;

#[doc = crate::_tags!(construction code rand)]
/// Generates a XORSHIFT sequence using the given operation basis and shift triplet.
#[doc = crate::_doc_location!("num/prob/rand")]
///
/// # Usage:
/// `xorshift_basis![<basis>: (<a>, <b>, <c>) <state>];`
///
/// Notes
/// - The `state` has to be different from 0.
/// - The `basis` has to be a value between 0 and 7.
/// - The `(a, b, c)` triplet has to be a valid one for its bit-size.
/// - When `basis` is a constant the macro is optimized away and has 0 overhead.
///
/// # Panics
/// If the basis is outside range `0..=7`.
//
// - The canonical 32-bit example uses triplet  #40:( 5,17,13) with basis 1.
// - The canonical 64-bit example uses triplet #155:(13, 7,17) with basis 0.
macro_rules! xorshift_basis {
    [$state:ident, $basis:expr, ($a:expr, $b:expr, $c:expr)] => {
        match $basis {
            0 => { $state^=$state << $a; $state^=$state >> $b; $state^=$state << $c; },
            1 => { $state^=$state << $c; $state^=$state >> $b; $state^=$state << $a; },
            2 => { $state^=$state >> $a; $state^=$state << $b; $state^=$state >> $c; },
            3 => { $state^=$state >> $c; $state^=$state << $b; $state^=$state >> $a; },
            4 => { $state^=$state << $a; $state^=$state << $c; $state^=$state >> $b; },
            5 => { $state^=$state << $c; $state^=$state << $a; $state^=$state >> $b; },
            6 => { $state^=$state >> $a; $state^=$state >> $c; $state^=$state << $b; },
            7 => { $state^=$state >> $c; $state^=$state >> $a; $state^=$state << $b; },
            _ => panic!("Error: xorshift $basis must be between 0..=7"),
        }
    };
}
pub(crate) use xorshift_basis;