carl  24.04
Computer ARithmetic Library
Bitset.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include "../util/boost_util.h"
4 
5 #include <boost/dynamic_bitset.hpp>
6 
7 #include <ostream>
8 
9 namespace carl {
10 
11  /**
12  * This class is a simple wrapper around boost::dynamic_bitset.
13  * Its purpose is to allow for on-the-fly resizing of the bitset.
14  * Formally, a Bitset object represents an infinite bitset that starts with the bits stored in mData extended by mDefault.
15  * Whenever a bit is written that is not yet stored explicitly in mData or two Bitset objects with different mData sizes are involved, the size of mData is expanded transparently.
16  *
17  * Note that some operations only make sense for a certain value of `mDefault`.
18  * For example, `any()` or `none()` require `mDefault` to be `false`.
19  */
20  class Bitset {
21  public:
22  friend struct std::hash<carl::Bitset>;
23 
24  /// Underlying storage type.
25  using BaseType = boost::dynamic_bitset<>;
26  /// Sentinel element for iteration.
27  static auto constexpr npos = BaseType::npos;
28  /// Number of bits in each storage block.
29  static auto constexpr bits_per_block = BaseType::bits_per_block;
30 
31  /**
32  * Iterate for iterate over all bits of a Bitset that are set to true.
33  *
34  * If you want to iterate of all bits that are false use `operator~()`.
35  */
36  struct iterator {
37  private:
38  /// The Bitset iterated over.
39  const Bitset& mBitset;
40  /// The current bit.
41  std::size_t mBit;
42 
43  /// Check that two iterators speak about the same Bitset.
44  bool compatible(const iterator& rhs) const {
45  return &mBitset == &rhs.mBitset;
46  }
47  public:
48  /// Construct a new iterator from a Bitset and a bit.
49  iterator(const Bitset& b, std::size_t bit): mBitset(b), mBit(bit) {}
50 
51  /// Retrieve the index into the Bitset.
52  operator std::size_t() const {
53  return mBit;
54  }
55  /// Retrieve the index into the Bitset.
56  std::size_t operator*() const {
57  return mBit;
58  }
59  /// Step to the next bit that is set to true.
61  mBit = mBitset.find_next(mBit);
62  return *this;
63  }
64  /// Step to the next bit that is set to true.
66  iterator res(*this);
67  ++(*this);
68  return res;
69  }
70  /// Compare two iterators. Asserts that they are compatible.
71  bool operator==(const iterator& rhs) const {
72  assert(compatible(rhs));
73  return mBit == rhs.mBit;
74  }
75  /// Compare two iterators. Asserts that they are compatible.
76  bool operator!=(const iterator& rhs) const {
77  assert(compatible(rhs));
78  return !(*this == rhs);
79  }
80  /// Compare two iterators. Asserts that they are compatible.
81  bool operator<(const iterator& rhs) const {
82  assert(compatible(rhs));
83  return mBit < rhs.mBit;
84  }
85  };
86 
87  private:
88  /// The actual data.
89  mutable BaseType mData;
90  /// The default value for bits beyond mData.
91  bool mDefault;
92  /// Resize mData to hold at least pos bits.
93  void ensureSize(std::size_t pos) {
94  if (pos >= mData.size()) {
95  mData.resize(pos+1);
96  }
97  }
98  public:
99  /// Create an empty bitset.
100  explicit Bitset(bool defaultValue = false): mDefault(defaultValue) {}
101  /// Create a bitset from a BaseType object.
102  Bitset(BaseType&& base, bool defaultValue): mData(std::move(base)), mDefault(defaultValue) {}
103  /// Create a bitset from a list of bits indices that shall be set to true.
104  Bitset(const std::initializer_list<std::size_t>& bits, bool defaultValue = false): mDefault(defaultValue) {
105  for (auto b: bits) {
106  set(b);
107  }
108  }
109 
110  /// Resize the Bitset to hold at least num_bits bits. New bits are set to the given value.
111  auto resize(std::size_t num_bits, bool value) const {
112  return mData.resize(num_bits, value);
113  }
114  /// Resize the Bitset to hold at least num_bits bits. New bits are set to mDefault.
115  auto resize(std::size_t num_bits) const {
116  return mData.resize(num_bits, mDefault);
117  }
118 
119  /// Sets all bits to false that are true in rhs.
120  Bitset& operator-=(const Bitset& rhs) {
121  assert(mDefault == rhs.mDefault);
122  alignSize(*this, rhs);
123  mData -= rhs.mData;
124  return *this;
125  }
126  /// Computes the bitwise and with rhs.
127  Bitset& operator&=(const Bitset& rhs) {
128  alignSize(*this, rhs);
129  mData &= rhs.mData;
130  return *this;
131  }
132  /// Computes the bitwise or with rhs.
133  Bitset& operator|=(const Bitset& rhs) {
134  alignSize(*this, rhs);
135  mData |= rhs.mData;
136  return *this;
137  }
138 
139  /// Sets the given bit to a value, true by default.
140  Bitset& set(std::size_t n, bool value = true) {
141  ensureSize(n);
142  mData.set(n, value);
143  return *this;
144  }
145  /// Sets the a range of bits to a value, true by default.
146  Bitset& set_interval(std::size_t start, std::size_t end, bool value = true) {
147  ensureSize(end);
148  for (; start <= end; start++) {
149  mData.set(start, value);
150  }
151  return *this;
152  }
153  /// Resets a bit to false.
154  Bitset& reset(std::size_t n) {
155  ensureSize(n);
156  mData.reset(n);
157  return *this;
158  }
159  /// Retrieves the value of the given bit.
160  bool test(std::size_t n) const {
161  if (n >= mData.size()) {
162  return mDefault;
163  }
164  return mData.test(n);
165  }
166  /// Checks if any bits are set to true. Asserts that mDefault is false.
167  bool any() const {
168  assert(!mDefault);
169  return mData.any();
170  }
171  /// Checks if no bits are set to true. Asserts that mDefault is false.
172  bool none() const {
173  assert(!mDefault);
174  return mData.none();
175  }
176 
177  /// Counts the number of bits that are set to true. Asserts that mDefault is false.
178  auto count() const noexcept {
179  assert(!mDefault);
180  return mData.count();
181  }
182 
183  /// Retrieves the size of mData.
184  auto size() const {
185  return mData.size();
186  }
187  /// Retrieves the number of blocks used to store mData.
188  auto num_blocks() const {
189  return mData.num_blocks();
190  }
191  /// Checks wether the bits set is a subset of the bits set in rhs.
192  auto is_subset_of(const Bitset& rhs) const {
193  if (mDefault && !rhs.mDefault) {
194  return false;
195  }
196  alignSize(*this, rhs);
197  return mData.is_subset_of(rhs.mData);
198  }
199  /// Retrieves the index of the first bit that is set to true.
200  std::size_t find_first() const {
201  return mData.find_first();
202  }
203  /// Retrieves the index of the first bit set to true after the given position.
204  std::size_t find_next(std::size_t pos) const {
205  return mData.find_next(pos);
206  }
207  /// Returns an iterator to the first bit that is set to true.
208  iterator begin() const {
209  return iterator(*this, find_first());
210  }
211  /// Returns an past-the-end iterator.
212  iterator end() const {
213  return iterator(*this, npos);
214  }
215 
216  /// Ensures that the explicitly stored bits of lhs and rhs have the same size.
217  friend void alignSize(const Bitset& lhs, const Bitset& rhs) {
218  if (lhs.size() < rhs.size()) {
219  lhs.resize(rhs.size());
220  } else if (lhs.size() > rhs.size()) {
221  rhs.resize(lhs.size());
222  }
223  }
224 
225  /// Compares lhs and rhs.
226  friend bool operator==(const Bitset& lhs, const Bitset& rhs) {
227  alignSize(lhs, rhs);
228  return (lhs.mData == rhs.mData) && (lhs.mDefault == rhs.mDefault);
229  }
230  /// Compares lhs and rhs according to some order.
231  friend bool operator<(const Bitset& lhs, const Bitset& rhs) {
232  if (lhs.size() < rhs.size()) {
233  return true;
234  }
235  if (lhs.size() > rhs.size()) {
236  return false;
237  }
238  return lhs.mData < rhs.mData;
239  }
240 
241  /// Returns the bitwise negation of lhs.
242  friend Bitset operator~(const Bitset& lhs) {
243  return Bitset(~lhs.mData, !lhs.mDefault);
244  }
245  /// Returns the bitwise `and` of lhs and rhs.
246  friend Bitset operator&(const Bitset& lhs, const Bitset& rhs) {
247  alignSize(lhs, rhs);
248  return Bitset(lhs.mData & rhs.mData, lhs.mDefault && rhs.mDefault);
249  }
250  /// Returns the bitwise `or` of lhs and rhs.
251  friend Bitset operator|(const Bitset& lhs, const Bitset& rhs) {
252  alignSize(lhs, rhs);
253  return Bitset(lhs.mData | rhs.mData, lhs.mDefault || rhs.mDefault);
254  }
255 
256  /// Outputs `b` to `os` using the format `<explicit bits>[<default>]`.
257  friend std::ostream& operator<<(std::ostream& os, const Bitset& b) {
258  return os << b.mData << '|' << b.mDefault;
259  }
260  };
261 }
262 
263 namespace std {
264 
265 template<>
266 struct hash<carl::Bitset> {
267  std::size_t operator()(const carl::Bitset& bs) const {
268  return std::hash<carl::Bitset::BaseType>()(bs.mData);
269  }
270 };
271 
272 }
carl is the main namespace for the library.
This class is a simple wrapper around boost::dynamic_bitset.
Definition: Bitset.h:20
static constexpr auto bits_per_block
Number of bits in each storage block.
Definition: Bitset.h:29
friend std::ostream & operator<<(std::ostream &os, const Bitset &b)
Outputs b to os using the format <explicit bits>[<default>].
Definition: Bitset.h:257
auto is_subset_of(const Bitset &rhs) const
Checks wether the bits set is a subset of the bits set in rhs.
Definition: Bitset.h:192
Bitset & operator|=(const Bitset &rhs)
Computes the bitwise or with rhs.
Definition: Bitset.h:133
Bitset(bool defaultValue=false)
Create an empty bitset.
Definition: Bitset.h:100
iterator end() const
Returns an past-the-end iterator.
Definition: Bitset.h:212
friend bool operator==(const Bitset &lhs, const Bitset &rhs)
Compares lhs and rhs.
Definition: Bitset.h:226
Bitset(const std::initializer_list< std::size_t > &bits, bool defaultValue=false)
Create a bitset from a list of bits indices that shall be set to true.
Definition: Bitset.h:104
friend void alignSize(const Bitset &lhs, const Bitset &rhs)
Ensures that the explicitly stored bits of lhs and rhs have the same size.
Definition: Bitset.h:217
bool mDefault
The default value for bits beyond mData.
Definition: Bitset.h:91
bool none() const
Checks if no bits are set to true. Asserts that mDefault is false.
Definition: Bitset.h:172
auto num_blocks() const
Retrieves the number of blocks used to store mData.
Definition: Bitset.h:188
friend Bitset operator~(const Bitset &lhs)
Returns the bitwise negation of lhs.
Definition: Bitset.h:242
friend Bitset operator|(const Bitset &lhs, const Bitset &rhs)
Returns the bitwise or of lhs and rhs.
Definition: Bitset.h:251
std::size_t find_first() const
Retrieves the index of the first bit that is set to true.
Definition: Bitset.h:200
friend bool operator<(const Bitset &lhs, const Bitset &rhs)
Compares lhs and rhs according to some order.
Definition: Bitset.h:231
void ensureSize(std::size_t pos)
Resize mData to hold at least pos bits.
Definition: Bitset.h:93
std::size_t find_next(std::size_t pos) const
Retrieves the index of the first bit set to true after the given position.
Definition: Bitset.h:204
auto resize(std::size_t num_bits, bool value) const
Resize the Bitset to hold at least num_bits bits. New bits are set to the given value.
Definition: Bitset.h:111
Bitset & reset(std::size_t n)
Resets a bit to false.
Definition: Bitset.h:154
Bitset(BaseType &&base, bool defaultValue)
Create a bitset from a BaseType object.
Definition: Bitset.h:102
static constexpr auto npos
Sentinel element for iteration.
Definition: Bitset.h:27
auto resize(std::size_t num_bits) const
Resize the Bitset to hold at least num_bits bits. New bits are set to mDefault.
Definition: Bitset.h:115
auto count() const noexcept
Counts the number of bits that are set to true. Asserts that mDefault is false.
Definition: Bitset.h:178
Bitset & set(std::size_t n, bool value=true)
Sets the given bit to a value, true by default.
Definition: Bitset.h:140
Bitset & operator&=(const Bitset &rhs)
Computes the bitwise and with rhs.
Definition: Bitset.h:127
Bitset & operator-=(const Bitset &rhs)
Sets all bits to false that are true in rhs.
Definition: Bitset.h:120
bool any() const
Checks if any bits are set to true. Asserts that mDefault is false.
Definition: Bitset.h:167
auto size() const
Retrieves the size of mData.
Definition: Bitset.h:184
BaseType mData
The actual data.
Definition: Bitset.h:89
iterator begin() const
Returns an iterator to the first bit that is set to true.
Definition: Bitset.h:208
Bitset & set_interval(std::size_t start, std::size_t end, bool value=true)
Sets the a range of bits to a value, true by default.
Definition: Bitset.h:146
boost::dynamic_bitset<> BaseType
Underlying storage type.
Definition: Bitset.h:25
bool test(std::size_t n) const
Retrieves the value of the given bit.
Definition: Bitset.h:160
friend Bitset operator&(const Bitset &lhs, const Bitset &rhs)
Returns the bitwise and of lhs and rhs.
Definition: Bitset.h:246
Iterate for iterate over all bits of a Bitset that are set to true.
Definition: Bitset.h:36
bool compatible(const iterator &rhs) const
Check that two iterators speak about the same Bitset.
Definition: Bitset.h:44
iterator(const Bitset &b, std::size_t bit)
Construct a new iterator from a Bitset and a bit.
Definition: Bitset.h:49
std::size_t operator*() const
Retrieve the index into the Bitset.
Definition: Bitset.h:56
bool operator!=(const iterator &rhs) const
Compare two iterators. Asserts that they are compatible.
Definition: Bitset.h:76
std::size_t mBit
The current bit.
Definition: Bitset.h:41
bool operator==(const iterator &rhs) const
Compare two iterators. Asserts that they are compatible.
Definition: Bitset.h:71
bool operator<(const iterator &rhs) const
Compare two iterators. Asserts that they are compatible.
Definition: Bitset.h:81
iterator & operator++()
Step to the next bit that is set to true.
Definition: Bitset.h:60
const Bitset & mBitset
The Bitset iterated over.
Definition: Bitset.h:39
iterator operator++(int)
Step to the next bit that is set to true.
Definition: Bitset.h:65
std::size_t operator()(const carl::Bitset &bs) const
Definition: Bitset.h:267