diff options
-rw-r--r-- | bitset.h | 99 | ||||
-rw-r--r-- | test/bitset.cc | 88 |
2 files changed, 187 insertions, 0 deletions
diff --git a/bitset.h b/bitset.h new file mode 100644 index 0000000..638a126 --- /dev/null +++ b/bitset.h @@ -0,0 +1,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 diff --git a/test/bitset.cc b/test/bitset.cc new file mode 100644 index 0000000..755a79c --- /dev/null +++ b/test/bitset.cc @@ -0,0 +1,88 @@ +#if __cplusplus >= 201703L +#include <bitset.h> + +enum bits { a, b, c, d }; + +int main() { + { + bitset<bits> t; + assert(t.is_empty()); + assert(!t.is_set(a)); + assert(!t.is_set(b)); + assert(!t.is_set(c)); + assert(!t.is_set(d)); + } + { + bitset<bits> t(b); + assert(!t.is_empty()); + assert(!t.is_set(a)); + assert(t.is_set(b)); + assert(!t.is_set(c)); + assert(!t.is_set(d)); + } + { + bitset<bits> t(a, c); + assert(!t.is_empty()); + assert(t.is_set(a)); + assert(!t.is_set(b)); + assert(t.is_set(c)); + assert(!t.is_set(d)); + } + { + bitset<bits> t; + t.set(b, d); + assert(!t.is_empty()); + assert(!t.is_set(a)); + assert(t.is_set(b)); + assert(!t.is_set(c)); + assert(t.is_set(d)); + t.set(c); + assert(!t.is_empty()); + assert(!t.is_set(a)); + assert(t.is_set(b)); + assert(t.is_set(c)); + assert(t.is_set(d)); + + t.unset(); + assert(!t.is_empty()); + t.unset(b, d); + assert(!t.is_empty()); + assert(!t.is_set(a)); + assert(!t.is_set(b)); + assert(t.is_set(c)); + assert(!t.is_set(d)); + t.unset(c); + assert(t.is_empty()); + assert(!t.is_set(a)); + assert(!t.is_set(b)); + assert(!t.is_set(c)); + assert(!t.is_set(d)); + } + { + bitset<bits> t; + t.set(a, b, d); + assert(!t.any()); + assert(!t.any(c)); + assert(t.any(a)); + assert(t.any(a, c)); + assert(t.any(a, b)); + } + { + bitset<bits> t; + t.set(a, b, d); + assert(!t.all()); + assert(!t.all(c)); + assert(t.all(a)); + assert(!t.all(a, c)); + assert(t.all(a, b)); + assert(t.all(a, b, d)); + assert(!t.all(a, b, c, d)); + } + return 0; +} +#else +#include <cstdio> +int main() { + puts("[bitset]: not built with >cpp17"); +} +#endif |