mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
refactor: moving SourceIterMarker into source_iter_marker.rs
This commit is contained in:
parent
840c4e2873
commit
5ac6709b95
@ -60,7 +60,7 @@ use core::fmt;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::intrinsics::{arith_offset, assume};
|
||||
use core::iter::{
|
||||
FromIterator, InPlaceIterable, SourceIter, TrustedLen,
|
||||
FromIterator, TrustedLen,
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{self, ManuallyDrop, MaybeUninit};
|
||||
@ -101,6 +101,8 @@ use self::is_zero::IsZero;
|
||||
|
||||
mod is_zero;
|
||||
|
||||
mod source_iter_marker;
|
||||
|
||||
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
|
||||
///
|
||||
/// # Examples
|
||||
@ -2356,109 +2358,6 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_in_place_with_drop<T>(
|
||||
src_end: *const T,
|
||||
) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
|
||||
move |mut sink, 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!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
|
||||
ptr::write(sink.dst, item);
|
||||
sink.dst = sink.dst.add(1);
|
||||
}
|
||||
Ok(sink)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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> {}
|
||||
|
||||
// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
|
||||
// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
|
||||
// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
|
||||
// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
|
||||
// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
|
||||
// several other specializations already depend on.
|
||||
impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}
|
||||
|
||||
impl<T, I> SpecFromIter<T, I> for Vec<T>
|
||||
where
|
||||
I: Iterator<Item = T> + SourceIterMarker,
|
||||
{
|
||||
default fn from_iter(mut iterator: I) -> Self {
|
||||
// Additional requirements which cannot expressed via trait bounds. We rely on const eval
|
||||
// instead:
|
||||
// a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
|
||||
// b) size match as required by Alloc contract
|
||||
// c) alignments match as required by Alloc contract
|
||||
if mem::size_of::<T>() == 0
|
||||
|| mem::size_of::<T>()
|
||||
!= mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
|
||||
|| mem::align_of::<T>()
|
||||
!= mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
|
||||
{
|
||||
// fallback to more generic implementations
|
||||
return SpecFromIterNested::from_iter(iterator);
|
||||
}
|
||||
|
||||
let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
|
||||
let inner = iterator.as_inner().as_into_iter();
|
||||
(
|
||||
inner.buf.as_ptr(),
|
||||
inner.ptr,
|
||||
inner.buf.as_ptr() as *mut T,
|
||||
inner.end as *const T,
|
||||
inner.cap,
|
||||
)
|
||||
};
|
||||
|
||||
// use try-fold since
|
||||
// - it vectorizes better for some iterator adapters
|
||||
// - unlike most internal iteration methods, it only takes a &mut self
|
||||
// - it lets us thread the write pointer through its innards and get it back in the end
|
||||
let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
|
||||
let sink = iterator
|
||||
.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
|
||||
.unwrap();
|
||||
// iteration succeeded, don't drop head
|
||||
let dst = ManuallyDrop::new(sink).dst;
|
||||
|
||||
let src = unsafe { iterator.as_inner().as_into_iter() };
|
||||
// check if SourceIter contract was upheld
|
||||
// caveat: if they weren't we may not even make it to this point
|
||||
debug_assert_eq!(src_buf, src.buf.as_ptr());
|
||||
// check InPlaceIterable contract. This is only possible if the iterator advanced the
|
||||
// source pointer at all. If it uses unchecked access via TrustedRandomAccess
|
||||
// then the source pointer will stay in its initial position and we can't use it as reference
|
||||
if src.ptr != src_ptr {
|
||||
debug_assert!(
|
||||
dst as *const _ <= src.ptr,
|
||||
"InPlaceIterable contract violation, write pointer advanced beyond read pointer"
|
||||
);
|
||||
}
|
||||
|
||||
// drop any remaining values at the tail of the source
|
||||
src.drop_remaining();
|
||||
// but prevent drop of the allocation itself once IntoIter goes out of scope
|
||||
src.forget_allocation();
|
||||
|
||||
let vec = unsafe {
|
||||
let len = dst.offset_from(dst_buf) as usize;
|
||||
Vec::from_raw_parts(dst_buf, len, cap)
|
||||
};
|
||||
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T>
|
||||
where
|
||||
I: Iterator<Item = &'a T>,
|
||||
|
110
library/alloc/src/vec/source_iter_marker.rs
Normal file
110
library/alloc/src/vec/source_iter_marker.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use core::iter::{
|
||||
InPlaceIterable, SourceIter,
|
||||
};
|
||||
use core::mem::{self, ManuallyDrop};
|
||||
use core::ptr::{self};
|
||||
|
||||
use super::{Vec, InPlaceDrop, AsIntoIter, SpecFromIter, SpecFromIterNested};
|
||||
|
||||
/// 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]
|
||||
pub (super) trait SourceIterMarker: SourceIter<Source: AsIntoIter> {}
|
||||
|
||||
// The std-internal SourceIter/InPlaceIterable traits are only implemented by chains of
|
||||
// Adapter<Adapter<Adapter<IntoIter>>> (all owned by core/std). Additional bounds
|
||||
// on the adapter implementations (beyond `impl<I: Trait> Trait for Adapter<I>`) only depend on other
|
||||
// traits already marked as specialization traits (Copy, TrustedRandomAccess, FusedIterator).
|
||||
// I.e. the marker does not depend on lifetimes of user-supplied types. Modulo the Copy hole, which
|
||||
// several other specializations already depend on.
|
||||
impl<T> SourceIterMarker for T where T: SourceIter<Source: AsIntoIter> + InPlaceIterable {}
|
||||
|
||||
impl<T, I> SpecFromIter<T, I> for Vec<T>
|
||||
where
|
||||
I: Iterator<Item = T> + SourceIterMarker,
|
||||
{
|
||||
default fn from_iter(mut iterator: I) -> Self {
|
||||
// Additional requirements which cannot expressed via trait bounds. We rely on const eval
|
||||
// instead:
|
||||
// a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic
|
||||
// b) size match as required by Alloc contract
|
||||
// c) alignments match as required by Alloc contract
|
||||
if mem::size_of::<T>() == 0
|
||||
|| mem::size_of::<T>()
|
||||
!= mem::size_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
|
||||
|| mem::align_of::<T>()
|
||||
!= mem::align_of::<<<I as SourceIter>::Source as AsIntoIter>::Item>()
|
||||
{
|
||||
// fallback to more generic implementations
|
||||
return SpecFromIterNested::from_iter(iterator);
|
||||
}
|
||||
|
||||
let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe {
|
||||
let inner = iterator.as_inner().as_into_iter();
|
||||
(
|
||||
inner.buf.as_ptr(),
|
||||
inner.ptr,
|
||||
inner.buf.as_ptr() as *mut T,
|
||||
inner.end as *const T,
|
||||
inner.cap,
|
||||
)
|
||||
};
|
||||
|
||||
// use try-fold since
|
||||
// - it vectorizes better for some iterator adapters
|
||||
// - unlike most internal iteration methods, it only takes a &mut self
|
||||
// - it lets us thread the write pointer through its innards and get it back in the end
|
||||
let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
|
||||
let sink = iterator
|
||||
.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end))
|
||||
.unwrap();
|
||||
// iteration succeeded, don't drop head
|
||||
let dst = ManuallyDrop::new(sink).dst;
|
||||
|
||||
let src = unsafe { iterator.as_inner().as_into_iter() };
|
||||
// check if SourceIter contract was upheld
|
||||
// caveat: if they weren't we may not even make it to this point
|
||||
debug_assert_eq!(src_buf, src.buf.as_ptr());
|
||||
// check InPlaceIterable contract. This is only possible if the iterator advanced the
|
||||
// source pointer at all. If it uses unchecked access via TrustedRandomAccess
|
||||
// then the source pointer will stay in its initial position and we can't use it as reference
|
||||
if src.ptr != src_ptr {
|
||||
debug_assert!(
|
||||
dst as *const _ <= src.ptr,
|
||||
"InPlaceIterable contract violation, write pointer advanced beyond read pointer"
|
||||
);
|
||||
}
|
||||
|
||||
// drop any remaining values at the tail of the source
|
||||
src.drop_remaining();
|
||||
// but prevent drop of the allocation itself once IntoIter goes out of scope
|
||||
src.forget_allocation();
|
||||
|
||||
let vec = unsafe {
|
||||
let len = dst.offset_from(dst_buf) as usize;
|
||||
Vec::from_raw_parts(dst_buf, len, cap)
|
||||
};
|
||||
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
fn write_in_place_with_drop<T>(
|
||||
src_end: *const T,
|
||||
) -> impl FnMut(InPlaceDrop<T>, T) -> Result<InPlaceDrop<T>, !> {
|
||||
move |mut sink, 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!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation");
|
||||
ptr::write(sink.dst, item);
|
||||
sink.dst = sink.dst.add(1);
|
||||
}
|
||||
Ok(sink)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user