diff options
Diffstat (limited to 'chilbert/BigBitVec.hpp')
-rw-r--r-- | chilbert/BigBitVec.hpp | 258 |
1 files changed, 188 insertions, 70 deletions
diff --git a/chilbert/BigBitVec.hpp b/chilbert/BigBitVec.hpp index 7302880..29d9a5a 100644 --- a/chilbert/BigBitVec.hpp +++ b/chilbert/BigBitVec.hpp @@ -39,6 +39,50 @@ public: static constexpr size_t bits_per_rack = sizeof(Rack) * CHAR_BIT; + /** Mask for a bit that can be incremented like an index. + * + * This enables fast iteration while setting or resetting bits since it is + * internally stored as a mask which avoids repeated index math. + */ + class Mask + { + public: + void operator++() + { + if ((m_mask <<= 1) == 0) { + m_mask = 1; + ++m_rack; + } + } + + void operator--() + { + if ((m_mask >>= 1) == 0) { + m_mask = Rack{1} << (bits_per_rack - 1); + --m_rack; + } + } + + bool operator==(const Mask& mask) const + { + return m_rack == mask.m_rack && m_mask == mask.m_mask; + } + + bool operator!=(const Mask& mask) const { return !operator==(mask); } + + private: + friend class CBigBitVec; + + Mask(const size_t index) + : m_rack{index / bits_per_rack} + , m_mask{Rack{1} << (index - m_rack * bits_per_rack)} + { + } + + size_t m_rack; + Rack m_mask; + }; + explicit CBigBitVec(const size_t bits) : m_pcRacks{make_racks(num_racks(bits))} , m_iRacks{bits == 0 ? 0 : num_racks(bits)} @@ -83,16 +127,11 @@ public: /// Truncate to a given precision in bits (zero MSBs) CBigBitVec& truncate(const size_t bits) { - assert(bits <= size()); - const Ref ref(bits); - if (ref.rack >= m_iRacks) { - return *this; - } + const Mask m = mask(bits); - // Truncate rack that contains the split point - m_pcRacks[ref.rack] &= ((Rack{1} << ref.bit) - 1); + m_pcRacks[m.m_rack] &= (m.m_mask - 1); - for (size_t i = ref.rack + 1; i < m_iRacks; ++i) { + for (size_t i = m.m_rack + 1; i < m_iRacks; ++i) { m_pcRacks[i] = 0; } @@ -145,50 +184,59 @@ public: CBigBitVec& operator=(CBigBitVec&& vec) = default; + /// Return the value of the bit covered by `mask` + bool test(const Mask mask) const + { + return m_pcRacks[mask.m_rack] & mask.m_mask; + } + /// Return the value of the `index`th bit - bool test(const size_t index) const + bool test(const size_t index) const { return test(mask(index)); } + + /// Set the bit covered by `mask` to 1 + CBigBitVec& set(const Mask mask) { - assert(index < size()); - const Ref ref(index); - return testBit(m_pcRacks[ref.rack], ref.bit); + m_pcRacks[mask.m_rack] |= mask.m_mask; + return *this; } /// Set the `index`th bit to 1 - CBigBitVec& set(const size_t index) + CBigBitVec& set(const size_t index) { return set(mask(index)); } + + /// Reset the bit covered by `mask` to 0 + CBigBitVec& reset(const Mask mask) { - assert(index < size()); - const Ref ref(index); - setBit(m_pcRacks[ref.rack], ref.bit); + m_pcRacks[mask.m_rack] &= ~mask.m_mask; return *this; } /// Reset the `index`th bit to 0 - CBigBitVec& reset(const size_t index) + CBigBitVec& reset(const size_t index) { return reset(mask(index)); } + + /// Set the bit covered by `mask` to `value` + CBigBitVec& set(const Mask mask, const bool value) { - assert(index < size()); - const Ref ref(index); - m_pcRacks[ref.rack] &= ~(Rack{1} << ref.bit); + auto& rack = m_pcRacks[mask.m_rack]; + rack ^= (-Rack{value} ^ rack) & mask.m_mask; return *this; } /// Set the `index`th bit to `value` CBigBitVec& set(const size_t index, const bool value) { - assert(index < size()); - const Ref ref(index); - setBit(m_pcRacks[ref.rack], ref.bit, value); - return *this; + return set(mask(index), value); } - /// Flip the value of the `index`th bit - CBigBitVec& flip(const size_t index) + /// Flip the value of the bit covered by `mask` + CBigBitVec& flip(const Mask mask) { - assert(index < size()); - const Ref ref(index); - m_pcRacks[ref.rack] ^= (Rack{1} << ref.bit); + m_pcRacks[mask.m_rack] ^= mask.m_mask; return *this; } + /// Flip the value of the `index`th bit + CBigBitVec& flip(const size_t index) { return flip(mask(index)); } + CBigBitVec& operator&=(const CBigBitVec& vec) { for (size_t i = 0; i < std::min(m_iRacks, vec.m_iRacks); ++i) { @@ -249,40 +297,34 @@ public: CBigBitVec& operator<<=(const size_t bits) { - assert(bits < size()); - - // No shift? if (bits == 0) { return *this; - } - - const Ref ref(bits); - - // All racks? - if (ref.rack >= m_iRacks) { + } else if (bits >= size()) { reset(); return *this; } - // Do rack shifts. - if (ref.rack > 0) { - for (size_t i = m_iRacks - 1; i >= ref.rack; --i) { - m_pcRacks[i] = m_pcRacks[i - ref.rack]; + const Index index{bits}; + + if (index.rack > 0) { + // Shift entire racks + for (size_t i = m_iRacks - 1; i >= index.rack; --i) { + m_pcRacks[i] = m_pcRacks[i - index.rack]; } - for (size_t i = 0; i < ref.rack; ++i) { + for (size_t i = 0; i < index.rack; ++i) { m_pcRacks[i] = 0; } } - // Do bit shifts. - if (ref.bit > 0) { - size_t bi = bits_per_rack - ref.bit; + if (index.bit > 0) { + // Shift bits within racks + size_t bi = bits_per_rack - index.bit; size_t i; - for (i = m_iRacks - 1; i >= ref.rack + 1; --i) { - m_pcRacks[i] <<= ref.bit; + for (i = m_iRacks - 1; i >= index.rack + 1; --i) { + m_pcRacks[i] <<= index.bit; m_pcRacks[i] |= m_pcRacks[i - 1] >> bi; } - m_pcRacks[i] <<= ref.bit; + m_pcRacks[i] <<= index.bit; } return *this; @@ -297,41 +339,35 @@ public: CBigBitVec& operator>>=(const size_t bits) { - assert(bits < size()); - - // No shift? if (bits == 0) { return *this; - } - - const Ref ref(bits); - - // All racks? - if (ref.rack >= m_iRacks) { + } else if (bits >= size()) { reset(); return *this; } - // Do rack shifts. - if (ref.rack > 0) { + const Index index{bits}; + + if (index.rack > 0) { + // Shift entire racks size_t i; - for (i = 0; i < m_iRacks - ref.rack; ++i) { - m_pcRacks[i] = m_pcRacks[i + ref.rack]; + for (i = 0; i < m_iRacks - index.rack; ++i) { + m_pcRacks[i] = m_pcRacks[i + index.rack]; } for (; i < m_iRacks; ++i) { m_pcRacks[i] = 0; } } - // Do bit shifts. - if (ref.bit > 0) { - size_t bi = bits_per_rack - ref.bit; + if (index.bit > 0) { + // Shift bits within racks + size_t bi = bits_per_rack - index.bit; size_t i; - for (i = 0; i < m_iRacks - ref.rack - 1; ++i) { - m_pcRacks[i] >>= ref.bit; + for (i = 0; i < m_iRacks - index.rack - 1; ++i) { + m_pcRacks[i] >>= index.bit; m_pcRacks[i] |= m_pcRacks[i + 1] << bi; } - m_pcRacks[i] >>= ref.bit; + m_pcRacks[i] >>= index.bit; } return *this; @@ -451,10 +487,92 @@ public: /// Return the number of racks size_t rackCount() const { return m_iRacks; } + template <class BitVec> + class iterator_base : public Mask + { + public: + iterator_base& operator++() + { + Mask::operator++(); + return *this; + } + + iterator_base& operator--() + { + Mask::operator--(); + return *this; + } + + bool operator==(const iterator_base& iterator_base) const + { + return m_vec == iterator_base.m_vec && + Mask::operator==(iterator_base); + } + + bool operator!=(const iterator_base& iterator_base) const + { + return !operator==(iterator_base); + } + + bool operator*() const { return m_vec->test(*this); } + + protected: + iterator_base(BitVec& vec, const size_t index) + : Mask{index} + , m_vec{&vec} + { + } + + BitVec* m_vec; + }; + + class iterator : public iterator_base<CBigBitVec> + { + public: + void set() { m_vec->set(*this); } + void reset() { m_vec->reset(*this); } + + private: + friend class CBigBitVec; + + iterator(CBigBitVec& vec, const size_t index) + : iterator_base{vec, index} + { + } + }; + + class const_iterator : public iterator_base<const CBigBitVec> + { + private: + friend class CBigBitVec; + + const_iterator(const CBigBitVec& vec, const size_t index) + : iterator_base{vec, index} + { + } + }; + + Mask mask(const size_t i = 0) const + { + assert(i <= size()); + return Mask{i}; + } + + iterator begin(const size_t i = 0) { return iterator(*this, i); } + + iterator end() { return iterator(*this, size()); } + + const_iterator begin(const size_t i = 0) const + { + return const_iterator(*this, i); + } + + const_iterator end() const { return const_iterator(*this, size()); } + private: - struct Ref + struct Index { - Ref(const size_t bits) + Index(const size_t bits) : rack{bits / bits_per_rack} , bit{bits - rack * bits_per_rack} { |