/** * Copyright 2013-2021 Software Radio Systems Limited * * This file is part of srsLTE. * * srsLTE is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * srsLTE is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * A copy of the GNU Affero General Public License can be found in * the LICENSE file in the top-level directory of this distribution * and at http://www.gnu.org/licenses/. * */ #ifndef SRSLTE_DYN_BITSET_H #define SRSLTE_DYN_BITSET_H #include "adt_utils.h" #include #include #include namespace srslte { constexpr uint32_t ceil_div(uint32_t x, uint32_t y) { return (x + y - 1) / y; } template class bounded_bitset { typedef uint64_t word_t; static const size_t bits_per_word = 8 * sizeof(word_t); public: constexpr bounded_bitset() : buffer(), cur_size(0) {} constexpr explicit bounded_bitset(size_t cur_size_) : buffer(), cur_size(cur_size_) {} constexpr size_t max_size() const noexcept { return N; } size_t size() const noexcept { return cur_size; } void resize(size_t new_size) { if (new_size > max_size()) { std::string msg = "ERROR: new size=" + std::to_string(new_size) + " exceeds bitset capacity=" + std::to_string(max_size()); THROW_BAD_ACCESS(msg.c_str()); } if (new_size == cur_size) { return; } cur_size = new_size; sanitize_(); for (size_t i = nof_words_(); i < max_nof_words_(); ++i) { get_word_(i) = static_cast(0); } } void set(size_t pos, bool val) { assert_within_bounds_(pos, true); if (val) { set_(pos); } else { reset_(pos); } } void set(size_t pos) { assert_within_bounds_(pos, true); set_(pos); } void reset(size_t pos) { assert_within_bounds_(pos, true); reset_(pos); } void reset() noexcept { for (size_t i = 0; i < nof_words_(); ++i) { buffer[i] = static_cast(0); } } bool test(size_t pos) const { assert_within_bounds_(pos, true); return test_(pos); } bounded_bitset& flip() noexcept { for (size_t i = 0; i < nof_words_(); ++i) { buffer[i] = ~buffer[i]; } sanitize_(); return *this; } bounded_bitset& fill(size_t startpos, size_t endpos, bool value = true) { assert_within_bounds_(startpos, false); assert_within_bounds_(endpos, false); // NOTE: can be optimized if (value) { for (size_t i = startpos; i < endpos; ++i) { set_(i); } } else { for (size_t i = startpos; i < endpos; ++i) { reset_(i); } } return *this; } bool all() const noexcept { const size_t nw = nof_words_(); if (nw == 0) { return true; } word_t allset = ~static_cast(0); for (size_t i = 0; i < nw - 1; i++) { if (buffer[i] != allset) { return false; } } return buffer[nw - 1] == (allset >> (nw * bits_per_word - size())); } bool any() const noexcept { for (size_t i = 0; i < nof_words_(); ++i) { if (buffer[i] != static_cast(0)) { return true; } } return false; } bool any(size_t start, size_t stop) const { assert_within_bounds_(start, false); assert_within_bounds_(stop, false); // NOTE: can be optimized for (size_t i = start; i < stop; ++i) { if (test_(i)) { return true; } } return false; } bool none() const noexcept { return !any(); } size_t count() const noexcept { size_t result = 0; for (size_t i = 0; i < nof_words_(); i++) { // result += __builtin_popcountl(buffer[i]); word_t w = buffer[i]; for (; w; w >>= 1u) { result += (w & 1u); } } return result; } bool operator==(const bounded_bitset& other) const noexcept { if (size() != other.size()) { return false; } for (uint32_t i = 0; i < nof_words_(); ++i) { if (buffer[i] != other.buffer[i]) { return false; } } return true; } bool operator!=(const bounded_bitset& other) const noexcept { return not(*this == other); } bounded_bitset& operator|=(const bounded_bitset& other) { if (other.size() != size()) { std::string msg = "operator|= called for bitsets of different sizes (" + std::to_string(size()) + "!=" + std::to_string(other.size()) + ")"; THROW_BAD_ACCESS(msg.c_str()); } for (size_t i = 0; i < nof_words_(); ++i) { buffer[i] |= other.buffer[i]; } return *this; } bounded_bitset& operator&=(const bounded_bitset& other) { if (other.size() != size()) { std::string msg = "operator&= called for bitsets of different sizes (" + std::to_string(size()) + "!=" + std::to_string(other.size()) + ")"; THROW_BAD_ACCESS(msg.c_str()); } for (size_t i = 0; i < nof_words_(); ++i) { buffer[i] &= other.buffer[i]; } return *this; } bounded_bitset operator~() const noexcept { bounded_bitset ret(*this); ret.flip(); return ret; } std::string to_string() const { std::string s; s.assign(size(), '0'); if (not reversed) { for (size_t i = size(); i > 0; --i) { if (test(i - 1)) { s[size() - i] = '1'; } } } else { for (size_t i = 0; i < size(); ++i) { if (test(i)) { s[i] = '1'; } } } return s; } uint64_t to_uint64() const { if (nof_words_() > 1) { std::string msg = "ERROR: cannot convert bitset of size=" + std::to_string(size()) + " to uint64_t"; THROW_BAD_ACCESS(msg.c_str()); } return get_word_(0); } std::string to_hex() const noexcept { size_t nof_digits = (size() - 1) / 4 + 1; char cstr[ceil_div(ceil_div(N, bits_per_word) * bits_per_word, 4) + 1]; size_t count = 0; for (int i = nof_words_() - 1; i >= 0; --i) { count += sprintf(&cstr[count], "%016" PRIx64, buffer[i]); } size_t skip = nof_words_() * bits_per_word / 4 - nof_digits; // printf("bitstring: %s\n", to_string().c_str()); return std::string(&cstr[skip], &cstr[nof_digits + skip + 1]); } private: word_t buffer[(N - 1) / bits_per_word + 1]; size_t cur_size; void sanitize_() { size_t n = size() % bits_per_word; size_t nwords = nof_words_(); if (n != 0 and nwords > 0) { buffer[nwords - 1] &= ~((~static_cast(0)) << n); } } bool test_(size_t pos) const noexcept { pos = reversed ? size() - 1 - pos : pos; return ((get_word_(pos) & maskbit(pos)) != static_cast(0)); } void set_(size_t pos) noexcept { pos = reversed ? size() - 1 - pos : pos; get_word_(pos) |= maskbit(pos); } void reset_(size_t pos) noexcept { pos = reversed ? size() - 1 - pos : pos; get_word_(pos) &= ~(maskbit(pos)); } size_t nof_words_() const noexcept { return size() > 0 ? (size() - 1) / bits_per_word + 1 : 0; } word_t& get_word_(size_t pos) noexcept { return buffer[pos / bits_per_word]; } const word_t& get_word_(size_t pos) const { return buffer[pos / bits_per_word]; } size_t word_idx_(size_t pos) const { return pos / bits_per_word; } void assert_within_bounds_(size_t pos, bool strict) const { if (pos > size() or (strict and pos == size())) { std::string msg = "ERROR: index=" + std::to_string(pos) + "is out of bounds for bitset of size=" + std::to_string(size()); THROW_BAD_ACCESS(msg.c_str()); } } 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; } }; template inline bounded_bitset operator&(const bounded_bitset& lhs, const bounded_bitset& rhs)noexcept { bounded_bitset res(lhs); res &= rhs; return res; } template inline bounded_bitset operator|(const bounded_bitset& lhs, const bounded_bitset& rhs) noexcept { bounded_bitset res(lhs); res |= rhs; return res; } template inline bounded_bitset fliplr(const bounded_bitset& other) noexcept { bounded_bitset ret(other.size()); for (uint32_t i = 0; i < ret.size(); ++i) { if (other.test(i)) { ret.set(ret.size() - 1 - i); } } return ret; } } // namespace srslte #endif // SRSLTE_DYN_BITSET_H