Skip to content

GH-51289: [C++] Add iterator-based bit-run traversal - #51310

Open
akashchamp wants to merge 2 commits into
apache:mainfrom
akashchamp:GH-51289-bit-run-iterators
Open

akashchamp wants to merge 2 commits into
apache:mainfrom
akashchamp:GH-51289-bit-run-iterators

Conversation

@akashchamp

@akashchamp akashchamp commented Sep 11, 2026 •

Copy link
Copy Markdown

Fixes #51289

Rationale for this change

The callback-based bit-run visitors require callers to route early termination through callback status handling. These ranges allow normal iterator control flow, including breaking once a caller has found the run it needs.

What changes are included in this PR?

  • Add IterateBitRuns, IterateSetBitRuns, and IterateTwoSetBitRuns as C++20 input ranges.
  • Preserve the existing BitRun type and introduce PositionedBitRun for full bit runs so iterator values expose position, length, and set state.
  • Each iterator exposes a single friend operator==(iterator, std::default_sentinel_t) and relies on C++20 rewritten comparisons for != and the reversed order; PositionedBitRun uses a defaulted operator==.
  • BaseSetBitRunReader::length_ is no longer const, so the reader (and the iterators wrapping it) get compiler-generated copy/move special members instead of hand-written ones.
  • Cover offsets, null bitmaps, empty inputs, iterator copying and post-increment, and intersections longer than the legacy visitor's internal chunk size.

Are these changes tested?

  • clang-format --dry-run --Werror (clang-format 18.1.8, as pinned in .pre-commit-config.yaml) and git diff --check
  • arrow-bit-utility-test --gtest_filter='*BitRun*:*Bitmap*:*BitUtil*' on macOS (Apple clang 17, Debug build): 147 tests from 19 suites pass, including the new TestSetBitRunReader.IterateBitRuns, IterateSetBitRuns and IterateTwoSetBitRuns
  • A standalone C++20 translation unit that static_asserts std::ranges::input_range, std::input_iterator, std::sentinel_for<std::default_sentinel_t, ...> and std::copyable for all three iterators, and exercises it == end, end == it, it != end, end != it.

Are there any user-facing changes?

No public API changes. This adds internal C++ traversal helpers for callers that need iterator control flow.

Was AI used for this PR?

In accordance to the AI generation guidelines, please disclose below whether and how AI was used in this PR.

PR code and description written by:

  • Human
  • AI

Reviewed before submission by:

  • Human
  • AI
  • Not reviewed

Assisted-by: Codex, Claude

AI assistance was used for the initial implementation and regression tests, and for the review follow-ups (the comparison-operator cleanup and the removal of the hand-written copy members). I reviewed the final code, kept the change scoped to the requested API, and validated the behavior above.

@akashchamp
akashchamp requested a review from pitrou as a code owner September 11, 2026 22:58
@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #51289 has been automatically assigned in GitHub to PR creator.

Comment thread cpp/src/arrow/util/bit_run_reader.h Outdated
Comment thread cpp/src/arrow/util/bit_run_reader.h Outdated
Comment thread cpp/src/arrow/util/bit_run_reader.h Outdated
Comment thread cpp/src/arrow/util/bit_run_reader.h Outdated
Comment thread cpp/src/arrow/util/bitmap_test.cc Outdated
@pitrou

pitrou commented Sep 14, 2026

Copy link
Copy Markdown
Member

@akashchamp Is it possible to find potential call sites in the codebase that would benefit from these constructs?

@HuaHuaY Perhaps you'll be interested in taking a look at this.

@github-actions github-actions Bot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Sep 14, 2026
@HuaHuaY
HuaHuaY self-requested a review September 14, 2026 15:47

@HuaHuaY HuaHuaY left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I submit a suggestion first and I’ll review the PR in detail later. Please rebase main — that should fix some of the random CI errors.

Comment thread cpp/src/arrow/util/bit_run_reader.h Outdated
Address review feedback on the iterator-based bit-run traversal:

