1 // Copyright 2015 The Android Open Source Project
2 //
3 // This software is licensed under the terms of the GNU General Public
4 // License version 2, as published by the Free Software Foundation, and
5 // may be copied, distributed, and modified under those terms.
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License for more details.
11
12 #pragma once
13
14 #include <type_traits>
15
16 // This header defines some utitily methods to manipulate scoped enums as flags
17 // C++11 scoped enums by default don't support flag operations (e.g. if (a & b))
18 // We need to define bitwise operations for them to be able to have strongly
19 // typed flags in our code.
20 //
21 // To enable the flag operators for your enum, most probably you just need to
22 // include this file. The only exception is if your enum is located in some
23 // namespace other than android, android::base or global. In that case you also
24 // need to add the following using to bring in the operators:
25 //
26 // using namespace ::android::base::EnumFlags;
27
28 namespace android {
29 namespace base {
30 namespace EnumFlags {
31
32 // A predicate which checks if template agument is a scoped enum
33 template<class E>
34 using is_scoped_enum = std::integral_constant<
35 bool,
36 std::is_enum<E>::value && !std::is_convertible<E, int>::value>;
37
38 template <class E>
39 using underlying_enum_type = typename std::underlying_type<E>::type;
40
41 template <class E, class Res = E>
42 using enable_if_scoped_enum =
43 typename std::enable_if<is_scoped_enum<E>::value, Res>::type;
44
45 template <class E>
46 enable_if_scoped_enum<E> operator|(E l, E r) {
47 return static_cast<E>(static_cast<underlying_enum_type<E>>(l)
48 | static_cast<underlying_enum_type<E>>(r));
49 }
50
51 template <class E>
52 enable_if_scoped_enum<E> operator&(E l, E r) {
53 return static_cast<E>(static_cast<underlying_enum_type<E>>(l)
54 & static_cast<underlying_enum_type<E>>(r));
55 }
56
57 template <class E>
58 enable_if_scoped_enum<E> operator~(E e) {
59 return static_cast<E>(~static_cast<underlying_enum_type<E>>(e));
60 }
61
62 template <class E>
63 enable_if_scoped_enum<E> operator|=(E& l, E r) {
64 return l = (l | r);
65 }
66
67 template <class E>
68 enable_if_scoped_enum<E> operator&=(E& l, E r) {
69 return l = (l & r);
70 }
71
72 template <class E>
73 enable_if_scoped_enum<E, bool> operator!(E e) {
74 return !static_cast<underlying_enum_type<E>>(e);
75 }
76
77 template <class E>
78 enable_if_scoped_enum<E, bool> operator!=(E e, int val) {
79 return static_cast<underlying_enum_type<E>>(e) !=
80 static_cast<underlying_enum_type<E>>(val);
81 }
82
83 template <class E>
84 enable_if_scoped_enum<E, bool> operator!=(int val, E e) {
85 return e != val;
86 }
87
88 template <class E>
89 enable_if_scoped_enum<E, bool> operator==(E e, int val) {
90 return static_cast<underlying_enum_type<E>>(e) ==
91 static_cast<underlying_enum_type<E>>(val);
92 }
93
94 template <class E>
95 enable_if_scoped_enum<E, bool> operator==(int val, E e) {
96 return e == val;
97 }
98
99 template <class E>
nonzero(E e)100 enable_if_scoped_enum<E, bool> nonzero(E e) {
101 return static_cast<underlying_enum_type<E>>(e) != 0;
102 }
103
104 } // namespace EnumFlags
105
106 // For the ADL to kick in let's make sure we bring all the operators into our
107 // main AndroidEmu namespaces...
108 using namespace ::android::base::EnumFlags;
109
110 } // namespace base
111
112 using namespace ::android::base::EnumFlags;
113
114 } // namespace android
115
116 // ... and into the global one, where most of the client functions are
117 using namespace ::android::base::EnumFlags;
118