Skip to content

Commit fd7ece5

Browse files
committed
IteratorRandom::sample: allow large "amount"
1 parent 8336923 commit fd7ece5

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ You may also find the [Upgrade Guide](https://rust-random.github.io/book/update.
1919
- Remove fns `SeedableRng::from_os_rng`, `try_from_os_rng` (#1674)
2020
- Remove `Clone` support for `StdRng`, `ReseedingRng` (#1677)
2121
- Use `postcard` instead of `bincode` to test the serde feature (#1693)
22+
- Avoid excessive allocation `IteratorRandom::sample` when `amount` is much larger than iterator size
2223

2324
### Additions
2425
- Add fns `IndexedRandom::choose_iter`, `choose_weighted_iter` (#1632)

src/seq/iterator.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,22 @@ pub trait IteratorRandom: Iterator + Sized {
245245
where
246246
R: Rng + ?Sized,
247247
{
248-
let mut reservoir = Vec::with_capacity(amount);
248+
let (size_lower_bound, _size_upper_bound) = self.size_hint();
249+
250+
// If the requested amount is much larger than the iterator size,
251+
// avoid excessive allocation even that it is temporary.
252+
// This also prevents allocation panic for small iterators but large requested amount.
253+
let capacity = core::cmp::min(
254+
amount,
255+
core::cmp::max(
256+
size_lower_bound,
257+
(32usize << 10)
258+
.checked_div(size_of::<Self::Item>())
259+
.unwrap_or(0),
260+
),
261+
);
262+
263+
let mut reservoir = Vec::with_capacity(capacity);
249264
reservoir.extend(self.by_ref().take(amount));
250265

251266
// Continue unless the iterator was exhausted

0 commit comments

Comments
 (0)