Home | History | Annotate | Download | only in ADT
      1 //===-- llvm/ADT/BitmaskEnum.h ----------------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLVM_ADT_BITMASKENUM_H
     11 #define LLVM_ADT_BITMASKENUM_H
     12 
     13 #include <cassert>
     14 #include <type_traits>
     15 #include <utility>
     16 
     17 #include "llvm/Support/MathExtras.h"
     18 
     19 /// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can
     20 /// perform bitwise operations on it without putting static_cast everywhere.
     21 ///
     22 /// \code
     23 ///   enum MyEnum {
     24 ///     E1 = 1, E2 = 2, E3 = 4, E4 = 8,
     25 ///     LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4)
     26 ///   };
     27 ///
     28 ///   void Foo() {
     29 ///     MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast!
     30 ///   }
     31 /// \endcode
     32 ///
     33 /// Normally when you do a bitwise operation on an enum value, you get back an
     34 /// instance of the underlying type (e.g. int).  But using this macro, bitwise
     35 /// ops on your enum will return you back instances of the enum.  This is
     36 /// particularly useful for enums which represent a combination of flags.
     37 ///
     38 /// The parameter to LLVM_MARK_AS_BITMASK_ENUM should be the largest individual
     39 /// value in your enum.
     40 ///
     41 /// All of the enum's values must be non-negative.
     42 #define LLVM_MARK_AS_BITMASK_ENUM(LargestValue)                                \
     43   LLVM_BITMASK_LARGEST_ENUMERATOR = LargestValue
     44 
     45 /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used
     46 /// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace.
     47 ///
     48 /// Suppose you have an enum foo::bar::MyEnum.  Before using
     49 /// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put
     50 /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or
     51 /// namespace foo::bar.  This allows the relevant operator overloads to be found
     52 /// by ADL.
     53 ///
     54 /// You don't need to use this macro in namespace llvm; it's done at the bottom
     55 /// of this file.
     56 #define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()                               \
     57   using ::llvm::BitmaskEnumDetail::operator~;                                  \
     58   using ::llvm::BitmaskEnumDetail::operator|;                                  \
     59   using ::llvm::BitmaskEnumDetail::operator&;                                  \
     60   using ::llvm::BitmaskEnumDetail::operator^;                                  \
     61   using ::llvm::BitmaskEnumDetail::operator|=;                                 \
     62   using ::llvm::BitmaskEnumDetail::operator&=;                                 \
     63   /* Force a semicolon at the end of this macro. */                            \
     64   using ::llvm::BitmaskEnumDetail::operator^=
     65 
     66 namespace llvm {
     67 
     68 /// Traits class to determine whether an enum has a
     69 /// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator.
     70 template <typename E, typename Enable = void>
     71 struct is_bitmask_enum : std::false_type {};
     72 
     73 template <typename E>
     74 struct is_bitmask_enum<
     75     E, typename std::enable_if<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >=
     76                                0>::type> : std::true_type {};
     77 namespace BitmaskEnumDetail {
     78 
     79 /// Get a bitmask with 1s in all places up to the high-order bit of E's largest
     80 /// value.
     81 template <typename E> typename std::underlying_type<E>::type Mask() {
     82   // On overflow, NextPowerOf2 returns zero with the type uint64_t, so
     83   // subtracting 1 gives us the mask with all bits set, like we want.
     84   return NextPowerOf2(static_cast<typename std::underlying_type<E>::type>(
     85              E::LLVM_BITMASK_LARGEST_ENUMERATOR)) -
     86          1;
     87 }
     88 
     89 /// Check that Val is in range for E, and return Val cast to E's underlying
     90 /// type.
     91 template <typename E> typename std::underlying_type<E>::type Underlying(E Val) {
     92   auto U = static_cast<typename std::underlying_type<E>::type>(Val);
     93   assert(U >= 0 && "Negative enum values are not allowed.");
     94   assert(U <= Mask<E>() && "Enum value too large (or largest val too small?)");
     95   return U;
     96 }
     97 
     98 template <typename E,
     99           typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
    100 E operator~(E Val) {
    101   return static_cast<E>(~Underlying(Val) & Mask<E>());
    102 }
    103 
    104 template <typename E,
    105           typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
    106 E operator|(E LHS, E RHS) {
    107   return static_cast<E>(Underlying(LHS) | Underlying(RHS));
    108 }
    109 
    110 template <typename E,
    111           typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
    112 E operator&(E LHS, E RHS) {
    113   return static_cast<E>(Underlying(LHS) & Underlying(RHS));
    114 }
    115 
    116 template <typename E,
    117           typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
    118 E operator^(E LHS, E RHS) {
    119   return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));
    120 }
    121 
    122 // |=, &=, and ^= return a reference to LHS, to match the behavior of the
    123 // operators on builtin types.
    124 
    125 template <typename E,
    126           typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
    127 E &operator|=(E &LHS, E RHS) {
    128   LHS = LHS | RHS;
    129   return LHS;
    130 }
    131 
    132 template <typename E,
    133           typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
    134 E &operator&=(E &LHS, E RHS) {
    135   LHS = LHS & RHS;
    136   return LHS;
    137 }
    138 
    139 template <typename E,
    140           typename = typename std::enable_if<is_bitmask_enum<E>::value>::type>
    141 E &operator^=(E &LHS, E RHS) {
    142   LHS = LHS ^ RHS;
    143   return LHS;
    144 }
    145 
    146 } // namespace BitmaskEnumDetail
    147 
    148 // Enable bitmask enums in namespace ::llvm and all nested namespaces.
    149 LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
    150 
    151 } // namespace llvm
    152 
    153 #endif
    154