-
Notifications
You must be signed in to change notification settings - Fork 37.7k
util: add BitSet #30160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
util: add BitSet #30160
Conversation
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. Code CoverageFor detailed information about the code coverage, see the test coverage report. ReviewsSee the guideline for information on the review process.
If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
0505f4f
to
aeef8a4
Compare
692e533
to
3bc131a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looked at 3bc131a
Concept: Bummer that std::countr_zero
and std::countl_zero
aren't implemented for std::bitset
. And for iterating it seems like one would be using std::vector<bool>
and hoping for the best in terms of implementation. So makes sense to introduce BitSet
.
Summary still mentions operator/
instead of operator-
.
(Fuzz-code is too new to me to comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
f03f3fe
to
18ec3fc
Compare
Added additional --- a/src/util/bitset.h
+++ b/src/util/bitset.h
@@ -101,6 +101,7 @@ class IntBitSet
/** Progress to the next 1 bit (only if != IteratorEnd). */
constexpr Iterator& operator++() noexcept
{
+ Assume(m_val != 0);
m_val &= m_val - I{1U};
if (m_val != 0) m_pos = std::countr_zero(m_val);
return *this;
@@ -272,6 +273,7 @@ class MultiIntBitSet
/** Progress to the next 1 bit (only if != IteratorEnd). */
constexpr Iterator& operator++() noexcept
{
+ Assume(m_idx < N);
m_val &= m_val - I{1U};
if (m_val == 0) {
while (true) { |
Concept ACK. |
concept ACK requested changes were included, will continue review
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ACK c99063e
(Ran git range-diff 3bc131a~2..3bc131a c99063e~2..c99063e
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
c99063e seems to need swap
fuzz coverage
rest of comments are nits
constexpr void Reset(unsigned pos) noexcept | ||
{ | ||
Assume(pos < MAX_SIZE); | ||
m_val &= ~I(I{1U} << pos); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe just use conditional Set
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't benchmarked or investigated compiled code, but I want to give the compiler every opportunity to use the simpler operation here (the conditional Set
is more complex, and inlining will hopefully strength-reduce it, but I prefer not counting on that).
return *this; | ||
} | ||
/** Set a bit to 0. */ | ||
void constexpr Reset(unsigned pos) noexcept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe just use conditional Set
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same reasoning as here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 1e08ba3 so far, the code looks correct to me. Planning to review and run the fuzz test tomorrow.
This adds a bitset module that implements a BitSet<N> class, a variant of std::bitset with a few additional features that cannot be implemented in a wrapper without performance loss (specifically, finding first and last bit set, or iterating over all set bits).
Made a few small changes still: @@ -107,7 +107,11 @@ class IntBitSet
return *this;
}
/** Get the current bit position (only if != IteratorEnd). */
- constexpr const unsigned& operator*() const noexcept { return m_pos; }
+ constexpr unsigned operator*() const noexcept
+ {
+ Assume(m_val != 0);
+ return m_pos;
+ }
};
public:
@@ -231,6 +235,8 @@ class MultiIntBitSet
static constexpr unsigned LIMB_BITS = std::numeric_limits<I>::digits;
/** Number of elements this set type supports. */
static constexpr unsigned MAX_SIZE = LIMB_BITS * N;
+ // No overflow allowed here.
+ static_assert(MAX_SIZE / LIMB_BITS == N);
/** Array whose member integers store the bits of the set. */
std::array<I, N> m_val;
/** Dummy type to return using end(). Only used for comparing with Iterator. */
@@ -293,7 +299,11 @@ class MultiIntBitSet
return *this;
}
/** Get the current bit position (only if != IteratorEnd). */
- constexpr const unsigned& operator*() const noexcept { return m_pos; }
+ constexpr unsigned operator*() const noexcept
+ {
+ Assume(m_idx < N);
+ return m_pos;
+ }
};
public: |
ACK 47f705b swap coverage added, some of the nits taken, and a couple reviewed via |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
re-ACK 47f705b
Used same range-diff as instagibbs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code-review ACK 47f705b
ACK 47f705b |
Ported to the CMake-based build system in hebasto#264. |
Extracted from #30126.
This introduces the
BitSet
data structure, inspired bystd::bitset
, but with a few features that cannot be implemented on top without efficiency loss:First
)Last
)begin
andend
).And a few other operators/member functions that help readability for #30126:
operator-
for set subtractionOverlaps()
for testing whether intersection is non-emptyIsSupersetOf()
for testing (non-strict) supersetnessIsSubsetOf()
for testing (non-strict) subsetnessFill()
to construct a set with all numbers from 0 to n-1, inclusiveSingleton()
to construct a set with one specific element.Everything is tested through a simulation-based fuzz test that compares the behavior with normal
std::bitset
equivalent operations.