From e2eaf43b4ab88327c5511fabe4910823d7965de6 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 13 Mar 2022 17:26:29 -0700 Subject: [PATCH] [util] Add templated bitset class Add a new bitset class which allows for arbitrarily-large bit sets, with specializations for 32 and 64 bit sets. Eventually the enum_bitfields code should probably be reconsidered and moved to bitsets, since it doesn't work everywhere. --- src/libraries/util/util/bitset.h | 168 +++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 src/libraries/util/util/bitset.h diff --git a/src/libraries/util/util/bitset.h b/src/libraries/util/util/bitset.h new file mode 100644 index 0000000..756310f --- /dev/null +++ b/src/libraries/util/util/bitset.h @@ -0,0 +1,168 @@ +#pragma once +/// \file bitset.h +/// Definition of the `bitset` template class + +#if __has_include() +#include +#else +#define assert(...) +#endif + +#include + + +namespace util { + +/// A statically-sized templated bitset +template +class bitset +{ + static constexpr unsigned num_elems = (N + 63) / 64; + +public: + template + inline bool get(T i) const { + assert(static_cast(i) < N); + return bits(i) & bit(i); + } + + template + inline bitset & set(T i) { + assert(static_cast(i) < N); + bits(i) |= bit(i); + return *this; + } + + template + inline bitset & clear(T i) { + assert(static_cast(i) < N); + bits(i) &= ~bit(i); + return *this; + } + + template + inline bool operator[](T i) const { return get(i); } + + inline bool empty() const { + for (uint64_t i = 0; i < num_elems; ++i) + if (m_bits[i]) return false; + return true; + } + +private: + template + inline uint64_t bit(T i) const { return (1ull << (static_cast(i) & 63)); } + + template + inline uint64_t &bits(T i) { return m_bits[static_cast(i) >> 6]; } + + template + inline uint64_t bits(T i) const { return m_bits[static_cast(i) >> 6]; } + + uint64_t m_bits[num_elems] = {0}; +}; + +/// A statically-sized templated bitset +template <> +class bitset<64> +{ + static constexpr unsigned num_elems = 1; + +public: + bitset(uint64_t v = 0) : m_bits {v} {} + + bitset(const bitset<64> &o) : m_bits {o.m_bits} {} + + template + inline bitset & operator=(T v) { m_bits = static_cast(v); return *this; } + + inline operator uint64_t () const { return m_bits; } + + template + inline bool get(T i) const { + assert(static_cast(i) < 64); + return m_bits & bit(i); + } + + template + inline bitset & set(T i) { + assert(static_cast(i) < 64); + m_bits |= bit(i); + return *this; + } + + template + inline bitset & clear(T i) { + assert(static_cast(i) < 64); + m_bits &= ~bit(i); + return *this; + } + + template + inline bool operator[](T i) const { return get(i); } + + inline bool empty() const { return m_bits == 0; } + + inline uint64_t value() const { return m_bits; } + +private: + template + inline uint64_t bit(T i) const { return (1ull << static_cast(i)); } + + uint64_t m_bits; +}; + +/// A statically-sized templated bitset +template <> +class bitset<32> +{ + static constexpr unsigned num_elems = 1; + +public: + bitset(uint32_t v = 0) : m_bits {v} {} + + bitset(const bitset<32> &o) : m_bits {o.m_bits} {} + + template + inline bitset & operator=(T v) { m_bits = static_cast(v); return *this; } + + inline operator uint32_t () const { return m_bits; } + + template + inline bool get(T i) const { + assert(static_cast(i) < 32); + return m_bits & bit(i); + } + + template + inline bitset & set(T i) { + assert(static_cast(i) < 32); + m_bits |= bit(i); + return *this; + } + + template + inline bitset & clear(T i) { + assert(static_cast(i) < 32); + m_bits &= ~bit(i); + return *this; + } + + template + inline bool operator[](T i) const { return get(i); } + + inline bool empty() const { return m_bits == 0; } + + inline uint32_t value() const { return m_bits; } + +private: + template + inline uint32_t bit(T i) const { return (1u << static_cast(i)); } + + uint32_t m_bits; +}; + +using bitset64 = bitset<64>; +using bitset32 = bitset<32>; + +} // namespace util