Skip to content

Commit 18391e2

Browse files
committed
spec next chunk for trustedlen
1 parent d3f16d2 commit 18391e2

File tree

1 file changed

+34
-2
lines changed

1 file changed

+34
-2
lines changed

library/core/src/array/mod.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::convert::Infallible;
1111
use crate::error::Error;
1212
use crate::hash::{self, Hash};
1313
use crate::intrinsics::transmute_unchecked;
14-
use crate::iter::{UncheckedIterator, repeat_n};
14+
use crate::iter::{TrustedLen, UncheckedIterator, repeat_n};
1515
use crate::marker::Destruct;
1616
use crate::mem::{self, ManuallyDrop, MaybeUninit};
1717
use crate::ops::{
@@ -976,9 +976,15 @@ impl<T: [const] Destruct> const Drop for Guard<'_, T> {
976976
/// dropped.
977977
///
978978
/// Used for [`Iterator::next_chunk`].
979-
#[inline]
980979
pub(crate) fn iter_next_chunk<T, const N: usize>(
981980
iter: &mut impl Iterator<Item = T>,
981+
) -> Result<[T; N], IntoIter<T, N>> {
982+
iter.spec_next_chunk()
983+
}
984+
985+
#[inline]
986+
fn generic_iter_next_chunk<T, const N: usize>(
987+
iter: &mut impl Iterator<Item = T>,
982988
) -> Result<[T; N], IntoIter<T, N>> {
983989
let mut array = [const { MaybeUninit::uninit() }; N];
984990
let r = iter_next_chunk_erased(&mut array, iter);
@@ -994,6 +1000,32 @@ pub(crate) fn iter_next_chunk<T, const N: usize>(
9941000
}
9951001
}
9961002

1003+
pub(crate) trait SpecNextChunk<T, const N: usize>: Iterator<Item = T> {
1004+
fn spec_next_chunk(&mut self) -> Result<[T; N], IntoIter<T, N>>;
1005+
}
1006+
impl<I: Iterator<Item = T>, T, const N: usize> SpecNextChunk<T, N> for I {
1007+
default fn spec_next_chunk(&mut self) -> Result<[T; N], IntoIter<T, N>> {
1008+
generic_iter_next_chunk(self)
1009+
}
1010+
}
1011+
1012+
impl<I: Iterator<Item = T> + TrustedLen, T, const N: usize> SpecNextChunk<T, N> for I {
1013+
fn spec_next_chunk(&mut self) -> Result<[T; N], IntoIter<T, N>> {
1014+
if self.size_hint().0 < N {
1015+
let mut array = [const { MaybeUninit::uninit() }; N];
1016+
let initialized =
1017+
// SAFETY: Has to error out; trusted len means that
1018+
// SAFETY: there may only be less than N elements
1019+
unsafe { iter_next_chunk_erased(&mut array, self).unwrap_err_unchecked() };
1020+
// SAFETY: Only the first `initialized` elements were populated
1021+
Err(unsafe { IntoIter::new_unchecked(array, 0..initialized) })
1022+
} else {
1023+
// SAFETY: must be at least N elements; safe to unwrap N elements.
1024+
Ok(from_fn(|_| unsafe { self.next().unwrap_unchecked() }))
1025+
}
1026+
}
1027+
}
1028+
9971029
/// Version of [`iter_next_chunk`] using a passed-in slice in order to avoid
9981030
/// needing to monomorphize for every array length.
9991031
///

0 commit comments

Comments
 (0)