1
+ use crate :: iter:: { DoubleEndedIterator , FusedIterator , Iterator , TrustedLen } ;
1
2
use crate :: ops:: Try ;
2
3
use crate :: usize;
3
4
4
- use super :: super :: { DoubleEndedIterator , FusedIterator , Iterator , TrustedLen } ;
5
-
6
5
/// An iterator that links two iterators together, in a chain.
7
6
///
8
7
/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its
@@ -14,37 +13,34 @@ use super::super::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
14
13
#[ must_use = "iterators are lazy and do nothing unless consumed" ]
15
14
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
16
15
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 > ,
20
23
}
21
24
impl < A , B > Chain < A , B > {
22
25
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 ) }
24
27
}
25
28
}
26
29
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
+ } ;
48
44
}
49
45
50
46
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
@@ -57,128 +53,99 @@ where
57
53
58
54
#[ inline]
59
55
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,
70
59
}
71
60
}
72
61
73
62
#[ inline]
74
63
#[ rustc_inherit_overflow_checks]
75
64
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 ,
80
70
}
81
71
}
82
72
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
84
74
where
85
75
Self : Sized ,
86
76
F : FnMut ( Acc , Self :: Item ) -> R ,
87
77
R : Try < Ok = Acc > ,
88
78
{
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 ;
98
82
}
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 ;
101
86
}
102
- Try :: from_ok ( accum )
87
+ Try :: from_ok ( acc )
103
88
}
104
89
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
106
91
where
107
92
F : FnMut ( Acc , Self :: Item ) -> Acc ,
108
93
{
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) ;
115
96
}
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) ;
121
99
}
122
- accum
100
+ acc
123
101
}
124
102
125
103
#[ inline]
126
104
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) ;
137
109
}
110
+ n -= 1 ;
138
111
}
139
- ChainState :: Back => { }
112
+ self . a = None ;
140
113
}
141
- if let ChainState :: Back = self . state { self . b . nth ( n) } else { None }
114
+ fuse ! ( self . b. nth( n) )
142
115
}
143
116
144
117
#[ inline]
145
118
fn find < P > ( & mut self , mut predicate : P ) -> Option < Self :: Item >
146
119
where
147
120
P : FnMut ( & Self :: Item ) -> bool ,
148
121
{
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,
159
125
}
160
126
}
161
127
162
128
#[ inline]
163
129
fn last ( self ) -> Option < A :: Item > {
164
- match self . state {
165
- ChainState :: Both => {
130
+ match self {
131
+ Chain { a : Some ( a ) , b : Some ( b ) } => {
166
132
// 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 ( ) ;
169
135
b_last. or ( a_last)
170
136
}
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 ,
173
140
}
174
141
}
175
142
176
143
#[ inline]
177
144
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 ( ) ;
182
149
183
150
let lower = a_lower. saturating_add ( b_lower) ;
184
151
@@ -189,8 +156,9 @@ where
189
156
190
157
( lower, upper)
191
158
}
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 ) ) ,
194
162
}
195
163
}
196
164
}
@@ -203,82 +171,71 @@ where
203
171
{
204
172
#[ inline]
205
173
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,
216
177
}
217
178
}
218
179
219
180
#[ inline]
220
181
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) ;
231
186
}
187
+ n -= 1 ;
232
188
}
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,
234
202
}
235
- if let ChainState :: Front = self . state { self . a . nth_back ( n) } else { None }
236
203
}
237
204
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
239
206
where
240
207
Self : Sized ,
241
208
F : FnMut ( Acc , Self :: Item ) -> R ,
242
209
R : Try < Ok = Acc > ,
243
210
{
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 ;
253
214
}
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 ;
256
218
}
257
- Try :: from_ok ( accum )
219
+ Try :: from_ok ( acc )
258
220
}
259
221
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
261
223
where
262
224
F : FnMut ( Acc , Self :: Item ) -> Acc ,
263
225
{
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) ;
270
228
}
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) ;
276
231
}
277
- accum
232
+ acc
278
233
}
279
234
}
280
235
281
236
// 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.
282
239
#[ stable( feature = "fused" , since = "1.26.0" ) ]
283
240
impl < A , B > FusedIterator for Chain < A , B >
284
241
where
0 commit comments