• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIBBRILLO_BRILLO_ENUM_FLAGS_H_
6 #define LIBBRILLO_BRILLO_ENUM_FLAGS_H_
7 
8 #include <type_traits>
9 
10 // This is a helper for generating type-safe bitwise operators for flags that
11 // are defined by an enumeration.  By default, when a bitwise operation is
12 // performed on two enumerators of an enumeration, the result is the base type
13 // (int), not a value of the enumeration:
14 //
15 // enum SomeEnumOfFlags {
16 //    ONE = 1,
17 //    TWO = 2,
18 //    THREE = 4,
19 //     // etc.
20 // };
21 //
22 //  SomeEnumOfFlags flags = static_cast<SomeEnumOfFlags>(ONE | TWO);
23 //
24 //  By enabling these operators for an enum type:
25 //
26 //  DECLARE_FLAGS_ENUM(SomeEnumOfFlags);
27 //
28 //  The syntax is simplified to:
29 //
30 //  SomeEnumOfFlags flags = ONE | TWO;
31 //
32 //  But the following still does not compile without using a cast (as is
33 //  expected):
34 //
35 //  SomeEnumOfFlags flags = ONE | 2;
36 
37 // This is the macro used to declare that an enum type |ENUM| should have bit-
38 // wise operators defined for it.
39 #define DECLARE_FLAGS_ENUM(ENUM) \
40 template <typename> struct EnumFlagTraitType; \
41 template <> struct EnumFlagTraitType<ENUM> { using EnumFlagType = ENUM; }; \
42 EnumFlagTraitType<ENUM> GetEnumFlagTraitType(ENUM) __attribute__((used));
43 
44 
45 // Setup the templates used to declare that the operators should exist for a
46 // given type T.
47 
48 namespace enum_details {
49 
50 template <typename T>
51 using FlagEnumTraits = decltype(GetEnumFlagTraitType(std::declval<T>()));
52 
53 template <typename T>
54 using Void = void;
55 
56 template <typename T, typename = void>
57 struct IsFlagEnum : std::false_type {};
58 
59 template <typename T>
60 struct IsFlagEnum<T, Void<typename FlagEnumTraits<T>::EnumFlagType>>
61     : std::true_type {};
62 
63 }  // namespace enum_details
64 
65 // The operators themselves, conditional on having been declared that they are
66 // flag-style enums.
67 
68 // T operator~(T&)
69 template <typename T>
70 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
71 operator~(const T& l) {
72   return static_cast<T>(
73       ~static_cast<typename std::underlying_type<T>::type>(l));
74 }
75 
76 // T operator|(T&, T&)
77 template <typename T>
78 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
79 operator|(const T& l, const T& r) {
80   return static_cast<T>(
81              static_cast<typename std::underlying_type<T>::type>(l) |
82              static_cast<typename std::underlying_type<T>::type>(r));
83 }
84 
85 // T operator&(T&, T&)
86 template <typename T>
87 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
88 operator&(const T& l, const T& r) {
89   return static_cast<T>(
90              static_cast<typename std::underlying_type<T>::type>(l) &
91              static_cast<typename std::underlying_type<T>::type>(r));
92 }
93 
94 // T operator^(T&, T&)
95 template <typename T>
96 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
97 operator^(const T& l, const T& r) {
98   return static_cast<T>(static_cast<typename std::underlying_type<T>::type>(l) ^
99                         static_cast<typename std::underlying_type<T>::type>(r));
100 }
101 
102 // T operator|=(T&, T&)
103 template <typename T>
104 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
105 operator|=(T& l, const T& r) {
106   return l = static_cast<T>(
107              static_cast<typename std::underlying_type<T>::type>(l) |
108              static_cast<typename std::underlying_type<T>::type>(r));
109 }
110 
111 // T operator&=(T&, T&)
112 template <typename T>
113 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
114 operator&=(T& l, const T& r) {
115   return l = static_cast<T>(
116              static_cast<typename std::underlying_type<T>::type>(l) &
117              static_cast<typename std::underlying_type<T>::type>(r));
118 }
119 
120 // T operator^=(T&, T&)
121 template <typename T>
122 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
123 operator^=(T& l, const T& r) {
124   return l = static_cast<T>(
125              static_cast<typename std::underlying_type<T>::type>(l) ^
126              static_cast<typename std::underlying_type<T>::type>(r));
127 }
128 
129 #endif  // LIBBRILLO_BRILLO_ENUM_FLAGS_H_
130