File tree Expand file tree Collapse file tree 2 files changed +72
-3
lines changed
Expand file tree Collapse file tree 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 {
705705 }
706706 n -= 1 ;
707707 }
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 )
711736 }
712737}
713738
Original file line number Diff line number Diff line change @@ -179,6 +179,50 @@ fn test_iterator_step_by_nth() {
179179 assert_eq ! ( it. clone( ) . nth( 42 ) , None ) ;
180180}
181181
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+
182226#[ test]
183227#[ should_panic]
184228fn test_iterator_step_by_zero ( ) {
You can’t perform that action at this time.
0 commit comments