Skip to content

Optimize iterator chains better #38038

Open
@bluss

Description

@bluss

The iterator adaptor .chain() and similar code uses a state flag that changes mid-loop; the compiler should recognize this and try to split it into two consecutive loops if possible.

Reproduction in code (playground)

pub fn visit_both(a: &[u32], b: &[u32], f: fn(u32)) {
    for &elt in chain(a, b) {
        f(elt)
    }
}

/// this is a simplified version of std::iter::Chain
pub struct Chain<I> { front: bool, a: I, b: I }

fn chain<I>(a: I, b: I) -> Chain<I::IntoIter> where I: IntoIterator {
    Chain { front: true, a: a.into_iter(), b: b.into_iter() }
}

impl<I> Iterator for Chain<I> where I: Iterator {
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        if self.front {
            if let elt @ Some(_) = self.a.next() {
                return elt;
            }
            self.front = false;
        }
        self.b.next()
    }
}

Actual Behaviour

There is only one call instruction in visit_both's generated code, indicating the loop was not split.

Expected Behaviour

Generated code should be more similar to two consecutive loops.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-enhancementCategory: An issue proposing an enhancement or a PR with one.I-slowIssue: Problems and improvements with respect to performance of generated code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions