diff --git a/lib/include/srsran/adt/bounded_bitset.h b/lib/include/srsran/adt/bounded_bitset.h index 22d656668..37226db90 100644 --- a/lib/include/srsran/adt/bounded_bitset.h +++ b/lib/include/srsran/adt/bounded_bitset.h @@ -26,6 +26,31 @@ constexpr uint32_t ceil_div(uint32_t x, uint32_t y) return (x + y - 1) / y; } +template +Integer mask_trailing_ones(size_t N) +{ + static_assert(std::is_unsigned::value, "T must be unsigned integer"); + return N == 0 ? 0 : (static_cast(-1) >> (sizeof(Integer) * 8U - N)); +} + +template +Integer mask_leading_ones(size_t N) +{ + return ~mask_trailing_ones(8U * sizeof(Integer) - N); +} + +template +Integer mask_trailing_zeros(size_t N) +{ + return mask_leading_ones(8U * sizeof(Integer) - N); +} + +template +Integer mask_leading_zeros(size_t N) +{ + return mask_trailing_ones(8U * sizeof(Integer) - N); +} + template class bounded_bitset { @@ -100,8 +125,7 @@ public: bounded_bitset& fill(size_t startpos, size_t endpos, bool value = true) { - assert_within_bounds_(startpos, false); - assert_within_bounds_(endpos, false); + assert_range_bounds_(startpos, endpos); // NOTE: can be optimized if (value) { for (size_t i = startpos; i < endpos; ++i) { @@ -115,6 +139,37 @@ public: return *this; } + int find_first(size_t startpos, size_t endpos, bool value = true) const noexcept + { + assert_range_bounds_(startpos, endpos); + if (startpos == endpos) { + return -1; + } + + size_t startword = startpos / bits_per_word; + size_t lastword = (endpos - 1) / bits_per_word; + + for (size_t i = startword; i <= lastword; ++i) { + word_t w = buffer[i]; + if (not value) { + w = ~w; + } + + if (i == startword) { + size_t offset = startpos % bits_per_word; + w &= mask_trailing_zeros(offset); + } + if (i == lastword) { + size_t offset = (endpos - 1) % bits_per_word; + w &= mask_trailing_ones(offset + 1); + } + if (w != 0) { + return static_cast(i * bits_per_word + (bits_per_word - __builtin_clzl(w) - 1)); + } + } + return -1; + } + bool all() const noexcept { const size_t nw = nof_words_(); @@ -307,6 +362,15 @@ private: size()); } + void assert_range_bounds_(size_t startpos, size_t endpos) const + { + srsran_assert(startpos <= endpos and endpos <= size(), + "ERROR: range [%zd, %zd) out-of-bounds for bitsize of size=%zd", + startpos, + endpos, + size()); + } + static word_t maskbit(size_t pos) { return (static_cast(1)) << (pos % bits_per_word); } static size_t max_nof_words_() { return (N - 1) / bits_per_word + 1; } diff --git a/lib/test/adt/bounded_bitset_test.cc b/lib/test/adt/bounded_bitset_test.cc index fbc7f3437..2790880ee 100644 --- a/lib/test/adt/bounded_bitset_test.cc +++ b/lib/test/adt/bounded_bitset_test.cc @@ -13,6 +13,14 @@ #include "srsran/adt/bounded_bitset.h" #include "srsran/common/test_common.h" +void test_bit_operations() +{ + TESTASSERT(0 == srsran::mask_trailing_ones(0)); + TESTASSERT(0b11 == srsran::mask_trailing_ones(2)); + TESTASSERT(0b11111111 == srsran::mask_trailing_ones(8)); + TESTASSERT(0b1111 == srsran::mask_trailing_ones(4)); +} + int test_zero_bitset() { srsran::bounded_bitset<25> mask; @@ -176,14 +184,34 @@ int test_bitset_resize() return SRSRAN_SUCCESS; } +void test_bitset_find() +{ + { + srsran::bounded_bitset<25> bitset(6); + bitset.set(2); + TESTASSERT(bitset.find_first(0, 6) == 2); + TESTASSERT(bitset.find_first(3, 6) == -1); + bitset.set(5); + TESTASSERT(bitset.find_first(3, 6) == 5); + } + { + srsran::bounded_bitset<100> bitset(95); + bitset.set(94); + TESTASSERT(bitset.find_first(0, 93) == -1); + TESTASSERT(bitset.find_first(0, bitset.size()) == 94); + } +} + int main() { + test_bit_operations(); TESTASSERT(test_zero_bitset() == SRSRAN_SUCCESS); TESTASSERT(test_ones_bitset() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_set() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_bitwise_oper() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_print() == SRSRAN_SUCCESS); TESTASSERT(test_bitset_resize() == SRSRAN_SUCCESS); + test_bitset_find(); printf("Success\n"); return 0; }