From 4b1d97451bbdbc9c5d86063ac6f9f56f53af77c9 Mon Sep 17 00:00:00 2001 From: Noam Koren Date: Sat, 13 Mar 2021 18:45:59 +0200 Subject: [PATCH 1/6] Use const-generics to support arrays of all sizes --- src/distributions/other.rs | 19 +++++++++++++++++++ src/rng.rs | 12 ++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/distributions/other.rs b/src/distributions/other.rs index f62fe59aa73..ab4e4d84c97 100644 --- a/src/distributions/other.rs +++ b/src/distributions/other.rs @@ -156,6 +156,24 @@ 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 = "nightly")] +impl Distribution<[T; N]> for Standard +where + Standard: Distribution, + T: Default + Copy, +{ + #[inline] + fn sample(&self, _rng: &mut R) -> [T; N] { + let mut sample = [Default::default(); N]; + for elem in &mut sample { + *elem = _rng.gen(); + } + + sample + } +} + +#[cfg(not(feature = "nightly"))] macro_rules! array_impl { // recursive, given at least one type parameter: {$n:expr, $t:ident, $($ts:ident,)*} => { @@ -176,6 +194,7 @@ macro_rules! array_impl { }; } +#[cfg(not(feature = "nightly"))] 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 Distribution> for Standard diff --git a/src/rng.rs b/src/rng.rs index bb977a54379..213b4ff8760 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -394,6 +394,16 @@ impl_fill!(i8, i16, i32, i64, isize,); #[cfg(not(target_os = "emscripten"))] impl_fill!(i128); +#[cfg(feature = "nightly")] +impl Fill for [T; N] +where [T]: Fill +{ + fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { + self[..].try_fill(rng) + } +} + +#[cfg(not(feature = "nightly"))] macro_rules! impl_fill_arrays { ($n:expr,) => {}; ($n:expr, $N:ident) => { @@ -413,8 +423,10 @@ macro_rules! impl_fill_arrays { impl_fill_arrays!(!div $n / 2, $($NN,)*); }; } +#[cfg(not(feature = "nightly"))] #[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 = "nightly"))] impl_fill_arrays!(!div 4096, N,N,N,N,N,N,N,); #[cfg(test)] From 65b170759b2bd1ab496ffa26c2e25fedbbcb3fe8 Mon Sep 17 00:00:00 2001 From: Noam Koren Date: Mon, 15 Mar 2021 00:07:31 +0200 Subject: [PATCH 2/6] Add min_const_gen feature --- Cargo.toml | 3 +++ src/distributions/other.rs | 6 +++--- src/rng.rs | 8 ++++---- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index afd13391d9d..3b6592dffdd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,9 @@ std_rng = ["rand_chacha", "rand_hc"] # Option: enable SmallRng small_rng = [] +# Option: TODO - enable SmallRng +min_const_gen = [] + [workspace] members = [ "rand_core", diff --git a/src/distributions/other.rs b/src/distributions/other.rs index ab4e4d84c97..55d0c90987f 100644 --- a/src/distributions/other.rs +++ b/src/distributions/other.rs @@ -156,7 +156,7 @@ 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 = "nightly")] +#[cfg(feature = "min_const_gen")] impl Distribution<[T; N]> for Standard where Standard: Distribution, @@ -173,7 +173,7 @@ where } } -#[cfg(not(feature = "nightly"))] +#[cfg(not(feature = "min_const_gen"))] macro_rules! array_impl { // recursive, given at least one type parameter: {$n:expr, $t:ident, $($ts:ident,)*} => { @@ -194,7 +194,7 @@ macro_rules! array_impl { }; } -#[cfg(not(feature = "nightly"))] +#[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 Distribution> for Standard diff --git a/src/rng.rs b/src/rng.rs index 213b4ff8760..7bbaa49483b 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -394,7 +394,7 @@ impl_fill!(i8, i16, i32, i64, isize,); #[cfg(not(target_os = "emscripten"))] impl_fill!(i128); -#[cfg(feature = "nightly")] +#[cfg(feature = "min_const_gen")] impl Fill for [T; N] where [T]: Fill { @@ -403,7 +403,7 @@ where [T]: Fill } } -#[cfg(not(feature = "nightly"))] +#[cfg(not(feature = "min_const_gen"))] macro_rules! impl_fill_arrays { ($n:expr,) => {}; ($n:expr, $N:ident) => { @@ -423,10 +423,10 @@ macro_rules! impl_fill_arrays { impl_fill_arrays!(!div $n / 2, $($NN,)*); }; } -#[cfg(not(feature = "nightly"))] +#[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 = "nightly"))] +#[cfg(not(feature = "min_const_gen"))] impl_fill_arrays!(!div 4096, N,N,N,N,N,N,N,); #[cfg(test)] From ffb6f360ad3612c35e62731b16ed65df223a17eb Mon Sep 17 00:00:00 2001 From: Noam Koren Date: Mon, 15 Mar 2021 00:20:15 +0200 Subject: [PATCH 3/6] Use MaybeUninit to initialize a random array, remove Default + Copy trait bounds --- src/distributions/other.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/distributions/other.rs b/src/distributions/other.rs index 55d0c90987f..16b352ac382 100644 --- a/src/distributions/other.rs +++ b/src/distributions/other.rs @@ -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 ----- @@ -158,18 +161,17 @@ tuple_impl! {A, B, C, D, E, F, G, H, I, J, K, L} #[cfg(feature = "min_const_gen")] impl Distribution<[T; N]> for Standard -where - Standard: Distribution, - T: Default + Copy, +where Standard: Distribution { #[inline] fn sample(&self, _rng: &mut R) -> [T; N] { - let mut sample = [Default::default(); N]; - for elem in &mut sample { - *elem = _rng.gen(); + let mut buff: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; + + for elem in &mut buff { + *elem = MaybeUninit::new(_rng.gen()); } - sample + unsafe { mem::transmute_copy::<_, _>(&buff) } } } From 773ba59c9afff59588ca54cc3651196a2ebaee19 Mon Sep 17 00:00:00 2001 From: Noam Koren Date: Sat, 20 Mar 2021 11:43:57 +0200 Subject: [PATCH 4/6] Update docs --- Cargo.toml | 2 +- src/distributions/mod.rs | 2 ++ src/rng.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3b6592dffdd..33477f77c92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ std_rng = ["rand_chacha", "rand_hc"] # Option: enable SmallRng small_rng = [] -# Option: TODO - enable SmallRng +# Option: enable generating random arrays of any size using min-const-generics min_const_gen = [] [workspace] diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 652f52a1831..8c0232714df 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -279,6 +279,8 @@ 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. +/// For arrays of size larger than 32 elements, enable the `min_const_gen` +/// feature. /// * `Option` first generates a `bool`, and if true generates and returns /// `Some(value)` where `value: T`, otherwise returning `None`. /// diff --git a/src/rng.rs b/src/rng.rs index 7bbaa49483b..6d99fc97cf4 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -71,6 +71,7 @@ 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. + /// For arrays larger than 32 elements, enable the `min_const_gen` feature. /// /// For arrays of integers, especially for those with small element types /// (< 64 bit), it will likely be faster to instead use [`Rng::fill`]. From 399c8cc564b157a9f1519450ae40b4a5810bad0b Mon Sep 17 00:00:00 2001 From: Noam Koren Date: Tue, 23 Mar 2021 15:52:08 +0200 Subject: [PATCH 5/6] Update docs --- src/distributions/mod.rs | 4 ++-- src/rng.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 8c0232714df..16a6e2412d6 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -279,8 +279,8 @@ 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. -/// For arrays of size larger than 32 elements, enable the `min_const_gen` -/// feature. +/// When using `rustc` ≥ 1.51, enable the `min_const_gen` feature to support +/// arrays larger than 32 elements. /// * `Option` first generates a `bool`, and if true generates and returns /// `Some(value)` where `value: T`, otherwise returning `None`. /// diff --git a/src/rng.rs b/src/rng.rs index 6d99fc97cf4..8bffa7b6e0e 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -71,7 +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. - /// For arrays larger than 32 elements, enable the `min_const_gen` feature. + /// 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`]. From 5161f70fb7143e72870abbb1072de763d714d1de Mon Sep 17 00:00:00 2001 From: Noam Koren Date: Tue, 23 Mar 2021 23:51:00 +0200 Subject: [PATCH 6/6] Update docs --- Cargo.toml | 3 ++- src/distributions/mod.rs | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 33477f77c92..a1bfb5b5efa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,8 @@ std_rng = ["rand_chacha", "rand_hc"] # Option: enable SmallRng small_rng = [] -# Option: enable generating random arrays of any size using min-const-generics +# Option: for rustc ≥ 1.51, enable generating random arrays of any size +# using min-const-generics min_const_gen = [] [workspace] diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 16a6e2412d6..911d1604aae 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -281,6 +281,10 @@ where /// 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` first generates a `bool`, and if true generates and returns /// `Some(value)` where `value: T`, otherwise returning `None`. ///