Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix subtraction overflow in DuplicatesBy size_hint #552

Merged
merged 4 commits into from Aug 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 11 additions & 6 deletions src/duplicates_impl.rs
Expand Up @@ -84,13 +84,18 @@ mod private {
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let (_, hi) = self.iter.size_hint();
// There are `hi` number of items left in the base iterator. In the best case scenario,
// these items are exactly the same as the ones pending (i.e items seen exactly once so
// far), plus (hi - pending) / 2 pairs of never seen before items.
let hi = hi.map(|hi| {
let max_pending = std::cmp::min(self.meta.pending, hi);
let max_new = std::cmp::max(hi - self.meta.pending, 0) / 2;
max_pending + max_new
if hi <= self.meta.pending {
// fewer or equally many iter-remaining elements than pending elements
// => at most, each iter-remaining element is matched
hi
} else {
// fewer pending elements than iter-remaining elements
// => at most:
// * each pending element is matched
// * the other iter-remaining elements come in pairs
self.meta.pending + (hi - self.meta.pending) / 2
}
});
// The lower bound is always 0 since we might only get unique items from now on
(0, hi)
Expand Down
7 changes: 7 additions & 0 deletions tests/test_std.rs
Expand Up @@ -84,6 +84,13 @@ fn duplicates() {
it::assert_equal(ys.iter(), xs.iter().rev().duplicates().rev());
let ys_rev = [1, 0];
it::assert_equal(ys_rev.iter(), xs.iter().duplicates().rev());

let xs = vec![0, 1, 2, 1, 2];
let ys = vec![1, 2];
assert_eq!(ys, xs.iter().duplicates().cloned().collect_vec());
assert_eq!(ys, xs.iter().rev().duplicates().rev().cloned().collect_vec());
let ys_rev = vec![2, 1];
assert_eq!(ys_rev, xs.iter().duplicates().rev().cloned().collect_vec());
}

#[test]
Expand Down