From c8df88d8c61197d8f019efa0ba373ed14a28d914 Mon Sep 17 00:00:00 2001 From: Bardur Arantsson Date: Tue, 29 Mar 2016 20:32:55 +0200 Subject: Introduce new way of handling flags --- src/CMakeLists.txt | 1 + src/flag_set.hpp | 144 +++++++++++++++++++++++++++++++ src/include/tome/pp/global_constexpr.hpp | 21 +++++ 3 files changed, 166 insertions(+) create mode 100644 src/flag_set.hpp create mode 100644 src/include/tome/pp/global_constexpr.hpp (limited to 'src') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6d942dfe..a68e056b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -118,6 +118,7 @@ SET(SRCS_TESTS ../tests/get_level_device.cc ../tests/harness.cc ../tests/lua_get_level.cc + ../tests/flag_set.cc ) ADD_LIBRARY(game 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 +#include +#include + +#include "tome/pp/global_constexpr.hpp" + +/** + * Set of binary flags. + */ +template 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 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() + +/** + * 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 { }; diff --git a/src/include/tome/pp/global_constexpr.hpp b/src/include/tome/pp/global_constexpr.hpp new file mode 100644 index 00000000..83168c59 --- /dev/null +++ b/src/include/tome/pp/global_constexpr.hpp @@ -0,0 +1,21 @@ +#pragma once + +/** + * Macro for declaring a global constexpr variable without + * violating the ODR and without running into the SIOF. + * + * Shamelessly cribbed from http://stackoverflow.com/a/20374473 + */ +#define PP_GLOBAL_CONSTEXPR_CONST(type, var, value) \ +namespace global_constexpr { namespace var { \ +template \ +struct wrapper \ +{ \ + static constexpr type var = value; \ +}; \ +template \ +constexpr type wrapper::var; \ +} } \ +namespace { \ +auto const& var = global_constexpr::var::wrapper<>::var; \ +} -- cgit v1.2.3