diff options
author | Bardur Arantsson <bardur@scientician.net> | 2016-03-29 20:32:55 +0200 |
---|---|---|
committer | Bardur Arantsson <bardur@scientician.net> | 2016-03-29 20:32:55 +0200 |
commit | c8df88d8c61197d8f019efa0ba373ed14a28d914 (patch) | |
tree | 75335e7c9d0784ec4fa267c1a85f42e68100484c /src/flag_set.hpp | |
parent | 1a8a922f380a6401972f57beae602f3e8eca37e7 (diff) |
Introduce new way of handling flags
Diffstat (limited to 'src/flag_set.hpp')
-rw-r--r-- | src/flag_set.hpp | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/flag_set.hpp b/src/flag_set.hpp new file mode 100644 index 00000000..cbc4e7aa --- /dev/null +++ b/src/flag_set.hpp @@ -0,0 +1,144 @@ +#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: + + 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; + } + + 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; + } + + 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]; + } + + constexpr operator bool() const + { + return !empty(); + } + + 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; + } + +}; + +// 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 { }; |