Skip to content

Commit 5cec957

Browse files
committed
specialize Clone of array IntoIter
1 parent 3514361 commit 5cec957

2 files changed

Lines changed: 75 additions & 3 deletions

File tree

library/core/src/array/iter/iter_inner.rs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
//! Defines the `IntoIter` owned iterator for arrays.
22
3+
use crate::clone::TrivialClone;
34
use crate::mem::MaybeUninit;
45
use crate::num::NonZero;
56
use crate::ops::{IndexRange, NeverShortCircuit, Try};
6-
use crate::{fmt, iter};
7+
use crate::{fmt, iter, ptr};
78

89
#[allow(private_bounds)]
910
trait PartialDrop {
@@ -99,9 +100,26 @@ impl<T, const N: usize> PolymorphicIter<[MaybeUninit<T>; N]> {
99100
impl<T: Clone, const N: usize> Clone for PolymorphicIter<[MaybeUninit<T>; N]> {
100101
#[inline]
101102
fn clone(&self) -> Self {
103+
SpecPolymorphicIterClone::<N>::spec_clone(self)
104+
}
105+
}
106+
107+
trait SpecPolymorphicIterClone<const N: usize> {
108+
fn spec_clone(
109+
this: &PolymorphicIter<[MaybeUninit<Self>; N]>,
110+
) -> PolymorphicIter<[MaybeUninit<Self>; N]>
111+
where
112+
Self: Sized;
113+
}
114+
115+
impl<T: Clone, const N: usize> SpecPolymorphicIterClone<N> for T {
116+
#[inline]
117+
default fn spec_clone(
118+
this: &PolymorphicIter<[MaybeUninit<Self>; N]>,
119+
) -> PolymorphicIter<[MaybeUninit<Self>; N]> {
102120
// Note, we don't really need to match the exact same alive range, so
103121
// we can just clone into offset 0 regardless of where `self` is.
104-
let mut new = Self::empty();
122+
let mut new = PolymorphicIter::<[MaybeUninit<T>; N]>::empty();
105123

106124
fn clone_into_new<U: Clone>(
107125
source: &PolymorphicIter<[MaybeUninit<U>]>,
@@ -118,7 +136,33 @@ impl<T: Clone, const N: usize> Clone for PolymorphicIter<[MaybeUninit<T>; N]> {
118136
}
119137
}
120138

121-
clone_into_new(self, &mut new);
139+
clone_into_new(this, &mut new);
140+
new
141+
}
142+
}
143+
144+
impl<T: TrivialClone, const N: usize> SpecPolymorphicIterClone<N> for T {
145+
#[inline]
146+
fn spec_clone(
147+
this: &PolymorphicIter<[MaybeUninit<Self>; N]>,
148+
) -> PolymorphicIter<[MaybeUninit<Self>; N]> {
149+
// Note, we don't really need to match the exact same alive range, so
150+
// we can just clone into offset 0 regardless of where `self` is.
151+
let mut new = PolymorphicIter::<[MaybeUninit<T>; N]>::empty();
152+
153+
let len = this.alive.len();
154+
155+
// SAFETY: These two allocations can not overlap since `new` is allocated
156+
// on the stack of this function.
157+
unsafe {
158+
ptr::copy_nonoverlapping(
159+
this.data.as_ptr().add(this.alive.start()),
160+
new.data.as_mut_ptr(),
161+
len,
162+
);
163+
new.alive = IndexRange::zero_to(len);
164+
}
165+
122166
new
123167
}
124168
}

library/coretests/tests/array.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,34 @@ fn iterator_clone() {
106106
assert_eq!(clone.next_back(), Some(4));
107107
assert_eq!(it.next(), Some(2));
108108
assert_eq!(clone.next(), Some(2));
109+
assert_eq!(it.next(), None);
110+
assert_eq!(clone.next(), None);
111+
}
112+
113+
#[test]
114+
fn iterator_clone_spec() {
115+
#[derive(Debug, PartialEq)]
116+
struct Foo(i32);
117+
118+
impl Clone for Foo {
119+
fn clone(&self) -> Self {
120+
// nontrivial clone
121+
Foo(-self.0)
122+
}
123+
}
124+
125+
let mut it = IntoIterator::into_iter([Foo(0), Foo(2), Foo(4), Foo(6), Foo(8)]);
126+
assert_eq!(it.next(), Some(Foo(0)));
127+
assert_eq!(it.next_back(), Some(Foo(8)));
128+
let mut clone = it.clone();
129+
assert_eq!(it.next_back(), Some(Foo(6)));
130+
assert_eq!(clone.next_back(), Some(Foo(-6)));
131+
assert_eq!(it.next_back(), Some(Foo(4)));
132+
assert_eq!(clone.next_back(), Some(Foo(-4)));
133+
assert_eq!(it.next(), Some(Foo(2)));
134+
assert_eq!(clone.next(), Some(Foo(-2)));
135+
assert_eq!(it.next(), None);
136+
assert_eq!(clone.next(), None);
109137
}
110138

111139
#[test]

0 commit comments

Comments
 (0)