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