Line data Source code
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/Attributes.h"
15 : #include "mozilla/IntegerTypeTraits.h"
16 :
17 : namespace mozilla {
18 :
19 : /*
20 : * The problem that CastableTypedEnumResult aims to solve is that
21 : * typed enums are not convertible to bool, and there is no way to make them
22 : * be, yet user code wants to be able to write
23 : *
24 : * if (myFlags & Flags::SOME_PARTICULAR_FLAG) (1)
25 : *
26 : * There are different approaches to solving this. Most of them require
27 : * adapting user code. For example, we could implement operator! and have
28 : * the user write
29 : *
30 : * if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG)) (2)
31 : *
32 : * Or we could supply a IsNonZero() or Any() function returning whether
33 : * an enum value is nonzero, and have the user write
34 : *
35 : * if (Any(Flags & Flags::SOME_PARTICULAR_FLAG)) (3)
36 : *
37 : * But instead, we choose to preserve the original user syntax (1) as it
38 : * is inherently more readable, and to ease porting existing code to typed
39 : * enums. We achieve this by having operator& and other binary bitwise
40 : * operators have as return type a class, CastableTypedEnumResult,
41 : * that wraps a typed enum but adds bool convertibility.
42 : */
43 : template<typename E>
44 : class CastableTypedEnumResult
45 : {
46 : private:
47 : const E mValue;
48 :
49 : public:
50 5827187 : explicit constexpr CastableTypedEnumResult(E aValue)
51 5827187 : : mValue(aValue)
52 5827187 : {}
53 :
54 1141773 : constexpr operator E() const { return mValue; }
55 :
56 : template<typename DestinationType>
57 : explicit constexpr
58 4512568 : operator DestinationType() const { return DestinationType(mValue); }
59 :
60 173046 : constexpr bool operator !() const { return !bool(mValue); }
61 : };
62 :
63 : #define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \
64 : template<typename E> \
65 : constexpr ReturnType \
66 : operator Op(const OtherType& aE, const CastableTypedEnumResult<E>& aR) \
67 : { \
68 : return ReturnType(aE Op OtherType(aR)); \
69 : } \
70 : template<typename E> \
71 : constexpr ReturnType \
72 : operator Op(const CastableTypedEnumResult<E>& aR, const OtherType& aE) \
73 : { \
74 : return ReturnType(OtherType(aR) Op aE); \
75 : } \
76 : template<typename E> \
77 : constexpr ReturnType \
78 : operator Op(const CastableTypedEnumResult<E>& aR1, \
79 : const CastableTypedEnumResult<E>& aR2) \
80 : { \
81 : return ReturnType(OtherType(aR1) Op OtherType(aR2)); \
82 : }
83 :
84 142 : MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E, CastableTypedEnumResult<E>)
85 137603 : MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E, CastableTypedEnumResult<E>)
86 : MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E, CastableTypedEnumResult<E>)
87 605 : MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E, bool)
88 146 : MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E, bool)
89 :
90 : template <typename E>
91 : constexpr CastableTypedEnumResult<E>
92 0 : operator ~(const CastableTypedEnumResult<E>& aR)
93 : {
94 0 : return CastableTypedEnumResult<E>(~(E(aR)));
95 : }
96 :
97 : #define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \
98 : template<typename E> \
99 : E& \
100 : operator Op(E& aR1, \
101 : const CastableTypedEnumResult<E>& aR2) \
102 : { \
103 : return aR1 Op E(aR2); \
104 : }
105 :
106 167783 : MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=)
107 53069 : MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=)
108 : MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(^=)
109 :
110 : #undef MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP
111 :
112 : #undef MOZ_CASTABLETYPEDENUMRESULT_BINOP
113 :
114 : namespace detail {
115 : template<typename E>
116 : struct UnsignedIntegerTypeForEnum
117 : : UnsignedStdintTypeForSize<sizeof(E)>
118 : {};
119 : } // namespace detail
120 :
121 : } // namespace mozilla
122 :
123 : #define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \
124 : inline constexpr mozilla::CastableTypedEnumResult<Name> \
125 : operator Op(Name a, Name b) \
126 : { \
127 : typedef mozilla::CastableTypedEnumResult<Name> Result; \
128 : typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
129 : return Result(Name(U(a) Op U(b))); \
130 : } \
131 : \
132 : inline Name& \
133 : operator Op##=(Name& a, Name b) \
134 : { \
135 : return a = a Op b; \
136 : }
137 :
138 : /**
139 : * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators
140 : * for the given enum type. Use this to enable using an enum type as bit-field.
141 : */
142 : #define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \
143 : MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \
144 : MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \
145 : MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \
146 : inline constexpr mozilla::CastableTypedEnumResult<Name> \
147 : operator~(Name a) \
148 : { \
149 : typedef mozilla::CastableTypedEnumResult<Name> Result; \
150 : typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
151 : return Result(Name(~(U(a)))); \
152 : }
153 :
154 : #endif // mozilla_TypedEnumBits_h
|