Skip to content

Ironing out StepBy<Range>'s performance issues #51557

Open
@Emerentius

Description

@Emerentius

The behaviour of <Range<_> as Iterator>::nth has a slight mismatch with StepBy (or Step depending on your viewpoint) as @scottmcm has found out, resulting in sub-optimal performance.
On every iteration, the range has to first step forwards n-1 times to get the next element and then advance again by 1.

I'm hoping we can improve step_by into a 100% zero-cost abstraction.

It seems like the performance issue is specific to StepBy<Range>. I'm thinking therefore that we could specialize Iterator for StepBy<Range<I>> such that it would use @scottmcm's suggested semantics. Like this:

impl<I> Iterator for StepBy<Range<I>>
where
    I: Step
{
    fn next(&mut self) -> Option<Self::Item> {
        self.first = false;
        if let Some(mut n) = self.start.add_usize(self.step+1) {
            if n < self.end {
                std::mem::swap(&mut self.start, &mut n);
                return Some(n);
            }
        }

        self.start = self.end.clone();
        None
    }
}

That also avoids the branch on a regular next(). I haven't looked at the other methods but that boolean in StepBy could possibly become superfluous. During construction of the StepBy adapter, the size in .step_by(size) is decremented and this specialization has to counter-add 1 every time but that should be optimized away if inlined.

If someone were to depend on side-effects in Step::add_usize (when the trait is stabilized), this pre-stepping would become weird. Same thing with a hypothetical next_and_skip_ahead().

@scottmcm what do you think of this?

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-libs-apiRelevant to the library API 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