Skip to content

feat(clp-s::filter): Add BitmapView class for bitmaps passed across FFI boundaries.#2337

Merged
gibber9809 merged 21 commits into
y-scope:mainfrom
gibber9809:bitmap-view
Jul 13, 2026
Merged

feat(clp-s::filter): Add BitmapView class for bitmaps passed across FFI boundaries.#2337
gibber9809 merged 21 commits into
y-scope:mainfrom
gibber9809:bitmap-view

Conversation

@gibber9809

@gibber9809 gibber9809 commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Description

As part of the extensible indexing interface, we expect to handle bitmaps passed into C++ through an FFI layer. That will generally mean that we'll be passed a bitmap as an array plus a field indicating the size of the bitmap, and have to interpret it according to some convention.

The BitmapView class added in this PR is designed to work with such bitmaps, and supports arbitrary element sizes in the backing array via templates. This class implements standard bitmap methods over this backing array (test_bit/set_bit), and also offers a templated convenience method that allows users to pass a visitor function that visits and optionally modifies the state of every bit set to 1 in the bitmap.

Checklist

  • The PR satisfies the contribution guidelines.
  • This is a breaking change and that has been indicated in the PR title, OR this isn't a
    breaking change.
  • Necessary docs have been updated, OR no docs need to be updated.

Validation performed

  • Added unit tests for BitmapView.

Summary by CodeRabbit

  • New Features
    • Introduced a BitmapView wrapper for bit-level reads and writes, including visitor-based filtering of already-set bits.
  • Tests
    • Added unit tests covering creation validation, test_bit results, set_bit out-of-range handling, and filter_set_bits behavior across component boundaries.
  • Chores
    • Updated the build configuration to include the new bitmap view component and its tests when testing is enabled.

@gibber9809 gibber9809 requested a review from a team as a code owner June 17, 2026 19:56
@coderabbitai

coderabbitai Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

BitmapView is added as a non-owning bitmap wrapper with bit access and filtered iteration. The header is registered in the filter build, and a new unit test source covers creation, bit operations, and component-boundary behaviour.

Changes

BitmapView Implementation, Wiring, and Tests

Layer / File(s) Summary
SetBitVisitorReq, BitmapView interface, and basic read/write ops
components/core/src/clp_s/filter/BitmapView.hpp
Defines SetBitVisitorReq and introduces BitmapView with create(), get_num_bits(), test_bit(), set_bit(), the private constructor, and internal state.
filter_set_bits bulk iteration algorithm
components/core/src/clp_s/filter/BitmapView.hpp
Implements filter_set_bits() to scan each backing component, invoke the visitor for each set bit, rebuild each component from the visitor results, and propagate visitor errors.
CMake wiring and unit tests
components/core/src/clp_s/filter/CMakeLists.txt, components/core/src/clp_s/CMakeLists.txt, components/core/src/clp_s/filter/tests/test-clp_s-bitmap_view.cpp
Adds BitmapView.hpp to the filter library sources and the new test file to the unit-test target. Tests cover create() validation, get_num_bits(), test_bit(), set_bit(), filter_set_bits(), and component-boundary behaviour.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding clp-s::filter::BitmapView for FFI-passed bitmaps.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/core/src/clp_s/filter/tests/test-clp_s-bitmap_view.cpp`:
- Around line 89-102: The current test only validates the error case when
set_bit is called with an out-of-bounds index. Add new TEST_CASE blocks to test
the success cases for set_bit. Create one test that calls set_bit with a valid
index to set a bit to true, then verifies the change using test_bit. Create
another test that calls set_bit with a valid index to set a bit to false, then
verifies the bit was cleared using test_bit. This will ensure the set_bit method
works correctly for both setting and clearing bits in the happy path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 5f79fb33-4d9e-4bd9-9ca3-8bb1160477eb

📥 Commits

Reviewing files that changed from the base of the PR and between 566bc8f and 9aaeb0f.

📒 Files selected for processing (4)
  • components/core/src/clp_s/CMakeLists.txt
  • components/core/src/clp_s/filter/BitmapView.hpp
  • components/core/src/clp_s/filter/CMakeLists.txt
  • components/core/src/clp_s/filter/tests/test-clp_s-bitmap_view.cpp

Comment on lines +89 to +102
TEST_CASE(
"BitmapView set_bit returns result_out_of_range for an out-of-bounds index",
"[clp_s][filter]"
) {
constexpr size_t cNumBits{13};
std::array<uint64_t, 1> storage{};

auto result = clp_s::filter::BitmapView<uint64_t>::create(storage.data(), cNumBits);
REQUIRE_FALSE(result.has_error());

auto const set_result = result.value().set_bit(cNumBits, true);
REQUIRE(set_result.has_error());
REQUIRE(std::errc::result_out_of_range == set_result.error());
}

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.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider adding explicit tests for set_bit success cases.

While the filter_set_bits tests indirectly verify bit manipulation, adding dedicated test cases that explicitly call set_bit to set a bit to true and clear a bit to false, then verify the changes with test_bit, would improve confidence in the method's correctness and make the test suite more complete.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/core/src/clp_s/filter/tests/test-clp_s-bitmap_view.cpp` around
lines 89 - 102, The current test only validates the error case when set_bit is
called with an out-of-bounds index. Add new TEST_CASE blocks to test the success
cases for set_bit. Create one test that calls set_bit with a valid index to set
a bit to true, then verifies the change using test_bit. Create another test that
calls set_bit with a valid index to set a bit to false, then verifies the bit
was cleared using test_bit. This will ensure the set_bit method works correctly
for both setting and clearing bits in the happy path.

