BitSet.h
Go to the documentation of this file.
1 /****
2  * Sming Framework Project - Open Source framework for high efficiency native ESP8266 development.
3  * Created 2015 by Skurydin Alexey
4  * http://github.com/SmingHub/Sming
5  * All files of the Sming Core are provided under the LGPL v3 license.
6  *
7  * BitSet.h - Strongly typed sets of values
8  *
9  * @author: 2020 - Mikee47 <mike@sillyhouse.net>
10  *
11  ****/
12 
13 #pragma once
14 
15 #include <cstddef>
16 #include <cstdint>
17 #include <limits>
18 #include <type_traits>
19 #include <WString.h>
20 
43 template <typename S, typename E, size_t size_ = sizeof(S) * 8> class BitSet
44 {
45 public:
46  static_assert(std::is_integral<S>::value && std::is_unsigned<S>::value,
47  "BitSet requires an unsigned integral storage type");
48  static_assert(std::is_enum<E>::value || (std::is_integral<E>::value && std::is_unsigned<E>::value),
49  "BitSets may use only enum or unsigned integral type elements");
50  static_assert(size_ > 0, "BitSet size cannot be zero!");
51  static_assert(size_ <= (sizeof(S) * 8), "BitSet has too many elements for storage type");
52 
53  class BitRef
54  {
55  public:
56  operator bool() const
57  {
58  return bitset.test(e);
59  }
60 
61  BitRef& operator=(bool b)
62  {
63  bitset.set(e, b);
64  return *this;
65  }
66 
67  private:
68  friend BitSet;
69  BitRef(BitSet& bitset, E e) : bitset(bitset), e(e)
70  {
71  }
72 
73  BitSet& bitset;
74  E e;
75  };
76 
80  constexpr BitSet() = default;
81 
86  template <typename S2> constexpr BitSet(const BitSet<S2, E>& bitset) : bitSetValue(bitset.value())
87  {
88  }
89 
94  constexpr BitSet(S value) : bitSetValue(value)
95  {
96  }
97 
102  constexpr BitSet(E e) : bitSetValue{bitVal(e)}
103  {
104  }
105 
109  bool operator==(const BitSet& other) const
110  {
111  return bitSetValue == other.bitSetValue;
112  }
113 
117  bool operator!=(const BitSet& other) const
118  {
119  return bitSetValue != other.bitSetValue;
120  }
121 
125  constexpr BitSet operator~() const
126  {
127  return BitSet(~bitSetValue & domain().bitSetValue);
128  }
129 
133  static constexpr size_t size()
134  {
135  return size_;
136  }
137 
141  static constexpr BitSet domain()
142  {
143  return std::numeric_limits<S>::max() >> ((sizeof(S) * 8) - size_);
144  }
145 
149  static constexpr S bitVal(E e)
150  {
151  return S{1U} << unsigned(e);
152  }
153 
158  {
159  bitSetValue = ~bitSetValue & domain().bitSetValue;
160  return *this;
161  }
162 
166  BitSet& flip(E e)
167  {
168  bitSetValue ^= bitVal(e);
169  return *this;
170  }
171 
175  size_t count() const
176  {
177  return __builtin_popcount(bitSetValue);
178  }
179 
183  BitSet& operator+=(const BitSet& rhs)
184  {
185  bitSetValue |= rhs.bitSetValue;
186  return *this;
187  }
188 
192  BitSet& operator-=(const BitSet& rhs)
193  {
194  bitSetValue &= ~rhs.bitSetValue;
195  return *this;
196  }
197 
201  BitSet& operator&=(const BitSet& rhs)
202  {
203  bitSetValue &= rhs.bitSetValue;
204  return *this;
205  }
206 
210  BitSet& operator|=(const BitSet& rhs)
211  {
212  bitSetValue |= rhs.bitSetValue;
213  return *this;
214  }
215 
219  BitSet& operator^=(const BitSet& rhs)
220  {
221  bitSetValue ^= rhs.bitSetValue;
222  return *this;
223  }
224 
228  bool test(E e) const
229  {
230  return (bitSetValue & bitVal(e)) != 0;
231  }
232 
238  bool operator[](E e) const
239  {
240  return test(e);
241  }
242 
250  BitRef operator[](E e)
251  {
252  return BitRef{*this, e};
253  }
254 
258  bool any() const
259  {
260  return bitSetValue != 0;
261  }
262 
267  bool any(const BitSet& other) const
268  {
269  return (bitSetValue & other.bitSetValue) != 0;
270  }
271 
275  bool all() const
276  {
277  return bitSetValue == domain().bitSetValue;
278  }
279 
283  bool none() const
284  {
285  return bitSetValue == S{0};
286  }
287 
291  BitSet& set()
292  {
293  bitSetValue = domain().bitSetValue;
294  return *this;
295  }
296 
302  BitSet& set(E e, bool state = true)
303  {
304  if(state) {
305  bitSetValue |= bitVal(e);
306  } else {
307  bitSetValue &= ~bitVal(e);
308  }
309  return *this;
310  }
311 
316  {
317  bitSetValue = S{0};
318  return *this;
319  }
320 
324  BitSet& reset(E e)
325  {
326  return set(e, false);
327  }
328 
332  bool operator==(E e) const
333  {
334  return bitSetValue == bitVal(e);
335  }
336 
340  explicit constexpr operator S() const
341  {
342  return bitSetValue;
343  }
344 
348  constexpr S value() const
349  {
350  return bitSetValue;
351  }
352 
353  /*
354  * use a function pointer to allow for "if (s)" without the
355  * complications of an operator bool(). for more information,
356  * see: http://www.artima.com/cppsource/safebool.html
357  */
358  using IfHelperType = void (BitSet::*)() const;
359 
360  /*
361  * Provides safe bool() operator
362  * Evaluates as false if set is empty
363  */
364  operator IfHelperType() const
365  {
366  return any() ? &BitSet::IfHelper : 0;
367  }
368 
369 private:
370  void IfHelper() const
371  {
372  }
373 
374  S bitSetValue{0};
375 };
376 
377 template <typename S, typename E, size_t size_>
379 {
380  return BitSet<S, E, size_>(S(x) & S(y));
381 }
382 
383 template <typename S, typename E, size_t size_>
385 {
386  return BitSet<S, E, size_>(S(x) | S(y));
387 }
388 
389 template <typename S, typename E, size_t size_>
391 {
392  return x | BitSet<S, E, size_>(b);
393 }
394 
395 template <typename S, typename E, size_t size_>
397 {
398  return x | y;
399 }
400 
401 template <typename S, typename E, size_t size_>
403 {
404  return BitSet<S, E, size_>(S(x) & ~S(y));
405 }
406 
407 template <typename S, typename E, size_t size_>
408 inline constexpr BitSet<S, E, size_> operator+(const BitSet<S, E, size_>& x, E b)
409 {
410  return x | b;
411 }
412 
413 template <typename S, typename E, size_t size_>
414 inline constexpr BitSet<S, E, size_> operator-(const BitSet<S, E, size_>& x, E b)
415 {
417 }
418 
419 template <typename S, typename E, size_t size_>
421 {
422  return BitSet<S, E, size_>(S(x) ^ S(y));
423 }
424 
425 template <typename S, typename E, size_t size_>
427 {
428  return x ^ BitSet<S, E, size_>(b);
429 }
430 
431 /*
432  * These allow construction of a maximally-sized BitSet in an expression,
433  * which is then copy-constructed to the actual value. For example:
434  *
435  * constexpr BitSet<uint8_t, Fruit> fixedBasket = Fruit::apple | Fruit::orange;
436  *
437  * `is_convertible` prevents match to regular enums or integral values, but allows enum class.
438  *
439  */
440 template <typename E>
441 constexpr
442  typename std::enable_if<std::is_enum<E>::value && !std::is_convertible<E, int>::value, BitSet<uint32_t, E>>::type
443  operator|(E a, E b)
444 {
446 }
447 
448 template <typename E>
449 constexpr
450  typename std::enable_if<std::is_enum<E>::value && !std::is_convertible<E, int>::value, BitSet<uint32_t, E>>::type
451  operator+(E a, E b)
452 {
453  return a | b;
454 }
455 
456 template <typename T> typename std::enable_if<std::is_integral<T>::value, String>::type toString(T value)
457 {
458  return String(value);
459 }
460 
465 template <typename S, typename E, size_t size_>
466 String toString(const BitSet<S, E, size_>& bitset, const String& separator = ", ")
467 {
468  extern String toString(E e);
469 
470  String s = String::empty;
471 
472  for(unsigned i = 0; i < bitset.size(); ++i) {
473  if(!bitset[E(i)]) {
474  continue;
475  }
476 
477  if(s.length() != 0) {
478  s += separator;
479  }
480  s += toString(E(i));
481  }
482 
483  return s;
484 }
485 
std::enable_if< std::is_integral< T >::value, String >::type toString(T value)
Definition: BitSet.h:456
constexpr BitSet(S value)
Construct from a raw set of bits.
Definition: BitSet.h:94
bool operator==(E e) const
Determine if set consists of only the one given element.
Definition: BitSet.h:332
static const String empty
An empty string evaluates to true.
Definition: WString.h:149
bool operator[](E e) const
Read-only [] operator.
Definition: BitSet.h:238
BitSet & flip()
Flip all bits in the set.
Definition: BitSet.h:157
constexpr BitSet< S, E, size_ > operator &(const BitSet< S, E, size_ > &x, const BitSet< S, E, size_ > &y)
Definition: BitSet.h:378
BitSet & operator+=(const BitSet &rhs)
Union: Add elements to set.
Definition: BitSet.h:183
constexpr BitSet(E e)
Construct set containing a single value.
Definition: BitSet.h:102
constexpr S value() const
Get stored bits for this bitset.
Definition: BitSet.h:348
BitSet & reset(E e)
Clear the state of the given bit (i.e. remove it from the set)
Definition: BitSet.h:324
static constexpr size_t size()
Get the number of possible elements in the set.
Definition: BitSet.h:133
static constexpr S bitVal(E e)
Get the bitmask corresponding to a given value.
Definition: BitSet.h:149
bool none() const
Test if set is empty.
Definition: BitSet.h:283
constexpr BitSet< S, E, size_ > operator^(BitSet< S, E, size_ > x, BitSet< S, E, size_ > y)
Definition: BitSet.h:420
The String class.
Definition: WString.h:136
BitSet & operator|=(const BitSet &rhs)
Union: Add elements to set.
Definition: BitSet.h:210
void(BitSet::*)() const IfHelperType
Definition: BitSet.h:358
static constexpr BitSet domain()
Get the set of all possible values.
Definition: BitSet.h:141
size_t length(void) const
Obtain the String length in characters, excluding NUL terminator.
Definition: WString.h:237
bool operator==(const BitSet &other) const
Compare this set with another for equality.
Definition: BitSet.h:109
Definition: BitSet.h:53
BitSet & operator^=(const BitSet &rhs)
XOR - toggle state of bits using another set.
Definition: BitSet.h:219
BitRef & operator=(bool b)
Definition: BitSet.h:61
constexpr BitSet< S, E, size_ > operator-(const BitSet< S, E, size_ > &x, const BitSet< S, E, size_ > &y)
Definition: BitSet.h:402
constexpr BitSet< S, E, size_ > operator+(const BitSet< S, E, size_ > &x, const BitSet< S, E, size_ > &y)
Definition: BitSet.h:396
size_t count() const
Get the number of elements in the set, i.e. bits set to 1.
Definition: BitSet.h:175
Manage a set of bit values using enumeration.
Definition: BitSet.h:43
BitSet & set()
Add all possible values to the bit set.
Definition: BitSet.h:291
bool any() const
Determine if set contains any values.
Definition: BitSet.h:258
BitRef operator[](E e)
Read/write [] operator.
Definition: BitSet.h:250
bool all() const
Test if set contains all possible values.
Definition: BitSet.h:275
BitSet & operator-=(const BitSet &rhs)
Remove elements from set.
Definition: BitSet.h:192
constexpr BitSet< S, E, size_ > operator|(BitSet< S, E, size_ > x, BitSet< S, E, size_ > y)
Definition: BitSet.h:384
BitSet & operator &=(const BitSet &rhs)
Intersection: Leave only elements common to both sets.
Definition: BitSet.h:201
BitSet & reset()
Remove all values from the set.
Definition: BitSet.h:315
bool operator!=(const BitSet &other) const
Compare this set with another for inequality.
Definition: BitSet.h:117
constexpr BitSet operator~() const
Obtain a set containing all elements not in this one.
Definition: BitSet.h:125
BitSet & flip(E e)
Flip state of the given bit.
Definition: BitSet.h:166
bool test(E e) const
Test to see if given element is in the set.
Definition: BitSet.h:228
constexpr BitSet(const BitSet< S2, E > &bitset)
Copy constructor.
Definition: BitSet.h:86
bool any(const BitSet &other) const
Determine if set contains any values from another set i.e. intersection != [].
Definition: BitSet.h:267