• Home
  • 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>> : std::true_type {};
61 
62 }  // namespace enum_details
63 
64 // The operators themselves, conditional on having been declared that they are
65 // flag-style enums.
66 
67 // T operator~(T&)
68 template <typename T>
69 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
70 operator~(const T& l) {
71   return static_cast<T>( ~static_cast<typename std::underlying_type<T>::type>(l));
72 }
73 
74 // T operator|(T&, T&)
75 template <typename T>
76 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
77 operator|(const T& l, const T& r) {
78   return static_cast<T>(
79              static_cast<typename std::underlying_type<T>::type>(l) |
80              static_cast<typename std::underlying_type<T>::type>(r));
81 }
82 
83 // T operator&(T&, T&)
84 template <typename T>
85 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
86 operator&(const T& l, const T& r) {
87   return static_cast<T>(
88              static_cast<typename std::underlying_type<T>::type>(l) &
89              static_cast<typename std::underlying_type<T>::type>(r));
90 }
91 
92 // T operator^(T&, T&)
93 template <typename T>
94 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type operator^(
95     const T& l, const T& r) {
96   return static_cast<T>(static_cast<typename std::underlying_type<T>::type>(l) ^
97                         static_cast<typename std::underlying_type<T>::type>(r));
98 };
99 
100 // T operator|=(T&, T&)
101 template <typename T>
102 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type operator|=(
103     T& l, const T& r) {
104   return l = static_cast<T>(
105              static_cast<typename std::underlying_type<T>::type>(l) |
106              static_cast<typename std::underlying_type<T>::type>(r));
107 };
108 
109 // T operator&=(T&, T&)
110 template <typename T>
111 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type operator&=(
112     T& l, const T& r) {
113   return l = static_cast<T>(
114              static_cast<typename std::underlying_type<T>::type>(l) &
115              static_cast<typename std::underlying_type<T>::type>(r));
116 };
117 
118 // T operator^=(T&, T&)
119 template <typename T>
120 constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type operator^=(
121     T& l, const T& r) {
122   return l = static_cast<T>(
123              static_cast<typename std::underlying_type<T>::type>(l) ^
124              static_cast<typename std::underlying_type<T>::type>(r));
125 };
126 
127 #endif  // LIBBRILLO_BRILLO_ENUM_FLAGS_H_
128