// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_UTIL_ENUM_H namespace ircd { inline namespace util { // For conforming enums include a _NUM_ as the last element, // then num_of() works template constexpr typename std::underlying_type::type num_of() noexcept { return static_cast::type>(Enum::_NUM_); } // Iteration of a num_of() conforming enum template typename std::enable_if::value, void>::type for_each(const std::function &func) { for(size_t i(0); i < num_of(); ++i) func(static_cast(i)); } /** * flag-enum utilities * * This relaxes the strong typing of enums to allow bitflags with operations on the elements * with intuitive behavior. * * If the project desires absolute guarantees on the strong enum typing then this can be tucked * away in some namespace and imported into select scopes instead. */ template constexpr typename std::enable_if::value, Enum>::type operator~(const Enum &a) noexcept { using enum_t = typename std::underlying_type::type; return static_cast(~static_cast(a)); } template constexpr typename std::enable_if::value, bool>::type operator!(const Enum &a) noexcept { using enum_t = typename std::underlying_type::type; return !static_cast(a); } template constexpr typename std::enable_if::value, Enum>::type operator|(const Enum &a, const Enum &b) noexcept { using enum_t = typename std::underlying_type::type; return static_cast(static_cast(a) | static_cast(b)); } template constexpr typename std::enable_if::value, Enum>::type operator&(const Enum &a, const Enum &b) noexcept { using enum_t = typename std::underlying_type::type; return static_cast(static_cast(a) & static_cast(b)); } template constexpr typename std::enable_if::value, Enum>::type operator^(const Enum &a, const Enum &b) noexcept { using enum_t = typename std::underlying_type::type; return static_cast(static_cast(a) ^ static_cast(b)); } template constexpr typename std::enable_if::value, Enum &>::type operator|=(Enum &a, const Enum &b) noexcept { using enum_t = typename std::underlying_type::type; return (a = (a | b)); } template constexpr typename std::enable_if::value, Enum &>::type operator&=(Enum &a, const Enum &b) noexcept { using enum_t = typename std::underlying_type::type; return (a = (a & b)); } template constexpr typename std::enable_if::value, Enum &>::type operator^=(Enum &a, const Enum &b) noexcept { using enum_t = typename std::underlying_type::type; return (a = (a ^ b)); } template typename std::enable_if::value, typename std::underlying_type::type>::type combine_flags(const it &begin, const it &end) noexcept { using type = typename std::underlying_type::type; return std::accumulate(begin, end, type(0), [] (auto ret, const auto &val) { return ret |= type(val); }); } template typename std::enable_if::value, typename std::underlying_type::type>::type combine_flags(const std::initializer_list &list) noexcept { return combine_flags(begin(list), end(list)); } } // namespace util } // namespace ircd