@gibber9809 gibber9809 requested a review from LinZhihao-723 June 17, 2026 20:54
ShangDanLuXian pushed a commit to ShangDanLuXian/clp that referenced this pull request Jun 18, 2026
…andidate-archive bitmap.

Replace the placeholder `clp_s::indexing::Bitmap` with `clp_s::filter::BitmapView`
as the bitmap passed to `IndexRunner::filter`. Both are non-owning, bit-packed
views designed to be passed across an FFI boundary, so the indexing interface
should build directly on the shared `BitmapView` rather than duplicating it.

- Remove `indexing/Bitmap.{hpp,cpp}` and its unit test.
- `IndexRunner::filter` now takes a `CandidateArchiveBitmapView`
  (`clp_s::filter::BitmapView<uint64_t>`); an index narrows the candidate set via
  `BitmapView::filter_set_bits`.

NOTE: Depends on `clp_s::filter::BitmapView` from y-scope#2337; this branch
requires that change in its base to build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q47Ekc4mUW8XLZkouFfe6W

@LinZhihao-723 LinZhihao-723 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed the implementation. Haven't checked the tests yet.

class BitmapView {
public:
// Static constants
static constexpr size_t cNumBitsPerComponent{sizeof(BitmapComponentType) * 8};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I feel like this can be a private member. Is it possible that we're gonna need this outside of the member methods?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Kind of -- I think if we add utility methods to do bitwise combinations of multiple bitmaps we might want to make that work for BitmapView classes with differently sized underlying components. May have to use friend classes for that and/or expose more public APIs for that anyway though, so I'd be fine making this private for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shall we put it in a util namespace?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Do you mean into a utils subdirectory + namespace here, just a utils namespace here, or moving it elsewhere in the codebase as a general utility?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I was thinking of moving it somewhere in the codebase as a general utility.
But I guess we should eventually move these things into ystdlib... so leaving it under filter namespace for now is probably ok.

* failure:
* - std::errc::invalid_argument if either `bitmap_array` is null or `num_bits` is zero.
*/
[[nodiscard]] static auto create(BitmapComponentType* bitmap_array, size_t num_bits)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

To be safer, I think we should use std::span instead of a raw pointer.

