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/. */
8 * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS allows using a typed enum as bit flags.
11 #ifndef mozilla_TypedEnumBits_h
12 #define mozilla_TypedEnumBits_h
14 #include "mozilla/Attributes.h"
15 #include "mozilla/IntegerTypeTraits.h"
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
24 * if (myFlags & Flags::SOME_PARTICULAR_FLAG) (1)
26 * There are different approaches to solving this. Most of them require
27 * adapting user code. For example, we could implement operator! and have
30 * if (!!(myFlags & Flags::SOME_PARTICULAR_FLAG)) (2)
32 * Or we could supply a IsNonZero() or Any() function returning whether
33 * an enum value is nonzero, and have the user write
35 * if (Any(Flags & Flags::SOME_PARTICULAR_FLAG)) (3)
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.
44 class CastableTypedEnumResult
{
49 explicit constexpr CastableTypedEnumResult(E aValue
) : mValue(aValue
) {}
51 constexpr operator E() const { return mValue
; }
53 template <typename DestinationType
>
54 explicit constexpr operator DestinationType() const {
55 return DestinationType(mValue
);
58 constexpr bool operator!() const { return !bool(mValue
); }
61 #define MOZ_CASTABLETYPEDENUMRESULT_BINOP(Op, OtherType, ReturnType) \
62 template <typename E> \
63 constexpr ReturnType operator Op(const OtherType& aE, \
64 const CastableTypedEnumResult<E>& aR) { \
65 return ReturnType(aE Op OtherType(aR)); \
67 template <typename E> \
68 constexpr ReturnType operator Op(const CastableTypedEnumResult<E>& aR, \
69 const OtherType& aE) { \
70 return ReturnType(OtherType(aR) Op aE); \
72 template <typename E> \
73 constexpr ReturnType operator Op(const CastableTypedEnumResult<E>& aR1, \
74 const CastableTypedEnumResult<E>& aR2) { \
75 return ReturnType(OtherType(aR1) Op OtherType(aR2)); \
78 MOZ_CASTABLETYPEDENUMRESULT_BINOP(|, E
, CastableTypedEnumResult
<E
>)
79 MOZ_CASTABLETYPEDENUMRESULT_BINOP(&, E
, CastableTypedEnumResult
<E
>)
80 MOZ_CASTABLETYPEDENUMRESULT_BINOP(^, E
, CastableTypedEnumResult
<E
>)
81 MOZ_CASTABLETYPEDENUMRESULT_BINOP(==, E
, bool)
82 MOZ_CASTABLETYPEDENUMRESULT_BINOP(!=, E
, bool)
85 constexpr CastableTypedEnumResult
<E
> operator~(
86 const CastableTypedEnumResult
<E
>& aR
) {
87 return CastableTypedEnumResult
<E
>(~(E(aR
)));
90 #define MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(Op) \
91 template <typename E> \
92 E& operator Op(E& aR1, const CastableTypedEnumResult<E>& aR2) { \
93 return aR1 Op E(aR2); \
96 MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(&=)
97 MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(|=)
98 MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP(^=)
100 #undef MOZ_CASTABLETYPEDENUMRESULT_COMPOUND_ASSIGN_OP
102 #undef MOZ_CASTABLETYPEDENUMRESULT_BINOP
105 template <typename E
>
106 struct UnsignedIntegerTypeForEnum
: UnsignedStdintTypeForSize
<sizeof(E
)> {};
107 } // namespace detail
109 } // namespace mozilla
111 #define MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, Op) \
112 inline constexpr mozilla::CastableTypedEnumResult<Name> operator Op( \
114 typedef mozilla::CastableTypedEnumResult<Name> Result; \
115 typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
116 return Result(Name(U(a) Op U(b))); \
119 inline Name& operator Op##=(Name& a, Name b) { return a = a Op b; }
122 * MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS generates standard bitwise operators
123 * for the given enum type. Use this to enable using an enum type as bit-field.
125 #define MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(Name) \
126 MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, |) \
127 MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, &) \
128 MOZ_MAKE_ENUM_CLASS_BINOP_IMPL(Name, ^) \
129 inline constexpr mozilla::CastableTypedEnumResult<Name> operator~(Name a) { \
130 typedef mozilla::CastableTypedEnumResult<Name> Result; \
131 typedef mozilla::detail::UnsignedIntegerTypeForEnum<Name>::Type U; \
132 return Result(Name(~(U(a)))); \
135 #endif // mozilla_TypedEnumBits_h