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