@@ -192,23 +192,33 @@ macro_rules! iterator {
192192 }
193193
194194 #[ inline]
195- fn fold<B , F >( mut self , init: B , mut f: F ) -> B
195+ fn fold<B , F >( self , init: B , mut f: F ) -> B
196196 where
197197 F : FnMut ( B , Self :: Item ) -> B ,
198198 {
199- // Handling the 0-len case explicitly and then using a do-while style loop
200- // helps the optimizer. See issue #106288
199+ // this implementation consists of the following optimizations compared to the
200+ // default implementation:
201+ // - do-while loop, as is llvm's preferred loop shape,
202+ // see https://releases.llvm.org/16.0.0/docs/LoopTerminology.html#more-canonical-loops
203+ // - bumps an index instead of a pointer since the latter case inhibits
204+ // some optimizations, see #111603
205+ // - avoids Option wrapping/matching
201206 if is_empty!( self ) {
202207 return init;
203208 }
204209 let mut acc = init;
205- // SAFETY: The 0-len case was handled above so one loop iteration is guaranteed.
206- unsafe {
207- loop {
208- acc = f( acc, next_unchecked!( self ) ) ;
209- if is_empty!( self ) {
210- break ;
211- }
210+ let mut i = 0 ;
211+ let len = len!( self ) ;
212+ loop {
213+ // SAFETY: the loop iterates `i in 0..len`, which always is in bounds of
214+ // the slice allocation
215+ acc = f( acc, unsafe { & $( $mut_ ) ? * self . ptr. add( i) . as_ptr( ) } ) ;
216+ // SAFETY: `i` can't overflow since it'll only reach usize::MAX if the
217+ // slice had that length, in which case we'll break out of the loop
218+ // after the increment
219+ i = unsafe { i. unchecked_add( 1 ) } ;
220+ if i == len {
221+ break ;
212222 }
213223 }
214224 acc
0 commit comments