aboutsummaryrefslogtreecommitdiff
path: root/bitset.h
blob: 638a126353c73a58f3e0606dd53bba6a94dcd9ff (plain) (blame)
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
#ifndef UTILS_BITSET_H
#define UTILS_BITSET_H

#include <cassert>
#include <type_traits>

// -- BITSET -------------------------------------------------------------------

/// bitset
///
/// A simple bitset type, to experiment with with c++17 fold expressions and
/// type checked template argument packs.
///
/// Typically a bitset<> is created from an enum holding the bits of interest.
///
/// ```
/// enum mybits { x, y, z };
///
/// bitset<mybits> b;
///
/// b.set(x, y)
/// assert(b.is_set(x));
/// assert(b.any(x,z));
/// assert(!b.all(x,z));
/// ```
template <typename Bits>
struct bitset {
  using bits_t = std::underlying_type_t<Bits>;

  // -- CONSTRUCTOR ------------------------------------------------------------

  template <typename... Bit>
  constexpr explicit bitset(Bit... bit) {
    (set(bit), ...);
  }

  // -- SET/UNSET --------------------------------------------------------------

  template <typename... Bit>
  void set(Bit... bit) {
    (op<Bit>([&]() { set(bit); }), ...);
  }

  void set(Bits v) {
    m_val |= shifted(v);
  }

  template <typename... Bit>
  void unset(Bit... bit) {
    (op<Bit>([&]() { unset(bit); }), ...);
  }

  void unset(Bits v) {
    m_val &= ~shifted(v);
  }

  void clear() {
    m_val = 0;
  }

  // -- QUERY ------------------------------------------------------------------

  constexpr bool is_empty() const {
    return m_val == 0;
  }

  constexpr bool is_set(Bits v) const {
    return m_val & shifted(v);
  }

  template <typename... Bit>
  constexpr bool any(Bit... bit) const {
    return (is_set(bit) || ...);
  }

  template <typename... Bit>
  constexpr bool all(Bit... bit) const {
    return sizeof...(Bit) == 0 ? false : (is_set(bit) && ...);
  }

  // -- INTERNAL ---------------------------------------------------------------

 private:
  constexpr static bits_t shifted(Bits bit) {
    assert(0 <= bit && bit < static_cast<bits_t>(sizeof(bits_t) * 8));
    return static_cast<bits_t>(1) << bit;
  }

  template <typename T, typename F>
  static constexpr auto op(F&& f) -> decltype(f()) {
    static_assert(std::is_same_v<Bits, T>);
    return f();
  }

 private:
  bits_t m_val = 0;
};

#endif