@@ -2107,6 +2107,34 @@ impl<T> SpecFrom<T, IntoIter<T>> for Vec<T> {
2107
2107
}
2108
2108
}
2109
2109
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
+
2110
2138
// Further specialization potential once
2111
2139
// https://github.com/rust-lang/rust/issues/62645 has been solved:
2112
2140
// T can be split into IN and OUT which only need to have the same size and alignment
@@ -2125,46 +2153,23 @@ where
2125
2153
let inner = unsafe { iterator. as_inner ( ) . as_into_iter ( ) } ;
2126
2154
( inner. buf . as_ptr ( ) , inner. end , inner. cap )
2127
2155
} ;
2128
- let dst = src_buf;
2129
2156
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
2130
2161
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 ( ) ;
2144
2168
// iteration succeeded, don't drop head
2145
2169
let sink = mem:: ManuallyDrop :: new ( sink) ;
2146
2170
sink. dst
2147
2171
} 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 ( )
2168
2173
} ;
2169
2174
2170
2175
let src = unsafe { iterator. as_inner ( ) . as_into_iter ( ) } ;
0 commit comments