Skip to content

Commit 6c2e8f6

Browse files
Takashiidobephimuemue
authored andcommitted
Fix PadUsing::next_back (2) PadUsing counts elements_from_next and elements_from_next_back
Remove fold/rfold: Correctness is more important than performance. Maybe we can come back and re-implement them later. Fixes: #1065
1 parent 417b526 commit 6c2e8f6

1 file changed

Lines changed: 53 additions & 51 deletions

File tree

src/pad_tail.rs

Lines changed: 53 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::size_hint;
21
use std::iter::{Fuse, FusedIterator};
32

43
/// An iterator adaptor that pads a sequence to a minimum length by filling
@@ -11,28 +10,36 @@ use std::iter::{Fuse, FusedIterator};
1110
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
1211
pub struct PadUsing<I, F> {
1312
iter: Fuse<I>,
14-
min: usize,
15-
pos: usize,
13+
elements_from_next: usize,
14+
elements_from_next_back: usize,
15+
elements_required: usize,
1616
filler: F,
1717
}
1818

1919
impl<I, F> std::fmt::Debug for PadUsing<I, F>
2020
where
2121
I: std::fmt::Debug,
2222
{
23-
debug_fmt_fields!(PadUsing, iter, min, pos);
23+
debug_fmt_fields!(
24+
PadUsing,
25+
iter,
26+
elements_from_next,
27+
elements_from_next_back,
28+
elements_required
29+
);
2430
}
2531

2632
/// Create a new `PadUsing` iterator.
27-
pub fn pad_using<I, F>(iter: I, min: usize, filler: F) -> PadUsing<I, F>
33+
pub fn pad_using<I, F>(iter: I, elements_required: usize, filler: F) -> PadUsing<I, F>
2834
where
2935
I: Iterator,
3036
F: FnMut(usize) -> I::Item,
3137
{
3238
PadUsing {
3339
iter: iter.fuse(),
34-
min,
35-
pos: 0,
40+
elements_from_next: 0,
41+
elements_from_next_back: 0,
42+
elements_required,
3643
filler,
3744
}
3845
}
@@ -46,38 +53,34 @@ where
4653

4754
#[inline]
4855
fn next(&mut self) -> Option<Self::Item> {
49-
match self.iter.next() {
50-
None => {
51-
if self.pos < self.min {
52-
let e = Some((self.filler)(self.pos));
53-
self.pos += 1;
54-
e
55-
} else {
56-
None
57-
}
58-
}
59-
e => {
60-
self.pos += 1;
61-
e
62-
}
56+
let total_consumed = self.elements_from_next + self.elements_from_next_back;
57+
58+
if total_consumed >= self.elements_required {
59+
self.iter.next()
60+
} else if let Some(e) = self.iter.next() {
61+
self.elements_from_next += 1;
62+
Some(e)
63+
} else {
64+
let e = (self.filler)(self.elements_from_next);
65+
self.elements_from_next += 1;
66+
Some(e)
6367
}
6468
}
6569

6670
fn size_hint(&self) -> (usize, Option<usize>) {
67-
let tail = self.min.saturating_sub(self.pos);
68-
size_hint::max(self.iter.size_hint(), (tail, Some(tail)))
69-
}
71+
let total_consumed = self.elements_from_next + self.elements_from_next_back;
72+
73+
if total_consumed >= self.elements_required {
74+
return self.iter.size_hint();
75+
}
76+
77+
let elements_remaining = self.elements_required - total_consumed;
78+
let (low, high) = self.iter.size_hint();
79+
80+
let lower_bound = low.max(elements_remaining);
81+
let upper_bound = high.map(|h| h.max(elements_remaining));
7082

71-
fn fold<B, G>(self, mut init: B, mut f: G) -> B
72-
where
73-
G: FnMut(B, Self::Item) -> B,
74-
{
75-
let mut pos = self.pos;
76-
init = self.iter.fold(init, |acc, item| {
77-
pos += 1;
78-
f(acc, item)
79-
});
80-
(pos..self.min).map(self.filler).fold(init, f)
83+
(lower_bound, upper_bound)
8184
}
8285
}
8386

@@ -87,25 +90,24 @@ where
8790
F: FnMut(usize) -> I::Item,
8891
{
8992
fn next_back(&mut self) -> Option<Self::Item> {
90-
if self.min == 0 {
91-
self.iter.next_back()
92-
} else if self.iter.len() >= self.min {
93-
self.min -= 1;
94-
self.iter.next_back()
95-
} else {
96-
self.min -= 1;
97-
Some((self.filler)(self.min))
93+
let total_consumed = self.elements_from_next + self.elements_from_next_back;
94+
95+
if total_consumed >= self.elements_required {
96+
return self.iter.next_back();
9897
}
99-
}
10098

101-
fn rfold<B, G>(self, mut init: B, mut f: G) -> B
102-
where
103-
G: FnMut(B, Self::Item) -> B,
104-
{
105-
init = (self.iter.len()..self.min)
106-
.map(self.filler)
107-
.rfold(init, &mut f);
108-
self.iter.rfold(init, f)
99+
let elements_remaining = self.elements_required - total_consumed;
100+
self.elements_from_next_back += 1;
101+
102+
if self.iter.len() < elements_remaining {
103+
Some((self.filler)(
104+
self.elements_required - self.elements_from_next_back,
105+
))
106+
} else {
107+
let item = self.iter.next_back();
108+
debug_assert!(item.is_some()); // If this triggers, we should not have incremented elements_from_next_back, and the input iterator mistakenly reported that it would be able to produce at least elements_remaining items.
109+
item
110+
}
109111
}
110112
}
111113

0 commit comments

Comments
 (0)