@@ -2212,6 +2212,34 @@ impl<T> SpecFrom<T, IntoIter<T>> for Vec<T> {
22122212 }
22132213}
22142214
2215+ fn write_in_place < T > ( src_end : * const T ) -> impl FnMut ( * mut T , T ) -> Result < * mut T , !> {
2216+ move |mut dst, item| {
2217+ unsafe {
2218+ // the InPlaceIterable contract cannot be verified precisely here since
2219+ // try_fold has an exclusive reference to the source pointer
2220+ // all we can do is check if it's still in range
2221+ debug_assert ! ( dst as * const _ <= src_end, "InPlaceIterable contract violation" ) ;
2222+ ptr:: write ( dst, item) ;
2223+ dst = dst. add ( 1 ) ;
2224+ }
2225+ Ok ( dst)
2226+ }
2227+ }
2228+
2229+ fn write_in_place_with_drop < T > (
2230+ src_end : * const T ,
2231+ ) -> impl FnMut ( InPlaceDrop < T > , T ) -> Result < InPlaceDrop < T > , !> {
2232+ move |mut sink, item| {
2233+ unsafe {
2234+ // same caveat as above
2235+ debug_assert ! ( sink. dst as * const _ <= src_end, "InPlaceIterable contract violation" ) ;
2236+ ptr:: write ( sink. dst , item) ;
2237+ sink. dst = sink. dst . add ( 1 ) ;
2238+ }
2239+ Ok ( sink)
2240+ }
2241+ }
2242+
22152243// Further specialization potential once
22162244// https://github.com/rust-lang/rust/issues/62645 has been solved:
22172245// T can be split into IN and OUT which only need to have the same size and alignment
@@ -2230,46 +2258,23 @@ where
22302258 let inner = unsafe { iterator. as_inner ( ) . as_into_iter ( ) } ;
22312259 ( inner. buf . as_ptr ( ) , inner. end , inner. cap )
22322260 } ;
2233- let dst = src_buf;
22342261
2262+ // use try-fold
2263+ // - it vectorizes better for some iterator adapters
2264+ // - unlike most internal iteration methods methods it only takes a &mut self
2265+ // - lets us thread the write pointer through its innards and get it back in the end
22352266 let dst = if mem:: needs_drop :: < T > ( ) {
2236- // special-case drop handling since it prevents vectorization
2237- let mut sink = InPlaceDrop { inner : src_buf, dst } ;
2238- let _ = iterator. try_for_each :: < _ , Result < _ , !> > ( |item| {
2239- unsafe {
2240- debug_assert ! (
2241- sink. dst as * const _ <= src_end,
2242- "InPlaceIterable contract violation"
2243- ) ;
2244- ptr:: write ( sink. dst , item) ;
2245- sink. dst = sink. dst . add ( 1 ) ;
2246- }
2247- Ok ( ( ) )
2248- } ) ;
2267+ // special-case drop handling since it forces us to lug that extra field around which
2268+ // can inhibit optimizations
2269+ let sink = InPlaceDrop { inner : src_buf, dst : src_buf } ;
2270+ let sink = iterator
2271+ . try_fold :: < _ , _ , Result < _ , !> > ( sink, write_in_place_with_drop ( src_end) )
2272+ . unwrap ( ) ;
22492273 // iteration succeeded, don't drop head
22502274 let sink = mem:: ManuallyDrop :: new ( sink) ;
22512275 sink. dst
22522276 } else {
2253- // use try-fold
2254- // - it vectorizes better
2255- // - unlike most internal iteration methods methods it only takes a &mut self
2256- // - lets us thread the write pointer through its innards and get it back in the end
2257- iterator
2258- . try_fold :: < _ , _ , Result < _ , !> > ( dst, move |mut dst, item| {
2259- unsafe {
2260- // the InPlaceIterable contract cannot be verified precisely here since
2261- // try_fold has an exclusive reference to the source pointer
2262- // all we can do is check if it's still in range
2263- debug_assert ! (
2264- dst as * const _ <= src_end,
2265- "InPlaceIterable contract violation"
2266- ) ;
2267- ptr:: write ( dst, item) ;
2268- dst = dst. add ( 1 ) ;
2269- }
2270- Ok ( dst)
2271- } )
2272- . unwrap ( )
2277+ iterator. try_fold :: < _ , _ , Result < _ , !> > ( src_buf, write_in_place ( src_end) ) . unwrap ( )
22732278 } ;
22742279
22752280 let src = unsafe { iterator. as_inner ( ) . as_into_iter ( ) } ;
0 commit comments