Skip to content

Commit 2c82c5e

Browse files
Merge #552
552: Fix subtraction overflow in DuplicatesBy size_hint r=phimuemue a=arpankapoor Sample that panics with `attempt to subtract with overflow` in a `debug` build: ```rust use itertools::Itertools; fn main() { println!("{:?}", vec!["a", "b", "c", "c"].iter().duplicates().collect_vec()); } ``` Co-authored-by: Arpan Kapoor <a@arpankapoor.com>
2 parents c2587f0 + 4a14bf7 commit 2c82c5e

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

src/duplicates_impl.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,18 @@ mod private {
8484
#[inline]
8585
fn size_hint(&self) -> (usize, Option<usize>) {
8686
let (_, hi) = self.iter.size_hint();
87-
// There are `hi` number of items left in the base iterator. In the best case scenario,
88-
// these items are exactly the same as the ones pending (i.e items seen exactly once so
89-
// far), plus (hi - pending) / 2 pairs of never seen before items.
9087
let hi = hi.map(|hi| {
91-
let max_pending = std::cmp::min(self.meta.pending, hi);
92-
let max_new = std::cmp::max(hi - self.meta.pending, 0) / 2;
93-
max_pending + max_new
88+
if hi <= self.meta.pending {
89+
// fewer or equally many iter-remaining elements than pending elements
90+
// => at most, each iter-remaining element is matched
91+
hi
92+
} else {
93+
// fewer pending elements than iter-remaining elements
94+
// => at most:
95+
// * each pending element is matched
96+
// * the other iter-remaining elements come in pairs
97+
self.meta.pending + (hi - self.meta.pending) / 2
98+
}
9499
});
95100
// The lower bound is always 0 since we might only get unique items from now on
96101
(0, hi)

tests/test_std.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ fn duplicates() {
8484
it::assert_equal(ys.iter(), xs.iter().rev().duplicates().rev());
8585
let ys_rev = [1, 0];
8686
it::assert_equal(ys_rev.iter(), xs.iter().duplicates().rev());
87+
88+
let xs = vec![0, 1, 2, 1, 2];
89+
let ys = vec![1, 2];
90+
assert_eq!(ys, xs.iter().duplicates().cloned().collect_vec());
91+
assert_eq!(ys, xs.iter().rev().duplicates().rev().cloned().collect_vec());
92+
let ys_rev = vec![2, 1];
93+
assert_eq!(ys_rev, xs.iter().duplicates().rev().cloned().collect_vec());
8794
}
8895

8996
#[test]

0 commit comments

Comments
 (0)