Skip to content

Commit

Permalink
finish improved has_true() function
Browse files Browse the repository at this point in the history
  • Loading branch information
Samuel Li authored and Samuel Li committed Mar 31, 2024
1 parent 9695e7a commit 32d87cd
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 15 deletions.
9 changes: 7 additions & 2 deletions include/Bitmask.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,13 @@ class Bitmask {
auto rbit(size_t idx) const -> bool;

// Functions to perform bulk tests.
auto has_true(size_t start, size_t len) const -> bool; // Is there any true in this range?
auto count_true() const -> size_t; // How many 1's in this mask?
//
// Two versions of the `has_true()` function. Both versions return -1 in case of no true found.
// - Position == false: it returns 1 indicating finding a true.
// - Position == true: it returns the offset relative to `start` of the first true.
template <bool Position>
auto has_true(size_t start, size_t len) const -> int64_t;
auto count_true() const -> size_t; // How many 1's in this mask?

// Functions for write
//
Expand Down
44 changes: 34 additions & 10 deletions src/Bitmask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,40 @@ auto sperr::Bitmask::rbit(size_t idx) const -> bool
return (word != 0);
}

auto sperr::Bitmask::has_true(size_t start, size_t len) const -> bool
template <bool Position>
auto sperr::Bitmask::has_true(size_t start, size_t len) const -> int64_t
{
auto long_idx = start / 64;
auto processed_bits = size_t{0};
auto processed_bits = int64_t{0};

// Collect the remaining bits from the start long.
auto word = m_buf[long_idx];
auto answer = uint64_t{0};
for (auto i = start % 64; i < 64 && processed_bits < len; i++) {
answer |= word & (uint64_t{1} << i);
if constexpr (Position) {
if (answer != 0)
return processed_bits;
}
processed_bits++;
}
if (answer != 0)
return true;
if constexpr (!Position) {
if (answer != 0)
return 1;
}

// Examine the subsequent full longs.
while (processed_bits + 64 <= len) {
if (m_buf[++long_idx] != 0)
return true;
word = m_buf[++long_idx];
if (word) {
if constexpr (Position) {
for (int64_t i = 0; i < 64; i++)
if (word & (uint64_t{1} << i))
return processed_bits + i;
}
else
return 1;
}
processed_bits += 64;
}

Expand All @@ -69,14 +84,23 @@ auto sperr::Bitmask::has_true(size_t start, size_t len) const -> bool
assert(nbits < 64);
word = m_buf[++long_idx];
answer = 0;
for (size_t i = 0; i < nbits; i++)
for (size_t i = 0; i < nbits; i++) {
answer |= word & (uint64_t{1} << i);
if (answer != 0)
return true;
if constexpr (Position) {
if (answer != 0)
return processed_bits + i;
}
}
if constexpr (!Position) {
if (answer != 0)
return 1;
}
}

return false;
return -1;
}
template auto sperr::Bitmask::has_true<true>(size_t, size_t) const -> int64_t;
template auto sperr::Bitmask::has_true<false>(size_t, size_t) const -> int64_t;

auto sperr::Bitmask::count_true() const -> size_t
{
Expand Down
39 changes: 36 additions & 3 deletions test_scripts/bitstream_unit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -374,11 +374,11 @@ TEST(Bitmask, has_true)

// Loop over all range length
for (size_t len = 0; len < mask_size - start; len++) {
bool ans1 = mask.has_true(start, len);
bool ans2 = false;
auto ans1 = mask.has_true<false>(start, len);
auto ans2 = -1l;
for (size_t i = start; i < start + len; i++)
if (mask.rbit(i)) {
ans2 = true;
ans2 = 1l;
break;
}
EXPECT_EQ(ans1, ans2);
Expand All @@ -388,6 +388,39 @@ TEST(Bitmask, has_true)
}
}

TEST(Bitmask, has_true_position)
{
const size_t mask_size = 130;

// Loop over all positions
for (size_t idx = 0; idx < mask_size; idx++) {
auto mask = Mask(mask_size);
mask.wtrue(idx);

// Loop over all starting positions
for (size_t start = 0; start < mask_size; start++) {

// Loop over all range length
for (size_t len = 0; len < mask_size - start; len++) {
auto ans1 = mask.has_true<true>(start, len);
auto ans2 = -1l;
for (size_t i = start; i < start + len; i++)
if (mask.rbit(i)) {
ans2 = i - start;
break;
}
EXPECT_EQ(ans1, ans2) << "idx = " << idx << ", start = " << start << ", len = " << len << std::endl;
if (ans1 != ans2)
goto END_LABEL;
}

}
}

END_LABEL:
{}
}

#if defined __cpp_lib_three_way_comparison && defined __cpp_impl_three_way_comparison
TEST(Bitmask, spaceship)
{
Expand Down

0 comments on commit 32d87cd

Please sign in to comment.