Skip to content

Optimize iterator chains better #38038

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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