Skip to content

Commit 2bdea23

Browse files
Boost performance for sample_floyd
1 parent 7808f4e commit 2bdea23

File tree

2 files changed

+14
-5
lines changed

2 files changed

+14
-5
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
1212
- Fix feature `simd_support` for recent nightly rust (#1586)
1313
- Add `Alphabetic` distribution. (#1587)
1414
- Re-export `rand_core` (#1602)
15+
- Boost performance of `sample_floyd` (#1621)
1516

1617
## [0.9.0] - 2025-01-27
1718
### Security and unsafe

src/seq/index.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
//! Low-level API for sampling indices
1010
use alloc::vec::{self, Vec};
11+
use core::ptr;
1112
use core::slice;
1213
use core::{hash::Hash, ops::AddAssign};
1314
// BTreeMap is not as fast in tests, but better than nothing.
@@ -447,12 +448,19 @@ where
447448
// the last entry. This bijection proves the algorithm fair.
448449
debug_assert!(amount <= length);
449450
let mut indices = Vec::with_capacity(amount as usize);
450-
for j in length - amount..length {
451-
let t = rng.random_range(..=j);
452-
if let Some(pos) = indices.iter().position(|&x| x == t) {
453-
indices[pos] = j;
451+
let mut len = 0;
452+
let ptr = indices.as_mut_ptr();
453+
// safety: the index is bounded by the length of indices
454+
unsafe {
455+
for j in length - amount..length {
456+
let t = rng.random_range(..=j);
457+
if let Some(pos) = indices.iter().position(|&x| x == t) {
458+
*indices.get_unchecked_mut(pos) = j;
459+
}
460+
ptr::write(ptr.add(len), t);
461+
len += 1;
462+
indices.set_len(len);
454463
}
455-
indices.push(t);
456464
}
457465
IndexVec::from(indices)
458466
}

0 commit comments

Comments
 (0)