File tree 2 files changed +72
-3
lines changed
2 files changed +72
-3
lines changed Original file line number Diff line number Diff line change @@ -705,9 +705,34 @@ impl<I> Iterator for StepBy<I> where I: Iterator {
705
705
}
706
706
n -= 1 ;
707
707
}
708
- // n and self.step are indices, thus we need to add 1 before multiplying.
709
- // After that we need to subtract 1 from the result to convert it back to an index.
710
- self . iter . nth ( ( n + 1 ) * ( self . step + 1 ) - 1 )
708
+ // n and self.step are indices, we need to add 1 to get the amount of elements
709
+ // When calling `.nth`, we need to subtract 1 again to convert back to an index
710
+ // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1`
711
+ let mut step = self . step + 1 ;
712
+ // n + 1 could overflow
713
+ // thus, if n is usize::MAX, instead of adding one, we call .nth(step)
714
+ if n == usize:: MAX {
715
+ self . iter . nth ( step - 1 ) ;
716
+ } else {
717
+ n += 1 ;
718
+ }
719
+
720
+ // overflow handling
721
+ while n. checked_mul ( step) . is_none ( ) {
722
+ let div_n = usize:: MAX / n;
723
+ let div_step = usize:: MAX / step;
724
+ let nth_n = div_n * n;
725
+ let nth_step = div_step * step;
726
+ let nth = if nth_n > nth_step {
727
+ step -= div_n;
728
+ nth_n
729
+ } else {
730
+ n -= div_step;
731
+ nth_step
732
+ } ;
733
+ self . iter . nth ( nth - 1 ) ;
734
+ }
735
+ self . iter . nth ( n * step - 1 )
711
736
}
712
737
}
713
738
Original file line number Diff line number Diff line change @@ -179,6 +179,50 @@ fn test_iterator_step_by_nth() {
179
179
assert_eq ! ( it. clone( ) . nth( 42 ) , None ) ;
180
180
}
181
181
182
+ #[ test]
183
+ fn test_iterator_step_by_nth_overflow ( ) {
184
+ #[ cfg( target_pointer_width = "8" ) ]
185
+ type Bigger = u16 ;
186
+ #[ cfg( target_pointer_width = "16" ) ]
187
+ type Bigger = u32 ;
188
+ #[ cfg( target_pointer_width = "32" ) ]
189
+ type Bigger = u64 ;
190
+ #[ cfg( target_pointer_width = "64" ) ]
191
+ type Bigger = u128 ;
192
+
193
+ #[ derive( Clone ) ]
194
+ struct Test ( Bigger ) ;
195
+ impl < ' a > Iterator for & ' a mut Test {
196
+ type Item = i32 ;
197
+ fn next ( & mut self ) -> Option < Self :: Item > { Some ( 21 ) }
198
+ fn nth ( & mut self , n : usize ) -> Option < Self :: Item > {
199
+ self . 0 += n as Bigger + 1 ;
200
+ Some ( 42 )
201
+ }
202
+ }
203
+
204
+ let mut it = Test ( 0 ) ;
205
+ let root = usize:: MAX >> ( :: std:: mem:: size_of :: < usize > ( ) * 8 / 2 ) ;
206
+ let n = root + 20 ;
207
+ ( & mut it) . step_by ( n) . nth ( n) ;
208
+ assert_eq ! ( it. 0 , n as Bigger * n as Bigger ) ;
209
+
210
+ // large step
211
+ let mut it = Test ( 0 ) ;
212
+ ( & mut it) . step_by ( usize:: MAX ) . nth ( 5 ) ;
213
+ assert_eq ! ( it. 0 , ( usize :: MAX as Bigger ) * 5 ) ;
214
+
215
+ // n + 1 overflows
216
+ let mut it = Test ( 0 ) ;
217
+ ( & mut it) . step_by ( 2 ) . nth ( usize:: MAX ) ;
218
+ assert_eq ! ( it. 0 , ( usize :: MAX as Bigger ) * 2 ) ;
219
+
220
+ // n + 1 overflows
221
+ let mut it = Test ( 0 ) ;
222
+ ( & mut it) . step_by ( 1 ) . nth ( usize:: MAX ) ;
223
+ assert_eq ! ( it. 0 , ( usize :: MAX as Bigger ) * 1 ) ;
224
+ }
225
+
182
226
#[ test]
183
227
#[ should_panic]
184
228
fn test_iterator_step_by_zero ( ) {
You can’t perform that action at this time.
0 commit comments