Skip to content

Commit 5530858

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

File tree

3 files changed

+34
-23
lines changed

3 files changed

+34
-23
lines changed

library/alloc/src/collections/binary_heap.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,8 +1186,10 @@ unsafe impl<T> SourceIter for IntoIter<T> {
11861186
#[unstable(issue = "none", feature = "inplace_iteration")]
11871187
unsafe impl<I> InPlaceIterable for IntoIter<I> {}
11881188

1189-
impl<I> AsIntoIter<I> for IntoIter<I> {
1190-
fn as_into_iter(&mut self) -> &mut vec::IntoIter<I> {
1189+
impl<I> AsIntoIter for IntoIter<I> {
1190+
type Item = I;
1191+
1192+
fn as_into_iter(&mut self) -> &mut vec::IntoIter<Self::Item> {
11911193
&mut self.iter
11921194
}
11931195
}

library/alloc/src/vec.rs

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2240,23 +2240,28 @@ fn write_in_place_with_drop<T>(
22402240
}
22412241
}
22422242

2243-
// Further specialization potential once
2244-
// https://github.com/rust-lang/rust/issues/62645 has been solved:
2245-
// T can be split into IN and OUT which only need to have the same size and alignment
22462243
impl<T, I> SpecFrom<T, I> for Vec<T>
22472244
where
2248-
I: Iterator<Item = T> + InPlaceIterable + SourceIter<Source: AsIntoIter<T>>,
2245+
I: Iterator<Item = T> + InPlaceIterable + SourceIter<Source: AsIntoIter>,
22492246
{
22502247
default fn from_iter(mut iterator: I) -> Self {
2251-
// This specialization only makes sense if we're juggling real allocations.
2252-
// Additionally some of the pointer arithmetic would panic on ZSTs.
2253-
if mem::size_of::<T>() == 0 {
2248+
// Additional requirements which cannot expressed via trait bounds. We rely on const eval
2249+
// instead:
2250+
// a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
2251+
// b) size match as required by Alloc contract
2252+
// c) alignments match as required by Alloc contract
2253+
if mem::size_of::<T>() == 0
2254+
|| mem::size_of::<T>()
2255+
!= mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
2256+
|| mem::align_of::<T>()
2257+
!= mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
2258+
{
22542259
return SpecFromNested::from_iter(iterator);
22552260
}
22562261

2257-
let (src_buf, src_end, cap) = {
2258-
let inner = unsafe { iterator.as_inner().as_into_iter() };
2259-
(inner.buf.as_ptr(), inner.end, inner.cap)
2262+
let (src_buf, dst_buf, dst_end, cap) = unsafe {
2263+
let inner = iterator.as_inner().as_into_iter();
2264+
(inner.buf.as_ptr(), inner.buf.as_ptr() as *mut T, inner.end as *const T, inner.cap)
22602265
};
22612266

22622267
// use try-fold
@@ -2266,15 +2271,15 @@ where
22662271
let dst = if mem::needs_drop::<T>() {
22672272
// special-case drop handling since it forces us to lug that extra field around which
22682273
// can inhibit optimizations
2269-
let sink = InPlaceDrop { inner: src_buf, dst: src_buf };
2274+
let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
22702275
let sink = iterator
2271-
.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(src_end))
2276+
.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
22722277
.unwrap();
22732278
// iteration succeeded, don't drop head
22742279
let sink = mem::ManuallyDrop::new(sink);
22752280
sink.dst
22762281
} else {
2277-
iterator.try_fold::<_, _, Result<_, !>>(src_buf, write_in_place(src_end)).unwrap()
2282+
iterator.try_fold::<_, _, Result<_, !>>(dst_buf, write_in_place(dst_end)).unwrap()
22782283
};
22792284

22802285
let src = unsafe { iterator.as_inner().as_into_iter() };
@@ -2289,8 +2294,8 @@ where
22892294
src.forget_in_place();
22902295

22912296
let vec = unsafe {
2292-
let len = dst.offset_from(src_buf) as usize;
2293-
Vec::from_raw_parts(src_buf, len, cap)
2297+
let len = dst.offset_from(dst_buf) as usize;
2298+
Vec::from_raw_parts(dst_buf, len, cap)
22942299
};
22952300

22962301
vec
@@ -3010,12 +3015,15 @@ unsafe impl<T> SourceIter for IntoIter<T> {
30103015
}
30113016

30123017
// internal helper trait for in-place iteration specialization.
3013-
pub(crate) trait AsIntoIter<T> {
3014-
fn as_into_iter(&mut self) -> &mut IntoIter<T>;
3018+
pub(crate) trait AsIntoIter {
3019+
type Item;
3020+
fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item>;
30153021
}
30163022

3017-
impl<T> AsIntoIter<T> for IntoIter<T> {
3018-
fn as_into_iter(&mut self) -> &mut IntoIter<T> {
3023+
impl<T> AsIntoIter for IntoIter<T> {
3024+
type Item = T;
3025+
3026+
fn as_into_iter(&mut self) -> &mut IntoIter<Self::Item> {
30193027
self
30203028
}
30213029
}

library/alloc/tests/vec.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -820,11 +820,12 @@ fn test_from_iter_specialization_with_iterator_adapters() {
820820
.zip(std::iter::repeat(1usize))
821821
.map(|(a, b)| a + b)
822822
.peekable()
823-
.skip(1);
823+
.skip(1)
824+
.map(|e| std::num::NonZeroUsize::new(e));
824825
assert_in_place_trait(&iter);
825826
let sink = iter.collect::<Vec<_>>();
826827
let sinkptr = sink.as_ptr();
827-
assert_eq!(srcptr, sinkptr);
828+
assert_eq!(srcptr, sinkptr as *const usize);
828829
}
829830

830831
#[test]

0 commit comments

Comments
 (0)