diff options
Diffstat (limited to 'src/flag_set.hpp')
-rw-r--r-- | src/flag_set.hpp | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/flag_set.hpp b/src/flag_set.hpp new file mode 100644 index 00000000..7960de42 --- /dev/null +++ b/src/flag_set.hpp @@ -0,0 +1,201 @@ +#pragma once + +#include <array> +#include <cassert> +#include <cstdint> + +#include "tome/pp/global_constexpr.hpp" + +/** + * Set of binary flags. + */ +template<std::size_t Tiers> struct flag_set +{ +private: + static constexpr std::size_t tiers = Tiers; + std::uint32_t m_data[tiers]; + +public: + static constexpr const std::size_t nbits = tiers * 32; + +public: + + constexpr flag_set() + : m_data { 0 } + { + // It is *extremely* important that there are absolutely + // NO dependencies on any global objects in here; lest we + // fall into SIOF territory; see DECLARE_FLAG_ZERO_IMPL + } + + // This method is a workaround for a a segmentation fault + // when compiling with GCC 5.3.0 (Arch Linux). We should be + // able to use make() directly in DECLARE_FLAG_MAKE_INIT, + // but GCC segfaults. + template<std::uint32_t tier, std::size_t index> static constexpr flag_set make_static() + { + static_assert(tier < tiers, "tier >= tiers"); + static_assert(index < 32, "index >= 32"); + flag_set f; + f.m_data[tier] = (1UL << index); + return f; + } + + static constexpr flag_set make(std::uint32_t tier, std::size_t index) + { + assert(tier < tiers); + assert(index < 32); + flag_set f; + f.m_data[tier] = (1UL << index); + return f; + } + + static constexpr flag_set make_bit(std::size_t ibit) + { + assert(ibit < nbits); + flag_set f; + f.m_data[ibit / 32] = (1UL << (ibit % 32)); + return f; + } + + constexpr std::size_t size() const + { + return tiers; + } + + constexpr bool empty() const + { + for (std::size_t i = 0; i < tiers; i++) + { + if (m_data[i]) + { + return false; + } + } + return true; + } + + constexpr std::size_t count() const + { + std::size_t n = 0; + for (std::size_t i = 0; i < nbits; i++) + { + if (bit(i)) + { + n += 1; + } + } + return n; + } + + uint32_t &operator[](std::size_t i) + { + assert(i < tiers); + return m_data[i]; + } + + constexpr uint32_t const &operator [](std::size_t i) const + { + assert(i < tiers); + return m_data[i]; + } + + explicit constexpr operator bool() const + { + return !empty(); + } + + constexpr bool operator == (flag_set const &other) const + { + for (std::size_t i = 0; i < tiers; i++) + { + if (m_data[i] != other.m_data[i]) + { + return false; + } + } + return true; + } + + constexpr bool operator != (flag_set const &other) const + { + return !(*this == other); + } + + constexpr bool bit(std::size_t i) const + { + assert(i < nbits); + return (m_data[i / 32] & (1UL << (i % 32))); + } + + flag_set &operator |= (flag_set const &other) + { + for (std::size_t i = 0; i < tiers; i++) + { + m_data[i] |= other.m_data[i]; + } + return *this; + } + + constexpr flag_set operator | (flag_set const &other) const + { + flag_set f; + for (std::size_t i = 0; i < tiers; i++) + { + f.m_data[i] = m_data[i] | other.m_data[i]; + } + return f; + } + + flag_set &operator &= (flag_set const &other) + { + for (std::size_t i = 0; i < tiers; i++) + { + m_data[i] &= other.m_data[i]; + } + return *this; + } + + constexpr flag_set operator & (flag_set const &other) const + { + flag_set f; + for (std::size_t i = 0; i < tiers; i++) + { + f.m_data[i] = m_data[i] & other.m_data[i]; + } + return f; + } + + constexpr flag_set operator ~ () const + { + flag_set f; + for (std::size_t i = 0; i < tiers; i++) + { + f.m_data[i] = ~m_data[i]; + } + return f; + } + +}; + +// Implementation details, because preprocessor. +#define DECLARE_FLAG_MAKE_INIT(type, tier, index) \ + type::make_static<tier-1,index>() + +/** + * Macro for declaring a "flag" constant. + */ +#define DECLARE_FLAG(type, name, tier, index) \ + PP_GLOBAL_CONSTEXPR_CONST(type, name, DECLARE_FLAG_MAKE_INIT(type, tier, index)) + +/** + * Macro for declaring a zero'ed "flag" variable. + */ +#define DECLARE_FLAG_ZERO_INTF(type, name) \ + extern type name + +/** + * Macro for declaring the implementation of a zero'ed "flag" variable. + */ +#define DECLARE_FLAG_ZERO_IMPL(type, name) \ + type name { }; |