Skip to content

Commit 859b8da

Browse files
committed
Implement Chain with Option fuses
The iterators are now "fused" with `Option` so we don't need separate state to track which part is already exhausted, and we may also get niche layout for `None`. We don't use the real `Fuse` adapter because its specialization for `FusedIterator` unconditionally descends into the iterator, and that could be expensive to keep revisiting stuff like nested chains. It also hurts compiler performance to add more iterator layers to `Chain`.
1 parent 39b6253 commit 859b8da

File tree

1 file changed

+106
-149
lines changed

1 file changed

+106
-149
lines changed

src/libcore/iter/adapters/chain.rs

+106-149
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1+
use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
12
use crate::ops::Try;
23
use crate::usize;
34

4-
use super::super::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
5-
65
/// An iterator that links two iterators together, in a chain.
76
///
87
/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its
@@ -14,37 +13,34 @@ use super::super::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
1413
#[must_use = "iterators are lazy and do nothing unless consumed"]
1514
#[stable(feature = "rust1", since = "1.0.0")]
1615
pub struct Chain<A, B> {
17-
a: A,
18-
b: B,
19-
state: ChainState,
16+
// These are "fused" with `Option` so we don't need separate state to track which part is
17+
// already exhausted, and we may also get niche layout for `None`. We don't use the real `Fuse`
18+
// adapter because its specialization for `FusedIterator` unconditionally descends into the
19+
// iterator, and that could be expensive to keep revisiting stuff like nested chains. It also
20+
// hurts compiler performance to add more iterator layers to `Chain`.
21+
a: Option<A>,
22+
b: Option<B>,
2023
}
2124
impl<A, B> Chain<A, B> {
2225
pub(in super::super) fn new(a: A, b: B) -> Chain<A, B> {
23-
Chain { a, b, state: ChainState::Both }
26+
Chain { a: Some(a), b: Some(b) }
2427
}
2528
}
2629

