From 07d4e92e89142ce1ca132fdbb8321cd8cee20246 Mon Sep 17 00:00:00 2001 From: Calvin Date: Sun, 30 Mar 2025 16:41:22 +0800 Subject: [PATCH] Boost performance for sample_floyd --- CHANGELOG.md | 1 + src/seq/index.rs | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b80b9bcc1e8..91d3805a81a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update. - Fix feature `simd_support` for recent nightly rust (#1586) - Add `Alphabetic` distribution. (#1587) - Re-export `rand_core` (#1602) +- Boost performance of `sample_floyd` (#1622) ## [0.9.0] - 2025-01-27 ### Security and unsafe diff --git a/src/seq/index.rs b/src/seq/index.rs index 852bdac76c4..c50df745e3f 100644 --- a/src/seq/index.rs +++ b/src/seq/index.rs @@ -8,6 +8,7 @@ //! Low-level API for sampling indices use alloc::vec::{self, Vec}; +use core::ptr; use core::slice; use core::{hash::Hash, ops::AddAssign}; // BTreeMap is not as fast in tests, but better than nothing. @@ -447,12 +448,19 @@ where // the last entry. This bijection proves the algorithm fair. debug_assert!(amount <= length); let mut indices = Vec::with_capacity(amount as usize); - for j in length - amount..length { - let t = rng.random_range(..=j); - if let Some(pos) = indices.iter().position(|&x| x == t) { - indices[pos] = j; + let mut len = 0; + let ptr = indices.as_mut_ptr(); + // safety: the index is bounded by the length of indices + unsafe { + for j in length - amount..length { + let t = rng.random_range(..=j); + if let Some(pos) = indices.iter().position(|&x| x == t) { + *indices.get_unchecked_mut(pos) = j; + } + ptr::write(ptr.add(len), t); + len += 1; + indices.set_len(len); } - indices.push(t); } IndexVec::from(indices) }