@@ -3,7 +3,7 @@ use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedF
33use crate :: num:: NonZero ;
44use crate :: ops:: Try ;
55use core:: array;
6- use core:: mem:: { ManuallyDrop , MaybeUninit } ;
6+ use core:: mem:: MaybeUninit ;
77use core:: ops:: ControlFlow ;
88
99/// An iterator that filters the elements of `iter` with `predicate`.
@@ -27,6 +27,42 @@ impl<I, P> Filter<I, P> {
2727 }
2828}
2929
30+ impl < I , P > Filter < I , P >
31+ where
32+ I : Iterator ,
33+ P : FnMut ( & I :: Item ) -> bool ,
34+ {
35+ #[ inline]
36+ fn next_chunk_dropless < const N : usize > (
37+ & mut self ,
38+ ) -> Result < [ I :: Item ; N ] , array:: IntoIter < I :: Item , N > > {
39+ let mut array: [ MaybeUninit < I :: Item > ; N ] = [ const { MaybeUninit :: uninit ( ) } ; N ] ;
40+ let mut initialized = 0 ;
41+
42+ let result = self . iter . try_for_each ( |element| {
43+ let idx = initialized;
44+ // branchless index update combined with unconditionally copying the value even when
45+ // it is filtered reduces branching and dependencies in the loop.
46+ initialized = idx + ( self . predicate ) ( & element) as usize ;
47+ // SAFETY: Loop conditions ensure the index is in bounds.
48+ unsafe { array. get_unchecked_mut ( idx) } . write ( element) ;
49+
50+ if initialized < N { ControlFlow :: Continue ( ( ) ) } else { ControlFlow :: Break ( ( ) ) }
51+ } ) ;
52+
53+ match result {
54+ ControlFlow :: Break ( ( ) ) => {
55+ // SAFETY: The loop above is only explicitly broken when the array has been fully initialized
56+ Ok ( unsafe { MaybeUninit :: array_assume_init ( array) } )
57+ }
58+ ControlFlow :: Continue ( ( ) ) => {
59+ // SAFETY: The range is in bounds since the loop breaks when reaching N elements.
60+ Err ( unsafe { array:: IntoIter :: new_unchecked ( array, 0 ..initialized) } )
61+ }
62+ }
63+ }
64+ }
65+
3066#[ stable( feature = "core_impl_debug" , since = "1.9.0" ) ]
3167impl < I : fmt:: Debug , P > fmt:: Debug for Filter < I , P > {
3268 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
@@ -64,52 +100,16 @@ where
64100 fn next_chunk < const N : usize > (
65101 & mut self ,
66102 ) -> Result < [ Self :: Item ; N ] , array:: IntoIter < Self :: Item , N > > {
67- let mut array: [ MaybeUninit < Self :: Item > ; N ] = [ const { MaybeUninit :: uninit ( ) } ; N ] ;
68-
69- struct Guard < ' a , T > {
70- array : & ' a mut [ MaybeUninit < T > ] ,
71- initialized : usize ,
72- }
73-
74- impl < T > Drop for Guard < ' _ , T > {
75- #[ inline]
76- fn drop ( & mut self ) {
77- if const { crate :: mem:: needs_drop :: < T > ( ) } {
78- // SAFETY: self.initialized is always <= N, which also is the length of the array.
79- unsafe {
80- core:: ptr:: drop_in_place ( MaybeUninit :: slice_assume_init_mut (
81- self . array . get_unchecked_mut ( ..self . initialized ) ,
82- ) ) ;
83- }
84- }
103+ // avoid codegen for the dead branch
104+ let fun = const {
105+ if crate :: mem:: needs_drop :: < I :: Item > ( ) {
106+ array:: iter_next_chunk :: < I :: Item , N >
107+ } else {
108+ Self :: next_chunk_dropless :: < N >
85109 }
86- }
87-
88- let mut guard = Guard { array : & mut array, initialized : 0 } ;
89-
90- let result = self . iter . try_for_each ( |element| {
91- let idx = guard. initialized ;
92- guard. initialized = idx + ( self . predicate ) ( & element) as usize ;
93-
94- // SAFETY: Loop conditions ensure the index is in bounds.
95- unsafe { guard. array . get_unchecked_mut ( idx) } . write ( element) ;
96-
97- if guard. initialized < N { ControlFlow :: Continue ( ( ) ) } else { ControlFlow :: Break ( ( ) ) }
98- } ) ;
110+ } ;
99111
100- let guard = ManuallyDrop :: new ( guard) ;
101-
102- match result {
103- ControlFlow :: Break ( ( ) ) => {
104- // SAFETY: The loop above is only explicitly broken when the array has been fully initialized
105- Ok ( unsafe { MaybeUninit :: array_assume_init ( array) } )
106- }
107- ControlFlow :: Continue ( ( ) ) => {
108- let initialized = guard. initialized ;
109- // SAFETY: The range is in bounds since the loop breaks when reaching N elements.
110- Err ( unsafe { array:: IntoIter :: new_unchecked ( array, 0 ..initialized) } )
111- }
112- }
112+ fun ( self )
113113 }
114114
115115 #[ inline]
0 commit comments