Implement UncheckedIterator directly for RepeatN

This commit is contained in:
Scott McMurray 2024-08-01 21:58:34 -07:00
parent 425ae69588
commit 77ca30f195
2 changed files with 34 additions and 14 deletions

View File

@ -114,19 +114,12 @@ impl<A: Clone> Iterator for RepeatN<A> {
#[inline] #[inline]
fn next(&mut self) -> Option<A> { fn next(&mut self) -> Option<A> {
if self.count == 0 { if self.count > 0 {
return None; // SAFETY: Just checked it's not empty
} unsafe { Some(self.next_unchecked()) }
self.count -= 1;
Some(if self.count == 0 {
// SAFETY: the check above ensured that the count used to be non-zero,
// so element hasn't been dropped yet, and we just lowered the count to
// zero so it won't be dropped later, and thus it's okay to take it here.
unsafe { ManuallyDrop::take(&mut self.element) }
} else { } else {
A::clone(&self.element) None
}) }
} }
#[inline] #[inline]
@ -194,4 +187,18 @@ impl<A: Clone> FusedIterator for RepeatN<A> {}
#[unstable(feature = "trusted_len", issue = "37572")] #[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<A: Clone> TrustedLen for RepeatN<A> {} unsafe impl<A: Clone> TrustedLen for RepeatN<A> {}
#[unstable(feature = "trusted_len_next_unchecked", issue = "37572")] #[unstable(feature = "trusted_len_next_unchecked", issue = "37572")]
impl<A: Clone> UncheckedIterator for RepeatN<A> {} impl<A: Clone> UncheckedIterator for RepeatN<A> {
#[inline]
unsafe fn next_unchecked(&mut self) -> Self::Item {
// SAFETY: The caller promised the iterator isn't empty
self.count = unsafe { self.count.unchecked_sub(1) };
if self.count == 0 {
// SAFETY: the check above ensured that the count used to be non-zero,
// so element hasn't been dropped yet, and we just lowered the count to
// zero so it won't be dropped later, and thus it's okay to take it here.
unsafe { ManuallyDrop::take(&mut self.element) }
} else {
A::clone(&self.element)
}
}
}

View File

@ -1,8 +1,9 @@
//@ compile-flags: -O //@ compile-flags: -C opt-level=3
//@ only-x86_64 //@ only-x86_64
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(iter_repeat_n)] #![feature(iter_repeat_n)]
#![feature(array_repeat)]
#[derive(Clone)] #[derive(Clone)]
pub struct NotCopy(u16); pub struct NotCopy(u16);
@ -54,3 +55,15 @@ pub fn vec_extend_via_iter_repeat_n() -> Vec<u8> {
v.extend(std::iter::repeat_n(42_u8, n)); v.extend(std::iter::repeat_n(42_u8, n));
v v
} }
// Array repeat uses `RepeatN::next_unchecked` internally,
// so also check that the distinction disappears there.
#[no_mangle]
// CHECK-LABEL: @array_repeat_not_copy
pub unsafe fn array_repeat_not_copy(item: NotCopy) -> [NotCopy; 8] {
// CHECK: insertelement {{.+}} i16 %item
// CHECK: shufflevector <8 x i16> {{.+}} zeroinitializer
// CHECK: store <8 x i16>
std::array::repeat(item)
}