move free-standing method into trait impl
This commit is contained in:
parent
0f122e1119
commit
085eb20a61
1 changed files with 75 additions and 79 deletions
|
@ -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> {
|
impl<T> SpecFrom<T, IntoIter<T>> for Vec<T> {
|
||||||
fn from_iter(iterator: IntoIter<T>) -> Self {
|
fn from_iter(iterator: IntoIter<T>) -> Self {
|
||||||
// A common case is passing a vector into a function which immediately
|
// 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
|
where
|
||||||
I: Iterator<Item = T> + InPlaceIterable + SourceIter<Source = IntoIter<T>>,
|
I: Iterator<Item = T> + InPlaceIterable + SourceIter<Source = IntoIter<T>>,
|
||||||
{
|
{
|
||||||
default fn from_iter(iterator: I) -> Self {
|
default fn from_iter(mut iterator: I) -> Self {
|
||||||
from_into_iter_source(iterator)
|
// 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue