diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fa1ff740b2c..1086f094a72 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: env: RUSTDOCFLAGS: --cfg doc_cfg # --all builds all crates, but with default features for other crates (okay in this case) - run: cargo deadlinks --ignore-fragments -- --all --features nightly,serde1,getrandom,small_rng,min_const_gen + run: cargo deadlinks --ignore-fragments -- --all --features nightly,serde1,getrandom,small_rng test: runs-on: ${{ matrix.os }} @@ -47,7 +47,7 @@ jobs: # Test both windows-gnu and windows-msvc; use beta rust on one - os: ubuntu-latest target: x86_64-unknown-linux-gnu - toolchain: 1.36.0 # MSRV + toolchain: 1.51.0 # MSRV - os: ubuntu-latest deps: sudo apt-get update ; sudo apt install gcc-multilib target: i686-unknown-linux-gnu @@ -77,21 +77,15 @@ jobs: cargo test --target ${{ matrix.target }} --all-features cargo test --target ${{ matrix.target }} --benches --features=nightly cargo test --target ${{ matrix.target }} --manifest-path rand_distr/Cargo.toml --benches - cargo test --target ${{ matrix.target }} --lib --tests --no-default-features --features min_const_gen + cargo test --target ${{ matrix.target }} --lib --tests --no-default-features - name: Test rand run: | cargo test --target ${{ matrix.target }} --lib --tests --no-default-features cargo build --target ${{ matrix.target }} --no-default-features --features alloc,getrandom,small_rng cargo test --target ${{ matrix.target }} --lib --tests --no-default-features --features=alloc,getrandom,small_rng cargo test --target ${{ matrix.target }} --examples - - name: Test rand (all stable features, non-MSRV) - if: ${{ matrix.toolchain != '1.36.0' }} - run: | - cargo test --target ${{ matrix.target }} --features=serde1,log,small_rng,min_const_gen - - name: Test rand (all stable features, MSRV) - if: ${{ matrix.toolchain == '1.36.0' }} + - name: Test rand (all stable features) run: | - # const generics are not stable on 1.36.0 cargo test --target ${{ matrix.target }} --features=serde1,log,small_rng - name: Test rand_core run: | diff --git a/Cargo.toml b/Cargo.toml index d207177a720..bc39334db66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,7 +28,7 @@ features = ["small_rng", "serde1"] [features] # Meta-features: default = ["std", "std_rng"] -nightly = [] # enables performance optimizations requiring nightly rust +nightly = [] # some additions requiring nightly Rust serde1 = ["serde", "rand_core/serde1"] # Option (enabled by default): without "std" rand uses libcore; this option @@ -50,10 +50,6 @@ std_rng = ["rand_chacha"] # 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", diff --git a/README.md b/README.md index 8c576b4ec7f..40d1353441e 100644 --- a/README.md +++ b/README.md @@ -125,11 +125,9 @@ Optionally, the following dependencies can be enabled: Additionally, these features configure Rand: - `small_rng` enables inclusion of the `SmallRng` PRNG -- `nightly` enables some optimizations requiring nightly Rust +- `nightly` includes some additions requiring nightly Rust - `simd_support` (experimental) enables sampling of SIMD values (uniformly random SIMD integers and floats), requiring nightly Rust -- `min_const_gen` enables generating random arrays of - any size using min-const-generics, requiring Rust ≥ 1.51. Note that nightly features are not stable and therefore not all library and compiler versions will be compatible. This is especially true of Rand's diff --git a/src/distributions/mod.rs b/src/distributions/mod.rs index 716536d4ee8..a923f879d22 100644 --- a/src/distributions/mod.rs +++ b/src/distributions/mod.rs @@ -162,11 +162,9 @@ use crate::Rng; /// compound types where all component types are supported: /// /// * Tuples (up to 12 elements): each element is generated sequentially. -/// * Arrays (up to 32 elements): each element is generated sequentially; +/// * Arrays: each element is generated sequentially; /// see also [`Rng::fill`] which supports arbitrary array length for integer /// and float 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 diff --git a/src/distributions/other.rs b/src/distributions/other.rs index 184fce9d4e9..4cb31086734 100644 --- a/src/distributions/other.rs +++ b/src/distributions/other.rs @@ -20,7 +20,6 @@ use crate::Rng; #[cfg(feature = "serde1")] use serde::{Serialize, Deserialize}; -#[cfg(feature = "min_const_gen")] use core::mem::{self, MaybeUninit}; #[cfg(feature = "simd_support")] use core::simd::*; @@ -236,8 +235,6 @@ 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")] -#[cfg_attr(doc_cfg, doc(cfg(feature = "min_const_gen")))] impl Distribution<[T; N]> for Standard where Standard: Distribution { @@ -253,30 +250,6 @@ where Standard: Distribution } } -#[cfg(not(feature = "min_const_gen"))] -macro_rules! array_impl { - // recursive, given at least one type parameter: - {$n:expr, $t:ident, $($ts:ident,)*} => { - array_impl!{($n - 1), $($ts,)*} - - impl Distribution<[T; $n]> for Standard where Standard: Distribution { - #[inline] - fn sample(&self, _rng: &mut R) -> [T; $n] { - [_rng.gen::<$t>(), $(_rng.gen::<$ts>()),*] - } - } - }; - // empty case: - {$n:expr,} => { - impl Distribution<[T; $n]> for Standard { - fn sample(&self, _rng: &mut R) -> [T; $n] { [] } - } - }; -} - -#[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 where Standard: Distribution { diff --git a/src/rng.rs b/src/rng.rs index 79a9fbff46e..e82f18854e8 100644 --- a/src/rng.rs +++ b/src/rng.rs @@ -68,11 +68,9 @@ pub trait Rng: RngCore { /// /// # Arrays and tuples /// - /// The `rng.gen()` method is able to generate arrays (up to 32 elements) + /// The `rng.gen()` method is able to generate arrays /// 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`]. @@ -392,8 +390,6 @@ macro_rules! impl_fill { impl_fill!(u16, u32, u64, usize, u128,); impl_fill!(i8, i16, i32, i64, isize, i128,); -#[cfg_attr(doc_cfg, doc(cfg(feature = "min_const_gen")))] -#[cfg(feature = "min_const_gen")] impl Fill for [T; N] where [T]: Fill { @@ -402,32 +398,6 @@ where [T]: Fill } } -#[cfg(not(feature = "min_const_gen"))] -macro_rules! impl_fill_arrays { - ($n:expr,) => {}; - ($n:expr, $N:ident) => { - impl Fill for [T; $n] where [T]: Fill { - fn try_fill(&mut self, rng: &mut R) -> Result<(), Error> { - self[..].try_fill(rng) - } - } - }; - ($n:expr, $N:ident, $($NN:ident,)*) => { - impl_fill_arrays!($n, $N); - impl_fill_arrays!($n - 1, $($NN,)*); - }; - (!div $n:expr,) => {}; - (!div $n:expr, $N:ident, $($NN:ident,)*) => { - impl_fill_arrays!($n, $N); - 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)] mod test { use super::*; diff --git a/src/seq/index.rs b/src/seq/index.rs index b38e4649d1f..7682facd51e 100644 --- a/src/seq/index.rs +++ b/src/seq/index.rs @@ -267,9 +267,7 @@ where R: Rng + ?Sized { /// sometimes be useful to have the indices themselves so this is provided as /// an alternative. /// -/// This implementation uses `O(length + amount)` space and `O(length)` time -/// if the "nightly" feature is enabled, or `O(length)` space and -/// `O(length + amount * log length)` time otherwise. +/// This implementation uses `O(length + amount)` space and `O(length)` time. /// /// Panics if `amount > length`. #[cfg(feature = "std")] @@ -300,9 +298,7 @@ where /// /// This implementation uses the algorithm described by Efraimidis and Spirakis /// in this paper: https://doi.org/10.1016/j.ipl.2005.11.003 -/// It uses `O(length + amount)` space and `O(length)` time if the -/// "nightly" feature is enabled, or `O(length)` space and `O(length -/// + amount * log length)` time otherwise. +/// It uses `O(length + amount)` space and `O(length)` time. /// /// Panics if `amount > length`. #[cfg(feature = "std")] @@ -347,63 +343,33 @@ where } impl Eq for Element {} - #[cfg(feature = "nightly")] - { - let mut candidates = Vec::with_capacity(length.as_usize()); - let mut index = N::zero(); - while index < length { - let weight = weight(index.as_usize()).into(); - if !(weight >= 0.) { - return Err(WeightedError::InvalidWeight); - } - - let key = rng.gen::().powf(1.0 / weight); - candidates.push(Element { index, key }); - - index += N::one(); + let mut candidates = Vec::with_capacity(length.as_usize()); + let mut index = N::zero(); + while index < length { + let weight = weight(index.as_usize()).into(); + if !(weight >= 0.) { + return Err(WeightedError::InvalidWeight); } - // Partially sort the array to find the `amount` elements with the greatest - // keys. Do this by using `select_nth_unstable` to put the elements with - // the *smallest* keys at the beginning of the list in `O(n)` time, which - // provides equivalent information about the elements with the *greatest* keys. - let (_, mid, greater) - = candidates.select_nth_unstable(length.as_usize() - amount.as_usize()); - - let mut result: Vec = Vec::with_capacity(amount.as_usize()); - result.push(mid.index); - for element in greater { - result.push(element.index); - } - Ok(IndexVec::from(result)) - } - - #[cfg(not(feature = "nightly"))] - { - use alloc::collections::BinaryHeap; + let key = rng.gen::().powf(1.0 / weight); + candidates.push(Element { index, key }); - // Partially sort the array such that the `amount` elements with the largest - // keys are first using a binary max heap. - let mut candidates = BinaryHeap::with_capacity(length.as_usize()); - let mut index = N::zero(); - while index < length { - let weight = weight(index.as_usize()).into(); - if !(weight >= 0.) { - return Err(WeightedError::InvalidWeight); - } + index += N::one(); + } - let key = rng.gen::().powf(1.0 / weight); - candidates.push(Element { index, key }); + // Partially sort the array to find the `amount` elements with the greatest + // keys. Do this by using `select_nth_unstable` to put the elements with + // the *smallest* keys at the beginning of the list in `O(n)` time, which + // provides equivalent information about the elements with the *greatest* keys. + let (_, mid, greater) + = candidates.select_nth_unstable(length.as_usize() - amount.as_usize()); - index += N::one(); - } - - let mut result: Vec = Vec::with_capacity(amount.as_usize()); - while result.len() < amount.as_usize() { - result.push(candidates.pop().unwrap().index); - } - Ok(IndexVec::from(result)) + let mut result: Vec = Vec::with_capacity(amount.as_usize()); + result.push(mid.index); + for element in greater { + result.push(element.index); } + Ok(IndexVec::from(result)) } /// Randomly sample exactly `amount` indices from `0..length`, using Floyd's