1
+ use crate :: intrinsics;
1
2
use crate :: iter:: adapters:: { zip:: try_get_unchecked, SourceIter , TrustedRandomAccess } ;
2
3
use crate :: iter:: { FusedIterator , InPlaceIterable , TrustedLen } ;
3
4
use crate :: ops:: { Add , AddAssign , Try } ;
@@ -15,10 +16,149 @@ use crate::ops::{Add, AddAssign, Try};
15
16
pub struct Enumerate < I > {
16
17
iter : I ,
17
18
count : usize ,
19
+ len : usize ,
18
20
}
19
- impl < I > Enumerate < I > {
21
+ impl < I : Iterator > Enumerate < I > {
20
22
pub ( in crate :: iter) fn new ( iter : I ) -> Enumerate < I > {
21
- Enumerate { iter, count : 0 }
23
+ EnumerateImpl :: new ( iter)
24
+ }
25
+ }
26
+
27
+ /// Enumerate specialization trait
28
+ ///
29
+ /// This exists to work around https://bugs.llvm.org/show_bug.cgi?id=48965. It can be removed again
30
+ /// once this is solved in LLVM and the implementation of the trait functions can be folded again
31
+ /// into the corresponding functions on `Enumerate` based on the default implementation.
32
+ ///
33
+ /// The trait is implemented via specialization on any iterator that implements `TrustedRandomAccess`
34
+ /// to provide the information about the maximum value this iterator can return to the optimizer.
35
+ /// Specifically, for slices this allows the optimizer to know that the returned values are never
36
+ /// bigger than the size of the slice.
37
+ ///
38
+ /// The only difference between the default and specialized implementation is the use of
39
+ /// `intrinsics::assume()` on the to be returned values, and both implementations must be kept in
40
+ /// sync.
41
+ #[ doc( hidden) ]
42
+ trait EnumerateImpl < I > {
43
+ type Item ;
44
+ fn new ( iter : I ) -> Self ;
45
+ fn next ( & mut self ) -> Option < Self :: Item > ;
46
+ unsafe fn __iterator_get_unchecked ( & mut self , idx : usize ) -> Self :: Item
47
+ where
48
+ Self : TrustedRandomAccess ;
49
+ fn next_back ( & mut self ) -> Option < Self :: Item >
50
+ where
51
+ I : ExactSizeIterator + DoubleEndedIterator ;
52
+ }
53
+
54
+ impl < I > EnumerateImpl < I > for Enumerate < I >
55
+ where
56
+ I : Iterator ,
57
+ {
58
+ type Item = ( usize , I :: Item ) ;
59
+
60
+ default fn new ( iter : I ) -> Self {
61
+ Enumerate {
62
+ iter,
63
+ count : 0 ,
64
+ len : 0 , // unused
65
+ }
66
+ }
67
+
68
+ #[ inline]
69
+ default fn next ( & mut self ) -> Option < Self :: Item > {
70
+ let a = self . iter . next ( ) ?;
71
+ let i = self . count ;
72
+ // Possible undefined overflow.
73
+ AddAssign :: add_assign ( & mut self . count , 1 ) ;
74
+ Some ( ( i, a) )
75
+ }
76
+
77
+ #[ inline]
78
+ default unsafe fn __iterator_get_unchecked ( & mut self , idx : usize ) -> Self :: Item
79
+ where
80
+ Self : TrustedRandomAccess ,
81
+ {
82
+ // SAFETY: the caller must uphold the contract for
83
+ // `Iterator::__iterator_get_unchecked`.
84
+ let value = unsafe { try_get_unchecked ( & mut self . iter , idx) } ;
85
+ ( Add :: add ( self . count , idx) , value)
86
+ }
87
+
88
+ #[ inline]
89
+ default fn next_back ( & mut self ) -> Option < Self :: Item >
90
+ where
91
+ I : ExactSizeIterator + DoubleEndedIterator ,
92
+ {
93
+ let a = self . iter . next_back ( ) ?;
94
+ let len = self . iter . len ( ) ;
95
+ // Can safely add, `ExactSizeIterator` promises that the number of
96
+ // elements fits into a `usize`.
97
+ Some ( ( self . count + len, a) )
98
+ }
99
+ }
100
+
101
+ // This is the same code as above but using `intrinsics::assume()` to hint at the compiler
102
+ // that the returned index is smaller than the length of the underlying iterator.
103
+ //
104
+ // This could be bound to `TrustedLen + ExactSizeIterator` or `TrustedRandomAccess` to guarantee
105
+ // that the number of elements fits into an `usize` and that the returned length is actually the
106
+ // real length. `TrustedRandomAccess` was selected because specialization on `ExactSizeIterator` is
107
+ // not possible (yet?).
108
+ impl < I > EnumerateImpl < I > for Enumerate < I >
109
+ where
110
+ I : TrustedRandomAccess + Iterator ,
111
+ {
112
+ fn new ( iter : I ) -> Self {
113
+ let len = iter. size ( ) ;
114
+
115
+ Enumerate { iter, count : 0 , len }
116
+ }
117
+
118
+ #[ inline]
119
+ fn next ( & mut self ) -> Option < Self :: Item > {
120
+ let a = self . iter . next ( ) ?;
121
+ // SAFETY: There must be fewer than `self.len` items because of `TrustedLen`'s API contract
122
+ unsafe {
123
+ intrinsics:: assume ( self . count < self . len ) ;
124
+ }
125
+ let i = self . count ;
126
+ // Possible undefined overflow.
127
+ AddAssign :: add_assign ( & mut self . count , 1 ) ;
128
+ Some ( ( i, a) )
129
+ }
130
+
131
+ #[ inline]
132
+ unsafe fn __iterator_get_unchecked ( & mut self , idx : usize ) -> Self :: Item
133
+ where
134
+ Self : TrustedRandomAccess ,
135
+ {
136
+ // SAFETY: the caller must uphold the contract for
137
+ // `Iterator::__iterator_get_unchecked`.
138
+ let value = unsafe { try_get_unchecked ( & mut self . iter , idx) } ;
139
+ let idx = Add :: add ( self . count , idx) ;
140
+ // SAFETY: There must be fewer than `self.len` items because of `TrustedLen`'s API contract
141
+ unsafe {
142
+ intrinsics:: assume ( idx < self . len ) ;
143
+ }
144
+ ( idx, value)
145
+ }
146
+
147
+ #[ inline]
148
+ fn next_back ( & mut self ) -> Option < Self :: Item >
149
+ where
150
+ I : ExactSizeIterator + DoubleEndedIterator ,
151
+ {
152
+ let a = self . iter . next_back ( ) ?;
153
+ let len = self . iter . len ( ) ;
154
+ // Can safely add, `ExactSizeIterator` promises that the number of
155
+ // elements fits into a `usize`.
156
+ let idx = self . count + len;
157
+ // SAFETY: There must be fewer than `self.len` items because of `TrustedLen`'s API contract
158
+ unsafe {
159
+ intrinsics:: assume ( idx < self . len ) ;
160
+ }
161
+ Some ( ( idx, a) )
22
162
}
23
163
}
24
164
@@ -40,11 +180,7 @@ where
40
180
/// Might panic if the index of the element overflows a `usize`.
41
181
#[ inline]
42
182
fn next ( & mut self ) -> Option < ( usize , <I as Iterator >:: Item ) > {
43
- let a = self . iter . next ( ) ?;
44
- let i = self . count ;
45
- // Possible undefined overflow.
46
- AddAssign :: add_assign ( & mut self . count , 1 ) ;
47
- Some ( ( i, a) )
183
+ EnumerateImpl :: next ( self )
48
184
}
49
185
50
186
#[ inline]
@@ -114,10 +250,8 @@ where
114
250
where
115
251
Self : TrustedRandomAccess ,
116
252
{
117
- // SAFETY: the caller must uphold the contract for
118
- // `Iterator::__iterator_get_unchecked`.
119
- let value = unsafe { try_get_unchecked ( & mut self . iter , idx) } ;
120
- ( Add :: add ( self . count , idx) , value)
253
+ // SAFETY: Just forwarding to the actual implementation.
254
+ unsafe { EnumerateImpl :: __iterator_get_unchecked ( self , idx) }
121
255
}
122
256
}
123
257
@@ -128,11 +262,7 @@ where
128
262
{
129
263
#[ inline]
130
264
fn next_back ( & mut self ) -> Option < ( usize , <I as Iterator >:: Item ) > {
131
- let a = self . iter . next_back ( ) ?;
132
- let len = self . iter . len ( ) ;
133
- // Can safely add, `ExactSizeIterator` promises that the number of
134
- // elements fits into a `usize`.
135
- Some ( ( self . count + len, a) )
265
+ EnumerateImpl :: next_back ( self )
136
266
}
137
267
138
268
#[ inline]
0 commit comments