- Keep a single friend operator==(iterator, std::default_sentinel_t) per
  iterator and let C++20 rewritten comparisons provide operator!= and the
  reversed argument order, instead of also declaring instance methods.
- Give PositionedBitRun a defaulted operator== instead of hand-written
  free operator==/operator!=.
- Drop the const qualifier on BaseSetBitRunReader::length_ so the reader
  is assignable; this lets SetBitRunIterator and TwoSetBitRunIterator use
  the implicitly generated copy/move special members and removes the
  hand-written copy assignment operators and CopyReader helper.
- Remove a range-for/break block from TestSetBitRunReader.IterateBitRuns
  that only exercised language semantics already covered by the
  range.begin() checks that follow it.
@akashchamp
akashchamp force-pushed the GH-51289-bit-run-iterators branch from 2691d37 to 32a63cc Compare September 20, 2026 15:13
@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #51289 has been automatically assigned in GitHub to PR creator.

@akashchamp

Copy link
Copy Markdown
Author

Yes, there are several hand-rolled NextRun loops that would collapse into a range-for. The clearest ones: cpp/src/arrow/compare.cc:685 (RangeDataEqualsImpl) loops while(true) on SetBitRunReader::NextRun, checks length == 0 to return, and sets result_ = false on the first mismatch, which becomes for (const auto run : IterateSetBitRuns(...)) with an early return; cpp/src/arrow/compute/kernels/pivot_internal.cc:134 searches for the first unset validity bit by accumulating null_pos += run.length, and with IterateBitRuns the PositionedBitRun already carries the position so it is a find-first with break; cpp/src/arrow/array/concatenate.cc:616, cpp/src/arrow/compute/kernels/scalar_if_else.cc:1136 and :1155, and cpp/src/arrow/compute/kernels/hash_aggregate_numeric.cc:652 all keep a manual position counter and an if (run.length == 0) break sentinel check around BitRunReader that IterateBitRuns makes unnecessary; cpp/src/arrow/util/list_util.cc:75 (MinViewOffset) has the same while(true) shape around SetBitRunReader. I have kept this PR to the new helpers plus tests so it stays easy to review and would convert those sites in a follow-up, but I am happy to do compare.cc here if you would rather see one real caller in this PR.

@akashchamp

Copy link
Copy Markdown
Author

Rebased on main; that picks up GH-51327 (MinIO download URL) and GH-51335 (MATLAB Windows hashFiles), which were behind eight of the nine red jobs. The remaining one was the S3 FromUri tests on the Conda AVX2 job, which this PR does not touch.

@HuaHuaY

HuaHuaY commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

@github-actions crossbow submit -g cpp

@github-actions

Copy link
Copy Markdown

Revision: 32a63cc

Submitted crossbow builds: ursacomputing/crossbow @ actions-7417ccf146

Task Status
example-cpp-minimal-build-static GitHub Actions
example-cpp-minimal-build-static-system-dependency GitHub Actions
example-cpp-tutorial GitHub Actions
test-build-cpp-fuzz GitHub Actions
test-conda-cpp GitHub Actions
test-conda-cpp-valgrind GitHub Actions
test-debian-13-cpp-amd64 GitHub Actions
test-debian-13-cpp-i386 GitHub Actions
test-debian-experimental-cpp-gcc-15 GitHub Actions
test-fedora-42-cpp GitHub Actions
test-ubuntu-22.04-cpp GitHub Actions
test-ubuntu-22.04-cpp-bundled GitHub Actions
test-ubuntu-22.04-cpp-emscripten GitHub Actions
test-ubuntu-22.04-cpp-no-threading GitHub Actions
test-ubuntu-24.04-cpp GitHub Actions
test-ubuntu-24.04-cpp-gcc-13-bundled GitHub Actions
test-ubuntu-24.04-cpp-gcc-14 GitHub Actions
test-ubuntu-24.04-cpp-minimal-with-formats GitHub Actions
test-ubuntu-24.04-cpp-thread-sanitizer GitHub Actions

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[C++] Add iterator-based variants of bit-run visitors

3 participants