27-
// The iterator protocol specifies that iteration ends with the return value
28-
// `None` from `.next()` (or `.next_back()`) and it is unspecified what
29-
// further calls return. The chain adaptor must account for this since it uses
30-
// two subiterators.
31-
//
32-
// It uses three states:
33-
//
34-
// - Both: `a` and `b` are remaining
35-
// - Front: `a` remaining
36-
// - Back: `b` remaining
37-
//
38-
// The fourth state (neither iterator is remaining) only occurs after Chain has
39-
// returned None once, so we don't need to store this state.
40-
#[derive(Clone, Debug)]
41-
enum ChainState {
42-
// both front and back iterator are remaining
43-
Both,
44-
// only front is remaining
45-
Front,
46-
// only back is remaining
47-
Back,
30+
/// Fuse the iterator if the expression is `None`.
31+
macro_rules! fuse {
32+
($self:ident . $iter:ident . $($call:tt)+) => {
33+
match $self.$iter {
34+
Some(ref mut iter) => match iter.$($call)+ {
35+
None => {
36+
$self.$iter = None;
37+
None
38+
}
39+
item => item,
40+
},
41+
None => None,
42+
}
43+
};
4844
}
4945

5046
#[stable(feature = "rust1", since = "1.0.0")]
@@ -57,128 +53,99 @@ where
5753

5854
#[inline]
5955
fn next(&mut self) -> Option<A::Item> {
60-
match self.state {
61-
ChainState::Both => match self.a.next() {
62-
elt @ Some(..) => elt,
63-
None => {
64-
self.state = ChainState::Back;
65-
self.b.next()
66-
}
67-
},
68-
ChainState::Front => self.a.next(),
69-
ChainState::Back => self.b.next(),
56+
match fuse!(self.a.next()) {
57+
None => fuse!(self.b.next()),
58+
item => item,
7059
}
7160
}
7261

7362
#[inline]
7463
#[rustc_inherit_overflow_checks]
7564
fn count(self) -> usize {
76-
match self.state {
77-
ChainState::Both => self.a.count() + self.b.count(),
78-
ChainState::Front => self.a.count(),
79-
ChainState::Back => self.b.count(),
65+
match self {
66+
Chain { a: Some(a), b: Some(b) } => a.count() + b.count(),
67+
Chain { a: Some(a), b: None } => a.count(),
68+
Chain { a: None, b: Some(b) } => b.count(),
69+
Chain { a: None, b: None } => 0,
8070
}
8171
}
8272

83-
fn try_fold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
73+
fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
8474
where
8575
Self: Sized,
8676
F: FnMut(Acc, Self::Item) -> R,
8777
R: Try<Ok = Acc>,
8878
{
89-
let mut accum = init;
90-
match self.state {
91-
ChainState::Both | ChainState::Front => {
92-
accum = self.a.try_fold(accum, &mut f)?;
93-
if let ChainState::Both = self.state {
94-
self.state = ChainState::Back;
95-
}
96-
}
97-
_ => {}
79+
if let Some(ref mut a) = self.a {
80+
acc = a.try_fold(acc, &mut f)?;
81+
self.a = None;
9882
}
99-
if let ChainState::Back = self.state {
100-
accum = self.b.try_fold(accum, &mut f)?;
83+
if let Some(ref mut b) = self.b {
84+
acc = b.try_fold(acc, &mut f)?;
85+
self.b = None;
10186
}
102-
Try::from_ok(accum)
87+
Try::from_ok(acc)
10388
}
10489

105-
fn fold<Acc, F>(self, init: Acc, mut f: F) -> Acc
90+
fn fold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
10691
where
10792
F: FnMut(Acc, Self::Item) -> Acc,
10893
{
109-
let mut accum = init;
110-
match self.state {
111-
ChainState::Both | ChainState::Front => {
112-
accum = self.a.fold(accum, &mut f);
113-
}
114-
_ => {}
94+
if let Some(a) = self.a {
95+
acc = a.fold(acc, &mut f);
11596
}
116-
match self.state {
117-
ChainState::Both | ChainState::Back => {
118-
accum = self.b.fold(accum, &mut f);
119-
}
120-
_ => {}
97+
if let Some(b) = self.b {
98+
acc = b.fold(acc, &mut f);
12199
}
122-
accum
100+
acc
123101
}
124102

125103
#[inline]
126104
fn nth(&mut self, mut n: usize) -> Option<A::Item> {
127-
match self.state {
128-
ChainState::Both | ChainState::Front => {
129-
for x in self.a.by_ref() {
130-
if n == 0 {
131-
return Some(x);
132-
}
133-
n -= 1;
134-
}
135-
if let ChainState::Both = self.state {
136-
self.state = ChainState::Back;
105+
if let Some(ref mut a) = self.a {
106+
while let Some(x) = a.next() {
107+
if n == 0 {
108+
return Some(x);
137109
}
110+
n -= 1;
138111
}
139-
ChainState::Back => {}
112+
self.a = None;
140113
}
141-
if let ChainState::Back = self.state { self.b.nth(n) } else { None }
114+
fuse!(self.b.nth(n))
142115
}
143116

144117
#[inline]
145118
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
146119
where
147120
P: FnMut(&Self::Item) -> bool,
148121
{
149-
match self.state {
150-
ChainState::Both => match self.a.find(&mut predicate) {
151-
None => {
152-
self.state = ChainState::Back;
153-
self.b.find(predicate)
154-
}
155-
v => v,
156-
},
157-
ChainState::Front => self.a.find(predicate),
158-
ChainState::Back => self.b.find(predicate),
122+
match fuse!(self.a.find(&mut predicate)) {
123+
None => fuse!(self.b.find(predicate)),
124+
item => item,
159125
}
160126
}
161127

162128
#[inline]
163129
fn last(self) -> Option<A::Item> {
164-
match self.state {
165-
ChainState::Both => {
130+
match self {
131+
Chain { a: Some(a), b: Some(b) } => {
166132
// Must exhaust a before b.
167-
let a_last = self.a.last();
168-
let b_last = self.b.last();
133+
let a_last = a.last();
134+
let b_last = b.last();
169135
b_last.or(a_last)
170136
}
171-
ChainState::Front => self.a.last(),
172-
ChainState::Back => self.b.last(),
137+
Chain { a: Some(a), b: None } => a.last(),
138+
Chain { a: None, b: Some(b) } => b.last(),
139+
Chain { a: None, b: None } => None,
173140
}
174141
}
175142

176143
#[inline]
177144
fn size_hint(&self) -> (usize, Option<usize>) {
178-
match self.state {
179-
ChainState::Both => {
180-
let (a_lower, a_upper) = self.a.size_hint();
181-
let (b_lower, b_upper) = self.b.size_hint();
145+
match self {
146+
Chain { a: Some(a), b: Some(b) } => {
147+
let (a_lower, a_upper) = a.size_hint();
148+
let (b_lower, b_upper) = b.size_hint();
182149

183150
let lower = a_lower.saturating_add(b_lower);
184151

@@ -189,8 +156,9 @@ where
189156

190157
(lower, upper)
191158
}
192-
ChainState::Front => self.a.size_hint(),
193-
ChainState::Back => self.b.size_hint(),
159+
Chain { a: Some(a), b: None } => a.size_hint(),
160+
Chain { a: None, b: Some(b) } => b.size_hint(),
161+
Chain { a: None, b: None } => (0, Some(0)),
194162
}
195163
}
196164
}
@@ -203,82 +171,71 @@ where
203171
{
204172
#[inline]
205173
fn next_back(&mut self) -> Option<A::Item> {
206-
match self.state {
207-
ChainState::Both => match self.b.next_back() {
208-
elt @ Some(..) => elt,
209-
None => {
210-
self.state = ChainState::Front;
211-
self.a.next_back()
212-
}
213-
},
214-
ChainState::Front => self.a.next_back(),
215-
ChainState::Back => self.b.next_back(),
174+
match fuse!(self.b.next_back()) {
175+
None => fuse!(self.a.next_back()),
176+
item => item,
216177
}
217178
}
218179

219180
#[inline]
220181
fn nth_back(&mut self, mut n: usize) -> Option<A::Item> {
221-
match self.state {
222-
ChainState::Both | ChainState::Back => {
223-
for x in self.b.by_ref().rev() {
224-
if n == 0 {
225-
return Some(x);
226-
}
227-
n -= 1;
228-
}
229-
if let ChainState::Both = self.state {
230-
self.state = ChainState::Front;
182+
if let Some(ref mut b) = self.b {
183+
while let Some(x) = b.next_back() {
184+
if n == 0 {
185+
return Some(x);
231186
}
187+
n -= 1;
232188
}
233-
ChainState::Front => {}
189+
self.b = None;
190+
}
191+
fuse!(self.a.nth_back(n))
192+
}
193+
194+
#[inline]
195+
fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
196+
where
197+
P: FnMut(&Self::Item) -> bool,
198+
{
199+
match fuse!(self.b.rfind(&mut predicate)) {
200+
None => fuse!(self.a.rfind(predicate)),
201+
item => item,
234202
}
235-
if let ChainState::Front = self.state { self.a.nth_back(n) } else { None }
236203
}
237204

238-
fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R
205+
fn try_rfold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R
239206
where
240207
Self: Sized,
241208
F: FnMut(Acc, Self::Item) -> R,
242209
R: Try<Ok = Acc>,
243210
{
244-
let mut accum = init;
245-
match self.state {
246-
ChainState::Both | ChainState::Back => {
247-
accum = self.b.try_rfold(accum, &mut f)?;
248-
if let ChainState::Both = self.state {
249-
self.state = ChainState::Front;
250-
}
251-
}
252-
_ => {}
211+
if let Some(ref mut b) = self.b {
212+
acc = b.try_rfold(acc, &mut f)?;
213+
self.b = None;
253214
}
254-
if let ChainState::Front = self.state {
255-
accum = self.a.try_rfold(accum, &mut f)?;
215+
if let Some(ref mut a) = self.a {
216+
acc = a.try_rfold(acc, f)?;
217+
self.a = None;
256218
}
257-
Try::from_ok(accum)
219+
Try::from_ok(acc)
258220
}
259221

260-
fn rfold<Acc, F>(self, init: Acc, mut f: F) -> Acc
222+
fn rfold<Acc, F>(self, mut acc: Acc, mut f: F) -> Acc
261223
where
262224
F: FnMut(Acc, Self::Item) -> Acc,
263225
{
264-
let mut accum = init;
265-
match self.state {
266-
ChainState::Both | ChainState::Back => {
267-
accum = self.b.rfold(accum, &mut f);
268-
}
269-
_ => {}
226+
if let Some(b) = self.b {
227+
acc = b.rfold(acc, &mut f);
270228
}
271-
match self.state {
272-
ChainState::Both | ChainState::Front => {
273-
accum = self.a.rfold(accum, &mut f);
274-
}
275-
_ => {}
229+
if let Some(a) = self.a {
230+
acc = a.rfold(acc, f);
276231
}
277-
accum
232+
acc
278233
}
279234
}
280235

281236
// Note: *both* must be fused to handle double-ended iterators.
237+
// Now that we "fuse" both sides, we *could* implement this unconditionally,
238+
// but we should be cautious about committing to that in the public API.
282239
#[stable(feature = "fused", since = "1.26.0")]
283240
impl<A, B> FusedIterator for Chain<A, B>
284241
where

0 commit comments

Comments
 (0)