TypedEnumBits.h (5842B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS allows using a typed enum as bit flags. 9 */ 10 11 #ifndef mozilla_TypedEnumBits_h 12 #define mozilla_TypedEnumBits_h 13 14 #include "mozilla/IntegerTypeTraits.h" 15 16 namespace mozilla { 17 18 /* 19 * The problem that CastableTypedEnumResult aims to solve is that 20 * typed enums are not convertible to bool, and there is no way to make them 21 * be, yet user code wants to be able to write 22 * 23 * if (myFlags & Flags::SOME_PARTICULAR_FLAG) (1) 24 * 25 * There are different approaches to solving this. Most of them require 26 * adapting user code. For example, we could implement operator! and have 27 * the user write 28 * 29 * if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG)) (2) 30 * 31 * Or we could supply a IsNonZero() or Any() function returning whether 32 * an enum value is nonzero, and have the user write 33 * 34 * if (Any(Flags & Flags::SOME_PARTICULAR_FLAG)) (3) 35 * 36 * But instead, we choose to preserve the original user syntax (1) as it 37 * is inherently more readable, and to ease porting existing code to typed 38 * enums. We achieve this by having operator& and other binary bitwise 39 * operators have as return type a class, CastableTypedEnumResult, 40 * that wraps a typed enum but adds bool convertibility. 41 */ 42 template <typename E> 43 class CastableTypedEnumResult { 44 private: 45 const E mValue; 46 47 public: 48 explicit constexpr CastableTypedEnumResult(E aValue) : mValue(aValue) {} 49 50 constexpr operator E() const { return mValue; } 51 52 template <typename DestinationType> 53 explicit constexpr operator DestinationType() const { 54 return DestinationType(mValue); 55 } 56 57 constexpr bool operator!() const { return !bool(mValue); } 58 }; 59 60 #define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \ 61 template <typename E> \ 62 constexpr ReturnType operator Op(const OtherType& aE, \ 63 const CastableTypedEnumResult<E>& aR) { \ 64 return ReturnType(aE Op OtherType(aR)); \ 65 } \ 66 template <typename E> \ 67 constexpr ReturnType operator Op(const CastableTypedEnumResult<E>& aR, \ 68 const OtherType& aE) { \ 69 return ReturnType(OtherType(aR) Op aE); \ 70 } \ 71 template <typename E> \ 72 constexpr ReturnType operator Op(const CastableTypedEnumResult<E>& aR1, \ 73 const CastableTypedEnumResult<E>& aR2) { \ 74 return ReturnType(OtherType(aR1) Op OtherType(aR2)); \ 75 } 76 77 MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult<E>) 78 MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult<E>) 79 MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult<E>) 80 MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool) 81 MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool) 82 83 template <typename E> 84 constexpr CastableTypedEnumResult<E> operator~( 85 const CastableTypedEnumResult<E>& aR) { 86 return CastableTypedEnumResult<E>(~(E(aR))); 87 } 88 89 #define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \ 90 template <typename E> \ 91 E& operator Op(E & aR1, const CastableTypedEnumResult<E>& aR2) { \ 92 return aR1 Op E(aR2); \ 93 } 94 95 MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=) 96 MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=) 97 MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(^=) 98 99 #undef MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP 100 101 #undef MOZ_CASTABLETYPEDENUMRESULT_BINOP 102 103 namespace detail { 104 template <typename E> 105 struct UnsignedIntegerTypeForEnum : UnsignedStdintTypeForSize<sizeof(E)> {}; 106 } // namespace detail 107 108 } // namespace mozilla 109 110 #define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \ 111 inline constexpr mozilla::CastableTypedEnumResult<Name> operator Op( \ 112 Name a, Name b) { \ 113 typedef mozilla::CastableTypedEnumResult<Name> Result; \ 114 typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \ 115 return Result(Name(U(a) Op U(b))); \ 116 } \ 117 \ 118 inline Name& operator Op##=(Name & a, Name b) { return a = a Op b; } 119 120 /** 121 * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators 122 * for the given enum type. Use this to enable using an enum type as bit-field. 123 */ 124 #define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \ 125 MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \ 126 MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \ 127 MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \ 128 inline constexpr mozilla::CastableTypedEnumResult<Name> operator~(Name a) { \ 129 typedef mozilla::CastableTypedEnumResult<Name> Result; \ 130 typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \ 131 return Result(Name(~(U(a)))); \ 132 } 133 134 #endif // mozilla_TypedEnumBits_h