Skip to content

Commit

Permalink
Merge pull request #1104 from noslaver/const-generic-array-size
Browse files Browse the repository at this point in the history
Use const-generics to support arrays of all sizes
  • Loading branch information
dhardy committed Mar 25, 2021
2 parents 5760aed + 5161f70 commit 9555338
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Expand Up @@ -41,6 +41,10 @@ std_rng = ["rand_chacha", "rand_hc"]
# Option: enable SmallRng
small_rng = []

# Option: for rustc ≥ 1.51, enable generating random arrays of any size
# using min-const-generics
min_const_gen = []

[workspace]
members = [
"rand_core",
Expand Down
6 changes: 6 additions & 0 deletions src/distributions/mod.rs
Expand Up @@ -279,6 +279,12 @@ where
/// * Arrays (up to 32 elements): each element is generated sequentially;
/// see also [`Rng::fill`] which supports arbitrary array length for integer
/// types and tends to be faster for `u32` and smaller types.
/// When using `rustc` ≥ 1.51, enable the `min_const_gen` feature to support
/// arrays larger than 32 elements.
/// Note that [`Rng::fill`] and `Standard`'s array support are *not* equivalent:
/// the former is optimised for integer types (using fewer RNG calls for
/// element types smaller than the RNG word size), while the latter supports
/// any element type supported by `Standard`.
/// * `Option<T>` first generates a `bool`, and if true generates and returns
/// `Some(value)` where `value: T`, otherwise returning `None`.
///
Expand Down
21 changes: 21 additions & 0 deletions src/distributions/other.rs
Expand Up @@ -16,6 +16,9 @@ use crate::Rng;

#[cfg(feature = "serde1")]
use serde::{Serialize, Deserialize};
#[cfg(feature = "min_const_gen")]
use std::mem::{self, MaybeUninit};


// ----- Sampling distributions -----

Expand Down Expand Up @@ -156,6 +159,23 @@ tuple_impl! {A, B, C, D, E, F, G, H, I, J}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K}
tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L}

#[cfg(feature = "min_const_gen")]
impl<T, const N: usize> Distribution<[T; N]> for Standard
where Standard: Distribution<T>
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> [T; N] {
let mut buff: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };

for elem in &mut buff {
*elem = MaybeUninit::new(_rng.gen());
}

unsafe { mem::transmute_copy::<_, _>(&buff) }
}
}

#[cfg(not(feature = "min_const_gen"))]
macro_rules! array_impl {
// recursive, given at least one type parameter:
{$n:expr, $t:ident, $($ts:ident,)*} => {
Expand All @@ -176,6 +196,7 @@ macro_rules! array_impl {
};
}

#[cfg(not(feature = "min_const_gen"))]
array_impl! {32, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T,}

impl<T> Distribution<Option<T>> for Standard
Expand Down
14 changes: 14 additions & 0 deletions src/rng.rs
Expand Up @@ -71,6 +71,8 @@ pub trait Rng: RngCore {
/// The `rng.gen()` method is able to generate arrays (up to 32 elements)
/// and tuples (up to 12 elements), so long as all element types can be
/// generated.
/// When using `rustc` ≥ 1.51, enable the `min_const_gen` feature to support
/// arrays larger than 32 elements.
///
/// For arrays of integers, especially for those with small element types
/// (< 64 bit), it will likely be faster to instead use [`Rng::fill`].
Expand Down Expand Up @@ -394,6 +396,16 @@ impl_fill!(i8, i16, i32, i64, isize,);
#[cfg(not(target_os = "emscripten"))]
impl_fill!(i128);

#[cfg(feature = "min_const_gen")]
impl<T, const N: usize> Fill for [T; N]
where [T]: Fill
{
fn try_fill<R: Rng + ?Sized>(&mut self, rng: &mut R) -> Result<(), Error> {
self[..].try_fill(rng)
}
}

#[cfg(not(feature = "min_const_gen"))]
macro_rules! impl_fill_arrays {
($n:expr,) => {};
($n:expr, $N:ident) => {
Expand All @@ -413,8 +425,10 @@ macro_rules! impl_fill_arrays {
impl_fill_arrays!(!div $n / 2, $($NN,)*);
};
}
#[cfg(not(feature = "min_const_gen"))]
#[rustfmt::skip]
impl_fill_arrays!(32, N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,);
#[cfg(not(feature = "min_const_gen"))]
impl_fill_arrays!(!div 4096, N,N,N,N,N,N,N,);

#[cfg(test)]
Expand Down

0 comments on commit 9555338

Please sign in to comment.