aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Stoelp <johannes.stoelp@gmail.com>2024-03-26 21:47:29 +0100
committerJohannes Stoelp <johannes.stoelp@gmail.com>2024-03-26 21:47:29 +0100
commita15db74027fde75efef34f391d2a458bf64001d0 (patch)
tree6d0dbed3bcc8dad7cb8301382eab27c4540a79c5
parentd483452fc2ccaba5de26303a449fe5bd2ea1dc18 (diff)
downloadcpp-utils-a15db74027fde75efef34f391d2a458bf64001d0.tar.gz
cpp-utils-a15db74027fde75efef34f391d2a458bf64001d0.zip
bitset: initial state, play with fold expr
-rw-r--r--bitset.h99
-rw-r--r--test/bitset.cc88
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