#![no_std]
#![allow(clippy::style)]
#![warn(missing_docs)]
use core::sync::atomic::{AtomicU64, Ordering};
pub const KEY: u64 = 0x5d8491e219f6537d;
pub mod distr;
#[inline]
pub const fn rand32(counter: u64, key: u64) -> u32 {
let mut x = counter.wrapping_mul(key);
let y = x;
let z = y.wrapping_add(key);
x = x.wrapping_mul(x).wrapping_add(y);
x = (x >> 32) | (x << 32);
x = x.wrapping_mul(x).wrapping_add(z);
x = (x >> 32) | (x << 32);
x = x.wrapping_mul(x).wrapping_add(y);
x = (x >> 32) | (x << 32);
(x.wrapping_mul(x).wrapping_add(z) >> 32) as u32
}
#[inline]
pub const fn rand64(counter: u64, key: u64) -> u64 {
let mut x = counter.wrapping_mul(key);
let y = x;
let z = y.wrapping_add(key);
x = x.wrapping_mul(x).wrapping_add(y);
x = (x >> 32) | (x << 32);
x = x.wrapping_mul(x).wrapping_add(z);
x = (x >> 32) | (x << 32);
x = x.wrapping_mul(x).wrapping_add(y);
x = (x >> 32) | (x << 32);
x = x.wrapping_mul(x).wrapping_add(z);
let t = x;
x = (x >> 32) | (x << 32);
t ^ (x.wrapping_mul(x).wrapping_add(y) >> 32)
}
pub struct RandRes<T> {
pub counter: u64,
pub value: T
}
#[derive(Debug)]
pub struct Rand {
counter: AtomicU64,
key: u64,
}
impl Rand {
#[inline(always)]
pub const fn new(key: u64) -> Self {
Self::with_counter(0, key)
}
#[inline]
pub const fn with_counter(counter: u64, key: u64) -> Self {
Self {
counter: AtomicU64::new(counter),
key,
}
}
#[inline]
pub fn set_counter(&self, counter: u64) -> u64 {
self.counter.swap(counter, Ordering::AcqRel)
}
#[inline]
pub fn counter(&self) -> u64 {
self.counter.load(Ordering::Acquire)
}
#[inline]
pub fn next_full_u32(&self) -> RandRes<u32> {
let counter = self.counter.fetch_add(1, Ordering::AcqRel);
RandRes {
counter,
value: rand32(counter, self.key)
}
}
#[inline]
pub fn next_u32(&self) -> u32 {
rand32(self.counter.fetch_add(1, Ordering::AcqRel), self.key)
}
#[inline]
pub fn next_u32_up(&self, to: u32) -> u32 {
#[inline(always)]
fn mul_high_u32(a: u32, b: u32) -> u32 {
(((a as u64) * (b as u64)) >> 32) as u32
}
let mut result = self.next_u32();
let mut hi = mul_high_u32(result, to);
let mut lo = result.wrapping_mul(to);
if lo < to {
while lo < (to.wrapping_neg() % to) {
result = self.next_u32();
hi = mul_high_u32(result, to);
lo = result.wrapping_mul(to);
}
}
hi
}
#[inline]
pub fn next_full_u64(&self) -> RandRes<u64> {
let counter = self.counter.fetch_add(1, Ordering::AcqRel);
RandRes {
counter,
value: rand64(counter, self.key)
}
}
#[inline]
pub fn next_u64(&self) -> u64 {
rand64(self.counter.fetch_add(1, Ordering::AcqRel), self.key)
}
#[inline]
pub fn next_u64_up(&self, to: u64) -> u64 {
#[inline(always)]
fn mul_high_u64(a: u64, b: u64) -> u64 {
(((a as u128) * (b as u128)) >> 64) as u64
}
let mut result = self.next_u64();
let mut hi = mul_high_u64(result, to);
let mut lo = result.wrapping_mul(to);
if lo < to {
while lo < (to.wrapping_neg() % to) {
result = self.next_u64();
hi = mul_high_u64(result, to);
lo = result.wrapping_mul(to);
}
}
hi
}
}
impl Default for Rand {
#[inline(always)]
fn default() -> Self {
Self::new(KEY)
}
}