@@ -210,6 +210,69 @@ trait ZipImpl<A, B> {
210
210
Self : Iterator + TrustedRandomAccessNoCoerce ;
211
211
}
212
212
213
+ #[ inline]
214
+ fn ok < B , T > ( mut f : impl FnMut ( B , T ) -> B ) -> impl FnMut ( B , T ) -> Result < B , !> {
215
+ move |acc, x| Ok ( f ( acc, x) )
216
+ }
217
+
218
+ #[ inline]
219
+ fn check_fold < AItem , B : Iterator , T , F : FnMut ( T , ( AItem , B :: Item ) ) -> T > (
220
+ mut b : B ,
221
+ mut f : F ,
222
+ ) -> impl FnMut ( T , AItem ) -> T {
223
+ move |acc, x| match b. next ( ) {
224
+ Some ( y) => f ( acc, ( x, y) ) ,
225
+ None => panic ! ( "Iterator expected Some(item), found None." ) ,
226
+ }
227
+ }
228
+
229
+ #[ inline]
230
+ fn check_rfold < AItem , B : DoubleEndedIterator , T , F : FnMut ( T , ( AItem , B :: Item ) ) -> T > (
231
+ mut b : B ,
232
+ mut f : F ,
233
+ ) -> impl FnMut ( T , AItem ) -> T {
234
+ move |acc, x| match b. next_back ( ) {
235
+ Some ( y) => f ( acc, ( x, y) ) ,
236
+ None => panic ! ( "Iterator expected Some(item), found None." ) ,
237
+ }
238
+ }
239
+
240
+ #[ inline]
241
+ fn check_try_fold <
242
+ ' b ,
243
+ AItem ,
244
+ B : Iterator ,
245
+ T ,
246
+ R : Try < Output = T > ,
247
+ F : ' b + FnMut ( T , ( AItem , B :: Item ) ) -> R ,
248
+ > (
249
+ b : & ' b mut B ,
250
+ mut f : F ,
251
+ ) -> impl ' b + FnMut ( T , AItem ) -> ControlFlow < R , T > {
252
+ move |acc, x| match b. next ( ) {
253
+ Some ( y) => ControlFlow :: from_try ( f ( acc, ( x, y) ) ) ,
254
+ None => ControlFlow :: Break ( R :: from_output ( acc) ) ,
255
+ }
256
+ }
257
+
258
+ #[ inline]
259
+ fn check_try_rfold <
260
+ ' b ,
261
+ AItem ,
262
+ B : DoubleEndedIterator ,
263
+ T ,
264
+ R : Try < Output = T > ,
265
+ F : ' b + FnMut ( T , ( AItem , B :: Item ) ) -> R ,
266
+ > (
267
+ b : & ' b mut B ,
268
+ mut f : F ,
269
+ ) -> impl ' b + FnMut ( T , AItem ) -> ControlFlow < R , T > {
270
+ move |acc, x| match b. next_back ( ) {
271
+ Some ( y) => ControlFlow :: from_try ( f ( acc, ( x, y) ) ) ,
272
+ None => ControlFlow :: Break ( R :: from_output ( acc) ) ,
273
+ }
274
+ }
275
+
213
276
// Work around limitations of specialization, requiring `default` impls to be repeated
214
277
// in intermediary impls.
215
278
macro_rules! zip_impl_general_defaults {
@@ -255,99 +318,48 @@ macro_rules! zip_impl_general_defaults {
255
318
}
256
319
257
320
#[ inline]
258
- default fn fold<T , F >( self , init: T , mut f: F ) -> T
321
+ default fn fold<T , F >( mut self , init: T , f: F ) -> T
259
322
where
260
323
F : FnMut ( T , Self :: Item ) -> T ,
261
324
{
262
- let mut a = self . a;
263
- let mut b = self . b;
264
-
265
- let acc = a. try_fold( init, move |acc, x| match b. next( ) {
266
- Some ( y) => Ok ( f( acc, ( x, y) ) ) ,
267
- None => Err ( acc) ,
268
- } ) ;
269
-
270
- match acc {
271
- Ok ( exhausted_a) => exhausted_a,
272
- Err ( exhausted_b) => exhausted_b,
325
+ let ( lower, upper) = Iterator :: size_hint( & self ) ;
326
+ if upper == Some ( lower) {
327
+ self . a. fold( init, check_fold( self . b, f) )
328
+ } else {
329
+ ZipImpl :: try_fold( & mut self , init, ok( f) ) . unwrap( )
273
330
}
274
331
}
275
332
276
333
#[ inline]
277
- default fn try_fold<T , F , R >( & mut self , init: T , mut f: F ) -> R
334
+ default fn try_fold<T , F , R >( & mut self , init: T , f: F ) -> R
278
335
where
279
336
F : FnMut ( T , Self :: Item ) -> R ,
280
337
R : Try <Output = T >,
281
338
{
282
- let a = & mut self . a;
283
- let b = & mut self . b;
284
-
285
- let acc = a. try_fold( init, move |acc, x| match b. next( ) {
286
- Some ( y) => {
287
- let result = f( acc, ( x, y) ) ;
288
- match result. branch( ) {
289
- ControlFlow :: Continue ( continue_) => Ok ( continue_) ,
290
- ControlFlow :: Break ( break_) => Err ( R :: from_residual( break_) ) ,
291
- }
292
- }
293
- None => Err ( R :: from_output( acc) ) ,
294
- } ) ;
295
-
296
- match acc {
297
- Ok ( ok) => R :: from_output( ok) ,
298
- Err ( err) => err,
299
- }
339
+ self . a. try_fold( init, check_try_fold( & mut self . b, f) ) . into_try( )
300
340
}
301
341
302
342
#[ inline]
303
- default fn rfold<T , F >( mut self , init: T , mut f: F ) -> T
343
+ default fn rfold<T , F >( mut self , init: T , f: F ) -> T
304
344
where
305
345
A : DoubleEndedIterator + ExactSizeIterator ,
306
346
B : DoubleEndedIterator + ExactSizeIterator ,
307
347
F : FnMut ( T , Self :: Item ) -> T ,
308
348
{
309
349
self . adjust_back( ) ;
310
- let mut a = self . a;
311
- let mut b = self . b;
312
-
313
- let acc = a. try_rfold( init, move |acc, x| match b. next_back( ) {
314
- Some ( y) => Ok ( f( acc, ( x, y) ) ) ,
315
- None => Err ( acc) ,
316
- } ) ;
317
-
318
- match acc {
319
- Ok ( exhausted_a) => exhausted_a,
320
- Err ( exhausted_b) => exhausted_b,
321
- }
350
+ self . a. rfold( init, check_rfold( self . b, f) )
322
351
}
323
352
324
353
#[ inline]
325
- default fn try_rfold<T , F , R >( & mut self , init: T , mut f: F ) -> R
354
+ default fn try_rfold<T , F , R >( & mut self , init: T , f: F ) -> R
326
355
where
327
356
A : DoubleEndedIterator + ExactSizeIterator ,
328
357
B : DoubleEndedIterator + ExactSizeIterator ,
329
358
F : FnMut ( T , Self :: Item ) -> R ,
330
359
R : Try <Output = T >,
331
360
{
332
361
self . adjust_back( ) ;
333
- let a = & mut self . a;
334
- let b = & mut self . b;
335
-
336
- let acc = a. try_rfold( init, move |acc, x| match b. next_back( ) {
337
- Some ( y) => {
338
- let result = f( acc, ( x, y) ) ;
339
- match result. branch( ) {
340
- ControlFlow :: Continue ( c) => ControlFlow :: Continue ( c) ,
341
- ControlFlow :: Break ( b) => ControlFlow :: Break ( R :: from_residual( b) ) ,
342
- }
343
- }
344
- None => ControlFlow :: Break ( R :: from_output( acc) ) ,
345
- } ) ;
346
-
347
- match acc {
348
- ControlFlow :: Continue ( c) => R :: from_output( c) ,
349
- ControlFlow :: Break ( b) => b,
350
- }
362
+ self . a. try_rfold( init, check_try_rfold( & mut self . b, f) ) . into_try( )
351
363
}
352
364
} ;
353
365
}
@@ -411,6 +423,40 @@ where
411
423
}
412
424
}
413
425
426
+ #[ inline]
427
+ fn adjust_back_trusted_random_access <
428
+ A : TrustedRandomAccess + DoubleEndedIterator + ExactSizeIterator ,
429
+ B : TrustedRandomAccess + DoubleEndedIterator + ExactSizeIterator ,
430
+ > (
431
+ zipped : & mut Zip < A , B > ,
432
+ ) {
433
+ if A :: MAY_HAVE_SIDE_EFFECT || B :: MAY_HAVE_SIDE_EFFECT {
434
+ let sz_a = zipped. a . size ( ) ;
435
+ let sz_b = zipped. b . size ( ) ;
436
+ // Adjust a, b to equal length, make sure that only the first call
437
+ // of `next_back` does this, otherwise we will break the restriction
438
+ // on calls to `zipped.next_back()` after calling `get_unchecked()`.
439
+ if sz_a != sz_b {
440
+ let sz_a = zipped. a . size ( ) ;
441
+ if A :: MAY_HAVE_SIDE_EFFECT && sz_a > zipped. len {
442
+ for _ in 0 ..sz_a - zipped. len {
443
+ // since next_back() may panic we increment the counters beforehand
444
+ // to keep Zip's state in sync with the underlying iterator source
445
+ zipped. a_len -= 1 ;
446
+ zipped. a . next_back ( ) ;
447
+ }
448
+ debug_assert_eq ! ( zipped. a_len, zipped. len) ;
449
+ }
450
+ let sz_b = zipped. b . size ( ) ;
451
+ if B :: MAY_HAVE_SIDE_EFFECT && sz_b > zipped. len {
452
+ for _ in 0 ..sz_b - zipped. len {
453
+ zipped. b . next_back ( ) ;
454
+ }
455
+ }
456
+ }
457
+ }
458
+ }
459
+
414
460
#[ doc( hidden) ]
415
461
impl < A , B > ZipImpl < A , B > for Zip < A , B >
416
462
where
@@ -490,31 +536,7 @@ where
490
536
A : DoubleEndedIterator + ExactSizeIterator ,
491
537
B : DoubleEndedIterator + ExactSizeIterator ,
492
538
{
493
- if A :: MAY_HAVE_SIDE_EFFECT || B :: MAY_HAVE_SIDE_EFFECT {
494
- let sz_a = self . a . size ( ) ;
495
- let sz_b = self . b . size ( ) ;
496
- // Adjust a, b to equal length, make sure that only the first call
497
- // of `next_back` does this, otherwise we will break the restriction
498
- // on calls to `self.next_back()` after calling `get_unchecked()`.
499
- if sz_a != sz_b {
500
- let sz_a = self . a . size ( ) ;
501
- if A :: MAY_HAVE_SIDE_EFFECT && sz_a > self . len {
502
- for _ in 0 ..sz_a - self . len {
503
- // since next_back() may panic we increment the counters beforehand
504
- // to keep Zip's state in sync with the underlying iterator source
505
- self . a_len -= 1 ;
506
- self . a . next_back ( ) ;
507
- }
508
- debug_assert_eq ! ( self . a_len, self . len) ;
509
- }
510
- let sz_b = self . b . size ( ) ;
511
- if B :: MAY_HAVE_SIDE_EFFECT && sz_b > self . len {
512
- for _ in 0 ..sz_b - self . len {
513
- self . b . next_back ( ) ;
514
- }
515
- }
516
- }
517
- }
539
+ adjust_back_trusted_random_access ( self ) ;
518
540
if self . index < self . len {
519
541
// since get_unchecked executes code which can panic we increment the counters beforehand
520
542
// so that the same index won't be accessed twice, as required by TrustedRandomAccess
@@ -536,9 +558,19 @@ where
536
558
where
537
559
F : FnMut ( T , Self :: Item ) -> T ,
538
560
{
561
+ // we don't need to adjust `self.{index, len}` since we have ownership of the iterator
539
562
let mut accum = init;
540
- while let Some ( x) = <Self as ZipImpl < A , B > >:: next ( & mut self ) {
541
- accum = f ( accum, x) ;
563
+ let index = self . index ;
564
+ let len = self . len ;
565
+ for i in index..len {
566
+ // SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()`
567
+ accum = unsafe {
568
+ f ( accum, ( self . a . __iterator_get_unchecked ( i) , self . b . __iterator_get_unchecked ( i) ) )
569
+ } ;
570
+ }
571
+ if A :: MAY_HAVE_SIDE_EFFECT && len < self . a_len {
572
+ // SAFETY: `i` is smaller than `self.a_len`, which is equal to `self.a.len()`
573
+ unsafe { self . a . __iterator_get_unchecked ( len) } ;
542
574
}
543
575
accum
544
576
}
@@ -549,10 +581,27 @@ where
549
581
F : FnMut ( T , Self :: Item ) -> R ,
550
582
R : Try < Output = T > ,
551
583
{
584
+ let index = self . index ;
585
+ let len = self . len ;
586
+
552
587
let mut accum = init;
553
- while let Some ( x) = <Self as ZipImpl < A , B > >:: next ( self ) {
554
- accum = f ( accum, x) ?;
588
+
589
+ for i in index..len {
590
+ // adjust `self.index` beforehand in case once of the iterators panics.
591
+ self . index = i + 1 ;
592
+ // SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()`
593
+ accum = unsafe {
594
+ f ( accum, ( self . a . __iterator_get_unchecked ( i) , self . b . __iterator_get_unchecked ( i) ) ) ?
595
+ } ;
596
+ }
597
+
598
+ if A :: MAY_HAVE_SIDE_EFFECT && len < self . a_len {
599
+ self . index = len + 1 ;
600
+ self . len = len + 1 ;
601
+ // SAFETY: `i` is smaller than `self.a_len`, which is equal to `self.a.len()`
602
+ unsafe { self . a . __iterator_get_unchecked ( len) } ;
555
603
}
604
+
556
605
try { accum }
557
606
}
558
607
@@ -563,9 +612,18 @@ where
563
612
B : DoubleEndedIterator + ExactSizeIterator ,
564
613
F : FnMut ( T , Self :: Item ) -> T ,
565
614
{
615
+ // we don't need to adjust `self.{len, a_len}` since we have ownership of the iterator
616
+ adjust_back_trusted_random_access ( & mut self ) ;
617
+
566
618
let mut accum = init;
567
- while let Some ( x) = <Self as ZipImpl < A , B > >:: next_back ( & mut self ) {
568
- accum = f ( accum, x) ;
619
+ let index = self . index ;
620
+ let len = self . len ;
621
+ for i in 0 ..len - index {
622
+ let i = len - i - 1 ;
623
+ // SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()`
624
+ accum = unsafe {
625
+ f ( accum, ( self . a . __iterator_get_unchecked ( i) , self . b . __iterator_get_unchecked ( i) ) )
626
+ } ;
569
627
}
570
628
accum
571
629
}
@@ -578,9 +636,21 @@ where
578
636
F : FnMut ( T , Self :: Item ) -> R ,
579
637
R : Try < Output = T > ,
580
638
{
639
+ adjust_back_trusted_random_access ( self ) ;
640
+
581
641
let mut accum = init;
582
- while let Some ( x) = <Self as ZipImpl < A , B > >:: next_back ( self ) {
583
- accum = f ( accum, x) ?;
642
+ let index = self . index ;
643
+ let len = self . len ;
644
+ for i in 0 ..len - index {
645
+ // inner `i` goes backwards from `len` (exclusive) to `index` (inclusive)
646
+ let i = len - i - 1 ;
647
+ // adjust `self.{len, a_len}` beforehand in case once of the iterators panics.
648
+ self . len = i;
649
+ self . a_len -= 1 ;
650
+ // SAFETY: `i` is smaller than `self.len`, thus smaller than `self.a.len()` and `self.b.len()`
651
+ accum = unsafe {
652
+ f ( accum, ( self . a . __iterator_get_unchecked ( i) , self . b . __iterator_get_unchecked ( i) ) ) ?
653
+ } ;
584
654
}
585
655
try { accum }
586
656
}
0 commit comments