1 //===-- llvm/ADT/BitmaskEnum.h ----------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_ADT_BITMASKENUM_H 10 #define LLVM_ADT_BITMASKENUM_H 11 12 #include <cassert> 13 #include <type_traits> 14 #include <utility> 15 16 #include "llvm/ADT/STLForwardCompat.h" 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_DECLARE_ENUM_AS_BITMASK can be used to declare an enum type as a bit 46 /// set, so that bitwise operation on such enum does not require static_cast. 47 /// 48 /// \code 49 /// enum MyEnum { E1 = 1, E2 = 2, E3 = 4, E4 = 8 }; 50 /// LLVM_DECLARE_ENUM_AS_BITMASK(MyEnum, E4); 51 /// 52 /// void Foo() { 53 /// MyEnum A = (E1 | E2) & E3 ^ ~E4; // No static_cast 54 /// } 55 /// \endcode 56 /// 57 /// The second parameter to LLVM_DECLARE_ENUM_AS_BITMASK specifies the largest 58 /// bit value of the enum type. 59 /// 60 /// LLVM_DECLARE_ENUM_AS_BITMASK should be used in llvm namespace. 61 /// 62 /// This a non-intrusive alternative for LLVM_MARK_AS_BITMASK_ENUM. It allows 63 /// declaring more than one non-scoped enumerations as bitmask types in the same 64 /// scope. Otherwise it provides the same functionality as 65 /// LLVM_MARK_AS_BITMASK_ENUM. 66 #define LLVM_DECLARE_ENUM_AS_BITMASK(Enum, LargestValue) \ 67 template <> struct is_bitmask_enum<Enum> : std::true_type {}; \ 68 template <> struct largest_bitmask_enum_bit<Enum> { \ 69 static constexpr std::underlying_type_t<Enum> value = LargestValue; \ 70 } 71 72 /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used 73 /// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace. 74 /// 75 /// Suppose you have an enum foo::bar::MyEnum. Before using 76 /// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put 77 /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or 78 /// namespace foo::bar. This allows the relevant operator overloads to be found 79 /// by ADL. 80 /// 81 /// You don't need to use this macro in namespace llvm; it's done at the bottom 82 /// of this file. 83 #define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() \ 84 using ::llvm::BitmaskEnumDetail::operator~; \ 85 using ::llvm::BitmaskEnumDetail::operator|; \ 86 using ::llvm::BitmaskEnumDetail::operator&; \ 87 using ::llvm::BitmaskEnumDetail::operator^; \ 88 using ::llvm::BitmaskEnumDetail::operator|=; \ 89 using ::llvm::BitmaskEnumDetail::operator&=; \ 90 using ::llvm::BitmaskEnumDetail::operator^=; \ 91 /* Force a semicolon at the end of this macro. */ \ 92 using ::llvm::BitmaskEnumDetail::any 93 94 namespace llvm { 95 96 /// Traits class to determine whether an enum has a 97 /// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator. 98 template <typename E, typename Enable = void> 99 struct is_bitmask_enum : std::false_type {}; 100 101 template <typename E> 102 struct is_bitmask_enum< 103 E, std::enable_if_t<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= 0>> 104 : std::true_type {}; 105 106 /// Trait class to determine bitmask enumeration largest bit. 107 template <typename E, typename Enable = void> struct largest_bitmask_enum_bit; 108 109 template <typename E> 110 struct largest_bitmask_enum_bit< 111 E, std::enable_if_t<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= 0>> { 112 using UnderlyingTy = std::underlying_type_t<E>; 113 static constexpr UnderlyingTy value = 114 static_cast<UnderlyingTy>(E::LLVM_BITMASK_LARGEST_ENUMERATOR); 115 }; 116 117 namespace BitmaskEnumDetail { 118 119 /// Get a bitmask with 1s in all places up to the high-order bit of E's largest 120 /// value. 121 template <typename E> constexpr std::underlying_type_t<E> Mask() { 122 // On overflow, NextPowerOf2 returns zero with the type uint64_t, so 123 // subtracting 1 gives us the mask with all bits set, like we want. 124 return NextPowerOf2(largest_bitmask_enum_bit<E>::value) - 1; 125 } 126 127 /// Check that Val is in range for E, and return Val cast to E's underlying 128 /// type. 129 template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) { 130 auto U = llvm::to_underlying(Val); 131 assert(U >= 0 && "Negative enum values are not allowed."); 132 assert(U <= Mask<E>() && "Enum value too large (or largest val too small?)"); 133 return U; 134 } 135 136 constexpr unsigned bitWidth(uint64_t Value) { 137 return Value ? 1 + bitWidth(Value >> 1) : 0; 138 } 139 140 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 141 constexpr bool any(E Val) { 142 return Val != static_cast<E>(0); 143 } 144 145 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 146 constexpr E operator~(E Val) { 147 return static_cast<E>(~Underlying(Val) & Mask<E>()); 148 } 149 150 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 151 constexpr E operator|(E LHS, E RHS) { 152 return static_cast<E>(Underlying(LHS) | Underlying(RHS)); 153 } 154 155 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 156 constexpr E operator&(E LHS, E RHS) { 157 return static_cast<E>(Underlying(LHS) & Underlying(RHS)); 158 } 159 160 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 161 constexpr E operator^(E LHS, E RHS) { 162 return static_cast<E>(Underlying(LHS) ^ Underlying(RHS)); 163 } 164 165 // |=, &=, and ^= return a reference to LHS, to match the behavior of the 166 // operators on builtin types. 167 168 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 169 E &operator|=(E &LHS, E RHS) { 170 LHS = LHS | RHS; 171 return LHS; 172 } 173 174 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 175 E &operator&=(E &LHS, E RHS) { 176 LHS = LHS & RHS; 177 return LHS; 178 } 179 180 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 181 E &operator^=(E &LHS, E RHS) { 182 LHS = LHS ^ RHS; 183 return LHS; 184 } 185 186 } // namespace BitmaskEnumDetail 187 188 // Enable bitmask enums in namespace ::llvm and all nested namespaces. 189 LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); 190 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 191 constexpr unsigned BitWidth = BitmaskEnumDetail::bitWidth( 192 uint64_t{llvm::to_underlying(E::LLVM_BITMASK_LARGEST_ENUMERATOR)}); 193 194 } // namespace llvm 195 196 #endif 197