1
1
//! Macros used by iterators of slice.
2
2
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
+
3
24
// Inlining is_empty and len makes a huge performance difference
4
25
macro_rules! is_empty {
5
- // The way we encode the length of a ZST iterator, this works both for ZST
6
- // and non-ZST.
7
26
( $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 }
9
28
} ;
10
29
}
11
30
12
31
macro_rules! len {
13
32
( $self: ident) => { {
14
33
#![ allow( unused_unsafe) ] // we're sometimes used within an unsafe block
15
34
16
- let start = $self. ptr;
17
35
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( )
21
37
} else {
22
38
// To get rid of some bounds checks (see `position`), we use ptr_sub instead of
23
39
// offset_from (Tested by `codegen/slice-position-bounds-check`.)
24
40
// 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( ) ) }
26
42
}
27
43
} } ;
28
44
}
@@ -50,14 +66,6 @@ macro_rules! iterator {
50
66
( $self: ident) => { & $( $mut_ ) ? * $self. pre_dec_end( 1 ) }
51
67
}
52
68
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
-
61
69
impl <' a, T > $name<' a, T > {
62
70
// Helper function for creating a slice from the iterator.
63
71
#[ inline( always) ]
@@ -73,16 +81,15 @@ macro_rules! iterator {
73
81
// Unsafe because the offset must not exceed `self.len()`.
74
82
#[ inline( always) ]
75
83
unsafe fn post_inc_start( & mut self , offset: usize ) -> * $raw_mut T {
84
+ let old = self . ptr;
76
85
if T :: IS_ZST {
77
86
zst_shrink!( self , offset) ;
78
- self . ptr. as_ptr( )
79
87
} else {
80
- let old = self . ptr. as_ptr( ) ;
81
88
// SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
82
89
// 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) } ;
85
91
}
92
+ old. as_ptr( )
86
93
}
87
94
88
95
// Helper function for moving the end of the iterator backwards by `offset` elements,
@@ -155,9 +162,7 @@ macro_rules! iterator {
155
162
if n >= len!( self ) {
156
163
// This iterator is now empty.
157
164
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 ) ;
161
166
} else {
162
167
// SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
163
168
unsafe {
@@ -356,7 +361,11 @@ macro_rules! iterator {
356
361
fn nth_back( & mut self , n: usize ) -> Option <$elem> {
357
362
if n >= len!( self ) {
358
363
// 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
+ }
360
369
return None ;
361
370
}
362
371
// SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
0 commit comments