@@ -2107,6 +2107,34 @@ impl<T> SpecFrom<T, IntoIter<T>> for Vec<T> {
21072107 }
21082108}
21092109
2110+ fn write_in_place < T > ( src_end : * const T ) -> impl FnMut ( * mut T , T ) -> Result < * mut T , !> {
2111+ move |mut dst, item| {
2112+ unsafe {
2113+ // the InPlaceIterable contract cannot be verified precisely here since
2114+ // try_fold has an exclusive reference to the source pointer
2115+ // all we can do is check if it's still in range
2116+ debug_assert ! ( dst as * const _ <= src_end, "InPlaceIterable contract violation" ) ;
2117+ ptr:: write ( dst, item) ;
2118+ dst = dst. add ( 1 ) ;
2119+ }
2120+ Ok ( dst)
2121+ }
2122+ }
2123+
2124+ fn write_in_place_with_drop < T > (
2125+ src_end : * const T ,
2126+ ) -> impl FnMut ( InPlaceDrop < T > , T ) -> Result < InPlaceDrop < T > , !> {
2127+ move |mut sink, item| {
2128+ unsafe {
2129+ // same caveat as above
2130+ debug_assert ! ( sink. dst as * const _ <= src_end, "InPlaceIterable contract violation" ) ;
2131+ ptr:: write ( sink. dst , item) ;
2132+ sink. dst = sink. dst . add ( 1 ) ;
2133+ }
2134+ Ok ( sink)
2135+ }
2136+ }
2137+
21102138// Further specialization potential once
21112139// https://github.com/rust-lang/rust/issues/62645 has been solved:
21122140// T can be split into IN and OUT which only need to have the same size and alignment
@@ -2125,46 +2153,23 @@ where
21252153 let inner = unsafe { iterator. as_inner ( ) . as_into_iter ( ) } ;
21262154 ( inner. buf . as_ptr ( ) , inner. end , inner. cap )
21272155 } ;
2128- let dst = src_buf;
21292156
2157+ // use try-fold
2158+ // - it vectorizes better for some iterator adapters
2159+ // - unlike most internal iteration methods methods it only takes a &mut self
2160+ // - lets us thread the write pointer through its innards and get it back in the end
21302161 let dst = if mem:: needs_drop :: < T > ( ) {
2131- // special-case drop handling since it prevents vectorization
2132- let mut sink = InPlaceDrop { inner : src_buf, dst } ;
2133- let _ = iterator. try_for_each :: < _ , Result < _ , !> > ( |item| {
2134- unsafe {
2135- debug_assert ! (
2136- sink. dst as * const _ <= src_end,
2137- "InPlaceIterable contract violation"
2138- ) ;
2139- ptr:: write ( sink. dst , item) ;
2140- sink. dst = sink. dst . add ( 1 ) ;
2141- }
2142- Ok ( ( ) )
2143- } ) ;
2162+ // special-case drop handling since it forces us to lug that extra field around which
2163+ // can inhibit optimizations
2164+ let sink = InPlaceDrop { inner : src_buf, dst : src_buf } ;
2165+ let sink = iterator
2166+ . try_fold :: < _ , _ , Result < _ , !> > ( sink, write_in_place_with_drop ( src_end) )
2167+ . unwrap ( ) ;
21442168 // iteration succeeded, don't drop head
21452169 let sink = mem:: ManuallyDrop :: new ( sink) ;
21462170 sink. dst
21472171 } else {
2148- // use try-fold
2149- // - it vectorizes better
2150- // - unlike most internal iteration methods methods it only takes a &mut self
2151- // - lets us thread the write pointer through its innards and get it back in the end
2152- iterator
2153- . try_fold :: < _ , _ , Result < _ , !> > ( dst, move |mut dst, item| {
2154- unsafe {
2155- // the InPlaceIterable contract cannot be verified precisely here since
2156- // try_fold has an exclusive reference to the source pointer
2157- // all we can do is check if it's still in range
2158- debug_assert ! (
2159- dst as * const _ <= src_end,
2160- "InPlaceIterable contract violation"
2161- ) ;
2162- ptr:: write ( dst, item) ;
2163- dst = dst. add ( 1 ) ;
2164- }
2165- Ok ( dst)
2166- } )
2167- . unwrap ( )
2172+ iterator. try_fold :: < _ , _ , Result < _ , !> > ( src_buf, write_in_place ( src_end) ) . unwrap ( )
21682173 } ;
21692174
21702175 let src = unsafe { iterator. as_inner ( ) . as_into_iter ( ) } ;
0 commit comments