Skip to content

Commit 68ce47f

Browse files
committed
specialize iter::Chain when both sides have the same type
1 parent 7a98053 commit 68ce47f

File tree

1 file changed

+40
-1
lines changed

1 file changed

+40
-1
lines changed

library/core/src/iter/adapters/chain.rs

+40-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
2+
use crate::mem;
23
use crate::ops::Try;
34

45
/// An iterator that links two iterators together, in a chain.
@@ -47,7 +48,7 @@ where
4748

4849
#[inline]
4950
fn next(&mut self) -> Option<A::Item> {
50-
and_then_or_clear(&mut self.a, Iterator::next).or_else(|| self.b.as_mut()?.next())
51+
SpecChain::next(self)
5152
}
5253

5354
#[inline]
@@ -290,3 +291,41 @@ fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option
290291
}
291292
x
292293
}
294+
295+
#[rustc_unsafe_specialization_marker]
296+
trait SymmetricalArms {}
297+
298+
impl<A> SymmetricalArms for Chain<A, A> {}
299+
300+
trait SpecChain: Iterator {
301+
fn next(&mut self) -> Option<Self::Item>;
302+
}
303+
304+
impl<A, B> SpecChain for Chain<A, B>
305+
where
306+
A: Iterator,
307+
B: Iterator<Item = A::Item>,
308+
{
309+
#[inline]
310+
default fn next(&mut self) -> Option<A::Item> {
311+
and_then_or_clear(&mut self.a, Iterator::next).or_else(|| self.b.as_mut()?.next())
312+
}
313+
}
314+
315+
impl<A, B> SpecChain for Chain<A, B>
316+
where
317+
A: Iterator,
318+
B: Iterator<Item = A::Item>,
319+
Self: SymmetricalArms,
320+
{
321+
#[inline]
322+
fn next(&mut self) -> Option<A::Item> {
323+
let mut result = and_then_or_clear(&mut self.a, Iterator::next);
324+
if result.is_none() {
325+
// SAFETY: SymmetricalArms guarantees that A and B are the same type.
326+
unsafe { mem::swap(&mut self.a, &mut *(&mut self.b as *mut _ as *mut Option<A>)) };
327+
result = and_then_or_clear(&mut self.a, Iterator::next);
328+
}
329+
result
330+
}
331+
}

0 commit comments

Comments
 (0)