@@ -3020,6 +3020,28 @@ macro_rules! iterator {
30203020 { $( $mut_: tt ) * } ,
30213021 { $( $extra: tt) * }
30223022 ) => {
3023+ // Returns the first element and moves the start of the iterator forwards by 1.
3024+ // Greatly improves performance compared to an inlined function. The iterator
3025+ // must not be empty.
3026+ macro_rules! next_unchecked {
3027+ ( $self: ident) => { & $( $mut_ ) * * $self. post_inc_start( 1 ) }
3028+ }
3029+
3030+ // Returns the last element and moves the end of the iterator backwards by 1.
3031+ // Greatly improves performance compared to an inlined function. The iterator
3032+ // must not be empty.
3033+ macro_rules! next_back_unchecked {
3034+ ( $self: ident) => { & $( $mut_ ) * * $self. pre_dec_end( 1 ) }
3035+ }
3036+
3037+ // Shrinks the iterator when T is a ZST, by moving the end of the iterator
3038+ // backwards by `n`. `n` must not exceed `self.len()`.
3039+ macro_rules! zst_shrink {
3040+ ( $self: ident, $n: ident) => {
3041+ $self. end = ( $self. end as * $raw_mut u8 ) . wrapping_offset( -$n) as * $raw_mut T ;
3042+ }
3043+ }
3044+
30233045 impl <' a, T > $name<' a, T > {
30243046 // Helper function for creating a slice from the iterator.
30253047 #[ inline( always) ]
@@ -3029,12 +3051,11 @@ macro_rules! iterator {
30293051
30303052 // Helper function for moving the start of the iterator forwards by `offset` elements,
30313053 // returning the old start.
3032- // Unsafe because the offset must be in-bounds or one-past-the-end .
3054+ // Unsafe because the offset must not exceed `self.len()` .
30333055 #[ inline( always) ]
30343056 unsafe fn post_inc_start( & mut self , offset: isize ) -> * $raw_mut T {
30353057 if mem:: size_of:: <T >( ) == 0 {
3036- // This is *reducing* the length. `ptr` never changes with ZST.
3037- self . end = ( self . end as * $raw_mut u8 ) . wrapping_offset( -offset) as * $raw_mut T ;
3058+ zst_shrink!( self , offset) ;
30383059 self . ptr
30393060 } else {
30403061 let old = self . ptr;
@@ -3045,11 +3066,11 @@ macro_rules! iterator {
30453066
30463067 // Helper function for moving the end of the iterator backwards by `offset` elements,
30473068 // returning the new end.
3048- // Unsafe because the offset must be in-bounds or one-past-the-end .
3069+ // Unsafe because the offset must not exceed `self.len()` .
30493070 #[ inline( always) ]
30503071 unsafe fn pre_dec_end( & mut self , offset: isize ) -> * $raw_mut T {
30513072 if mem:: size_of:: <T >( ) == 0 {
3052- self . end = ( self . end as * $raw_mut u8 ) . wrapping_offset ( - offset) as * $raw_mut T ;
3073+ zst_shrink! ( self , offset) ;
30533074 self . ptr
30543075 } else {
30553076 self . end = self . end. offset( -offset) ;
@@ -3086,7 +3107,7 @@ macro_rules! iterator {
30863107 if is_empty!( self ) {
30873108 None
30883109 } else {
3089- Some ( & $ ( $mut_ ) * * self . post_inc_start ( 1 ) )
3110+ Some ( next_unchecked! ( self ) )
30903111 }
30913112 }
30923113 }
@@ -3115,11 +3136,10 @@ macro_rules! iterator {
31153136 }
31163137 return None ;
31173138 }
3118- // We are in bounds. `offset ` does the right thing even for ZSTs.
3139+ // We are in bounds. `post_inc_start ` does the right thing even for ZSTs.
31193140 unsafe {
3120- let elem = Some ( & $( $mut_ ) * * self . ptr. add( n) ) ;
3121- self . post_inc_start( ( n as isize ) . wrapping_add( 1 ) ) ;
3122- elem
3141+ self . post_inc_start( n as isize ) ;
3142+ Some ( next_unchecked!( self ) )
31233143 }
31243144 }
31253145
@@ -3136,13 +3156,13 @@ macro_rules! iterator {
31363156 let mut accum = init;
31373157 unsafe {
31383158 while len!( self ) >= 4 {
3139- accum = f( accum, & $ ( $mut_ ) * * self . post_inc_start ( 1 ) ) ?;
3140- accum = f( accum, & $ ( $mut_ ) * * self . post_inc_start ( 1 ) ) ?;
3141- accum = f( accum, & $ ( $mut_ ) * * self . post_inc_start ( 1 ) ) ?;
3142- accum = f( accum, & $ ( $mut_ ) * * self . post_inc_start ( 1 ) ) ?;
3159+ accum = f( accum, next_unchecked! ( self ) ) ?;
3160+ accum = f( accum, next_unchecked! ( self ) ) ?;
3161+ accum = f( accum, next_unchecked! ( self ) ) ?;
3162+ accum = f( accum, next_unchecked! ( self ) ) ?;
31433163 }
31443164 while !is_empty!( self ) {
3145- accum = f( accum, & $ ( $mut_ ) * * self . post_inc_start ( 1 ) ) ?;
3165+ accum = f( accum, next_unchecked! ( self ) ) ?;
31463166 }
31473167 }
31483168 Try :: from_ok( accum)
@@ -3213,11 +3233,25 @@ macro_rules! iterator {
32133233 if is_empty!( self ) {
32143234 None
32153235 } else {
3216- Some ( & $ ( $mut_ ) * * self . pre_dec_end ( 1 ) )
3236+ Some ( next_back_unchecked! ( self ) )
32173237 }
32183238 }
32193239 }
32203240
3241+ #[ inline]
3242+ fn nth_back( & mut self , n: usize ) -> Option <$elem> {
3243+ if n >= len!( self ) {
3244+ // This iterator is now empty.
3245+ self . end = self . ptr;
3246+ return None ;
3247+ }
3248+ // We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
3249+ unsafe {
3250+ self . pre_dec_end( n as isize ) ;
3251+ Some ( next_back_unchecked!( self ) )
3252+ }
3253+ }
3254+
32213255 #[ inline]
32223256 fn try_rfold<B , F , R >( & mut self , init: B , mut f: F ) -> R where
32233257 Self : Sized , F : FnMut ( B , Self :: Item ) -> R , R : Try <Ok =B >
@@ -3226,14 +3260,14 @@ macro_rules! iterator {
32263260 let mut accum = init;
32273261 unsafe {
32283262 while len!( self ) >= 4 {
3229- accum = f( accum, & $ ( $mut_ ) * * self . pre_dec_end ( 1 ) ) ?;
3230- accum = f( accum, & $ ( $mut_ ) * * self . pre_dec_end ( 1 ) ) ?;
3231- accum = f( accum, & $ ( $mut_ ) * * self . pre_dec_end ( 1 ) ) ?;
3232- accum = f( accum, & $ ( $mut_ ) * * self . pre_dec_end ( 1 ) ) ?;
3263+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
3264+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
3265+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
3266+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
32333267 }
32343268 // inlining is_empty everywhere makes a huge performance difference
32353269 while !is_empty!( self ) {
3236- accum = f( accum, & $ ( $mut_ ) * * self . pre_dec_end ( 1 ) ) ?;
3270+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
32373271 }
32383272 }
32393273 Try :: from_ok( accum)
0 commit comments