157
157
use crate :: alloc:: { handle_alloc_error, Global } ;
158
158
use core:: alloc:: Allocator ;
159
159
use core:: alloc:: Layout ;
160
- use core:: iter:: { InPlaceIterable , SourceIter , TrustedRandomAccessNoCoerce } ;
160
+ use core:: iter:: UncheckedIndexedIterator ;
161
+ use core:: iter:: { InPlaceIterable , SourceIter } ;
161
162
use core:: marker:: PhantomData ;
162
163
use core:: mem:: { self , ManuallyDrop , SizedTypeProperties } ;
163
164
use core:: num:: NonZeroUsize ;
@@ -237,7 +238,7 @@ where
237
238
return SpecFromIterNested :: from_iter ( iterator) ;
238
239
}
239
240
240
- let ( src_buf, src_ptr , src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
241
+ let ( src_buf, _src_ptr , src_cap, mut dst_buf, dst_end, dst_cap) = unsafe {
241
242
let inner = iterator. as_inner ( ) . as_into_iter ( ) ;
242
243
(
243
244
inner. buf . as_ptr ( ) ,
@@ -256,15 +257,11 @@ where
256
257
// check if SourceIter contract was upheld
257
258
// caveat: if they weren't we might not even make it to this point
258
259
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
- }
260
+ // check InPlaceIterable contract.
261
+ debug_assert ! (
262
+ unsafe { dst_buf. add( len) as * const _ } <= src. ptr. as_ptr( ) ,
263
+ "InPlaceIterable contract violation, write pointer advanced beyond read pointer"
264
+ ) ;
268
265
269
266
// The ownership of the source allocation and the new `T` values is temporarily moved into `dst_guard`.
270
267
// This is safe because
@@ -369,28 +366,93 @@ where
369
366
}
370
367
}
371
368
369
+ // impl<T, I> SpecInPlaceCollect<T, I> for I
370
+ // where
371
+ // I: Iterator<Item = T> + TrustedRandomAccessNoCoerce,
372
+ // {
373
+ // #[inline]
374
+ // unsafe fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize {
375
+ // let len = self.size();
376
+ // let mut drop_guard = InPlaceDrop { inner: dst_buf, dst: dst_buf };
377
+ // for i in 0..len {
378
+ // // Safety: InplaceIterable contract guarantees that for every element we read
379
+ // // one slot in the underlying storage will have been freed up and we can immediately
380
+ // // write back the result.
381
+ // unsafe {
382
+ // let dst = dst_buf.add(i);
383
+ // debug_assert!(dst as *const _ <= end, "InPlaceIterable contract violation");
384
+ // ptr::write(dst, self.__iterator_get_unchecked(i));
385
+ // // Since this executes user code which can panic we have to bump the pointer
386
+ // // after each step.
387
+ // drop_guard.dst = dst.add(1);
388
+ // }
389
+ // }
390
+ // mem::forget(drop_guard);
391
+ // len
392
+ // }
393
+ // }
394
+
372
395
impl < T , I > SpecInPlaceCollect < T , I > for I
373
396
where
374
- I : Iterator < Item = T > + TrustedRandomAccessNoCoerce ,
397
+ I : Iterator < Item = T > + UncheckedIndexedIterator ,
375
398
{
376
399
#[ inline]
377
400
unsafe fn collect_in_place ( & mut self , dst_buf : * mut T , end : * const T ) -> usize {
378
- let len = self . size ( ) ;
379
- let mut drop_guard = InPlaceDrop { inner : dst_buf, dst : dst_buf } ;
380
- for i in 0 ..len {
381
- // Safety: InplaceIterable contract guarantees that for every element we read
382
- // one slot in the underlying storage will have been freed up and we can immediately
383
- // write back the result.
401
+ let len = self . size_hint ( ) . 0 ;
402
+
403
+ if len == 0 {
404
+ return 0 ;
405
+ }
406
+
407
+ struct LoopGuard < ' a , I >
408
+ where
409
+ I : Iterator + UncheckedIndexedIterator ,
410
+ {
411
+ it : & ' a mut I ,
412
+ len : usize ,
413
+ idx : usize ,
414
+ dst_buf : * mut I :: Item ,
415
+ }
416
+
417
+ impl < I > Drop for LoopGuard < ' _ , I >
418
+ where
419
+ I : Iterator + UncheckedIndexedIterator ,
420
+ {
421
+ #[ inline]
422
+ fn drop ( & mut self ) {
423
+ unsafe {
424
+ let new_len = self . len - self . idx ;
425
+ self . it . set_front_index_from_end_unchecked ( new_len, self . len ) ;
426
+ if self . idx != self . len {
427
+ let raw_slice =
428
+ ptr:: slice_from_raw_parts_mut :: < I :: Item > ( self . dst_buf , self . idx ) ;
429
+ ptr:: drop_in_place ( raw_slice) ;
430
+ }
431
+ }
432
+ }
433
+ }
434
+
435
+ let mut state = LoopGuard { it : self , len, idx : 0 , dst_buf } ;
436
+
437
+ loop {
384
438
unsafe {
385
- let dst = dst_buf. add ( i) ;
439
+ let idx = state. idx ;
440
+ state. idx = state. idx . unchecked_add ( 1 ) ;
441
+ let dst = state. dst_buf . add ( idx) ;
386
442
debug_assert ! ( dst as * const _ <= end, "InPlaceIterable contract violation" ) ;
387
- ptr:: write ( dst, self . __iterator_get_unchecked ( i) ) ;
388
- // Since this executes user code which can panic we have to bump the pointer
389
- // after each step.
390
- drop_guard. dst = dst. add ( 1 ) ;
443
+ dst. write ( state. it . index_from_end_unchecked ( state. len - idx) ) ;
444
+ //drop_guard.dst = dst_buf.add(i).add(1);
445
+ }
446
+ if state. idx == len {
447
+ break ;
391
448
}
392
449
}
393
- mem:: forget ( drop_guard) ;
450
+
451
+ // disarm guard, we don't want the front elements to get dropped
452
+ mem:: forget ( state) ;
453
+ // since the guard is disarmed, update the iterator state
454
+ unsafe { self . set_front_index_from_end_unchecked ( 0 , len) } ;
455
+
394
456
len
395
457
}
396
458
}
0 commit comments