@@ -21,16 +21,15 @@ use super::{FusedIterator, TrustedLen};
21
21
#[ unstable( feature = "step_trait" ,
22
22
reason = "likely to be replaced by finer-grained traits" ,
23
23
issue = "42168" ) ]
24
- pub trait Step : PartialOrd + Sized {
24
+ pub trait Step : PartialOrd + Sized + Clone {
25
25
/// Steps `self` if possible.
26
- fn step ( & self , by : & Self ) -> Option < Self > ;
26
+ fn step ( & self , by : usize ) -> Option < Self > ;
27
27
28
28
/// Returns the number of steps between two step objects. The count is
29
29
/// inclusive of `start` and exclusive of `end`.
30
30
///
31
- /// Returns `None` if it is not possible to calculate `steps_between`
32
- /// without overflow.
33
- fn steps_between ( start : & Self , end : & Self , by : & Self ) -> Option < usize > ;
31
+ /// Returns `None` if the resultant number of steps overflows usize.
32
+ fn steps_between ( start : & Self , end : & Self , by : usize ) -> Option < usize > ;
34
33
35
34
/// Same as `steps_between`, but with a `by` of 1
36
35
fn steps_between_by_one ( start : & Self , end : & Self ) -> Option < usize > ;
@@ -58,25 +57,25 @@ macro_rules! step_impl_unsigned {
58
57
issue = "42168" ) ]
59
58
impl Step for $t {
60
59
#[ inline]
61
- fn step( & self , by: & $t) -> Option <$t> {
62
- ( * self ) . checked_add( * by)
60
+ fn step( & self , by: usize ) -> Option <$t> {
61
+ // If casting usize to Self fails, this means overflow happened.
62
+ Self :: cast( by) . ok( ) . and_then( |by| ( * self ) . checked_add( by) )
63
63
}
64
+
64
65
#[ inline]
65
66
#[ allow( trivial_numeric_casts) ]
66
- fn steps_between( start: & $t, end: & $t, by: & $t) -> Option <usize > {
67
- if * by == 0 { return None ; }
68
- if * start < * end {
69
- // Note: We assume $t <= usize here
70
- let diff = ( * end - * start) as usize ;
71
- let by = * by as usize ;
72
- if diff % by > 0 {
73
- Some ( diff / by + 1 )
67
+ fn steps_between( start: & $t, end: & $t, by: usize ) -> Option <usize > {
68
+ if by == 0 { return None ; }
69
+ Self :: cast( by) . ok( ) . and_then( |by| if * start < * end {
70
+ let diff = * end - * start;
71
+ usize :: cast( if diff % by > 0 {
72
+ diff / by + 1
74
73
} else {
75
- Some ( diff / by)
76
- }
74
+ diff / by
75
+ } ) . ok ( )
77
76
} else {
78
77
Some ( 0 )
79
- }
78
+ } )
80
79
}
81
80
82
81
#[ inline]
@@ -106,100 +105,39 @@ macro_rules! step_impl_unsigned {
106
105
107
106
#[ inline]
108
107
fn steps_between_by_one( start: & Self , end: & Self ) -> Option <usize > {
109
- Self :: steps_between( start, end, & 1 )
108
+ Self :: steps_between( start, end, 1 )
110
109
}
111
110
}
112
111
) * )
113
112
}
114
113
macro_rules! step_impl_signed {
115
- ( $( $t: ty) * ) => ( $(
114
+ ( $( $t: ty: $s : ty , ) * ) => ( $(
116
115
#[ unstable( feature = "step_trait" ,
117
116
reason = "likely to be replaced by finer-grained traits" ,
118
117
issue = "42168" ) ]
119
118
impl Step for $t {
120
119
#[ inline]
121
- fn step( & self , by: & $t ) -> Option <$t> {
122
- ( * self ) . checked_add( * by )
120
+ fn step( & self , by: usize ) -> Option <$t> {
121
+ Self :: cast ( by ) . ok ( ) . and_then ( |by| ( * self ) . checked_add( by ) )
123
122
}
123
+
124
124
#[ inline]
125
125
#[ allow( trivial_numeric_casts) ]
126
- fn steps_between( start: & $t, end: & $t, by: & $t) -> Option <usize > {
127
- if * by == 0 { return None ; }
128
- let diff: usize ;
129
- let by_u: usize ;
130
- if * by > 0 {
131
- if * start >= * end {
132
- return Some ( 0 ) ;
133
- }
134
- // Note: We assume $t <= isize here
135
- // Use .wrapping_sub and cast to usize to compute the
136
- // difference that may not fit inside the range of isize.
137
- diff = ( * end as isize ) . wrapping_sub( * start as isize ) as usize ;
138
- by_u = * by as usize ;
139
- } else {
140
- if * start <= * end {
141
- return Some ( 0 ) ;
142
- }
143
- diff = ( * start as isize ) . wrapping_sub( * end as isize ) as usize ;
144
- by_u = ( * by as isize ) . wrapping_mul( -1 ) as usize ;
145
- }
146
- if diff % by_u > 0 {
147
- Some ( diff / by_u + 1 )
126
+ fn steps_between( start: & $t, end: & $t, by: usize ) -> Option <usize > {
127
+ if by == 0 { return None ; }
128
+ <$s>:: cast( by) . ok( ) . and_then( |by| if * start < * end {
129
+ let diff = end. wrapping_sub( * start) as $s;
130
+ usize :: cast( if diff % by > 0 {
131
+ diff / by + 1
132
+ } else {
133
+ diff / by
134
+ } ) . ok( )
148
135
} else {
149
- Some ( diff / by_u)
150
- }
151
- }
152
-
153
- #[ inline]
154
- fn is_negative( & self ) -> bool {
155
- * self < 0
156
- }
157
-
158
- #[ inline]
159
- fn replace_one( & mut self ) -> Self {
160
- mem:: replace( self , 1 )
161
- }
162
-
163
- #[ inline]
164
- fn replace_zero( & mut self ) -> Self {
165
- mem:: replace( self , 0 )
166
- }
167
-
168
- #[ inline]
169
- fn add_one( & self ) -> Self {
170
- Add :: add( * self , 1 )
171
- }
172
-
173
- #[ inline]
174
- fn sub_one( & self ) -> Self {
175
- Sub :: sub( * self , 1 )
176
- }
177
-
178
- #[ inline]
179
- fn steps_between_by_one( start: & Self , end: & Self ) -> Option <usize > {
180
- Self :: steps_between( start, end, & 1 )
181
- }
182
- }
183
- ) * )
184
- }
185
-
186
- macro_rules! step_impl_no_between {
187
- ( $( $t: ty) * ) => ( $(
188
- #[ unstable( feature = "step_trait" ,
189
- reason = "likely to be replaced by finer-grained traits" ,
190
- issue = "42168" ) ]
191
- impl Step for $t {
192
- #[ inline]
193
- fn step( & self , by: & $t) -> Option <$t> {
194
- ( * self ) . checked_add( * by)
195
- }
196
- #[ inline]
197
- fn steps_between( _a: & $t, _b: & $t, _by: & $t) -> Option <usize > {
198
- None
136
+ Some ( 0 )
137
+ } )
199
138
}
200
139
201
140
#[ inline]
202
- #[ allow( unused_comparisons) ]
203
141
fn is_negative( & self ) -> bool {
204
142
* self < 0
205
143
}
@@ -226,23 +164,14 @@ macro_rules! step_impl_no_between {
226
164
227
165
#[ inline]
228
166
fn steps_between_by_one( start: & Self , end: & Self ) -> Option <usize > {
229
- Self :: steps_between( start, end, & 1 )
167
+ Self :: steps_between( start, end, 1 )
230
168
}
231
169
}
232
170
) * )
233
171
}
234
172
235
- step_impl_unsigned ! ( usize u8 u16 u32 ) ;
236
- step_impl_signed ! ( isize i8 i16 i32 ) ;
237
- #[ cfg( target_pointer_width = "64" ) ]
238
- step_impl_unsigned ! ( u64 ) ;
239
- #[ cfg( target_pointer_width = "64" ) ]
240
- step_impl_signed ! ( i64 ) ;
241
- // If the target pointer width is not 64-bits, we
242
- // assume here that it is less than 64-bits.
243
- #[ cfg( not( target_pointer_width = "64" ) ) ]
244
- step_impl_no_between ! ( u64 i64 ) ;
245
- step_impl_no_between ! ( u128 i128 ) ;
173
+ step_impl_unsigned ! ( usize u8 u16 u32 u64 u128 ) ;
174
+ step_impl_signed ! ( isize : usize , i8 : u8 , i16 : u16 , i32 : u32 , i64 : u64 , i128 : u128 , ) ;
246
175
247
176
macro_rules! range_exact_iter_impl {
248
177
( $( $t: ty) * ) => ( $(
@@ -300,6 +229,28 @@ impl<A: Step> Iterator for ops::Range<A> where
300
229
None => ( 0 , None )
301
230
}
302
231
}
232
+
233
+ #[ inline]
234
+ fn count ( self ) -> usize {
235
+ if let Some ( x) = Step :: steps_between_by_one ( & self . start , & self . end ) {
236
+ x
237
+ } else {
238
+ panic ! ( "accumulator overflowed while counting the elements" )
239
+ }
240
+ }
241
+
242
+ #[ inline]
243
+ fn nth ( & mut self , n : usize ) -> Option < Self :: Item > {
244
+ Step :: step ( & self . start , n) . and_then ( |next| if next < self . end {
245
+ self . start = next. add_one ( ) ;
246
+ Some ( next)
247
+ } else {
248
+ None
249
+ } )
250
+ }
251
+
252
+ // TODO: last specialisation if `A: Sub` and/or Range<A> is a DoubleEndedIterator.
253
+ // so self.end.sub_one() or self.next_back()
303
254
}
304
255
305
256
// These macros generate `ExactSizeIterator` impls for various range types.
@@ -313,11 +264,11 @@ range_incl_exact_iter_impl!(u8 u16 i8 i16);
313
264
//
314
265
// They need to guarantee that .size_hint() is either exact, or that
315
266
// the upper bound is None when it does not fit the type limits.
316
- range_trusted_len_impl ! ( usize isize u8 i8 u16 i16 u32 i32 i64 u64 ) ;
317
- range_incl_trusted_len_impl ! ( usize isize u8 i8 u16 i16 u32 i32 i64 u64 ) ;
267
+ range_trusted_len_impl ! ( usize isize u8 i8 u16 i16 u32 i32 i64 u64 i128 u128 ) ;
268
+ range_incl_trusted_len_impl ! ( usize isize u8 i8 u16 i16 u32 i32 i64 u64 i128 u128 ) ;
318
269
319
270
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
320
- impl < A : Step + Clone > DoubleEndedIterator for ops:: Range < A > where
271
+ impl < A : Step > DoubleEndedIterator for ops:: Range < A > where
321
272
for < ' a > & ' a A : Add < & ' a A , Output = A > ,
322
273
for < ' a > & ' a A : Sub < & ' a A , Output = A >
323
274
{
@@ -353,6 +304,23 @@ impl<A: Step> Iterator for ops::RangeFrom<A> where
353
304
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
354
305
( usize:: MAX , None )
355
306
}
307
+
308
+ #[ inline]
309
+ fn count ( self ) -> usize {
310
+ usize:: MAX
311
+ }
312
+
313
+ #[ inline]
314
+ fn nth ( & mut self , n : usize ) -> Option < Self :: Item > {
315
+ let next = Step :: step ( & self . start , n) . unwrap ( ) ;
316
+ self . start = next. add_one ( ) ;
317
+ Some ( next)
318
+ }
319
+
320
+ #[ cold]
321
+ fn last ( self ) -> Option < Self :: Item > {
322
+ panic ! ( "Iterator::last on a `x..` cannot work" )
323
+ }
356
324
}
357
325
358
326
#[ unstable( feature = "fused" , issue = "35602" ) ]
@@ -394,6 +362,46 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> where
394
362
None => ( 0 , None ) ,
395
363
}
396
364
}
365
+
366
+ #[ inline]
367
+ fn count ( self ) -> usize {
368
+ if self . start > self . end {
369
+ 0
370
+ } else {
371
+ if let Some ( x) = Step :: steps_between_by_one ( & self . start , & self . end ) {
372
+ x. add_one ( )
373
+ } else {
374
+ panic ! ( "accumulator overflowed while counting the elements" )
375
+ }
376
+ }
377
+ }
378
+
379
+ #[ inline]
380
+ fn nth ( & mut self , n : usize ) -> Option < Self :: Item > {
381
+ use cmp:: Ordering :: * ;
382
+ Step :: step ( & self . start , n) . and_then ( |next| match next. partial_cmp ( & self . end ) {
383
+ Some ( Less ) => {
384
+ self . start = next. add_one ( ) ;
385
+ Some ( next)
386
+ } ,
387
+ Some ( Equal ) => {
388
+ // Avoid overflow in the case `self.end` is a `max_value()`
389
+ self . end . replace_zero ( ) ;
390
+ self . start . replace_one ( ) ;
391
+ Some ( next)
392
+ } ,
393
+ _ => None
394
+ } )
395
+ }
396
+
397
+ #[ inline]
398
+ fn last ( self ) -> Option < Self :: Item > {
399
+ if self . start <= self . end {
400
+ Some ( self . end )
401
+ } else {
402
+ None
403
+ }
404
+ }
397
405
}
398
406
399
407
#[ unstable( feature = "inclusive_range" , reason = "recently added, follows RFC" , issue = "28237" ) ]
0 commit comments