Home | History | Annotate | Download | only in brillo
      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