| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef LIB_ESCHER_UTIL_ENUM_FLAGS_H_ |
| #define LIB_ESCHER_UTIL_ENUM_FLAGS_H_ |
| |
| #include "lib/escher/util/enum_utils.h" |
| |
| namespace escher { |
| |
| // Wrapper to allow bitwise operations on the members of an enum class. |
| // TODO(ES-148): write unit tests. |
| template <typename BitT> |
| class EnumFlags { |
| public: |
| using BitType = BitT; |
| using MaskType = typename std::underlying_type<BitT>::type; |
| |
| EnumFlags() : mask_(0) {} |
| EnumFlags(BitType bit) : mask_(static_cast<MaskType>(bit)) {} |
| EnumFlags(const EnumFlags<BitType>& other) : mask_(other.mask_) {} |
| explicit EnumFlags(MaskType flags) : mask_(flags) {} |
| |
| EnumFlags<BitType>& operator=(const EnumFlags<BitType>& other) { |
| mask_ = other.mask_; |
| return *this; |
| } |
| |
| EnumFlags<BitType>& operator&=(const EnumFlags<BitType>& other) { |
| mask_ &= other.mask_; |
| return *this; |
| } |
| |
| EnumFlags<BitType>& operator|=(const EnumFlags<BitType>& other) { |
| mask_ |= other.mask_; |
| return *this; |
| } |
| |
| EnumFlags<BitType>& operator^=(const EnumFlags<BitType>& other) { |
| mask_ ^= other.mask_; |
| return *this; |
| } |
| |
| EnumFlags<BitType> operator&(const EnumFlags<BitType>& other) const { |
| EnumFlags<BitType> result(*this); |
| result &= other; |
| return result; |
| } |
| |
| EnumFlags<BitType> operator|(const EnumFlags<BitType>& other) const { |
| EnumFlags<BitType> result(*this); |
| result |= other; |
| return result; |
| } |
| |
| EnumFlags<BitType> operator^(const EnumFlags<BitType>& other) const { |
| EnumFlags<BitType> result(*this); |
| result ^= other; |
| return result; |
| } |
| |
| EnumFlags<BitType> operator~() const { |
| EnumFlags<BitType> result(*this); |
| result.mask_ ^= EnumCast(BitType::kAllFlags); |
| return result; |
| } |
| |
| bool operator!() const { return mask_ == 0; } |
| |
| bool operator==(const EnumFlags<BitType>& other) const { |
| return mask_ == other.mask_; |
| } |
| |
| bool operator!=(const EnumFlags<BitType>& other) const { |
| return mask_ != other.mask_; |
| } |
| |
| explicit operator bool() const { return mask_ != 0; } |
| explicit operator MaskType() const { return mask_; } |
| |
| private: |
| MaskType mask_; |
| }; |
| |
| template <typename BitT> |
| EnumFlags<BitT> operator&(BitT bit, const EnumFlags<BitT>& flags) { |
| return flags & bit; |
| } |
| |
| template <typename BitT> |
| EnumFlags<BitT> operator|(BitT bit, const EnumFlags<BitT>& flags) { |
| return flags | bit; |
| } |
| |
| template <typename BitT> |
| EnumFlags<BitT> operator^(BitT bit, const EnumFlags<BitT>& flags) { |
| return flags ^ bit; |
| } |
| |
| // Reduce boilerplate by bundling two things that clients always want anyway: |
| // - a more convenient name: e.g. MyFlags instead of EnumFlags<MyFlagBits> |
| // - two inline functions for implicitly going from "Bits" to "Flags". |
| #define ESCHER_DECLARE_ENUM_FLAGS(FLAGS_NAME, BITS_NAME) \ |
| using FLAGS_NAME = EnumFlags<BITS_NAME>; \ |
| inline FLAGS_NAME operator|(BITS_NAME bit1, BITS_NAME bit2) { \ |
| return FLAGS_NAME(bit1) | bit2; \ |
| } \ |
| inline FLAGS_NAME operator~(BITS_NAME bit) { return ~(FLAGS_NAME(bit)); } |
| |
| } // namespace escher |
| |
| #endif // LIB_ESCHER_UTIL_ENUM_FLAGS_H_ |