Skip to content

🐛 (patch) Fix sub_scatter_span() on a view that is already trimmed - #22

Merged
kammce merged 1 commit into
mainfrom
fix-trimmed-sub-scatter-span
Oct 29, 2026
Merged

kammce merged 1 commit into
mainfrom
fix-trimmed-sub-scatter-span

Conversation

@kammce

@kammce kammce commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

sub_scatter_span() returned the wrong elements when called on a view that was itself made by sub_scatter_span(). It measured offsets from the raw chunks, so it ignored the view's own start and final length.

std::array<int, 6> data = { 1, 2, 3, 4, 5, 6 };
mem::scatter_array ssa = { data };
auto trimmed = ssa.sub_scatter_span({ .offset = 2 });     // 3 4 5 6
auto sub = trimmed.sub_scatter_span({ .offset = 1 });     // was 2 3 4 5 6, now 4 5 6
View Call Before After
One chunk 1…6, trimmed to 3 4 5 6 { .offset = 1 } 2 3 4 5 6 4 5 6
Chunks 1 2 3 | 4 5 | 6 7 8 9, trimmed to 2…9 { .offset = 1, .count = 3 } 2 3 4 3 4 5

A sub-view of an untrimmed span was already correct, which is why the existing tests passed.

Change

  • sub_scatter_span() now walks the chunks as the iterator presents them: trimmed by the view's start and final length. While it walks, it counts the elements in the chunks before the current one (elements_before). It stops at the first chunk that ends after the result's first element, then keeps walking to the first chunk that ends after its last. An element's index in its chunk is then its index in the view minus elements_before. Raw chunk offsets are computed only at the end.
    For chunks 1 2 3 | 4 5 | 6 7 8 9 with { .offset = 2, .count = 4 }, the result is elements 2 to 5 (3 4 5 6):

    Chunk elements_before Ends at Stops for
    0 (1 2 3) 0 3 element 2: index 2 − 0 = 2
    1 (4 5) 3 5 none (5 isn't after element 5)
    2 (6 7 8 9) 5 9 element 5: index 5 − 5 = 0

    The result spans chunks 0 to 2, starting at index 2 of chunk 0 and ending at index 0 of chunk 2.

  • The trimming lives in one private helper, trimmed_chunk(), which the iterator's get() now uses too, so the two can't disagree again.

  • The special case for single-chunk spans is gone, since the general walk covers it.

  • A count of zero returns an empty span, as an offset past the end already did.

Size

sub_scatter_span<unsigned char>() on a Cortex-M3, LLVM 23, -Os:

Function Before After
sub_scatter_span() 288 B 258 B
trimmed_chunk() (also used by the iterator) n/a 54 B
Total 288 B 312 B

Testing

  • New test: every sub-view of every sub-view, including offsets and counts past the end, is compared against the same range of a flat array. It runs over four layouts of the same nine elements: one chunk, three chunks, four chunks with an empty one in the middle, and one element per chunk. On main, 2,515 of these cases fail, all of them sub-views of a trimmed view.
  • New named tests for the cases in the table, and for a view trimmed at its last chunk.
  • The commented-out "single element span that exceeds its bounds" test is enabled, and it passes.
  • All 20 tests (14,342 assertions) pass on macOS with LLVM 23. The library also builds for the stm32f103c8.
  • CI passes: tests with clang-tidy on macOS and Linux, package validation on Linux x86_64 and ARM64, macOS and the Cortex-M sample, and lint.

sub_scatter_span() measured offsets from the raw chunks, ignoring the view's own start and final length. A sub-view of a sub-view therefore started too early or ran too long. It now walks the chunks trimmed the way the iterator presents them, which share one helper, and converts to raw chunk offsets at the end.
@kammce
kammce force-pushed the fix-trimmed-sub-scatter-span branch from cd3d9c2 to 69a0b55 Compare October 29, 2026 12:24

@kammce kammce left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lgtm

@kammce
kammce merged commit 9d55628 into main Oct 29, 2026
9 checks passed
@kammce
kammce deleted the fix-trimmed-sub-scatter-span branch October 29, 2026 12:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant