From 085eb20a61164067f5c71ec64dc23100006f91c9 Mon Sep 17 00:00:00 2001 From: The8472 Date: Sat, 23 Nov 2019 18:30:32 +0100 Subject: [PATCH] move free-standing method into trait impl --- library/alloc/src/vec.rs | 154 +++++++++++++++++++-------------------- 1 file 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 Drop for InPlaceDrop { } } -fn from_into_iter_source(mut iterator: I) -> Vec -where - I: Iterator + InPlaceIterable + SourceIter>, -{ - // 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::() == 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::() { - // 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::() { - // 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 SpecFrom> for Vec { fn from_iter(iterator: IntoIter) -> Self { // A common case is passing a vector into a function which immediately @@ -2298,8 +2221,81 @@ impl SpecFrom for Vec where I: Iterator + InPlaceIterable + SourceIter>, { - 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::() == 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::() { + // 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::() { + // 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 } }