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/Support/MathExtras.h" 17 18 /// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can 19 /// perform bitwise operations on it without putting static_cast everywhere. 20 /// 21 /// \code 22 /// enum MyEnum { 23 /// E1 = 1, E2 = 2, E3 = 4, E4 = 8, 24 /// LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4) 25 /// }; 26 /// 27 /// void Foo() { 28 /// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast! 29 /// } 30 /// \endcode 31 /// 32 /// Normally when you do a bitwise operation on an enum value, you get back an 33 /// instance of the underlying type (e.g. int). But using this macro, bitwise 34 /// ops on your enum will return you back instances of the enum. This is 35 /// particularly useful for enums which represent a combination of flags. 36 /// 37 /// The parameter to LLVM_MARK_AS_BITMASK_ENUM should be the largest individual 38 /// value in your enum. 39 /// 40 /// All of the enum's values must be non-negative. 41 #define LLVM_MARK_AS_BITMASK_ENUM(LargestValue) \ 42 LLVM_BITMASK_LARGEST_ENUMERATOR = LargestValue 43 44 /// LLVM_DECLARE_ENUM_AS_BITMASK can be used to declare an enum type as a bit 45 /// set, so that bitwise operation on such enum does not require static_cast. 46 /// 47 /// \code 48 /// enum MyEnum { E1 = 1, E2 = 2, E3 = 4, E4 = 8 }; 49 /// LLVM_DECLARE_ENUM_AS_BITMASK(MyEnum, E4); 50 /// 51 /// void Foo() { 52 /// MyEnum A = (E1 | E2) & E3 ^ ~E4; // No static_cast 53 /// } 54 /// \endcode 55 /// 56 /// The second parameter to LLVM_DECLARE_ENUM_AS_BITMASK specifies the largest 57 /// bit value of the enum type. 58 /// 59 /// LLVM_DECLARE_ENUM_AS_BITMASK should be used in llvm namespace. 60 /// 61 /// This a non-intrusive alternative for LLVM_MARK_AS_BITMASK_ENUM. It allows 62 /// declaring more than one non-scoped enumerations as bitmask types in the same 63 /// scope. Otherwise it provides the same functionality as 64 /// LLVM_MARK_AS_BITMASK_ENUM. 65 #define LLVM_DECLARE_ENUM_AS_BITMASK(Enum, LargestValue) \ 66 template <> struct is_bitmask_enum<Enum> : std::true_type {}; \ 67 template <> struct largest_bitmask_enum_bit<Enum> { \ 68 static constexpr std::underlying_type_t<Enum> value = LargestValue; \ 69 } 70 71 /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used 72 /// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace. 73 /// 74 /// Suppose you have an enum foo::bar::MyEnum. Before using 75 /// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put 76 /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or 77 /// namespace foo::bar. This allows the relevant operator overloads to be found 78 /// by ADL. 79 /// 80 /// You don't need to use this macro in namespace llvm; it's done at the bottom 81 /// of this file. 82 #define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() \ 83 using ::llvm::BitmaskEnumDetail::operator~; \ 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 /* Force a semicolon at the end of this macro. */ \ 90 using ::llvm::BitmaskEnumDetail::operator^= 91 92 namespace llvm { 93 94 /// Traits class to determine whether an enum has a 95 /// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator. 96 template <typename E, typename Enable = void> 97 struct is_bitmask_enum : std::false_type {}; 98 99 template <typename E> 100 struct is_bitmask_enum< 101 E, std::enable_if_t<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= 0>> 102 : std::true_type {}; 103 104 /// Trait class to determine bitmask enumeration largest bit. 105 template <typename E, typename Enable = void> struct largest_bitmask_enum_bit; 106 107 template <typename E> 108 struct largest_bitmask_enum_bit< 109 E, std::enable_if_t<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= 0>> { 110 using UnderlyingTy = std::underlying_type_t<E>; 111 static constexpr UnderlyingTy value = 112 static_cast<UnderlyingTy>(E::LLVM_BITMASK_LARGEST_ENUMERATOR); 113 }; 114 115 namespace BitmaskEnumDetail { 116 117 /// Get a bitmask with 1s in all places up to the high-order bit of E's largest 118 /// value. 119 template <typename E> constexpr std::underlying_type_t<E> Mask() { 120 // On overflow, NextPowerOf2 returns zero with the type uint64_t, so 121 // subtracting 1 gives us the mask with all bits set, like we want. 122 return NextPowerOf2(largest_bitmask_enum_bit<E>::value) - 1; 123 } 124 125 /// Check that Val is in range for E, and return Val cast to E's underlying 126 /// type. 127 template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) { 128 auto U = static_cast<std::underlying_type_t<E>>(Val); 129 assert(U >= 0 && "Negative enum values are not allowed."); 130 assert(U <= Mask<E>() && "Enum value too large (or largest val too small?)"); 131 return U; 132 } 133 134 constexpr unsigned bitWidth(uint64_t Value) { 135 return Value ? 1 + bitWidth(Value >> 1) : 0; 136 } 137 138 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 139 constexpr E operator~(E Val) { 140 return static_cast<E>(~Underlying(Val) & Mask<E>()); 141 } 142 143 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 144 constexpr E operator|(E LHS, E RHS) { 145 return static_cast<E>(Underlying(LHS) | Underlying(RHS)); 146 } 147 148 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 149 constexpr E operator&(E LHS, E RHS) { 150 return static_cast<E>(Underlying(LHS) & Underlying(RHS)); 151 } 152 153 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 154 constexpr E operator^(E LHS, E RHS) { 155 return static_cast<E>(Underlying(LHS) ^ Underlying(RHS)); 156 } 157 158 // |=, &=, and ^= return a reference to LHS, to match the behavior of the 159 // operators on builtin types. 160 161 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 162 E &operator|=(E &LHS, E RHS) { 163 LHS = LHS | RHS; 164 return LHS; 165 } 166 167 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 168 E &operator&=(E &LHS, E RHS) { 169 LHS = LHS & RHS; 170 return LHS; 171 } 172 173 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 174 E &operator^=(E &LHS, E RHS) { 175 LHS = LHS ^ RHS; 176 return LHS; 177 } 178 179 } // namespace BitmaskEnumDetail 180 181 // Enable bitmask enums in namespace ::llvm and all nested namespaces. 182 LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); 183 template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 184 constexpr unsigned BitWidth = BitmaskEnumDetail::bitWidth(uint64_t{ 185 static_cast<std::underlying_type_t<E>>( 186 E::LLVM_BITMASK_LARGEST_ENUMERATOR)}); 187 188 } // namespace llvm 189 190 #endif 191