@@ -210,6 +210,69 @@ trait ZipImpl<A, B> {
210210 Self : Iterator + TrustedRandomAccessNoCoerce ;
211211}
212212
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+
213276// Work around limitations of specialization, requiring `default` impls to be repeated
214277// in intermediary impls.
215278macro_rules! zip_impl_general_defaults {
@@ -255,99 +318,48 @@ macro_rules! zip_impl_general_defaults {
255318 }
256319
257320 #[ 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
259322 where
260323 F : FnMut ( T , Self :: Item ) -> T ,
261324 {
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( )
273330 }
274331 }
275332
276333 #[ 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
278335 where
279336 F : FnMut ( T , Self :: Item ) -> R ,
280337 R : Try <Output = T >,
281338 {
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( )
300340 }
301341
302342 #[ 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
304344 where
305345 A : DoubleEndedIterator + ExactSizeIterator ,
306346 B : DoubleEndedIterator + ExactSizeIterator ,
307347 F : FnMut ( T , Self :: Item ) -> T ,
308348 {
309349 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) )
322351 }
323352
324353 #[ 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
326355 where
327356 A : DoubleEndedIterator + ExactSizeIterator ,
328357 B : DoubleEndedIterator + ExactSizeIterator ,
329358 F : FnMut ( T , Self :: Item ) -> R ,
330359 R : Try <Output = T >,
331360 {
332361 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( )
351363 }
352364 } ;
353365}
@@ -411,6 +423,40 @@ where
411423 }
412424}
413425
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+
414460#[ doc( hidden) ]
415461impl < A , B > ZipImpl < A , B > for Zip < A , B >
416462where
@@ -490,31 +536,7 @@ where
490536 A : DoubleEndedIterator + ExactSizeIterator ,
491537 B : DoubleEndedIterator + ExactSizeIterator ,
492538 {
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 ) ;
518540 if self . index < self . len {
519541 // since get_unchecked executes code which can panic we increment the counters beforehand
520542 // so that the same index won't be accessed twice, as required by TrustedRandomAccess
@@ -536,9 +558,19 @@ where
536558 where
537559 F : FnMut ( T , Self :: Item ) -> T ,
538560 {
561+ // we don't need to adjust `self.{index, len}` since we have ownership of the iterator
539562 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) } ;
542574 }
543575 accum
544576 }
@@ -549,10 +581,27 @@ where
549581 F : FnMut ( T , Self :: Item ) -> R ,
550582 R : Try < Output = T > ,
551583 {
584+ let index = self . index ;
585+ let len = self . len ;
586+
552587 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) } ;
555603 }
604+
556605 try { accum }
557606 }
558607
@@ -563,9 +612,18 @@ where
563612 B : DoubleEndedIterator + ExactSizeIterator ,
564613 F : FnMut ( T , Self :: Item ) -> T ,
565614 {
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+
566618 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+ } ;
569627 }
570628 accum
571629 }
@@ -578,9 +636,21 @@ where
578636 F : FnMut ( T , Self :: Item ) -> R ,
579637 R : Try < Output = T > ,
580638 {
639+ adjust_back_trusted_random_access ( self ) ;
640+
581641 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+ } ;
584654 }
585655 try { accum }
586656 }
0 commit comments