1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
#ifndef BITVECTOR_H
#define BITVECTOR_H
#include <cstdint>
#include <vector>
#include <terraces/trees.hpp>
#include "bits.hpp"
#include "stack_allocator.hpp"
namespace terraces {
template <typename Bitvector>
class bitvector_iterator;
template <typename Allocator>
class basic_bitvector {
public:
using value_type = index;
using iterator = bitvector_iterator<Allocator>;
static index alloc_size(index size) { return size / bits::word_bits + 1; }
protected:
index m_size;
std::vector<value_type, Allocator> m_blocks;
void add_sentinel() {
// add sentinel bit for iteration
m_blocks[bits::block_index(m_size)] |= bits::set_mask(m_size);
}
public:
/** Initializes a bitvector with given size. */
basic_bitvector(index size, Allocator alloc)
: m_size{size}, m_blocks(alloc_size(size), 0, alloc) {
add_sentinel();
}
/** Sets a bit in the bitvector. */
void set(index i) {
assert(i < m_size);
m_blocks[bits::block_index(i)] |= bits::set_mask(i);
}
/** Clears a bit in the bitvector. */
void clr(index i) {
assert(i < m_size);
m_blocks[bits::block_index(i)] &= bits::clear_mask(i);
}
/** Flips a bit in the bitvector. */
void flip(index i) {
assert(i < m_size);
m_blocks[bits::block_index(i)] ^= bits::set_mask(i);
}
/** Returns a bit from the bitvector. */
bool get(index i) const {
assert(i < m_size);
return ((m_blocks[bits::block_index(i)] >> bits::shift_index(i)) & 1) != 0u;
}
/** Returns the size of the bitvector. */
index size() const { return m_size; }
/** Returns true if and only if no bit is set. */
bool empty() const;
/** Clears all bits in the bitvector. */
void blank();
/** Inverts all bits in the bitvector. */
void invert();
/** Applies element-wise xor from another bitvector. */
void bitwise_xor(const basic_bitvector<Allocator>& other);
/** Sets the values of this bitvector to the bitwise or of two bitvectors. */
void set_bitwise_or(const basic_bitvector<Allocator>& fst,
const basic_bitvector<Allocator>& snd);
/** Returns the index of the first set bit or size() if no bit is set. */
index first_set() const;
/** Returns the index of the next set bit after the index or size() if no bit is set. */
index next_set(index i) const;
/** Returns the index one past the last element. */
index last_set() const { return m_size; }
iterator begin() const;
iterator end() const;
Allocator get_allocator() const { return m_blocks.get_allocator(); }
bool operator<(const basic_bitvector<Allocator>& other) const {
assert(size() == other.size());
return m_blocks < other.m_blocks;
}
bool operator==(const basic_bitvector<Allocator>& other) const {
assert(size() == other.size());
return m_blocks == other.m_blocks;
}
bool operator!=(const basic_bitvector<Allocator>& other) const { return !(*this == other); }
};
using bitvector = basic_bitvector<utils::stack_allocator<index>>;
using simple_bitvector = basic_bitvector<std::allocator<bitvector::value_type>>;
template <typename Alloc>
class bitvector_iterator {
public:
using value_type = typename Alloc::value_type;
private:
const basic_bitvector<Alloc>& m_set;
index m_index;
public:
bitvector_iterator(const basic_bitvector<Alloc>& set, index i) : m_set{set}, m_index{i} {}
bitvector_iterator& operator++() {
m_index = m_set.next_set(m_index);
return *this;
}
bool operator==(const bitvector_iterator& other) const { return m_index == other.m_index; }
bool operator!=(const bitvector_iterator& other) const { return !(*this == other); }
const index& operator*() const { return m_index; }
};
template <typename Alloc>
auto basic_bitvector<Alloc>::begin() const -> iterator {
return {*this, first_set()};
}
template <typename Alloc>
auto basic_bitvector<Alloc>::end() const -> iterator {
return {*this, last_set()};
}
template <typename Alloc>
bool basic_bitvector<Alloc>::empty() const {
for (index b = 0; b < m_blocks.size() - 1; ++b) {
if (m_blocks[b]) {
return false;
}
}
return !(m_blocks[m_blocks.size() - 1] & bits::prefix_mask(bits::shift_index(m_size)));
}
template <typename Alloc>
void basic_bitvector<Alloc>::blank() {
for (auto& el : m_blocks) {
el = 0;
}
add_sentinel();
}
template <typename Alloc>
void basic_bitvector<Alloc>::bitwise_xor(const basic_bitvector<Alloc>& other) {
assert(size() == other.size());
for (index b = 0; b < m_blocks.size(); ++b) {
m_blocks[b] ^= other.m_blocks[b];
}
add_sentinel();
}
template <typename Alloc>
void basic_bitvector<Alloc>::invert() {
for (index b = 0; b < m_blocks.size() - 1; ++b) {
m_blocks[b] = ~m_blocks[b];
}
m_blocks[m_blocks.size() - 1] ^= bits::prefix_mask(bits::shift_index(m_size));
}
template <typename Alloc>
void basic_bitvector<Alloc>::set_bitwise_or(const basic_bitvector<Alloc>& fst,
const basic_bitvector<Alloc>& snd) {
assert(size() == fst.size() && size() == snd.size());
for (index b = 0; b < m_blocks.size(); ++b) {
m_blocks[b] = fst.m_blocks[b] | snd.m_blocks[b];
}
}
template <typename Alloc>
index basic_bitvector<Alloc>::first_set() const {
index b = 0;
while (!bits::has_next_bit0(m_blocks[b])) {
++b;
}
return bits::next_bit0(m_blocks[b], bits::base_index(b));
}
template <typename Alloc>
index basic_bitvector<Alloc>::next_set(index i) const {
++i;
index b = bits::block_index(i);
if (bits::has_next_bit(m_blocks[b], i)) {
// the next bit is in the current block
return bits::next_bit(m_blocks[b], i);
}
// the next bit is in a far-away block
do {
++b;
} while (!bits::has_next_bit0(m_blocks[b]));
return bits::next_bit0(m_blocks[b], bits::base_index(b));
}
/** Returns a bitvector containing size elements. */
template <typename Alloc>
basic_bitvector<Alloc> full_set(index size, Alloc a) {
basic_bitvector<Alloc> set{size, a};
set.invert();
return set;
}
} // namespace terraces
#endif // BITVECTOR_H
|