1+ use crate :: intrinsics;
12use crate :: iter:: adapters:: { zip:: try_get_unchecked, SourceIter , TrustedRandomAccess } ;
23use crate :: iter:: { FusedIterator , InPlaceIterable , TrustedLen } ;
34use crate :: ops:: { Add , AddAssign , Try } ;
@@ -15,10 +16,149 @@ use crate::ops::{Add, AddAssign, Try};
1516pub struct Enumerate < I > {
1617 iter : I ,
1718 count : usize ,
19+ len : usize ,
1820}
19- impl < I > Enumerate < I > {
21+ impl < I : Iterator > Enumerate < I > {
2022 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) )
22162 }
23163}
24164
@@ -40,11 +180,7 @@ where
40180 /// Might panic if the index of the element overflows a `usize`.
41181 #[ inline]
42182 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 )
48184 }
49185
50186 #[ inline]
@@ -114,10 +250,8 @@ where
114250 where
115251 Self : TrustedRandomAccess ,
116252 {
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) }
121255 }
122256}
123257
@@ -128,11 +262,7 @@ where
128262{
129263 #[ inline]
130264 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 )
136266 }
137267
138268 #[ inline]
0 commit comments