@@ -3019,6 +3019,28 @@ macro_rules! iterator {
30193019 { $( $mut_: tt ) * } ,
30203020 { $( $extra: tt) * }
30213021 ) => {
3022+ // Returns the first element and moves the start of the iterator forwards by 1.
3023+ // Greatly improves performance compared to an inlined function. The iterator
3024+ // must not be empty.
3025+ macro_rules! next_unchecked {
3026+ ( $self: ident) => { & $( $mut_ ) * * $self. post_inc_start( 1 ) }
3027+ }
3028+
3029+ // Returns the last element and moves the end of the iterator backwards by 1.
3030+ // Greatly improves performance compared to an inlined function. The iterator
3031+ // must not be empty.
3032+ macro_rules! next_back_unchecked {
3033+ ( $self: ident) => { & $( $mut_ ) * * $self. pre_dec_end( 1 ) }
3034+ }
3035+
3036+ // Shrinks the iterator when T is a ZST, by moving the end of the iterator
3037+ // backwards by `n`. `n` must not exceed `self.len()`.
3038+ macro_rules! zst_shrink {
3039+ ( $self: ident, $n: ident) => {
3040+ $self. end = ( $self. end as * $raw_mut u8 ) . wrapping_offset( -$n) as * $raw_mut T ;
3041+ }
3042+ }
3043+
30223044 impl <' a, T > $name<' a, T > {
30233045 // Helper function for creating a slice from the iterator.
30243046 #[ inline( always) ]
@@ -3028,12 +3050,11 @@ macro_rules! iterator {
30283050
30293051 // Helper function for moving the start of the iterator forwards by `offset` elements,
30303052 // returning the old start.
3031- // Unsafe because the offset must be in-bounds or one-past-the-end .
3053+ // Unsafe because the offset must not exceed `self.len()` .
30323054 #[ inline( always) ]
30333055 unsafe fn post_inc_start( & mut self , offset: isize ) -> * $raw_mut T {
30343056 if mem:: size_of:: <T >( ) == 0 {
3035- // This is *reducing* the length. `ptr` never changes with ZST.
3036- self . end = ( self . end as * $raw_mut u8 ) . wrapping_offset( -offset) as * $raw_mut T ;
3057+ zst_shrink!( self , offset) ;
30373058 self . ptr
30383059 } else {
30393060 let old = self . ptr;
@@ -3044,11 +3065,11 @@ macro_rules! iterator {
30443065
30453066 // Helper function for moving the end of the iterator backwards by `offset` elements,
30463067 // returning the new end.
3047- // Unsafe because the offset must be in-bounds or one-past-the-end .
3068+ // Unsafe because the offset must not exceed `self.len()` .
30483069 #[ inline( always) ]
30493070 unsafe fn pre_dec_end( & mut self , offset: isize ) -> * $raw_mut T {
30503071 if mem:: size_of:: <T >( ) == 0 {
3051- self . end = ( self . end as * $raw_mut u8 ) . wrapping_offset ( - offset) as * $raw_mut T ;
3072+ zst_shrink! ( self , offset) ;
30523073 self . ptr
30533074 } else {
30543075 self . end = self . end. offset( -offset) ;
@@ -3085,7 +3106,7 @@ macro_rules! iterator {
30853106 if is_empty!( self ) {
30863107 None
30873108 } else {
3088- Some ( & $ ( $mut_ ) * * self . post_inc_start ( 1 ) )
3109+ Some ( next_unchecked! ( self ) )
30893110 }
30903111 }
30913112 }
@@ -3114,11 +3135,10 @@ macro_rules! iterator {
31143135 }
31153136 return None ;
31163137 }
3117- // We are in bounds. `offset ` does the right thing even for ZSTs.
3138+ // We are in bounds. `post_inc_start ` does the right thing even for ZSTs.
31183139 unsafe {
3119- let elem = Some ( & $( $mut_ ) * * self . ptr. add( n) ) ;
3120- self . post_inc_start( ( n as isize ) . wrapping_add( 1 ) ) ;
3121- elem
3140+ self . post_inc_start( n as isize ) ;
3141+ Some ( next_unchecked!( self ) )
31223142 }
31233143 }
31243144
@@ -3135,13 +3155,13 @@ macro_rules! iterator {
31353155 let mut accum = init;
31363156 unsafe {
31373157 while len!( self ) >= 4 {
3138- accum = f( accum, & $ ( $mut_ ) * * self . post_inc_start ( 1 ) ) ?;
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 ) ) ?;
3158+ accum = f( accum, next_unchecked! ( self ) ) ?;
3159+ accum = f( accum, next_unchecked! ( self ) ) ?;
3160+ accum = f( accum, next_unchecked! ( self ) ) ?;
3161+ accum = f( accum, next_unchecked! ( self ) ) ?;
31423162 }
31433163 while !is_empty!( self ) {
3144- accum = f( accum, & $ ( $mut_ ) * * self . post_inc_start ( 1 ) ) ?;
3164+ accum = f( accum, next_unchecked! ( self ) ) ?;
31453165 }
31463166 }
31473167 Try :: from_ok( accum)
@@ -3212,11 +3232,25 @@ macro_rules! iterator {
32123232 if is_empty!( self ) {
32133233 None
32143234 } else {
3215- Some ( & $ ( $mut_ ) * * self . pre_dec_end ( 1 ) )
3235+ Some ( next_back_unchecked! ( self ) )
32163236 }
32173237 }
32183238 }
32193239
3240+ #[ inline]
3241+ fn nth_back( & mut self , n: usize ) -> Option <$elem> {
3242+ if n >= len!( self ) {
3243+ // This iterator is now empty.
3244+ self . end = self . ptr;
3245+ return None ;
3246+ }
3247+ // We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
3248+ unsafe {
3249+ self . pre_dec_end( n as isize ) ;
3250+ Some ( next_back_unchecked!( self ) )
3251+ }
3252+ }
3253+
32203254 #[ inline]
32213255 fn try_rfold<B , F , R >( & mut self , init: B , mut f: F ) -> R where
32223256 Self : Sized , F : FnMut ( B , Self :: Item ) -> R , R : Try <Ok =B >
@@ -3225,14 +3259,14 @@ macro_rules! iterator {
32253259 let mut accum = init;
32263260 unsafe {
32273261 while len!( self ) >= 4 {
3228- accum = f( accum, & $ ( $mut_ ) * * self . pre_dec_end ( 1 ) ) ?;
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 ) ) ?;
3262+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
3263+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
3264+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
3265+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
32323266 }
32333267 // inlining is_empty everywhere makes a huge performance difference
32343268 while !is_empty!( self ) {
3235- accum = f( accum, & $ ( $mut_ ) * * self . pre_dec_end ( 1 ) ) ?;
3269+ accum = f( accum, next_back_unchecked! ( self ) ) ?;
32363270 }
32373271 }
32383272 Try :: from_ok( accum)
0 commit comments