You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
2.8 KiB
92 lines
2.8 KiB
#include <algorithm> |
|
#include <climits> |
|
#include <cstddef> |
|
|
|
#include "utils/attributes.h" |
|
|
|
namespace devilution { |
|
|
|
/** |
|
* @brief A stack-allocated bit-vector with a fixed capacity and a fixed size < capacity. |
|
* |
|
* @tparam N capacity. |
|
*/ |
|
template <size_t N, typename Word = unsigned long> // NOLINT(google-runtime-int) |
|
class StaticBitVector { |
|
public: |
|
explicit StaticBitVector(size_t size) |
|
: size_(size) |
|
, num_words_(size / BitsPerWord + ((size % BitsPerWord) == 0 ? 0 : 1)) |
|
{ |
|
} |
|
|
|
[[nodiscard]] bool test(size_t pos) const { return (word(pos) & maskBit(pos)) != 0; } |
|
|
|
void set() { std::fill_n(words_, num_words_, ~Word { 0 }); } |
|
void set(size_t pos) { word(pos) |= maskBit(pos); } |
|
|
|
// Sets all bits in the [begin, begin+length) range to 1. |
|
// Length must not be zero. |
|
void set(size_t begin, size_t length) |
|
{ |
|
DVL_ASSUME(length != 0); |
|
const size_t firstWord = begin / BitsPerWord; |
|
const size_t lastWord = (begin + length - 1) / BitsPerWord; |
|
const Word firstWordMask = onesFrom(begin); |
|
const Word lastWordMask = onesUpTo(begin + length - 1); |
|
if (firstWord == lastWord) { |
|
words_[firstWord] |= firstWordMask & lastWordMask; |
|
return; |
|
} |
|
words_[firstWord] |= firstWordMask; |
|
std::fill(&words_[firstWord + 1], &words_[lastWord], ~Word { 0 }); |
|
words_[lastWord] |= lastWordMask; |
|
} |
|
|
|
void reset() { std::fill_n(words_, num_words_, Word { 0 }); } |
|
void reset(size_t pos) { word(pos) &= ~maskBit(pos); } |
|
|
|
// Sets all bits in the [begin, begin+length) range to 0. |
|
// Length must not be zero. |
|
void reset(size_t begin, size_t length) |
|
{ |
|
DVL_ASSUME(length != 0); |
|
const size_t firstWord = begin / BitsPerWord; |
|
const size_t lastWord = (begin + length - 1) / BitsPerWord; |
|
const Word firstWordMask = onesFrom(begin); |
|
const Word lastWordMask = onesUpTo(begin + length - 1); |
|
if (firstWord == lastWord) { |
|
words_[firstWord] &= ~(firstWordMask & lastWordMask); |
|
return; |
|
} |
|
words_[firstWord] &= ~firstWordMask; |
|
std::fill(&words_[firstWord + 1], &words_[lastWord], Word { 0 }); |
|
words_[lastWord] &= ~lastWordMask; |
|
} |
|
|
|
private: |
|
static constexpr Word onesFrom(size_t begin) |
|
{ |
|
return (~Word { 0 }) << (begin % BitsPerWord); |
|
} |
|
static constexpr Word onesUpTo(size_t last) |
|
{ |
|
return (~Word { 0 }) >> (BitsPerWord - (last % BitsPerWord) - 1); |
|
} |
|
|
|
static constexpr Word maskBit(size_t pos) |
|
{ |
|
return Word { 1 } << (pos % BitsPerWord); |
|
} |
|
Word word(size_t pos) const { return words_[pos / BitsPerWord]; } |
|
Word &word(size_t pos) { return words_[pos / BitsPerWord]; } |
|
|
|
static constexpr unsigned BitsPerWord = CHAR_BIT * sizeof(Word); |
|
static constexpr unsigned MaxNumWords = N / BitsPerWord + ((N % BitsPerWord) == 0 ? 0 : 1); |
|
Word words_[MaxNumWords] = {}; |
|
|
|
size_t size_; |
|
size_t num_words_; |
|
}; |
|
|
|
} // namespace devilution
|
|
|