Skip to content

Commit a724f9a

Browse files
committed
generalize in-place collect to types of same size and alignment
1 parent 0576929 commit a724f9a

File tree

3 files changed

+34
-23
lines changed

3 files changed

+34
-23
lines changed

src/liballoc/collections/binary_heap.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -1158,8 +1158,10 @@ unsafe impl<T> SourceIter for IntoIter<T> {
11581158
#[unstable(issue = "none", feature = "inplace_iteration")]
11591159
unsafe impl<I> InPlaceIterable for IntoIter<I> {}
11601160

1161-
impl<I> AsIntoIter<I> for IntoIter<I> {
1162-
fn as_into_iter(&mut self) -> &mut vec::IntoIter<I> {
1161+
impl<I> AsIntoIter for IntoIter<I> {
1162+
type Item = I;
1163+
1164+
fn as_into_iter(&mut self) -> &mut vec::IntoIter<Self::Item> {
11631165
&mut self.iter
11641166
}
11651167
}

src/liballoc/tests/vec.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -772,11 +772,12 @@ fn test_from_iter_specialization_with_iterator_adapters() {
772772
.zip(std::iter::repeat(1usize))
773773
.map(|(a, b)| a + b)
774774
.peekable()
775-
.skip(1);
775+
.skip(1)
776+
.map(|e| std::num::NonZeroUsize::new(e));
776777
assert_in_place_trait(&iter);
777778
let sink = iter.collect::<Vec<_>>();
778779
let sinkptr = sink.as_ptr();
779-
assert_eq!(srcptr, sinkptr);
780+
assert_eq!(srcptr, sinkptr as *const usize);
780781
}
781782

782783
#[test]

src/liballoc/vec.rs

+27-19
Original file line numberDiff line numberDiff line change
@@ -2135,23 +2135,28 @@ fn write_in_place_with_drop<T>(
21352135
}
21362136
}
21372137

2138-
// Further specialization potential once
2139-
// https://github.com/rust-lang/rust/issues/62645 has been solved:
2140-
// T can be split into IN and OUT which only need to have the same size and alignment
21412138
impl<T, I> SpecFrom<T, I> for Vec<T>
21422139
where
2143-
I: Iterator<Item = T> + InPlaceIterable + SourceIter<Source: AsIntoIter<T>>,
2140+
I: Iterator<Item = T> + InPlaceIterable + SourceIter<Source: AsIntoIter>,
21442141
{
21452142
default fn from_iter(mut iterator: I) -> Self {
2146-
// This specialization only makes sense if we're juggling real allocations.
2147-
// Additionally some of the pointer arithmetic would panic on ZSTs.
2148-
if mem::size_of::<T>() == 0 {
2143+
// Additional requirements which cannot expressed via trait bounds. We rely on const eval
2144+
// instead:
2145+
// a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
2146+
// b) size match as required by Alloc contract
2147+
// c) alignments match as required by Alloc contract
2148+
if mem::size_of::<T>() == 0
2149+
|| mem::size_of::<T>()
2150+
!= mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
2151+
|| mem::align_of::<T>()
2152+
!= mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
2153+
{
21492154
return SpecFromNested::from_iter(iterator);
21502155
}
21512156

2152-
let (src_buf, src_end, cap) = {
2153-
let inner = unsafe { iterator.as_inner().as_into_iter() };
2154-
(inner.buf.as_ptr(), inner.end, inner.cap)
2157+
let (src_buf, dst_buf, dst_end, cap) = unsafe {
2158+
let inner = iterator.as_inner().as_into_iter();
2159+
(inner.buf.as_ptr(), inner.buf.as_ptr() as *mut T, inner.end as *const T, inner.cap)
21552160
};
21562161

21572162
// use try-fold
@@ -2161,15 +2166,15 @@ where
21612166
let dst = if mem::needs_drop::<T>() {
21622167
// special-case drop handling since it forces us to lug that extra field around which
21632168
// can inhibit optimizations
2164-
let sink = InPlaceDrop { inner: src_buf, dst: src_buf };
2169+
let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
21652170
let sink = iterator
2166-
.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(src_end))
2171+
.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
21672172
.unwrap();
21682173
// iteration succeeded, don't drop head
21692174
let sink = mem::ManuallyDrop::new(sink);
21702175
sink.dst
21712176
} else {
2172-
iterator.try_fold::<_, _, Result<_, !>>(src_buf, write_in_place(src_end)).unwrap()
2177+
iterator.try_fold::<_, _, Result<_, !>>(dst_buf, write_in_place(dst_end)).unwrap()
21732178
};
21742179

21752180
let src = unsafe { iterator.as_inner().as_into_iter() };
@@ -2184,8 +2189,8 @@ where
21842189
src.forget_in_place();
21852190

21862191
let vec = unsafe {
2187-
let len = dst.offset_from(src_buf) as usize;
2188-
Vec::from_raw_parts(src_buf, len, cap)
2192+
let len = dst.offset_from(dst_buf) as usize;
2193+
Vec::from_raw_parts(dst_buf, len, cap)
21892194
};
21902195

21912196
vec
@@ -2856,12 +2861,15 @@ unsafe impl<T> SourceIter for IntoIter<T> {
28562861
}
28572862

28582863
// internal helper trait for in-place iteration specialization.
2859-
pub(crate) trait AsIntoIter<T> {
2860-
fn as_into_iter(&mut self) -> &mut IntoIter<T>;
2864+
pub(crate) trait AsIntoIter {
2865+
type Item;
2866+
fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item>;
28612867
}
28622868

2863-
impl<T> AsIntoIter<T> for IntoIter<T> {
2864-
fn as_into_iter(&mut self) -> &mut IntoIter<T> {
2869+
impl<T> AsIntoIter for IntoIter<T> {
2870+
type Item = T;
2871+
2872+
fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item> {
28652873
self
28662874
}
28672875
}

0 commit comments

Comments
 (0)