Skip to content

Commit 5b39ec8

Browse files
committed
specialize iter::Chain when both sides have the same type
1 parent 80be3ed commit 5b39ec8

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,5 +1,6 @@
11
use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
22
use crate::num::NonZeroUsize;
3+
use crate::mem;
34
use crate::ops::Try;
45

56
/// An iterator that links two iterators together, in a chain.
@@ -48,7 +49,7 @@ where
4849

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

5455
#[inline]
@@ -303,3 +304,41 @@ fn and_then_or_clear<T, U>(opt: &mut Option<T>, f: impl FnOnce(&mut T) -> Option
303304
}
304305
x
305306
}
307+
308+
#[rustc_unsafe_specialization_marker]
309+
trait SymmetricalArms {}
310+
311+
impl<A> SymmetricalArms for Chain<A, A> {}
312+
313+
trait SpecChain: Iterator {
314+
fn next(&mut self) -> Option<Self::Item>;
315+
}
316+
317+
impl<A, B> SpecChain for Chain<A, B>
318+
where
319+
A: Iterator,
320+
B: Iterator<Item = A::Item>,
321+
{
322+
#[inline]
323+
default fn next(&mut self) -> Option<A::Item> {
324+
and_then_or_clear(&mut self.a, Iterator::next).or_else(|| self.b.as_mut()?.next())
325+
}
326+
}
327+
328+
impl<A, B> SpecChain for Chain<A, B>
329+
where
330+
A: Iterator,
331+
B: Iterator<Item = A::Item>,
332+
Self: SymmetricalArms,
333+
{
334+
#[inline]
335+
fn next(&mut self) -> Option<A::Item> {
336+
let mut result = and_then_or_clear(&mut self.a, Iterator::next);
337+
if result.is_none() {
338+
// SAFETY: SymmetricalArms guarantees that A and B are the same type.
339+
unsafe { mem::swap(&mut self.a, &mut *(&mut self.b as *mut _ as *mut Option<A>)) };
340+
result = and_then_or_clear(&mut self.a, Iterator::next);
341+
}
342+
result
343+
}
344+
}

0 commit comments

Comments
 (0)