@@ -229,96 +229,106 @@ where
229
229
I : Iterator < Item = T > + InPlaceCollect ,
230
230
<I as SourceIter >:: Source : AsVecIntoIter ,
231
231
{
232
- default fn from_iter ( mut iterator : I ) -> Self {
233
- // See "Layout constraints" section in the module documentation. We rely on const
234
- // optimization here since these conditions currently cannot be expressed as trait bounds
235
- if const { !in_place_collectible :: < T , I :: Src > ( I :: MERGE_BY , I :: EXPAND_BY ) } {
236
- // fallback to more generic implementations
237
- return SpecFromIterNested :: from_iter ( iterator) ;
238
- }
239
-
240
- let ( src_buf, src_ptr, src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
241
- let inner = iterator. as_inner ( ) . as_into_iter ( ) ;
242
- (
243
- inner. buf . as_ptr ( ) ,
244
- inner. ptr ,
245
- inner. cap ,
246
- inner. buf . as_ptr ( ) as * mut T ,
247
- inner. end as * const T ,
248
- inner. cap * mem:: size_of :: < I :: Src > ( ) / mem:: size_of :: < T > ( ) ,
249
- )
232
+ default fn from_iter ( iterator : I ) -> Self {
233
+ // Select the implementation in const eval to avoid codegen of the dead branch to improve compile times.
234
+ let fun: fn ( I ) -> Vec < T > = const {
235
+ // See "Layout constraints" section in the module documentation. We use const conditions here
236
+ // since these conditions currently cannot be expressed as trait bounds
237
+ if in_place_collectible :: < T , I :: Src > ( I :: MERGE_BY , I :: EXPAND_BY ) {
238
+ from_iter_in_place
239
+ } else {
240
+ // fallback
241
+ SpecFromIterNested :: < T , I > :: from_iter
242
+ }
250
243
} ;
251
244
252
- // SAFETY: `dst_buf` and `dst_end` are the start and end of the buffer.
253
- let len = unsafe { SpecInPlaceCollect :: collect_in_place ( & mut iterator, dst_buf, dst_end) } ;
245
+ fun ( iterator)
246
+ }
247
+ }
254
248
255
- let src = unsafe { iterator. as_inner ( ) . as_into_iter ( ) } ;
256
- // check if SourceIter contract was upheld
257
- // caveat: if they weren't we might not even make it to this point
258
- debug_assert_eq ! ( src_buf, src. buf. as_ptr( ) ) ;
259
- // check InPlaceIterable contract. This is only possible if the iterator advanced the
260
- // source pointer at all. If it uses unchecked access via TrustedRandomAccess
261
- // then the source pointer will stay in its initial position and we can't use it as reference
262
- if src. ptr != src_ptr {
263
- debug_assert ! (
264
- unsafe { dst_buf. add( len) as * const _ } <= src. ptr. as_ptr( ) ,
265
- "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
266
- ) ;
267
- }
249
+ fn from_iter_in_place < I , T > ( mut iterator : I ) -> Vec < T >
250
+ where
251
+ I : Iterator < Item = T > + InPlaceCollect ,
252
+ <I as SourceIter >:: Source : AsVecIntoIter ,
253
+ {
254
+ let ( src_buf, src_ptr, src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
255
+ let inner = iterator. as_inner ( ) . as_into_iter ( ) ;
256
+ (
257
+ inner. buf . as_ptr ( ) ,
258
+ inner. ptr ,
259
+ inner. cap ,
260
+ inner. buf . as_ptr ( ) as * mut T ,
261
+ inner. end as * const T ,
262
+ inner. cap * mem:: size_of :: < I :: Src > ( ) / mem:: size_of :: < T > ( ) ,
263
+ )
264
+ } ;
268
265
269
- // The ownership of the source allocation and the new `T` values is temporarily moved into `dst_guard`.
270
- // This is safe because
271
- // * `forget_allocation_drop_remaining` immediately forgets the allocation
272
- // before any panic can occur in order to avoid any double free, and then proceeds to drop
273
- // any remaining values at the tail of the source.
274
- // * the shrink either panics without invalidating the allocation, aborts or
275
- // succeeds. In the last case we disarm the guard.
276
- //
277
- // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce
278
- // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the
279
- // module documentation why this is ok anyway.
280
- let dst_guard =
281
- InPlaceDstDataSrcBufDrop { ptr : dst_buf, len, src_cap, src : PhantomData :: < I :: Src > } ;
282
- src. forget_allocation_drop_remaining ( ) ;
266
+ // SAFETY: `dst_buf` and `dst_end` are the start and end of the buffer.
267
+ let len = unsafe { SpecInPlaceCollect :: collect_in_place ( & mut iterator, dst_buf, dst_end) } ;
283
268
284
- // Adjust the allocation if the source had a capacity in bytes that wasn't a multiple
285
- // of the destination type size.
286
- // Since the discrepancy should generally be small this should only result in some
287
- // bookkeeping updates and no memmove.
288
- if needs_realloc :: < I :: Src , T > ( src_cap , dst_cap ) {
289
- let alloc = Global ;
290
- debug_assert_ne ! ( src_cap , 0 ) ;
291
- debug_assert_ne ! ( dst_cap , 0 ) ;
292
- unsafe {
293
- // The old allocation exists, therefore it must have a valid layout.
294
- let src_align = mem :: align_of :: < I :: Src > ( ) ;
295
- let src_size = mem :: size_of :: < I :: Src > ( ) . unchecked_mul ( src_cap ) ;
296
- let old_layout = Layout :: from_size_align_unchecked ( src_size , src_align ) ;
269
+ let src = unsafe { iterator . as_inner ( ) . as_into_iter ( ) } ;
270
+ // check if SourceIter contract was upheld
271
+ // caveat: if they weren't we might not even make it to this point
272
+ debug_assert_eq ! ( src_buf , src . buf . as_ptr ( ) ) ;
273
+ // check InPlaceIterable contract. This is only possible if the iterator advanced the
274
+ // source pointer at all. If it uses unchecked access via TrustedRandomAccess
275
+ // then the source pointer will stay in its initial position and we can't use it as reference
276
+ if src . ptr != src_ptr {
277
+ debug_assert ! (
278
+ unsafe { dst_buf . add ( len ) as * const _ } <= src . ptr . as_ptr ( ) ,
279
+ "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
280
+ ) ;
281
+ }
297
282
298
- // The allocation must be equal or smaller for in-place iteration to be possible
299
- // therefore the new layout must be ≤ the old one and therefore valid.
300
- let dst_align = mem:: align_of :: < T > ( ) ;
301
- let dst_size = mem:: size_of :: < T > ( ) . unchecked_mul ( dst_cap) ;
302
- let new_layout = Layout :: from_size_align_unchecked ( dst_size, dst_align) ;
283
+ // The ownership of the source allocation and the new `T` values is temporarily moved into `dst_guard`.
284
+ // This is safe because
285
+ // * `forget_allocation_drop_remaining` immediately forgets the allocation
286
+ // before any panic can occur in order to avoid any double free, and then proceeds to drop
287
+ // any remaining values at the tail of the source.
288
+ // * the shrink either panics without invalidating the allocation, aborts or
289
+ // succeeds. In the last case we disarm the guard.
290
+ //
291
+ // Note: This access to the source wouldn't be allowed by the TrustedRandomIteratorNoCoerce
292
+ // contract (used by SpecInPlaceCollect below). But see the "O(1) collect" section in the
293
+ // module documentation why this is ok anyway.
294
+ let dst_guard =
295
+ InPlaceDstDataSrcBufDrop { ptr : dst_buf, len, src_cap, src : PhantomData :: < I :: Src > } ;
296
+ src. forget_allocation_drop_remaining ( ) ;
303
297
304
- let result = alloc. shrink (
305
- NonNull :: new_unchecked ( dst_buf as * mut u8 ) ,
306
- old_layout,
307
- new_layout,
308
- ) ;
309
- let Ok ( reallocated) = result else { handle_alloc_error ( new_layout) } ;
310
- dst_buf = reallocated. as_ptr ( ) as * mut T ;
311
- }
312
- } else {
313
- debug_assert_eq ! ( src_cap * mem:: size_of:: <I :: Src >( ) , dst_cap * mem:: size_of:: <T >( ) ) ;
298
+ // Adjust the allocation if the source had a capacity in bytes that wasn't a multiple
299
+ // of the destination type size.
300
+ // Since the discrepancy should generally be small this should only result in some
301
+ // bookkeeping updates and no memmove.
302
+ if needs_realloc :: < I :: Src , T > ( src_cap, dst_cap) {
303
+ let alloc = Global ;
304
+ debug_assert_ne ! ( src_cap, 0 ) ;
305
+ debug_assert_ne ! ( dst_cap, 0 ) ;
306
+ unsafe {
307
+ // The old allocation exists, therefore it must have a valid layout.
308
+ let src_align = mem:: align_of :: < I :: Src > ( ) ;
309
+ let src_size = mem:: size_of :: < I :: Src > ( ) . unchecked_mul ( src_cap) ;
310
+ let old_layout = Layout :: from_size_align_unchecked ( src_size, src_align) ;
311
+
312
+ // The allocation must be equal or smaller for in-place iteration to be possible
313
+ // therefore the new layout must be ≤ the old one and therefore valid.
314
+ let dst_align = mem:: align_of :: < T > ( ) ;
315
+ let dst_size = mem:: size_of :: < T > ( ) . unchecked_mul ( dst_cap) ;
316
+ let new_layout = Layout :: from_size_align_unchecked ( dst_size, dst_align) ;
317
+
318
+ let result =
319
+ alloc. shrink ( NonNull :: new_unchecked ( dst_buf as * mut u8 ) , old_layout, new_layout) ;
320
+ let Ok ( reallocated) = result else { handle_alloc_error ( new_layout) } ;
321
+ dst_buf = reallocated. as_ptr ( ) as * mut T ;
314
322
}
323
+ } else {
324
+ debug_assert_eq ! ( src_cap * mem:: size_of:: <I :: Src >( ) , dst_cap * mem:: size_of:: <T >( ) ) ;
325
+ }
315
326
316
- mem:: forget ( dst_guard) ;
327
+ mem:: forget ( dst_guard) ;
317
328
318
- let vec = unsafe { Vec :: from_raw_parts ( dst_buf, len, dst_cap) } ;
329
+ let vec = unsafe { Vec :: from_raw_parts ( dst_buf, len, dst_cap) } ;
319
330
320
- vec
321
- }
331
+ vec
322
332
}
323
333
324
334
fn write_in_place_with_drop < T > (
0 commit comments