diff options
| author | The8472 <git@infinite-source.de> | 2019-11-23 18:30:32 +0100 |
|---|---|---|
| committer | The8472 <git@infinite-source.de> | 2020-09-03 20:59:19 +0200 |
| commit | 085eb20a61164067f5c71ec64dc23100006f91c9 (patch) | |
| tree | 028b4b68aea814a30f1d69a6bf9aa23d6bcb63e4 | |
| parent | 0f122e11196875c75071f4e3ac4ce1a652e320bf (diff) | |
| download | rust-085eb20a61164067f5c71ec64dc23100006f91c9.tar.gz rust-085eb20a61164067f5c71ec64dc23100006f91c9.zip | |
move free-standing method into trait impl
| -rw-r--r-- | library/alloc/src/vec.rs | 154 |
1 files changed, 75 insertions, 79 deletions
diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 1e7f95a25cc..9327cf16c15 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2188,83 +2188,6 @@ impl<T> Drop for InPlaceDrop<T> { } } -fn from_into_iter_source<T, I>(mut iterator: I) -> Vec<T> -where - I: Iterator<Item = T> + InPlaceIterable + SourceIter<Source = IntoIter<T>>, -{ - // This specialization only makes sense if we're juggling real allocations. - // Additionally some of the pointer arithmetic would panic on ZSTs. - if mem::size_of::<T>() == 0 { - return SpecFromNested::from_iter(iterator); - } - - let src_buf = iterator.as_inner().buf.as_ptr(); - let src_end = iterator.as_inner().end; - let dst = src_buf; - - let dst = if mem::needs_drop::<T>() { - // special-case drop handling since it prevents vectorization - let mut sink = InPlaceDrop { inner: src_buf, dst, did_panic: true }; - let _ = iterator.try_for_each::<_, Result<_, !>>(|item| { - unsafe { - debug_assert!( - sink.dst as *const _ <= src_end, - "InPlaceIterable contract violation" - ); - ptr::write(sink.dst, item); - sink.dst = sink.dst.add(1); - } - Ok(()) - }); - sink.did_panic = false; - sink.dst - } else { - // use try-fold - // - it vectorizes better - // - unlike most internal iteration methods methods it only takes a &mut self - // - lets us thread the write pointer through its innards and get it back in the end - iterator - .try_fold::<_, _, Result<_, !>>(dst, move |mut dst, item| { - unsafe { - // the InPlaceIterable contract cannot be verified precisely here since - // try_fold has an exclusive reference to the source pointer - // all we can do is check if it's still in range - debug_assert!(dst as *const _ <= src_end, "InPlaceIterable contract violation"); - ptr::write(dst, item); - dst = dst.add(1); - } - Ok(dst) - }) - .unwrap() - }; - - let src = iterator.as_inner(); - // check if SourceIter and InPlaceIterable contracts were upheld. - // caveat: if they weren't we may not even make it to this point - debug_assert_eq!(src_buf, src.buf.as_ptr()); - debug_assert!(dst as *const _ <= src.ptr, "InPlaceIterable contract violation"); - - if mem::needs_drop::<T>() { - // drop tail if iterator was only partially exhaused - unsafe { - ptr::drop_in_place(src.as_mut_slice()); - } - } - - let vec = unsafe { - let len = dst.offset_from(src_buf) as usize; - Vec::from_raw_parts(src.buf.as_ptr(), len, src.cap) - }; - // prevent drop of the underlying storage by turning the IntoIter into - // the equivalent of Vec::new().into_iter() - src.cap = 0; - src.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) }; - src.ptr = src.buf.as_ptr(); - src.end = src.buf.as_ptr(); - - vec -} - impl<T> SpecFrom<T, IntoIter<T>> for Vec<T> { fn from_iter(iterator: IntoIter<T>) -> Self { // A common case is passing a vector into a function which immediately @@ -2298,8 +2221,81 @@ impl<T, I> SpecFrom<T, I> for Vec<T> where I: Iterator<Item = T> + InPlaceIterable + SourceIter<Source = IntoIter<T>>, { - default fn from_iter(iterator: I) -> Self { - from_into_iter_source(iterator) + default fn from_iter(mut iterator: I) -> Self { + // This specialization only makes sense if we're juggling real allocations. + // Additionally some of the pointer arithmetic would panic on ZSTs. + if mem::size_of::<T>() == 0 { + return SpecFromNested::from_iter(iterator); + } + + let src_buf = iterator.as_inner().buf.as_ptr(); + let src_end = iterator.as_inner().end; + let dst = src_buf; + + let dst = if mem::needs_drop::<T>() { + // special-case drop handling since it prevents vectorization + let mut sink = InPlaceDrop { inner: src_buf, dst, did_panic: true }; + let _ = iterator.try_for_each::<_, Result<_, !>>(|item| { + unsafe { + debug_assert!( + sink.dst as *const _ <= src_end, + "InPlaceIterable contract violation" + ); + ptr::write(sink.dst, item); + sink.dst = sink.dst.add(1); + } + Ok(()) + }); + sink.did_panic = false; + sink.dst + } else { + // use try-fold + // - it vectorizes better + // - unlike most internal iteration methods methods it only takes a &mut self + // - lets us thread the write pointer through its innards and get it back in the end + iterator + .try_fold::<_, _, Result<_, !>>(dst, move |mut dst, item| { + unsafe { + // the InPlaceIterable contract cannot be verified precisely here since + // try_fold has an exclusive reference to the source pointer + // all we can do is check if it's still in range + debug_assert!( + dst as *const _ <= src_end, + "InPlaceIterable contract violation" + ); + ptr::write(dst, item); + dst = dst.add(1); + } + Ok(dst) + }) + .unwrap() + }; + + let src = iterator.as_inner(); + // check if SourceIter and InPlaceIterable contracts were upheld. + // caveat: if they weren't we may not even make it to this point + debug_assert_eq!(src_buf, src.buf.as_ptr()); + debug_assert!(dst as *const _ <= src.ptr, "InPlaceIterable contract violation"); + + if mem::needs_drop::<T>() { + // drop tail if iterator was only partially exhaused + unsafe { + ptr::drop_in_place(src.as_mut_slice()); + } + } + + let vec = unsafe { + let len = dst.offset_from(src_buf) as usize; + Vec::from_raw_parts(src.buf.as_ptr(), len, src.cap) + }; + // prevent drop of the underlying storage by turning the IntoIter into + // the equivalent of Vec::new().into_iter() + src.cap = 0; + src.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) }; + src.ptr = src.buf.as_ptr(); + src.end = src.buf.as_ptr(); + + vec } } |
