Skip to content

Commit da6ab95

Browse files
committed
Auto merge of #56932 - clarcharr:iter_refactor, r=Centril
Refactor core::iter module A while back, I refactored `core::ops` in #42523 because the module had become a giant mess and was difficult to modify. Now, I'm doing the same with the `core::iter` module. Like the `core::ops` refactor, things have been split up into multiple commits to make rebasing easier, and so that you can follow changes. Although the diffs are hard to decipher, the only actual code changes I've made in the first few commits are to modify exports and imports. I save all of the actual code refactoring, e.g. modifying what methods are called, for the end.
2 parents 8611577 + 02bda7a commit da6ab95

File tree

16 files changed

+4032
-3862
lines changed

16 files changed

+4032
-3862
lines changed

src/libcore/iter/adapters/chain.rs

+260
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
use ops::Try;
2+
use usize;
3+
use super::super::{Iterator, DoubleEndedIterator, FusedIterator, TrustedLen};
4+
5+
/// An iterator that strings two iterators together.
6+
///
7+
/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its
8+
/// documentation for more.
9+
///
10+
/// [`chain`]: trait.Iterator.html#method.chain
11+
/// [`Iterator`]: trait.Iterator.html
12+
#[derive(Clone, Debug)]
13+
#[must_use = "iterators are lazy and do nothing unless consumed"]
14+
#[stable(feature = "rust1", since = "1.0.0")]
15+
pub struct Chain<A, B> {
16+
a: A,
17+
b: B,
18+
state: ChainState,
19+
}
20+
impl<A, B> Chain<A, B> {
21+
pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
22+
Chain { a, b, state: ChainState::Both }
23+
}
24+
}
25+
26+
// The iterator protocol specifies that iteration ends with the return value
27+
// `None` from `.next()` (or `.next_back()`) and it is unspecified what
28+
// further calls return. The chain adaptor must account for this since it uses
29+
// two subiterators.
30+
//
31+
// It uses three states:
32+
//
33+
// - Both: `a` and `b` are remaining
34+
// - Front: `a` remaining
35+
// - Back: `b` remaining
36+
//
37+
// The fourth state (neither iterator is remaining) only occurs after Chain has
38+
// returned None once, so we don't need to store this state.
39+
#[derive(Clone, Debug)]
40+
enum ChainState {
41+
// both front and back iterator are remaining
42+
Both,
43+
// only front is remaining
44+
Front,
45+
// only back is remaining
46+
Back,
47+
}
48+
49+
#[stable(feature = "rust1", since = "1.0.0")]
50+
impl<A, B> Iterator for Chain<A, B> where
51+
A: Iterator,
52+
B: Iterator<Item = A::Item>
53+
{
54+
type Item = A::Item;
55+
56+
#[inline]
57+
fn next(&mut self) -> Option<A::Item> {
58+
match self.state {
59+
ChainState::Both => match self.a.next() {
60+
elt @ Some(..) => elt,
61+
None => {
62+
self.state = ChainState::Back;
63+
self.b.next()
64+
}
65+
},
66+
ChainState::Front => self.a.next(),
67+
ChainState::Back => self.b.next(),
68+
}
69+
}
70+
71+
#[inline]
72+
#[rustc_inherit_overflow_checks]
73+
fn count(self) -> usize {
74+
match self.state {
75+
ChainState::Both => self.a.count() + self.b.count(),
76+
ChainState::Front => self.a.count(),
77+
ChainState::Back => self.b.count(),
78+
}
79+
}
80+
81+
fn try_fold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R where
82+
Self: Sized, F: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
83+
{
84+
let mut accum = init;
85+
match self.state {
86+
ChainState::Both | ChainState::Front => {
87+
accum = self.a.try_fold(accum, &mut f)?;
88+
if let ChainState::Both = self.state {
89+
self.state = ChainState::Back;
90+
}
91+
}
92+
_ => { }
93+
}
94+
if let ChainState::Back = self.state {
95+
accum = self.b.try_fold(accum, &mut f)?;
96+
}
97+
Try::from_ok(accum)
98+
}
99+
100+
fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
101+
where F: FnMut(Acc, Self::Item) -> Acc,
102+
{
103+
let mut accum = init;
104+
match self.state {
105+
ChainState::Both | ChainState::Front => {
106+
accum = self.a.fold(accum, &mut f);
107+
}
108+
_ => { }
109+
}
110+
match self.state {
111+
ChainState::Both | ChainState::Back => {
112+
accum = self.b.fold(accum, &mut f);
113+
}
114+
_ => { }
115+
}
116+
accum
117+
}
118+
119+
#[inline]
120+
fn nth(&mut self, mut n: usize) -> Option<A::Item> {
121+
match self.state {
122+
ChainState::Both | ChainState::Front => {
123+
for x in self.a.by_ref() {
124+
if n == 0 {
125+
return Some(x)
126+
}
127+
n -= 1;
128+
}
129+
if let ChainState::Both = self.state {
130+
self.state = ChainState::Back;
131+
}
132+
}
133+
ChainState::Back => {}
134+
}
135+
if let ChainState::Back = self.state {
136+
self.b.nth(n)
137+
} else {
138+
None
139+
}
140+
}
141+
142+
#[inline]
143+
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item> where
144+
P: FnMut(&Self::Item) -> bool,
145+
{
146+
match self.state {
147+
ChainState::Both => match self.a.find(&mut predicate) {
148+
None => {
149+
self.state = ChainState::Back;
150+
self.b.find(predicate)
151+
}
152+
v => v
153+
},
154+
ChainState::Front => self.a.find(predicate),
155+
ChainState::Back => self.b.find(predicate),
156+
}
157+
}
158+
159+
#[inline]
160+
fn last(self) -> Option<A::Item> {
161+
match self.state {
162+
ChainState::Both => {
163+
// Must exhaust a before b.
164+
let a_last = self.a.last();
165+
let b_last = self.b.last();
166+
b_last.or(a_last)
167+
},
168+
ChainState::Front => self.a.last(),
169+
ChainState::Back => self.b.last()
170+
}
171+
}
172+
173+
#[inline]
174+
fn size_hint(&self) -> (usize, Option<usize>) {
175+
let (a_lower, a_upper) = self.a.size_hint();
176+
let (b_lower, b_upper) = self.b.size_hint();
177+
178+
let lower = a_lower.saturating_add(b_lower);
179+
180+
let upper = match (a_upper, b_upper) {
181+
(Some(x), Some(y)) => x.checked_add(y),
182+
_ => None
183+
};
184+
185+
(lower, upper)
186+
}
187+
}
188+
189+
#[stable(feature = "rust1", since = "1.0.0")]
190+
impl<A, B> DoubleEndedIterator for Chain<A, B> where
191+
A: DoubleEndedIterator,
192+
B: DoubleEndedIterator<Item=A::Item>,
193+
{
194+
#[inline]
195+
fn next_back(&mut self) -> Option<A::Item> {
196+
match self.state {
197+
ChainState::Both => match self.b.next_back() {
198+
elt @ Some(..) => elt,
199+
None => {
200+
self.state = ChainState::Front;
201+
self.a.next_back()
202+
}
203+
},
204+
ChainState::Front => self.a.next_back(),
205+
ChainState::Back => self.b.next_back(),
206+
}
207+
}
208+
209+
fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R where
210+
Self: Sized, F: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc>
211+
{
212+
let mut accum = init;
213+
match self.state {
214+
ChainState::Both | ChainState::Back => {
215+
accum = self.b.try_rfold(accum, &mut f)?;
216+
if let ChainState::Both = self.state {
217+
self.state = ChainState::Front;
218+
}
219+
}
220+
_ => { }
221+
}
222+
if let ChainState::Front = self.state {
223+
accum = self.a.try_rfold(accum, &mut f)?;
224+
}
225+
Try::from_ok(accum)
226+
}
227+
228+
fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
229+
where F: FnMut(Acc, Self::Item) -> Acc,
230+
{
231+
let mut accum = init;
232+
match self.state {
233+
ChainState::Both | ChainState::Back => {
234+
accum = self.b.rfold(accum, &mut f);
235+
}
236+
_ => { }
237+
}
238+
match self.state {
239+
ChainState::Both | ChainState::Front => {
240+
accum = self.a.rfold(accum, &mut f);
241+
}
242+
_ => { }
243+
}
244+
accum
245+
}
246+
247+
}
248+
249+
// Note: *both* must be fused to handle double-ended iterators.
250+
#[stable(feature = "fused", since = "1.26.0")]
251+
impl<A, B> FusedIterator for Chain<A, B>
252+
where A: FusedIterator,
253+
B: FusedIterator<Item=A::Item>,
254+
{}
255+
256+
#[unstable(feature = "trusted_len", issue = "37572")]
257+
unsafe impl<A, B> TrustedLen for Chain<A, B>
258+
where A: TrustedLen, B: TrustedLen<Item=A::Item>,
259+
{}
260+

0 commit comments

Comments
 (0)