use std::collections::hash_map::RandomState;
use std::hash::BuildHasher;
use std::hash::Hasher;
pub fn fill_bytes<F>(buffer: &mut [u8], mut rng: F)
where
F: FnMut() -> u64,
{
if buffer.is_empty() {
return; }
for chunk in buffer.chunks_mut(8) {
let random_bytes = rng().to_le_bytes();
chunk.copy_from_slice(&random_bytes[..chunk.len()]);
}
}
#[track_caller]
fn convert_to_t<S, T>(input: S) -> T
where
T: TryFrom<S>,
S: std::fmt::Debug + Copy,
{
match T::try_from(input) {
Ok(value) => value,
Err(_) => panic!(
"Conversion failed: Cannot convert value {:?} of {} type into target type {}",
input,
std::any::type_name::<S>(),
std::any::type_name::<T>()
),
}
}
use std::convert::TryFrom;
#[track_caller]
pub fn fill_numbers<S, T, F>(buffer: &mut [T], mut rng: F)
where
F: FnMut() -> S,
T: Copy + TryFrom<S>,
S: std::fmt::Debug + Copy,
{
if buffer.is_empty() {
return; }
for item in buffer.iter_mut() {
*item = convert_to_t(rng()); }
}
use std::ops::{Bound, RangeBounds};
#[track_caller]
pub fn gen_range<R, F, T>(range: R, mut rng: F) -> T
where
R: RangeBounds<u64>,
F: FnMut() -> u64,
T: TryFrom<u64> + 'static, {
let start = match range.start_bound() {
Bound::Included(s) => *s,
_ => panic!("Invalid range: Start must be included."),
};
let (end, is_inclusive) = match range.end_bound() {
Bound::Included(e) => (*e, true),
Bound::Excluded(e) => (*e, false),
_ => panic!("Invalid range: End must be bounded."),
};
if end < start {
panic!("Invalid range: End must be greater than or equal to start.");
}
let range_size = if is_inclusive {
if end == u64::MAX {
if start == 0 {
u64::MAX
} else {
u64::MAX - start + 1
}
} else {
end - start + 1
}
} else {
end - start
};
if range_size == 0 {
panic!("Invalid range: Cannot generate a number from an empty range.");
}
let raw_random = rng();
let mapped_to_zero_based_range = raw_random % range_size;
let final_result = start + mapped_to_zero_based_range;
convert_to_t(final_result)
}
#[track_caller]
pub fn fill_range<R, F, T>(slice: &mut [T], range: R, mut rng: F)
where
R: RangeBounds<u64>,
F: FnMut() -> u64,
T: TryFrom<u64> + Copy,
{
let start = match range.start_bound() {
Bound::Included(s) => *s,
_ => panic!("Invalid range: Start must be included."),
};
let (end, is_inclusive) = match range.end_bound() {
Bound::Included(e) => (*e, true),
Bound::Excluded(e) => (*e, false),
_ => panic!("Invalid range: End must be bounded."),
};
if end < start {
panic!("Invalid range: End must be greater than or equal to start.");
}
let range_size = if is_inclusive {
if end == u64::MAX {
if start == 0 {
u64::MAX
} else {
u64::MAX - start + 1
}
} else {
end - start + 1
}
} else {
end - start
};
if range_size == 0 {
panic!("Invalid range: Cannot generate a number from an empty range.");
}
for i in 0..slice.len() {
let raw_random = rng();
let mapped_to_zero_based_range = raw_random % range_size;
let final_result = start + mapped_to_zero_based_range;
slice[i] = convert_to_t(final_result);
}
}
pub fn fast_u128() -> u128 {
let low = RandomState::new().build_hasher().finish(); let high = RandomState::new().build_hasher().finish();
((high as u128) << 64) | (low as u128) }
pub fn fast_u64() -> u64 {
let s = RandomState::new();
let hasher = s.build_hasher();
hasher.finish()
}
pub fn fast_u32() -> u32 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() & 0xFFFFFFFF) as u32
}
pub fn fast_u16() -> u16 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() & 0xFFFF) as u16
}
pub fn fast_u8() -> u8 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() & 0xFF) as u8
}
pub fn fast_usize() -> usize {
let s = RandomState::new();
let hasher = s.build_hasher();
hasher.finish() as usize
}
pub fn fast_i128() -> i128 {
let low = RandomState::new().build_hasher().finish() as i128; let high = RandomState::new().build_hasher().finish() as i128;
let full_value = (high << 64) | low;
full_value.abs() }
pub fn fast_i64() -> i64 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() & 0x7FFFFFFFFFFFFFFF) as i64 }
pub fn fast_i32() -> i32 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() & 0x7FFFFFFF) as i32 }
pub fn fast_i16() -> i16 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() & 0x7FFF) as i16 }
pub fn fast_i8() -> i8 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() & 0x7F) as i8 }
pub fn fast_isize() -> isize {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() & (isize::MAX as u64)) as isize }
pub fn fast_f32() -> f32 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() as f32) / (u64::MAX as f32)
}
pub fn fast_f64() -> f64 {
let s = RandomState::new();
let hasher = s.build_hasher();
(hasher.finish() as f64) / (u64::MAX as f64)
}
pub fn random_f64() -> f64 {
(random_u64() as f64) / (u64::MAX as f64)
}
pub fn random_f32() -> f32 {
(random_u64() as f32) / (u64::MAX as f32)
}
pub fn random_u128() -> u128 {
let lower_thread = std::thread::spawn(|| fast_u64());
let upper_thread = std::thread::spawn(|| fast_u64());
let low = match lower_thread.join() {
Ok(value) => value,
Err(_) => fast_u64(), };
let high = match upper_thread.join() {
Ok(value) => value,
Err(_) => fast_u64(), };
((high as u128) << 64) | (low as u128)
}
pub fn random_u64() -> u64 {
let handle = std::thread::spawn(|| fast_u64());
match handle.join() {
Ok(randomness) => randomness, Err(_) => {
fast_u64()
}
}
}
pub fn random_u32() -> u32 {
let handle = std::thread::spawn(|| fast_u32());
match handle.join() {
Ok(randomness) => randomness, Err(_) => {
fast_u32() }
}
}
pub fn random_u16() -> u16 {
let handle = std::thread::spawn(|| fast_u16());
match handle.join() {
Ok(randomness) => randomness,
Err(_) => fast_u16(), }
}
pub fn random_u8() -> u8 {
let handle = std::thread::spawn(|| fast_u8());
match handle.join() {
Ok(randomness) => randomness,
Err(_) => fast_u8(), }
}
pub fn random_usize() -> usize {
let handle = std::thread::spawn(|| fast_usize());
match handle.join() {
Ok(randomness) => randomness,
Err(_) => fast_usize(),
}
}
pub fn random_i128() -> i128 {
let lower_thread = std::thread::spawn(|| fast_u64());
let upper_thread = std::thread::spawn(|| fast_i64());
let low = match lower_thread.join() {
Ok(value) => value as i128,
Err(_) => fast_u64() as i128,
};
let high = match upper_thread.join() {
Ok(value) => value as i128,
Err(_) => fast_i64() as i128,
};
(high << 64) | low
}
pub fn random_i64() -> i64 {
let handle = std::thread::spawn(|| fast_i64());
match handle.join() {
Ok(randomness) => randomness,
Err(_) => fast_i64(),
}
}
pub fn random_i32() -> i32 {
let handle = std::thread::spawn(|| fast_i32());
match handle.join() {
Ok(randomness) => randomness,
Err(_) => fast_i32(),
}
}
pub fn random_i16() -> i16 {
let handle = std::thread::spawn(|| fast_i16());
match handle.join() {
Ok(randomness) => randomness,
Err(_) => fast_i16(),
}
}
pub fn random_i8() -> i8 {
let handle = std::thread::spawn(|| fast_i8());
match handle.join() {
Ok(randomness) => randomness,
Err(_) => fast_i8(),
}
}
pub fn random_isize() -> isize {
let handle = std::thread::spawn(|| fast_isize());
match handle.join() {
Ok(randomness) => randomness,
Err(_) => fast_isize(),
}
}
#[cfg(test)]
mod basic_tests;
#[cfg(test)]
mod generator_tests;
#[cfg(test)]
mod fill_tests;
#[cfg(test)]
mod overflow_tests;
#[cfg(test)]
mod closure_tests;