Skip to content

Commit ebfd083

Browse files
author
Clar Fon
committed
Move Chain and ChainState to own module
1 parent 520e8b0 commit ebfd083

File tree

2 files changed

+258
-251
lines changed

2 files changed

+258
-251
lines changed

src/libcore/iter/adapters/chain.rs

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

0 commit comments

Comments
 (0)