Skip to content

Commit 50a2248

Browse files
committed
reduce the work done per iteration for non-Drop, fused iterators
1 parent 2c2a695 commit 50a2248

File tree

1 file changed

+33
-13
lines changed

1 file changed

+33
-13
lines changed

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

+33-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::iter::{DoubleEndedIterator, FusedIterator, Iterator, TrustedLen};
22
use crate::num::NonZeroUsize;
3-
use crate::mem;
3+
use crate::{mem, ptr};
44
use crate::ops::Try;
55

66
/// An iterator that links two iterators together, in a chain.
@@ -365,35 +365,55 @@ where
365365

366366
impl<A, B> SpecChain for Chain<A, B>
367367
where
368-
A: Iterator,
369-
B: Iterator<Item = A::Item>,
368+
A: Iterator + FusedIterator,
369+
B: Iterator<Item = A::Item> + FusedIterator,
370370
Self: SymmetricalModuloLifetimes,
371371
{
372372
#[inline]
373373
fn next(&mut self) -> Option<A::Item> {
374-
let mut result = and_then_or_clear(&mut self.a, Iterator::next);
374+
let mut result = self.a.as_mut().and_then( Iterator::next);
375375
if result.is_none() {
376-
// SAFETY: SymmetricalModuloLifetimes guarantees that A and B are safe to swap
377-
unsafe { mem::swap(&mut self.a, &mut *(&mut self.b as *mut _ as *mut Option<A>)) };
378-
result = and_then_or_clear(&mut self.a, Iterator::next);
376+
if mem::needs_drop::<A>() {
377+
// swap iters to avoid running drop code inside the loop.
378+
// SAFETY: SymmetricalModuloLifetimes guarantees that A and B are safe to swap.
379+
unsafe { mem::swap(&mut self.a, &mut *(&mut self.b as *mut _ as *mut Option<A>)) };
380+
} else {
381+
// SAFETY: SymmetricalModuloLifetimes guarantees that A and B are safe to swap.
382+
// And they dont need drop, so we can overwrite the values directly.
383+
unsafe {
384+
ptr::write(&mut self.a, ptr::from_ref(&self.b).cast::<Option<A>>().read());
385+
ptr::write(&mut self.b, None);
386+
}
387+
}
388+
result = self.a.as_mut().and_then(Iterator::next);
379389
}
380390
result
381391
}
382392
}
383393

384394
impl<A, B> SpecChainBack for Chain<A, B>
385395
where
386-
A: DoubleEndedIterator,
387-
B: DoubleEndedIterator<Item = A::Item>,
396+
A: DoubleEndedIterator + FusedIterator,
397+
B: DoubleEndedIterator<Item = A::Item> + FusedIterator,
388398
Self: SymmetricalModuloLifetimes,
389399
{
390400
#[inline]
391401
fn next_back(&mut self) -> Option<Self::Item> {
392-
let mut result = and_then_or_clear(&mut self.b, DoubleEndedIterator::next_back);
402+
let mut result = self.b.as_mut().and_then( DoubleEndedIterator::next_back);
393403
if result.is_none() {
394-
// SAFETY: SymmetricalModuloLifetimes guarantees that A and B are safe to swap
395-
unsafe { mem::swap(&mut self.a, &mut *(&mut self.b as *mut _ as *mut Option<A>)) };
396-
result = and_then_or_clear(&mut self.b, DoubleEndedIterator::next_back);
404+
if mem::needs_drop::<A>() {
405+
// swap iters to avoid running drop code inside the loop.
406+
// SAFETY: SymmetricalModuloLifetimes guarantees that A and B are safe to swap.
407+
unsafe { mem::swap(&mut self.a, &mut *(&mut self.b as *mut _ as *mut Option<A>)) };
408+
} else {
409+
// SAFETY: SymmetricalModuloLifetimes guarantees that A and B are safe to swap.
410+
// And they dont need drop, so we can overwrite the values directly.
411+
unsafe {
412+
ptr::write(&mut self.b, ptr::from_ref(&self.a).cast::<Option<B>>().read());
413+
ptr::write(&mut self.a, None);
414+
}
415+
}
416+
result = self.b.as_mut().and_then(DoubleEndedIterator::next_back);
397417
}
398418
result
399419
}

0 commit comments

Comments
 (0)