  • Span should be the default representation for a non-owning array. It's also the way to avoid pointer arithmetic.
  • When passing the array across the FFI layer, it's worth not just passing the pointer but also the length of the underlying array, along with the number of bits.

[[nodiscard]] static auto create(BitmapComponentType* bitmap_array, size_t num_bits)
-> ystdlib::error_handling::Result<BitmapView> {
if (nullptr == bitmap_array || 0 == num_bits) {
return std::errc::invalid_argument;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shall we define our own error code? I prefer us to fully move away from the std::errc since when an error happens, the top-level caller that handles the error may lose context on exactly which component raises the error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Going to leave this until after I'm clear on whether/where you want me to move this code.

Not sure if I agree that this disambiguates anything in a useful way for error handling/debugging anyway though -- I think it would actually be harder to work with if every container-like class defined its own error codes for common things like out of range access; I could see an argument for creating a shared error code enum in ystdlib or something that provides common error codes for container-like classes though.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I could see an argument for creating a shared error code enum in ystdlib or something that provides common error codes for container-like classes though.

sgtm.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Created an issue to track #2368

Comment on lines +96 to +102
if (index >= m_num_bits) {
return std::errc::result_out_of_range;
}

auto const component_idx{index / cNumBitsPerComponent};
auto const bit_offset{index % cNumBitsPerComponent};
auto const bit_mask{static_cast<BitmapComponentType>(1) << bit_offset};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: maybe we can have a private method to return a tuple of these three + index validation?

* indicating the failure.
*/
template <typename SetBitVisitor>
concept SetBitVisitorConcept = requires(SetBitVisitor bit_handler, size_t bit_idx) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Forgot to add this in the convention doc...
I think we should rename it SetBitVisitorReq to meet our standard.

Comment thread components/core/src/clp_s/filter/BitmapView.hpp Outdated
@@ -1,5 +1,6 @@
set(
CLP_S_FILTER_SOURCES
BitmapView.hpp

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ops, catch a tab

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@components/core/src/clp_s/filter/BitmapView.hpp`:
- Around line 122-123: The filter_set_bits template currently takes
set_bit_visitor by value, which can cause unnecessary copies for stateful or
heavy callables. Update the BitmapView::filter_set_bits signature to take
SetBitVisitor&& and forward it through the implementation, preserving the
existing Result<void> behavior while avoiding extra copies for callers that pass
movable or expensive visitor objects.
- Around line 86-109: The bitmask values are being deduced as int after integral
promotion when BitmapComponentType is narrower than int, which can trigger
narrowing/conversion issues in BitmapView. In get_component_idx_and_bitmask and
the related bit-generation logic used by test_bit, set_bit, and filter_set_bits,
explicitly cast the full shifted expression back to BitmapComponentType so
bit_mask/current_bit stay in the component type instead of relying on implicit
narrowing. Keep the existing flow and return types unchanged, just tighten the
mask type at the point it is created.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 01ad2d0a-ae28-482a-b2bf-302fd298318e

📥 Commits

Reviewing files that changed from the base of the PR and between e8b4799 and 7b53587.

📒 Files selected for processing (3)
  • components/core/src/clp_s/filter/BitmapView.hpp
  • components/core/src/clp_s/filter/CMakeLists.txt
  • components/core/src/clp_s/filter/tests/test-clp_s-bitmap_view.cpp

Comment thread components/core/src/clp_s/filter/BitmapView.hpp
Comment on lines +122 to +123
[[nodiscard]] auto filter_set_bits(SetBitVisitor set_bit_visitor)
-> ystdlib::error_handling::Result<void> {

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.

🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Visitor passed by value.

set_bit_visitor is taken by value; for stateful/heavier callables this incurs an unnecessary copy per call to filter_set_bits. Consider taking it by forwarding reference (SetBitVisitor&& set_bit_visitor) since it's already a template parameter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/core/src/clp_s/filter/BitmapView.hpp` around lines 122 - 123, The
filter_set_bits template currently takes set_bit_visitor by value, which can
cause unnecessary copies for stateful or heavy callables. Update the
BitmapView::filter_set_bits signature to take SetBitVisitor&& and forward it
through the implementation, preserving the existing Result<void> behavior while
avoiding extra copies for callers that pass movable or expensive visitor
objects.

@gibber9809 gibber9809 requested a review from LinZhihao-723 July 5, 2026 16:58

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/core/src/clp_s/filter/BitmapView.hpp (1)

161-179: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Cast the shifted result before list-initialising bit_mask. static_cast<BitmapComponentType>(1) << bit_offset promotes to int, so BitmapComponentType const bit_mask{...} narrows for uint8_t/uint16_t instantiations and breaks this template. Use static_cast<BitmapComponentType>(static_cast<BitmapComponentType>(1) << bit_offset) here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/core/src/clp_s/filter/BitmapView.hpp` around lines 161 - 179, The
bitmask construction in BitmapView::get_component_idx_and_bitmask is narrowing
for smaller BitmapComponentType instantiations because the shift expression is
promoted before list-initialization. Update the bit_mask initialization so the
shifted value is cast back to BitmapComponentType before assignment, keeping the
template valid for uint8_t and uint16_t. Use the get_component_idx_and_bitmask
method and the bit_mask local as the fix point.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@components/core/src/clp_s/filter/BitmapView.hpp`:
- Around line 161-179: The bitmask construction in
BitmapView::get_component_idx_and_bitmask is narrowing for smaller
BitmapComponentType instantiations because the shift expression is promoted
before list-initialization. Update the bit_mask initialization so the shifted
value is cast back to BitmapComponentType before assignment, keeping the
template valid for uint8_t and uint16_t. Use the get_component_idx_and_bitmask
method and the bit_mask local as the fix point.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 78b8da53-e384-4fd2-a9c3-d7a53f7bcdba

📥 Commits

Reviewing files that changed from the base of the PR and between 7b53587 and 33cd32d.

📒 Files selected for processing (1)
  • components/core/src/clp_s/filter/BitmapView.hpp

@LinZhihao-723 LinZhihao-723 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Some nit docstring fixes. Otherwise the implementation lgtm.
Will do a brief check on the test cases soon.

Comment thread components/core/src/clp_s/filter/BitmapView.hpp Outdated
Comment thread components/core/src/clp_s/filter/BitmapView.hpp Outdated
Comment thread components/core/src/clp_s/filter/BitmapView.hpp Outdated
Comment thread components/core/src/clp_s/filter/BitmapView.hpp Outdated
Comment thread components/core/src/clp_s/filter/BitmapView.hpp Outdated

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

lgtm.

Co-authored-by: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com>

@LinZhihao-723 LinZhihao-723 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For the PR title, how about:

feat(clp-s::filter): Add `BitmapView` class for bitmaps passed across FFI boundaries.

@gibber9809 gibber9809 changed the title feat(clp-s::filter): Add BitmapView class for bitmaps passed through an FFI layer. feat(clp-s::filter): Add BitmapView class for bitmaps passed across FFI boundaries. Jul 6, 2026
@gibber9809

Copy link
Copy Markdown
Contributor Author

CI failure is unrelated to this PR -- macos build is timing out right now since it's doing an uncached clang-tidy check over the whole repo for some reason.

@gibber9809 gibber9809 merged commit 6a16d62 into y-scope:main Jul 13, 2026
29 of 31 checks passed
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.

2 participants