#![no_std]
pub mod counter;
pub mod duration;
pub mod mock_support;
pub mod splitmix;
pub mod xorshift;
pub mod wyrand;
pub use counter::Counter;
pub use splitmix::SplitMix;
pub use wyrand::Wyrand;
pub use xorshift::Xorshift;
pub use mock_support::RefCellExt;
use core::ops::Range;
pub type StdRand = Wyrand;
pub trait Rand {
#[inline(always)]
fn next_u16(&mut self) -> u16 {
self.next_u64() as u16
}
#[inline(always)]
fn next_u32(&mut self) -> u32 {
self.next_u64() as u32
}
fn next_u64(&mut self) -> u64;
#[inline(always)]
fn next_u128(&mut self) -> u128 {
u128::from(self.next_u64()) << 64 | u128::from(self.next_u64())
}
#[cfg(target_pointer_width = "16")]
#[inline(always)]
fn next_usize(&mut self) -> usize {
self.next_u16() as usize
}
#[cfg(target_pointer_width = "32")]
#[inline(always)]
fn next_usize(&mut self) -> usize {
self.next_u32() as usize
}
#[cfg(target_pointer_width = "64")]
#[inline(always)]
fn next_usize(&mut self) -> usize {
self.next_u64() as usize
}
#[cfg(target_pointer_width = "128")]
#[inline(always)]
fn next_usize(&mut self) -> usize {
self.next_u128() as usize
}
#[inline(always)]
fn next_bool(&mut self, p: Probability) -> bool {
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_sign_loss)]
let cutoff = (p.0 * u64::MAX as f64) as u64;
let mut next = self.next_u64();
if next == u64::MAX {
next = u64::MAX - 1;
}
next < cutoff
}
#[inline(always)]
fn next_lim_u16(&mut self, lim: u16) -> u16 {
assert_ne!(0, lim, "zero limit");
let mut full = u32::from(self.next_u16()) * u32::from(lim);
let mut low = full as u16;
if low < lim {
let cutoff = lim.wrapping_neg() % lim;
while low < cutoff {
full = u32::from(self.next_u16()) * u32::from(lim);
low = full as u16;
}
}
(full >> 16) as u16
}
#[inline(always)]
fn next_lim_u32(&mut self, lim: u32) -> u32 {
assert_ne!(0, lim, "zero limit");
let mut full = u64::from(self.next_u32()) * u64::from(lim);
let mut low = full as u32;
if low < lim {
let cutoff = lim.wrapping_neg() % lim;
while low < cutoff {
full = u64::from(self.next_u32()) * u64::from(lim);
low = full as u32;
}
}
(full >> 32) as u32
}
#[inline(always)]
fn next_lim_u64(&mut self, lim: u64) -> u64 {
assert_ne!(0, lim, "zero limit");
let mut full = u128::from(self.next_u64()) * u128::from(lim);
let mut low = full as u64;
if low < lim {
let cutoff = lim.wrapping_neg() % lim;
while low < cutoff {
full = u128::from(self.next_u64()) * u128::from(lim);
low = full as u64;
}
}
(full >> 64) as u64
}
#[inline(always)]
fn next_lim_u128(&mut self, lim: u128) -> u128 {
assert_ne!(0, lim, "zero limit");
if lim <= u128::from(u64::MAX) {
u128::from(self.next_lim_u64(lim as u64))
} else {
let cutoff = cutoff_u128(lim);
loop {
let rand = self.next_u128();
if rand <= cutoff {
return rand % lim;
}
}
}
}
#[cfg(target_pointer_width = "16")]
#[inline(always)]
fn next_lim_usize(&mut self, lim: usize) -> usize {
self.next_lim_u16(lim as u16) as usize
}
#[cfg(target_pointer_width = "32")]
#[inline(always)]
fn next_lim_usize(&mut self, lim: usize) -> usize {
self.next_lim_u32(lim as u32) as usize
}
#[cfg(target_pointer_width = "64")]
#[inline(always)]
fn next_lim_usize(&mut self, lim: usize) -> usize {
self.next_lim_u64(lim as u64) as usize
}
#[cfg(target_pointer_width = "128")]
#[inline(always)]
fn next_lim_usize(&mut self, lim: usize) -> usize {
self.next_lim_u128(lim as u128) as usize
}
}
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Probability(f64);
impl Probability {
#[inline(always)]
pub fn new(p: f64) -> Self {
assert!(p >= 0f64, "p ({p}) cannot be less than 0");
assert!(p <= 1f64, "p ({p}) cannot be greater than 1");
Self(p)
}
#[inline(always)]
pub const unsafe fn new_unchecked(p: f64) -> Self {
Self(p)
}
}
impl From<Probability> for f64 {
#[inline(always)]
fn from(p: Probability) -> Self {
p.0
}
}
impl From<f64> for Probability {
#[inline(always)]
fn from(p: f64) -> Self {
Probability::new(p)
}
}
pub trait Seeded {
type R: Rand;
fn seed(seed: u64) -> Self::R;
}
#[inline(always)]
fn cutoff_u128(lim: u128) -> u128 {
let overhang = (u128::MAX - lim + 1) % lim;
u128::MAX - overhang
}
pub trait RandLim<N> {
fn next_lim(&mut self, lim: N) -> N;
}
impl<R: Rand> RandLim<u16> for R {
#[inline(always)]
fn next_lim(&mut self, lim: u16) -> u16 {
self.next_lim_u16(lim)
}
}
impl<R: Rand> RandLim<u32> for R {
#[inline(always)]
fn next_lim(&mut self, lim: u32) -> u32 {
self.next_lim_u32(lim)
}
}
impl<R: Rand> RandLim<u64> for R {
#[inline(always)]
fn next_lim(&mut self, lim: u64) -> u64 {
self.next_lim_u64(lim)
}
}
impl<R: Rand> RandLim<u128> for R {
#[inline(always)]
fn next_lim(&mut self, lim: u128) -> u128 {
self.next_lim_u128(lim)
}
}
impl<R: Rand> RandLim<usize> for R {
#[inline(always)]
fn next_lim(&mut self, lim: usize) -> usize {
self.next_lim_usize(lim)
}
}
pub trait RandRange<N> {
fn next_range(&mut self, range: Range<N>) -> N;
}
impl<R: Rand> RandRange<u16> for R {
#[inline(always)]
fn next_range(&mut self, range: Range<u16>) -> u16 {
assert!(!range.is_empty(), "empty range");
let span = range.end - range.start;
range.start + self.next_lim_u16(span)
}
}
impl<R: Rand> RandRange<u32> for R {
#[inline(always)]
fn next_range(&mut self, range: Range<u32>) -> u32 {
assert!(!range.is_empty(), "empty range");
let span = range.end - range.start;
range.start + self.next_lim_u32(span)
}
}
impl<R: Rand> RandRange<u64> for R {
#[inline(always)]
fn next_range(&mut self, range: Range<u64>) -> u64 {
assert!(!range.is_empty(), "empty range");
let span = range.end - range.start;
range.start + self.next_lim_u64(span)
}
}
impl<R: Rand> RandRange<u128> for R {
#[inline(always)]
fn next_range(&mut self, range: Range<u128>) -> u128 {
assert!(!range.is_empty(), "empty range");
let span = range.end - range.start;
let random = self.next_lim_u128(span);
range.start + random
}
}
impl<R: Rand> RandRange<usize> for R {
#[cfg(target_pointer_width = "16")]
#[inline(always)]
fn next_range(&mut self, range: Range<usize>) -> usize {
self.next_range(range.start as u16..range.end as u16) as usize
}
#[cfg(target_pointer_width = "32")]
#[inline(always)]
fn next_range(&mut self, range: Range<usize>) -> usize {
self.next_range(range.start as u32..range.end as u32) as usize
}
#[cfg(target_pointer_width = "64")]
#[inline(always)]
fn next_range(&mut self, range: Range<usize>) -> usize {
self.next_range(range.start as u64..range.end as u64) as usize
}
#[cfg(target_pointer_width = "128")]
#[inline(always)]
fn next_range(&mut self, range: Range<usize>) -> usize {
self.next_range(range.start as u128..range.end as u128) as usize
}
}
#[cfg(test)]
extern crate alloc;
#[cfg(test)]
pub(crate) mod test_mock;
#[cfg(test)]
mod tests;