diff options
Diffstat (limited to 'chilbert/BigBitVec.hpp')
-rw-r--r-- | chilbert/BigBitVec.hpp | 395 |
1 files changed, 35 insertions, 360 deletions
diff --git a/chilbert/BigBitVec.hpp b/chilbert/BigBitVec.hpp index 977fabb..91a516d 100644 --- a/chilbert/BigBitVec.hpp +++ b/chilbert/BigBitVec.hpp @@ -22,32 +22,35 @@ #include "chilbert/BitVecIndex.hpp" #include "chilbert/BitVecIterator.hpp" #include "chilbert/BitVecMask.hpp" +#include "chilbert/MultiBitVec.hpp" #include "chilbert/Operations.hpp" #include <algorithm> -#include <cassert> -#include <climits> #include <cstddef> #include <cstdlib> #include <cstring> -#include <iostream> #include <memory> namespace chilbert { -class CBigBitVec +class CBigBitVec : public MultiBitVec<CBigBitVec> { public: - using Rack = uintptr_t; - using Mask = BitVecMask<Rack>; + struct RacksDeleter + { + void operator()(Rack* const racks) { free(racks); } + }; - using iterator = BitVecIterator<CBigBitVec>; - using const_iterator = ConstBitVecIterator<CBigBitVec>; + struct NullDeleter + { + void operator()(const Rack* const) {} + }; - static constexpr size_t bits_per_rack = sizeof(Rack) * CHAR_BIT; + using RacksPtr = std::unique_ptr<Rack[], RacksDeleter>; + using ConstRacksPtr = std::unique_ptr<const Rack[], NullDeleter>; explicit CBigBitVec(const size_t bits) - : m_pcRacks{make_racks(calculate_num_racks(bits))} + : m_racks{make_racks(calculate_num_racks(bits))} , m_size{bits} { } @@ -55,97 +58,32 @@ public: CBigBitVec(const size_t bits, const Rack value) : CBigBitVec{bits} { - m_pcRacks[0] = value; + m_racks[0] = value; } CBigBitVec(const CBigBitVec& vec) - : m_pcRacks{make_racks(vec.num_racks())} + : m_racks{make_racks(vec.num_racks())} , m_size{vec.m_size} { - if (vec.m_pcRacks) { - memcpy( - m_pcRacks.get(), vec.m_pcRacks.get(), sizeof(Rack) * num_racks()); + if (vec.data()) { + memcpy(data(), vec.data(), data_size()); } } CBigBitVec(CBigBitVec&& vec) = default; - /// Return the size in bits - size_t size() const { return m_size; } - - /// Set all bits to zero - CBigBitVec& reset() - { - memset(m_pcRacks.get(), 0, sizeof(Rack) * num_racks()); - return *this; - } - - /// Set all bits to one - CBigBitVec& set() - { - if (m_size) { - memset(m_pcRacks.get(), 0xFF, sizeof(Rack) * num_racks()); - const auto pad = m_size % bits_per_rack; - if (pad) { - m_pcRacks[num_racks() - 1] |= ~Rack{0} >> pad; - } - } - - return *this; - } - - /// Truncate to a given precision in bits (zero MSBs) - CBigBitVec& truncate(const size_t bits) - { - const Mask m = mask(bits); - - m_pcRacks[m.rack] &= (m.mask - 1); - - for (size_t i = m.rack + 1; i < num_racks(); ++i) { - m_pcRacks[i] = 0; - } - - return *this; - } - - bool operator==(const CBigBitVec& vec) const - { - return (num_racks() == vec.num_racks() && - (num_racks() == 0 || - !memcmp(racks(), vec.racks(), num_racks() * sizeof(Rack)))); - } - - bool operator!=(const CBigBitVec& vec) const { return !(*this == vec); } - - bool operator<(const CBigBitVec& vec) const - { - assert(size() == vec.size()); - - for (size_t ri = 0; ri < num_racks(); ++ri) { - size_t i = num_racks() - ri - 1; - if (m_pcRacks[i] < vec.m_pcRacks[i]) { - return true; - } else if (m_pcRacks[i] > vec.m_pcRacks[i]) { - return false; - } - } - return false; - } - CBigBitVec& operator=(const CBigBitVec& vec) { if (num_racks() < vec.num_racks()) { - m_pcRacks = make_racks(vec.num_racks()); - m_size = vec.m_size; - memcpy( - m_pcRacks.get(), vec.m_pcRacks.get(), sizeof(Rack) * num_racks()); + m_racks = make_racks(vec.num_racks()); + m_size = vec.m_size; + memcpy(data(), vec.data(), data_size()); } else if (vec.num_racks() > 0) { m_size = vec.m_size; - memcpy( - m_pcRacks.get(), vec.m_pcRacks.get(), sizeof(Rack) * num_racks()); + memcpy(data(), vec.data(), data_size()); } else { m_size = 0; - m_pcRacks.reset(); + m_racks.reset(); } return *this; @@ -153,269 +91,24 @@ 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.rack] & mask.mask; - } - - /// Return the value of the `index`th bit - bool test(const size_t index) const { return test(mask(index)); } - - /// Set the bit covered by `mask` to 1 - CBigBitVec& set(const Mask mask) - { - m_pcRacks[mask.rack] |= mask.mask; - return *this; - } - - /// Set the `index`th bit to 1 - CBigBitVec& set(const size_t index) { return set(mask(index)); } - - /// Reset the bit covered by `mask` to 0 - CBigBitVec& reset(const Mask mask) - { - m_pcRacks[mask.rack] &= ~mask.mask; - return *this; - } - - /// Reset the `index`th bit to 0 - 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) - { - auto& rack = m_pcRacks[mask.rack]; - rack ^= (-Rack{value} ^ rack) & mask.mask; - return *this; - } - - /// Set the `index`th bit to `value` - CBigBitVec& set(const size_t index, const bool value) - { - return set(mask(index), value); - } - - /// Flip the value of the bit covered by `mask` - CBigBitVec& flip(const Mask mask) - { - m_pcRacks[mask.rack] ^= mask.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(num_racks(), vec.num_racks()); ++i) { - m_pcRacks[i] &= vec.m_pcRacks[i]; - } - - return *this; - } - - CBigBitVec& operator|=(const CBigBitVec& vec) - { - for (size_t i = 0; i < std::min(num_racks(), vec.num_racks()); ++i) { - m_pcRacks[i] |= vec.m_pcRacks[i]; - } - - return *this; - } - - CBigBitVec& operator^=(const CBigBitVec& vec) - { - for (size_t i = 0; i < std::min(num_racks(), vec.num_racks()); ++i) { - m_pcRacks[i] ^= vec.m_pcRacks[i]; - } - - return *this; - } - - CBigBitVec& operator<<=(const size_t bits) - { - if (bits == 0) { - return *this; - } else if (bits >= size()) { - reset(); - return *this; - } - - const Index index{bits}; - - if (index.rack > 0) { - // Shift entire racks - for (size_t i = num_racks() - 1; i >= index.rack; --i) { - m_pcRacks[i] = m_pcRacks[i - index.rack]; - } - for (size_t i = 0; i < index.rack; ++i) { - m_pcRacks[i] = 0; - } - } - - if (index.bit > 0) { - // Shift bits within racks - size_t bi = bits_per_rack - index.bit; - size_t i; - for (i = num_racks() - 1; i >= index.rack + 1; --i) { - m_pcRacks[i] <<= index.bit; - m_pcRacks[i] |= m_pcRacks[i - 1] >> bi; - } - m_pcRacks[i] <<= index.bit; - } - - return *this; - } - - CBigBitVec& operator>>=(const size_t bits) - { - if (bits == 0) { - return *this; - } else if (bits >= size()) { - reset(); - return *this; - } - - const Index index{bits}; - - if (index.rack > 0) { - // Shift entire racks - size_t i; - for (i = 0; i < num_racks() - index.rack; ++i) { - m_pcRacks[i] = m_pcRacks[i + index.rack]; - } - for (; i < num_racks(); ++i) { - m_pcRacks[i] = 0; - } - } - - if (index.bit > 0) { - // Shift bits within racks - size_t bi = bits_per_rack - index.bit; - size_t i; - for (i = 0; i < num_racks() - index.rack - 1; ++i) { - m_pcRacks[i] >>= index.bit; - m_pcRacks[i] |= m_pcRacks[i + 1] << bi; - } - m_pcRacks[i] >>= index.bit; - } - - return *this; - } - - /// Right-rotate by `bits` positions - CBigBitVec& rotr(const size_t bits) - { - assert(bits <= size()); - if (bits == 0 || bits == size()) { - return *this; - } - - CBigBitVec t1(*this); - (*this) >>= bits; - t1 <<= (size() - bits); - (*this) |= t1; - - truncate(size()); - - return *this; - } - - /// Left-rotate by `bits` positions - CBigBitVec& rotl(const size_t bits) - { - assert(bits <= size()); - if (bits == 0 || bits == size()) { - return *this; - } - - CBigBitVec t1(*this); - (*this) <<= bits; - t1 >>= (size() - bits); - (*this) |= t1; - - truncate(size()); - - return *this; - } + /// Return the size in bits + size_t size() const { return m_size; } - /// Return true iff all bits are zero - bool none() const - { - for (size_t i = 0; i < num_racks(); ++i) { - if (m_pcRacks[i]) { - return false; - } - } - return true; - } + /// Return a reference to the `index`th rack + const Rack& rack(const size_t index) const { return m_racks[index]; } + Rack& rack(const size_t index) { return m_racks[index]; } - /// Return 1 + the index of the first set bit, or 0 if there are none - size_t find_first() const - { - for (size_t i = 0; i < num_racks(); ++i) { - const int j = ffs(m_pcRacks[i]); - if (j) { - return (i * bits_per_rack) + static_cast<size_t>(j); - } - } - return 0; - } + /// Return a raw pointer to the racks + Rack* data() { return m_racks.get(); } + const Rack* data() const { return m_racks.get(); } - /// Return the number of set bits - size_t count() const - { - size_t c = 0; - for (size_t i = 0; i < num_racks(); ++i) { - c += static_cast<size_t>(pop_count(m_pcRacks[i])); - } - return c; - } - - /// Flip all bits (one's complement) - CBigBitVec& flip() - { - for (size_t i = 0; i < num_racks(); ++i) { - m_pcRacks[i] = ~m_pcRacks[i]; - } - return *this; - } - - /// Return a pointer to the racks - Rack* racks() { return m_pcRacks.get(); } - const Rack* racks() const { return m_pcRacks.get(); } + /// Return the total size of all racks in bytes + size_t data_size() const { return num_racks() * sizeof(Rack); } /// Return the number of racks size_t num_racks() const { return calculate_num_racks(m_size); } - 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: - using Index = BitVecIndex<CBigBitVec>; - - struct RacksDeleter - { - void operator()(Rack* const racks) { free(racks); } - }; - - using RacksPtr = std::unique_ptr<Rack[], RacksDeleter>; - static size_t calculate_num_racks(const size_t bits) { return (std::max(bits, size_t(1)) + bits_per_rack - 1) / bits_per_rack; @@ -426,7 +119,7 @@ private: return RacksPtr{static_cast<Rack*>(calloc(n, sizeof(Rack)))}; } - RacksPtr m_pcRacks; + RacksPtr m_racks; size_t m_size; }; @@ -440,32 +133,14 @@ template <> void grayCode(CBigBitVec& value) { - CBigBitVec::Rack s = 0; - - for (intptr_t i = static_cast<intptr_t>(value.num_racks() - 1); i >= 0; - --i) { - const auto t = value.racks()[i] & 1; - grayCode(value.racks()[i]); - value.racks()[i] ^= (s << (CBigBitVec::bits_per_rack - 1)); - s = t; - } + grayCode(static_cast<MultiBitVec<CBigBitVec>&>(value)); } template <> void grayCodeInv(CBigBitVec& value) { - CBigBitVec::Rack s = 0; - - for (intptr_t i = static_cast<intptr_t>(value.num_racks() - 1); i >= 0; - --i) { - auto& rack = value.racks()[i]; - grayCodeInv(rack); - if (s) { - rack = ~rack; - } - s = rack & 1; - } + grayCodeInv(static_cast<MultiBitVec<CBigBitVec>&>(value)); } } // namespace chilbert |