diff options
| author | The8472 <git@infinite-source.de> | 2020-09-02 21:40:19 +0200 |
|---|---|---|
| committer | The8472 <git@infinite-source.de> | 2020-09-03 20:59:37 +0200 |
| commit | 8e5fe5569b5ffd59f57e0dab4380ba04b063330e (patch) | |
| tree | a317c72a339ae79fc8e5a084265021fac7c09bd5 | |
| parent | 64645865423990935a74abecc576a91f5b89f2cd (diff) | |
| download | rust-8e5fe5569b5ffd59f57e0dab4380ba04b063330e.tar.gz rust-8e5fe5569b5ffd59f57e0dab4380ba04b063330e.zip | |
improve comments and naming
| -rw-r--r-- | library/alloc/src/vec.rs | 81 |
1 files changed, 56 insertions, 25 deletions
diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 2e3f6ec60e5..5c474ab2cde 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -2014,7 +2014,7 @@ impl<T, I: SliceIndex<[T]>> IndexMut<I> for Vec<T> { impl<T> FromIterator<T> for Vec<T> { #[inline] fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Vec<T> { - <Self as SpecFrom<T, I::IntoIter>>::from_iter(iter.into_iter()) + <Self as SpecFromIter<T, I::IntoIter>>::from_iter(iter.into_iter()) } } @@ -2096,18 +2096,39 @@ impl<T> Extend<T> for Vec<T> { } } -// Specialization trait used for Vec::from_iter -trait SpecFrom<T, I> { +/// Specialization trait used for Vec::from_iter +/// +/// ## The delegation graph: +/// +/// ```text +/// +-------------+ +/// |FromIterator | +/// +-+-----------+ +/// | +/// v +/// +-+-------------------------------+ +---------------------+ +/// |SpecFromIter +---->+SpecFromIterNested | +/// |where I: | | |where I: | +/// | Iterator (default)----------+ | | Iterator (default) | +/// | vec::IntoIter | | | TrustedLen | +/// | SourceIterMarker---fallback-+ | | | +/// | slice::Iter | | | +/// | Iterator<Item = &Clone> | +---------------------+ +/// +---------------------------------+ +/// +/// ``` +trait SpecFromIter<T, I> { fn from_iter(iter: I) -> Self; } -// Another specialization trait for Vec::from_iter -// necessary to manually prioritize overlapping specializations -trait SpecFromNested<T, I> { +/// Another specialization trait for Vec::from_iter +/// necessary to manually prioritize overlapping specializations +/// see [`SpecFromIter`] for details. +trait SpecFromIterNested<T, I> { fn from_iter(iter: I) -> Self; } -impl<T, I> SpecFromNested<T, I> for Vec<T> +impl<T, I> SpecFromIterNested<T, I> for Vec<T> where I: Iterator<Item = T>, { @@ -2136,7 +2157,7 @@ where } } -impl<T, I> SpecFromNested<T, I> for Vec<T> +impl<T, I> SpecFromIterNested<T, I> for Vec<T> where I: TrustedLen<Item = T>, { @@ -2149,12 +2170,12 @@ where } } -impl<T, I> SpecFrom<T, I> for Vec<T> +impl<T, I> SpecFromIter<T, I> for Vec<T> where I: Iterator<Item = T>, { default fn from_iter(iterator: I) -> Self { - SpecFromNested::from_iter(iterator) + SpecFromIterNested::from_iter(iterator) } } @@ -2182,18 +2203,21 @@ impl<T> Drop for InPlaceDrop<T> { } } -impl<T> SpecFrom<T, IntoIter<T>> for Vec<T> { +impl<T> SpecFromIter<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 // re-collects into a vector. We can short circuit this if the IntoIter // has not been advanced at all. - // We can also reuse the memory and move the data to the front if - // allocating a new vector and moving to it would result in the same capacity - let non_zero_offset = iterator.buf.as_ptr() as *const _ != iterator.ptr; - if !non_zero_offset || iterator.len() >= iterator.cap / 2 { + // When it has been advanced We can also reuse the memory and move the data to the front. + // But we only do so when the resulting Vec wouldn't have more unused capacity + // than creating it through the generic FromIterator implementation would. That limitation + // is not strictly necessary as Vec's allocation behavior is intentionally unspecified. + // But it is a conservative choice. + let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr; + if !has_advanced || iterator.len() >= iterator.cap / 2 { unsafe { let it = ManuallyDrop::new(iterator); - if non_zero_offset { + if has_advanced { ptr::copy(it.ptr, it.buf.as_ptr(), it.len()); } return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap); @@ -2224,6 +2248,12 @@ fn write_in_place_with_drop<T>( } } +/// Specialization marker for collecting an iterator pipeline into a Vec while reusing the +/// source allocation, i.e. executing the pipeline in place. +/// +/// The SourceIter parent trait is necessary for the specializing function to access the allocation +/// which is to be reused. But it is not sufficient for the specialization to be valid. See +/// additional bounds on the impl. #[rustc_unsafe_specialization_marker] trait SourceIterMarker: SourceIter<Source: AsIntoIter> {} @@ -2235,7 +2265,7 @@ trait SourceIterMarker: SourceIter<Source: AsIntoIter> {} // several other specializations already depend on. impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {} -impl<T, I> SpecFrom<T, I> for Vec<T> +impl<T, I> SpecFromIter<T, I> for Vec<T> where I: Iterator<Item = T> + SourceIterMarker, { @@ -2251,7 +2281,8 @@ where || mem::align_of::<T>() != mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>() { - return SpecFromNested::from_iter(iterator); + // fallback to more generic implementations + return SpecFromIterNested::from_iter(iterator); } let (src_buf, dst_buf, dst_end, cap) = unsafe { @@ -2277,9 +2308,9 @@ where debug_assert!(dst as *const _ <= src.ptr, "InPlaceIterable contract violation"); // drop any remaining values at the tail of the source - src.drop_in_place(); + src.drop_remaining(); // but prevent drop of the allocation itself once IntoIter goes out of scope - src.forget_in_place(); + src.forget_allocation(); let vec = unsafe { let len = dst.offset_from(dst_buf) as usize; @@ -2290,17 +2321,17 @@ where } } -impl<'a, T: 'a, I> SpecFrom<&'a T, I> for Vec<T> +impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T> where I: Iterator<Item = &'a T>, T: Clone, { default fn from_iter(iterator: I) -> Self { - SpecFrom::from_iter(iterator.cloned()) + SpecFromIter::from_iter(iterator.cloned()) } } -impl<'a, T: 'a> SpecFrom<&'a T, slice::Iter<'a, T>> for Vec<T> +impl<'a, T: 'a> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> where T: Copy, { @@ -2824,7 +2855,7 @@ impl<T> IntoIter<T> { ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) } - fn drop_in_place(&mut self) { + fn drop_remaining(&mut self) { if mem::needs_drop::<T>() { unsafe { ptr::drop_in_place(self.as_mut_slice()); @@ -2835,7 +2866,7 @@ impl<T> IntoIter<T> { /// Relinquishes the backing allocation, equivalent to /// `ptr::write(&mut self, Vec::new().into_iter())` - fn forget_in_place(&mut self) { + fn forget_allocation(&mut self) { self.cap = 0; self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) }; self.ptr = self.buf.as_ptr(); |
