11//! Macros used by iterators of slice.
22
3+ // Shrinks the iterator when T is a ZST, setting the length to `new_len`.
4+ // `new_len` must not exceed `self.len()`.
5+ macro_rules! zst_set_len {
6+ ( $self: ident, $new_len: expr) => { {
7+ #![ allow( unused_unsafe) ] // we're sometimes used within an unsafe block
8+
9+ // SAFETY: same as `invalid(_mut)`, but the macro doesn't know
10+ // which versions of that function to call, so open-code it.
11+ $self. end = unsafe { mem:: transmute:: <usize , _>( $new_len) } ;
12+ } } ;
13+ }
14+
15+ // Shrinks the iterator when T is a ZST, reducing the length by `n`.
16+ // `n` must not exceed `self.len()`.
17+ macro_rules! zst_shrink {
18+ ( $self: ident, $n: ident) => {
19+ let new_len = $self. end. addr( ) - $n;
20+ zst_set_len!( $self, new_len) ;
21+ } ;
22+ }
23+
324// Inlining is_empty and len makes a huge performance difference
425macro_rules! is_empty {
5- // The way we encode the length of a ZST iterator, this works both for ZST
6- // and non-ZST.
726 ( $self: ident) => {
8- $self. ptr. as_ptr( ) as * const T == $self. end
27+ if T :: IS_ZST { $self. end . addr ( ) == 0 } else { $self . ptr. as_ptr( ) as * const _ == $self. end }
928 } ;
1029}
1130
1231macro_rules! len {
1332 ( $self: ident) => { {
1433 #![ allow( unused_unsafe) ] // we're sometimes used within an unsafe block
1534
16- let start = $self. ptr;
1735 if T :: IS_ZST {
18- // This _cannot_ use `ptr_sub` because we depend on wrapping
19- // to represent the length of long ZST slice iterators.
20- $self. end. addr( ) . wrapping_sub( start. as_ptr( ) . addr( ) )
36+ $self. end. addr( )
2137 } else {
2238 // To get rid of some bounds checks (see `position`), we use ptr_sub instead of
2339 // offset_from (Tested by `codegen/slice-position-bounds-check`.)
2440 // SAFETY: by the type invariant pointers are aligned and `start <= end`
25- unsafe { $self. end. sub_ptr( start . as_ptr( ) ) }
41+ unsafe { $self. end. sub_ptr( $self . ptr . as_ptr( ) ) }
2642 }
2743 } } ;
2844}
@@ -50,14 +66,6 @@ macro_rules! iterator {
5066 ( $self: ident) => { & $( $mut_ ) ? * $self. pre_dec_end( 1 ) }
5167 }
5268
53- // Shrinks the iterator when T is a ZST, by moving the end of the iterator
54- // backwards by `n`. `n` must not exceed `self.len()`.
55- macro_rules! zst_shrink {
56- ( $self: ident, $n: ident) => {
57- $self. end = $self. end. wrapping_byte_sub( $n) ;
58- }
59- }
60-
6169 impl <' a, T > $name<' a, T > {
6270 // Helper function for creating a slice from the iterator.
6371 #[ inline( always) ]
@@ -73,16 +81,15 @@ macro_rules! iterator {
7381 // Unsafe because the offset must not exceed `self.len()`.
7482 #[ inline( always) ]
7583 unsafe fn post_inc_start( & mut self , offset: usize ) -> * $raw_mut T {
84+ let old = self . ptr;
7685 if T :: IS_ZST {
7786 zst_shrink!( self , offset) ;
78- self . ptr. as_ptr( )
7987 } else {
80- let old = self . ptr. as_ptr( ) ;
8188 // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
8289 // so this new pointer is inside `self` and thus guaranteed to be non-null.
83- self . ptr = unsafe { NonNull :: new_unchecked( self . ptr. as_ptr( ) . add( offset) ) } ;
84- old
90+ self . ptr = unsafe { self . ptr. add( offset) } ;
8591 }
92+ old. as_ptr( )
8693 }
8794
8895 // Helper function for moving the end of the iterator backwards by `offset` elements,
@@ -155,9 +162,7 @@ macro_rules! iterator {
155162 if n >= len!( self ) {
156163 // This iterator is now empty.
157164 if T :: IS_ZST {
158- // We have to do it this way as `ptr` may never be 0, but `end`
159- // could be (due to wrapping).
160- self . end = self . ptr. as_ptr( ) ;
165+ zst_set_len!( self , 0 ) ;
161166 } else {
162167 // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
163168 unsafe {
@@ -356,7 +361,11 @@ macro_rules! iterator {
356361 fn nth_back( & mut self , n: usize ) -> Option <$elem> {
357362 if n >= len!( self ) {
358363 // This iterator is now empty.
359- self . end = self . ptr. as_ptr( ) ;
364+ if T :: IS_ZST {
365+ zst_set_len!( self , 0 ) ;
366+ } else {
367+ self . end = self . ptr. as_ptr( ) ;
368+ }
360369 return None ;
361370 }
362371 // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
0 commit comments