Skip to content

Tracking Issue for Iterator::next_chunk #98326

Open

Description

@rossmacarthur

View all comments

Feature gate: #![feature(iter_next_chunk)]

This is a tracking issue for the .next_chunk() and .next_chunk_back() method on iterators which allows you to advance the iterator N elements and return an array [T; N]

Public API

use core::array;

trait Iterator {
    type Item;
    
    fn next_chunk<const N: usize>(&mut self) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
    where
        Self: Sized;
}

trait DoubleEndedIterator {
    fn next_chunk_back<const N: usize>(&mut self) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
    where
        Self: Sized;
}

Steps / History

Unresolved Questions

  • Naming: other options include next_array() or next_array_chunk().
  • How should we handle N = 0?

Activity

  1. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    T-libs-api[DEPRECATED; DO NOT USE]
    on Jun 21, 2022
  2. ChayimFriedman2 commented on Jun 21, 2022

    @ChayimFriedman2
    Contributor

    Should this method support N=0? itertools does not, and it sounds plausible; however, if we want to do the same, we will have the same concern as <[T]>::array_chunks() that cannot be stabilized until generic_const_exprs or some subset will be stabilized.

  3. the8472 commented on Jun 25, 2022

    @the8472
    Member

    I'm wondering about the intended uses of this API.

    If it is for performance (autovectorization) then it seems fairly brittle. I just tried doing this benchmark:

    #[bench]
    fn bench_next_chunk(b: &mut Bencher) {
        let v = vec![13u8; 2048];
    
        b.iter(|| {
            const CHUNK: usize = 8;
    
            let mut sum = [0u32; CHUNK];
            let mut iter = black_box(v.clone()).into_iter();
    
            while let Ok(chunk) = iter.next_chunk::<CHUNK>() {
                for i in 0..CHUNK {
                    sum[i] += chunk[i] as u32;
                }
            }
    
            sum
        })
    }

    and it took 17,272 ns/iter when compiled with target-cpu=znver2. With a handrolled implementation I got 211 ns/iter. I encountered some 10x slowdowns in a few other combinations. Sometimes codegen-units=1 produced even worse assembly because vectorizer did silly things such as loading one byte at a time into a simd register with vpinsrb.

    And that's with direct, linear memory access on a Vec::IntoIter which should be relatively straight-forward to turn into masked simd loads. Many iterators yield references. A [&T; N] would need a gather-load which is expensive and only available on newer CPUs, this is unlike slice::array_chunks which yields &[T; N]. We could try specializing slice.iter().next_chunk() but then you might as well use array_chunks. And of course it'll get more complex with additional adapters.

    Another limitation is that it can't be used in a for-in loop or chained further with other iterator adapters, an issue #92393 didn't have.

  4. Lokathor commented on Sep 7, 2022

    @Lokathor
    Contributor

    This is probably an example of a case where you should first use copied(), and then chunk it, and then you turn that array into a simd type for the work, before possibly turning it back at the end of your loop.

    And the change into and out of simd form will have a cost, so you'll want to ensure you're doing enough work inside each loop pass or it might exceed the cost of the scalar only code.

  5. the8472 commented on Sep 7, 2022

    @the8472
    Member

    yeah that was just an example to illustrate that the default implementation is suboptimal and we'll need optimized implementations on most linear-memory sources and length-preserving adapters.

  6. Lokathor commented on Sep 7, 2022

    @Lokathor
    Contributor

    Mm, yeah.

    Myself I would imagine using this most on iterators that aren't linear memory sources, and "the point" would be to have a clean and unified way to turn some crazy data source into simple SIMD chunks.

  7. rossmacarthur commented on Nov 1, 2022

    @rossmacarthur
    ContributorAuthor

    Might be good to align the naming of this function with Iterator::array_chunks, i.e. either

    • Iterator::chunks
    • Iterator::next_chunk

    Or

    • Iterator::array_chunks
    • Iterator::next_array_chunk
  8. mark-i-m commented on Jan 24, 2023

    @mark-i-m
    Contributor

    So I'm finding myself caring less and less about the actual naming. I've wanted this feature at least 3 times in the last year and had to write my own version to get around. Can we just pick something and get the feature stabilized?

  9. ZhennanWu commented on Apr 23, 2023

    @ZhennanWu

    I believe the current implementation also suffers from this compiler optimization issue: #110734

    Godbolt: https://godbolt.org/z/Te5Wo9eh7

  10. the8472 commented on Apr 23, 2023

    @the8472
    Member

    I'm not sure what that issue has to do with next_chunk specifically. It seems to be mostly about the codegen for it.collect::<Vec<_>>(), which I think is easily disturbed by anything mutating the iterator.

  11. pitaj commented on May 25, 2023

    @pitaj
    Contributor

    Let's get this stabilized. Here are my answers to the Unresolved Questions:

    Naming: other options include next_array() or next_array_chunk().

    next_chunk seems like the best option to me.

    Should we also add next_chunk_back to DoubleEndedIterator?

    Probably, but that should be under a separate feature and not block this.

    How should we handle N = 0?

    It should be allowed and return a zero-length array without advancing the iterator. No good reason to forbid it.

  12. the8472 commented on May 25, 2023

    @the8472
    Member

    It should be allowed and return a zero-length array without advancing the iterator. No good reason to forbid it.

    For next_chunk it might not be a problem but for the chunks iterators on slices and for iterator.array_chunks() it is. So we might as well do something about it here

  13. pitaj commented on May 25, 2023

    @pitaj
    Contributor

    I disagree. For those, it's necessary by definition. There's no reason to apply the same logic here besides, in my opinion, a misguided desire for consistency. The behavior of next_chunk is totally reasonable for array length 0, unlike the others you mentioned.

    "Doing something about it" will pretty much require const expressions just like all the other ones, needlessly delaying the stabilization.

  14. the8472 commented on May 25, 2023

    @the8472
    Member

    Well, it would prevent implementations of next_chunk using those things internally

  15. 22 remaining items

  16. hanna-kruppe commented on Dec 24, 2025

    @hanna-kruppe
    Contributor

    The other alternative here is to piggy-back on some future language feature for in-place initialization, which also has to address fallibility somehow. The downside of transparently making the current API lower to "out-ptr for Some/Ok payload" ABI is that it also fails transparently: whenever move elimination doesn't fire for any reason, or a pointer to an entire Result<[T; N], _> is required, codegen will be just as inefficient as today, without any clue at the source level.

    In contrast, most in-place-init proposals have some explicit opt-in at the call site that guarantees no extra moves or temporaries. That's necessary for soundness in some use cases, but it's also useful for types (here: array lengths) large enough to overflow the stack. The downside is that there's some extra annotation burden, which may be a bad trade-off for an API that's partly about convenience. But depending on which (if any) approach is adopted, maybe the common case is succinct enough to be attractive for this API, too.

  17. added a commit that references this issue on Jan 20, 2026
  18. added 2 commits that reference this issue on Apr 18, 2026
  19. added a commit that references this issue on Apr 18, 2026
  20. asder8215 commented on May 19, 2026

    @asder8215
    Contributor

    Are we able to add DoubleEndedIterator::next_chunk_back underneath this tracking issue? The person who made the ACP for this method and the original PR had it marked under #![feature(iter_next_chunk)] feature gated. I picked up the PR here to get it over the finish line due to inactivity.

  21. added a commit that references this issue on Jul 1, 2026
  22. added a commit that references this issue on Jul 1, 2026
  23. added a commit that references this issue on Jul 1, 2026
  24. added a commit that references this issue on Jul 2, 2026
  25. aapoalas commented on Jul 3, 2026

    @aapoalas
    Contributor

    Added .next_chunk_back() to the tracking issue.

  26. asder8215 commented on Jul 3, 2026

    @asder8215
    Contributor

    @aapoalas to note, .next_chunk_back() should be underneath the DoubleEndedIterator trait not Iterator trait.

  27. giang299 commented on Jul 11, 2026

    @giang299
    • Naming: other options include next_array() or next_array_chunk().

    IT MUST BE next_chunk()
    next_chunk is amz naming. we already have a Vec::chunks(),..etc before, it's universal.

  28. added
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    T-libs-api[DEPRECATED; DO NOT USE]
    on Aug 12, 2026
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

    A-autovectorizationArea: Autovectorization, which can impact perf or code sizeC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCT-libsRelevant to the library 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