File tree 2 files changed +50
-8
lines changed
2 files changed +50
-8
lines changed Original file line number Diff line number Diff line change @@ -33,21 +33,32 @@ where
33
33
#[ inline]
34
34
fn next ( & mut self ) -> Option < I :: Item > {
35
35
if unlikely ( self . n > 0 ) {
36
- self . iter . nth ( crate :: mem:: take ( & mut self . n ) - 1 ) ?;
36
+ self . iter . nth ( crate :: mem:: take ( & mut self . n ) )
37
+ } else {
38
+ self . iter . next ( )
37
39
}
38
- self . iter . next ( )
39
40
}
40
41
41
42
#[ inline]
42
43
fn nth ( & mut self , n : usize ) -> Option < I :: Item > {
43
- // Can't just add n + self.n due to overflow.
44
44
if self . n > 0 {
45
- let to_skip = self . n ;
46
- self . n = 0 ;
47
- // nth(n) skips n+1
48
- self . iter . nth ( to_skip - 1 ) ?;
45
+ let skip: usize = crate :: mem:: take ( & mut self . n ) ;
46
+ // Checked add to handle overflow case.
47
+ let n = match skip. checked_add ( n) {
48
+ Some ( nth) => nth,
49
+ None => {
50
+ // In case of overflow, load skip value, before loading `n`.
51
+ // Because the amount of elements to iterate is beyond `usize::MAX`, this
52
+ // is split into two `nth` calls where the `skip` `nth` call is discarded.
53
+ self . iter . nth ( skip - 1 ) ?;
54
+ n
55
+ }
56
+ } ;
57
+ // Load nth element including skip.
58
+ self . iter . nth ( n)
59
+ } else {
60
+ self . iter . nth ( n)
49
61
}
50
- self . iter . nth ( n)
51
62
}
52
63
53
64
#[ inline]
Original file line number Diff line number Diff line change @@ -201,3 +201,34 @@ fn test_skip_non_fused() {
201
201
// advance it further. `Unfuse` tests that this doesn't happen by panicking in that scenario.
202
202
let _ = non_fused. skip ( 20 ) . next ( ) ;
203
203
}
204
+
205
+ #[ test]
206
+ fn test_skip_non_fused_nth_overflow ( ) {
207
+ let non_fused = Unfuse :: new ( 0 ..10 ) ;
208
+
209
+ // Ensures that calling skip and `nth` where the sum would overflow does not fail for non-fused
210
+ // iterators.
211
+ let _ = non_fused. skip ( 20 ) . nth ( usize:: MAX ) ;
212
+ }
213
+
214
+ #[ test]
215
+ fn test_skip_overflow_wrapping ( ) {
216
+ // Test to ensure even on overflowing on `skip+nth` the correct amount of elements are yielded.
217
+ struct WrappingIterator ( usize ) ;
218
+
219
+ impl Iterator for WrappingIterator {
220
+ type Item = usize ;
221
+
222
+ fn next ( & mut self ) -> core:: option:: Option < Self :: Item > {
223
+ <Self as Iterator >:: nth ( self , 0 )
224
+ }
225
+
226
+ fn nth ( & mut self , nth : usize ) -> core:: option:: Option < Self :: Item > {
227
+ self . 0 = self . 0 . wrapping_add ( nth. wrapping_add ( 1 ) ) ;
228
+ Some ( self . 0 )
229
+ }
230
+ }
231
+
232
+ let wrap = WrappingIterator ( 0 ) ;
233
+ assert_eq ! ( wrap. skip( 20 ) . nth( usize :: MAX ) , Some ( 20 ) ) ;
234
+ }
You can’t perform that action at this time.
0 commit comments