use core::ops::{Range, RangeInclusive};
use crate::RngSource;
mod sealed {
pub trait Sealed {}
}
pub trait RandInt: sealed::Sealed + Copy + PartialOrd {
#[doc(hidden)]
fn lemire_bounded(rng: &mut RngSource, range_size: Self) -> Self;
#[doc(hidden)]
fn add(self, n: Self) -> Self;
#[doc(hidden)]
fn sub(self, n: Self) -> Self;
#[doc(hidden)]
fn one() -> Self;
}
macro_rules! impl_rand_int_via_u32 {
($($t:ty),* $(,)?) => {
$(
impl sealed::Sealed for $t {}
impl RandInt for $t {
#[inline]
fn lemire_bounded(rng: &mut RngSource, range_size: Self) -> Self {
lemire_u32(rng, range_size as u32) as Self
}
#[inline]
fn add(self, n: Self) -> Self { self + n }
#[inline]
fn sub(self, n: Self) -> Self { self - n }
#[inline]
fn one() -> Self { 1 }
}
)*
};
}
impl_rand_int_via_u32!(u8, u16, u32);
impl sealed::Sealed for u64 {}
impl RandInt for u64 {
#[inline]
fn lemire_bounded(rng: &mut RngSource, range_size: Self) -> Self {
lemire_u64(rng, range_size)
}
#[inline]
fn add(self, n: Self) -> Self {
self + n
}
#[inline]
fn sub(self, n: Self) -> Self {
self - n
}
#[inline]
fn one() -> Self {
1
}
}
impl sealed::Sealed for usize {}
impl RandInt for usize {
#[inline]
fn lemire_bounded(rng: &mut RngSource, range_size: Self) -> Self {
#[cfg(target_pointer_width = "32")]
{
lemire_u32(rng, range_size as u32) as usize
}
#[cfg(target_pointer_width = "64")]
{
lemire_u64(rng, range_size as u64) as usize
}
}
#[inline]
fn add(self, n: Self) -> Self {
self + n
}
#[inline]
fn sub(self, n: Self) -> Self {
self - n
}
#[inline]
fn one() -> Self {
1
}
}
pub fn gen_range<T: RandInt>(rng: &mut RngSource, range: Range<T>) -> T {
debug_assert!(range.start < range.end, "gen_range: empty range");
let size = range.end.sub(range.start);
range.start.add(T::lemire_bounded(rng, size))
}
pub fn gen_range_inclusive<T: RandInt>(rng: &mut RngSource, range: RangeInclusive<T>) -> T {
let (start, end) = range.into_inner();
debug_assert!(start <= end, "gen_range_inclusive: inverted range");
let size = end.sub(start).add(T::one());
start.add(T::lemire_bounded(rng, size))
}
#[inline]
fn lemire_u32(rng: &mut RngSource, n: u32) -> u32 {
debug_assert!(n > 0, "lemire_u32: n == 0");
let mut buf = [0u8; 4];
loop {
rng.fill_bytes(&mut buf);
let x = u32::from_le_bytes(buf);
let m = u64::from(x) * u64::from(n);
let l = m as u32;
if l < n {
let t = n.wrapping_neg() % n;
if l < t {
continue;
}
}
return (m >> 32) as u32;
}
}
#[inline]
fn lemire_u64(rng: &mut RngSource, n: u64) -> u64 {
debug_assert!(n > 0, "lemire_u64: n == 0");
let mut buf = [0u8; 8];
loop {
rng.fill_bytes(&mut buf);
let x = u64::from_le_bytes(buf);
let m = u128::from(x) * u128::from(n);
let l = m as u64;
if l < n {
let t = n.wrapping_neg() % n;
if l < t {
continue;
}
}
return (m >> 64) as u64;
}
}