blob: 9ee09e288e2fc9532cdf1934da9d3685a73e5aaa [file] [log] [blame]
// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/// Initialize a RNG from a `u64` seed using `SplitMix64`.
macro_rules! from_splitmix {
($seed:expr) => { {
let mut rng = ::SplitMix64::seed_from_u64($seed);
Self::from_rng(&mut rng).unwrap()
} }
}
/// Apply the ** scrambler used by some RNGs from the xoshiro family.
macro_rules! starstar_u64 {
($x:expr) => {
$x.wrapping_mul(5).rotate_left(7).wrapping_mul(9)
}
}
/// Apply the ** scrambler used by some RNGs from the xoshiro family.
macro_rules! starstar_u32 {
($x:expr) => {
$x.wrapping_mul(0x9E3779BB).rotate_left(5).wrapping_mul(5)
}
}
/// Implement a jump function for an RNG from the xoshiro family.
macro_rules! impl_jump {
(u32, $self:expr, [$j0:expr, $j1:expr]) => {
const JUMP: [u32; 2] = [$j0, $j1];
let mut s0 = 0;
let mut s1 = 0;
for j in &JUMP {
for b in 0..32 {
if (j & 1 << b) != 0 {
s0 ^= $self.s0;
s1 ^= $self.s1;
}
$self.next_u32();
}
}
$self.s0 = s0;
$self.s1 = s1;
};
(u64, $self:expr, [$j0:expr, $j1:expr]) => {
const JUMP: [u64; 2] = [$j0, $j1];
let mut s0 = 0;
let mut s1 = 0;
for j in &JUMP {
for b in 0..64 {
if (j & 1 << b) != 0 {
s0 ^= $self.s0;
s1 ^= $self.s1;
}
$self.next_u64();
}
}
$self.s0 = s0;
$self.s1 = s1;
};
(u32, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
const JUMP: [u32; 4] = [$j0, $j1, $j2, $j3];
let mut s0 = 0;
let mut s1 = 0;
let mut s2 = 0;
let mut s3 = 0;
for j in &JUMP {
for b in 0..32 {
if (j & 1 << b) != 0 {
s0 ^= $self.s[0];
s1 ^= $self.s[1];
s2 ^= $self.s[2];
s3 ^= $self.s[3];
}
$self.next_u32();
}
}
$self.s[0] = s0;
$self.s[1] = s1;
$self.s[2] = s2;
$self.s[3] = s3;
};
(u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
const JUMP: [u64; 4] = [$j0, $j1, $j2, $j3];
let mut s0 = 0;
let mut s1 = 0;
let mut s2 = 0;
let mut s3 = 0;
for j in &JUMP {
for b in 0..64 {
if (j & 1 << b) != 0 {
s0 ^= $self.s[0];
s1 ^= $self.s[1];
s2 ^= $self.s[2];
s3 ^= $self.s[3];
}
$self.next_u64();
}
}
$self.s[0] = s0;
$self.s[1] = s1;
$self.s[2] = s2;
$self.s[3] = s3;
};
(u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr,
$j4:expr, $j5:expr, $j6:expr, $j7:expr]) => {
const JUMP: [u64; 8] = [$j0, $j1, $j2, $j3, $j4, $j5, $j6, $j7];
let mut s = [0; 8];
for j in &JUMP {
for b in 0..64 {
if (j & 1 << b) != 0 {
s[0] ^= $self.s[0];
s[1] ^= $self.s[1];
s[2] ^= $self.s[2];
s[3] ^= $self.s[3];
s[4] ^= $self.s[4];
s[5] ^= $self.s[5];
s[6] ^= $self.s[6];
s[7] ^= $self.s[7];
}
$self.next_u64();
}
}
$self.s = s;
};
}
/// Implement the xoroshiro iteration.
macro_rules! impl_xoroshiro_u32 {
($self:expr) => {
$self.s1 ^= $self.s0;
$self.s0 = $self.s0.rotate_left(26) ^ $self.s1 ^ ($self.s1 << 9);
$self.s1 = $self.s1.rotate_left(13);
}
}
/// Implement the xoroshiro iteration.
macro_rules! impl_xoroshiro_u64 {
($self:expr) => {
$self.s1 ^= $self.s0;
$self.s0 = $self.s0.rotate_left(24) ^ $self.s1 ^ ($self.s1 << 16);
$self.s1 = $self.s1.rotate_left(37);
}
}
/// Implement the xoshiro iteration for `u32` output.
macro_rules! impl_xoshiro_u32 {
($self:expr) => {
let t = $self.s[1] << 9;
$self.s[2] ^= $self.s[0];
$self.s[3] ^= $self.s[1];
$self.s[1] ^= $self.s[2];
$self.s[0] ^= $self.s[3];
$self.s[2] ^= t;
$self.s[3] = $self.s[3].rotate_left(11);
}
}
/// Implement the xoshiro iteration for `u64` output.
macro_rules! impl_xoshiro_u64 {
($self:expr) => {
let t = $self.s[1] << 17;
$self.s[2] ^= $self.s[0];
$self.s[3] ^= $self.s[1];
$self.s[1] ^= $self.s[2];
$self.s[0] ^= $self.s[3];
$self.s[2] ^= t;
$self.s[3] = $self.s[3].rotate_left(45);
}
}
/// Implement the large-state xoshiro iteration.
macro_rules! impl_xoshiro_large {
($self:expr) => {
let t = $self.s[1] << 11;
$self.s[2] ^= $self.s[0];
$self.s[5] ^= $self.s[1];
$self.s[1] ^= $self.s[2];
$self.s[7] ^= $self.s[3];
$self.s[3] ^= $self.s[4];
$self.s[4] ^= $self.s[5];
$self.s[0] ^= $self.s[6];
$self.s[6] ^= $self.s[7];
$self.s[6] ^= t;
$self.s[7] = $self.s[7].rotate_left(21);
}
}
/// Map an all-zero seed to a different one.
macro_rules! deal_with_zero_seed {
($seed:expr, $Self:ident) => {
if $seed.iter().all(|&x| x == 0) {
return $Self::seed_from_u64(0);
}
}
}
/// 512-bit seed for a generator.
///
/// This wrapper is necessary, because some traits required for a seed are not
/// implemented on large arrays.
#[derive(Clone)]
pub struct Seed512(pub [u8; 64]);
use core;
impl Seed512 {
/// Return an iterator over the seed.
pub fn iter(&self) -> core::slice::Iter<u8> {
self.0.iter()
}
}
impl core::fmt::Debug for Seed512 {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
self.0[..].fmt(f)
}
}
impl Default for Seed512 {
fn default() -> Seed512 {
Seed512([0; 64])
}
}
impl AsMut<[u8]> for Seed512 {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}