specialize slice_iter.copied().next_chunk()

This commit is contained in:
The 8472 2022-10-17 22:49:32 +02:00
parent 963d6f757c
commit 873a18e221

View file

@ -2,7 +2,10 @@
zip::try_get_unchecked, TrustedRandomAccess, TrustedRandomAccessNoCoerce,
};
use crate::iter::{FusedIterator, TrustedLen};
use crate::mem::MaybeUninit;
use crate::mem::SizedTypeProperties;
use crate::ops::Try;
use crate::{array, ptr};
/// An iterator that copies the elements of an underlying iterator.
///
@ -44,6 +47,15 @@ fn next(&mut self) -> Option<T> {
self.it.next().copied()
}
fn next_chunk<const N: usize>(
&mut self,
) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
where
Self: Sized,
{
<I as SpecNextChunk<'_, N, T>>::spec_next_chunk(&mut self.it)
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
@ -166,3 +178,65 @@ unsafe impl<'a, I, T: 'a> TrustedLen for Copied<I>
T: Copy,
{
}
trait SpecNextChunk<'a, const N: usize, T: 'a>: Iterator<Item = &'a T>
where
T: Copy,
{
fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>>;
}
impl<'a, const N: usize, I, T: 'a> SpecNextChunk<'a, N, T> for I
where
I: Iterator<Item = &'a T>,
T: Copy,
{
default fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
array::iter_next_chunk(&mut self.map(|e| *e))
}
}
impl<'a, const N: usize, T: 'a> SpecNextChunk<'a, N, T> for crate::slice::Iter<'a, T>
where
T: Copy,
{
fn spec_next_chunk(&mut self) -> Result<[T; N], array::IntoIter<T, N>> {
let mut raw_array = MaybeUninit::uninit_array();
let len = self.len();
if T::IS_ZST {
if len < N {
let _ = self.advance_by(len);
// SAFETY: ZSTs can be conjured ex nihilo; only the amount has to be correct
return Err(unsafe { array::IntoIter::new_unchecked(raw_array, 0..len) });
}
let _ = self.advance_by(N);
// SAFETY: ditto
return Ok(unsafe { MaybeUninit::array_assume_init(raw_array) });
}
if len < N {
// SAFETY: `len` indicates that this many elements are available and we just checked that
// it fits into the array.
unsafe {
ptr::copy_nonoverlapping(
self.as_ref().as_ptr(),
raw_array.as_mut_ptr() as *mut T,
len,
);
let _ = self.advance_by(len);
return Err(array::IntoIter::new_unchecked(raw_array, 0..len));
}
}
// SAFETY: `len` is larger than the array size. Copy a fixed amount here to fully initialize
// the array.
unsafe {
ptr::copy_nonoverlapping(self.as_ref().as_ptr(), raw_array.as_mut_ptr() as *mut T, N);
let _ = self.advance_by(N);
Ok(MaybeUninit::array_assume_init(raw_array))
}
}
}