10b57cec5SDimitry Andric //===-- llvm/ADT/BitmaskEnum.h ----------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #ifndef LLVM_ADT_BITMASKENUM_H 100b57cec5SDimitry Andric #define LLVM_ADT_BITMASKENUM_H 110b57cec5SDimitry Andric 120b57cec5SDimitry Andric #include <cassert> 130b57cec5SDimitry Andric #include <type_traits> 140b57cec5SDimitry Andric #include <utility> 150b57cec5SDimitry Andric 165f757f3fSDimitry Andric #include "llvm/ADT/STLForwardCompat.h" 170b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric /// LLVM_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you can 200b57cec5SDimitry Andric /// perform bitwise operations on it without putting static_cast everywhere. 210b57cec5SDimitry Andric /// 220b57cec5SDimitry Andric /// \code 230b57cec5SDimitry Andric /// enum MyEnum { 240b57cec5SDimitry Andric /// E1 = 1, E2 = 2, E3 = 4, E4 = 8, 250b57cec5SDimitry Andric /// LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4) 260b57cec5SDimitry Andric /// }; 270b57cec5SDimitry Andric /// 280b57cec5SDimitry Andric /// void Foo() { 290b57cec5SDimitry Andric /// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast! 300b57cec5SDimitry Andric /// } 310b57cec5SDimitry Andric /// \endcode 320b57cec5SDimitry Andric /// 330b57cec5SDimitry Andric /// Normally when you do a bitwise operation on an enum value, you get back an 340b57cec5SDimitry Andric /// instance of the underlying type (e.g. int). But using this macro, bitwise 350b57cec5SDimitry Andric /// ops on your enum will return you back instances of the enum. This is 360b57cec5SDimitry Andric /// particularly useful for enums which represent a combination of flags. 370b57cec5SDimitry Andric /// 380b57cec5SDimitry Andric /// The parameter to LLVM_MARK_AS_BITMASK_ENUM should be the largest individual 390b57cec5SDimitry Andric /// value in your enum. 400b57cec5SDimitry Andric /// 410b57cec5SDimitry Andric /// All of the enum's values must be non-negative. 420b57cec5SDimitry Andric #define LLVM_MARK_AS_BITMASK_ENUM(LargestValue) \ 430b57cec5SDimitry Andric LLVM_BITMASK_LARGEST_ENUMERATOR = LargestValue 440b57cec5SDimitry Andric 4506c3fb27SDimitry Andric /// LLVM_DECLARE_ENUM_AS_BITMASK can be used to declare an enum type as a bit 4606c3fb27SDimitry Andric /// set, so that bitwise operation on such enum does not require static_cast. 4706c3fb27SDimitry Andric /// 4806c3fb27SDimitry Andric /// \code 4906c3fb27SDimitry Andric /// enum MyEnum { E1 = 1, E2 = 2, E3 = 4, E4 = 8 }; 5006c3fb27SDimitry Andric /// LLVM_DECLARE_ENUM_AS_BITMASK(MyEnum, E4); 5106c3fb27SDimitry Andric /// 5206c3fb27SDimitry Andric /// void Foo() { 5306c3fb27SDimitry Andric /// MyEnum A = (E1 | E2) & E3 ^ ~E4; // No static_cast 5406c3fb27SDimitry Andric /// } 5506c3fb27SDimitry Andric /// \endcode 5606c3fb27SDimitry Andric /// 5706c3fb27SDimitry Andric /// The second parameter to LLVM_DECLARE_ENUM_AS_BITMASK specifies the largest 5806c3fb27SDimitry Andric /// bit value of the enum type. 5906c3fb27SDimitry Andric /// 6006c3fb27SDimitry Andric /// LLVM_DECLARE_ENUM_AS_BITMASK should be used in llvm namespace. 6106c3fb27SDimitry Andric /// 6206c3fb27SDimitry Andric /// This a non-intrusive alternative for LLVM_MARK_AS_BITMASK_ENUM. It allows 6306c3fb27SDimitry Andric /// declaring more than one non-scoped enumerations as bitmask types in the same 6406c3fb27SDimitry Andric /// scope. Otherwise it provides the same functionality as 6506c3fb27SDimitry Andric /// LLVM_MARK_AS_BITMASK_ENUM. 6606c3fb27SDimitry Andric #define LLVM_DECLARE_ENUM_AS_BITMASK(Enum, LargestValue) \ 6706c3fb27SDimitry Andric template <> struct is_bitmask_enum<Enum> : std::true_type {}; \ 6806c3fb27SDimitry Andric template <> struct largest_bitmask_enum_bit<Enum> { \ 6906c3fb27SDimitry Andric static constexpr std::underlying_type_t<Enum> value = LargestValue; \ 7006c3fb27SDimitry Andric } 7106c3fb27SDimitry Andric 720b57cec5SDimitry Andric /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() pulls the operator overloads used 730b57cec5SDimitry Andric /// by LLVM_MARK_AS_BITMASK_ENUM into the current namespace. 740b57cec5SDimitry Andric /// 750b57cec5SDimitry Andric /// Suppose you have an enum foo::bar::MyEnum. Before using 760b57cec5SDimitry Andric /// LLVM_MARK_AS_BITMASK_ENUM on MyEnum, you must put 770b57cec5SDimitry Andric /// LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() somewhere inside namespace foo or 780b57cec5SDimitry Andric /// namespace foo::bar. This allows the relevant operator overloads to be found 790b57cec5SDimitry Andric /// by ADL. 800b57cec5SDimitry Andric /// 810b57cec5SDimitry Andric /// You don't need to use this macro in namespace llvm; it's done at the bottom 820b57cec5SDimitry Andric /// of this file. 830b57cec5SDimitry Andric #define LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE() \ 840b57cec5SDimitry Andric using ::llvm::BitmaskEnumDetail::operator~; \ 850b57cec5SDimitry Andric using ::llvm::BitmaskEnumDetail::operator|; \ 860b57cec5SDimitry Andric using ::llvm::BitmaskEnumDetail::operator&; \ 870b57cec5SDimitry Andric using ::llvm::BitmaskEnumDetail::operator^; \ 880b57cec5SDimitry Andric using ::llvm::BitmaskEnumDetail::operator|=; \ 890b57cec5SDimitry Andric using ::llvm::BitmaskEnumDetail::operator&=; \ 905f757f3fSDimitry Andric using ::llvm::BitmaskEnumDetail::operator^=; \ 910b57cec5SDimitry Andric /* Force a semicolon at the end of this macro. */ \ 925f757f3fSDimitry Andric using ::llvm::BitmaskEnumDetail::any 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric namespace llvm { 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric /// Traits class to determine whether an enum has a 970b57cec5SDimitry Andric /// LLVM_BITMASK_LARGEST_ENUMERATOR enumerator. 980b57cec5SDimitry Andric template <typename E, typename Enable = void> 990b57cec5SDimitry Andric struct is_bitmask_enum : std::false_type {}; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric template <typename E> 1020b57cec5SDimitry Andric struct is_bitmask_enum< 1035ffd83dbSDimitry Andric E, std::enable_if_t<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= 0>> 1045ffd83dbSDimitry Andric : std::true_type {}; 10506c3fb27SDimitry Andric 10606c3fb27SDimitry Andric /// Trait class to determine bitmask enumeration largest bit. 10706c3fb27SDimitry Andric template <typename E, typename Enable = void> struct largest_bitmask_enum_bit; 10806c3fb27SDimitry Andric 10906c3fb27SDimitry Andric template <typename E> 11006c3fb27SDimitry Andric struct largest_bitmask_enum_bit< 11106c3fb27SDimitry Andric E, std::enable_if_t<sizeof(E::LLVM_BITMASK_LARGEST_ENUMERATOR) >= 0>> { 11206c3fb27SDimitry Andric using UnderlyingTy = std::underlying_type_t<E>; 11306c3fb27SDimitry Andric static constexpr UnderlyingTy value = 11406c3fb27SDimitry Andric static_cast<UnderlyingTy>(E::LLVM_BITMASK_LARGEST_ENUMERATOR); 11506c3fb27SDimitry Andric }; 11606c3fb27SDimitry Andric 1170b57cec5SDimitry Andric namespace BitmaskEnumDetail { 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric /// Get a bitmask with 1s in all places up to the high-order bit of E's largest 1200b57cec5SDimitry Andric /// value. 12181ad6265SDimitry Andric template <typename E> constexpr std::underlying_type_t<E> Mask() { 1220b57cec5SDimitry Andric // On overflow, NextPowerOf2 returns zero with the type uint64_t, so 1230b57cec5SDimitry Andric // subtracting 1 gives us the mask with all bits set, like we want. 12406c3fb27SDimitry Andric return NextPowerOf2(largest_bitmask_enum_bit<E>::value) - 1; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric /// Check that Val is in range for E, and return Val cast to E's underlying 1280b57cec5SDimitry Andric /// type. 12981ad6265SDimitry Andric template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) { 1305f757f3fSDimitry Andric auto U = llvm::to_underlying(Val); 1310b57cec5SDimitry Andric assert(U >= 0 && "Negative enum values are not allowed."); 1320b57cec5SDimitry Andric assert(U <= Mask<E>() && "Enum value too large (or largest val too small?)"); 1330b57cec5SDimitry Andric return U; 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric 1365ffd83dbSDimitry Andric constexpr unsigned bitWidth(uint64_t Value) { 1375ffd83dbSDimitry Andric return Value ? 1 + bitWidth(Value >> 1) : 0; 1385ffd83dbSDimitry Andric } 1395ffd83dbSDimitry Andric 1405ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 1415f757f3fSDimitry Andric constexpr bool any(E Val) { 1425f757f3fSDimitry Andric return Val != static_cast<E>(0); 1435f757f3fSDimitry Andric } 1445f757f3fSDimitry Andric 1455f757f3fSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 14681ad6265SDimitry Andric constexpr E operator~(E Val) { 1470b57cec5SDimitry Andric return static_cast<E>(~Underlying(Val) & Mask<E>()); 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric 1505ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 15181ad6265SDimitry Andric constexpr E operator|(E LHS, E RHS) { 1520b57cec5SDimitry Andric return static_cast<E>(Underlying(LHS) | Underlying(RHS)); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric 1555ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 15681ad6265SDimitry Andric constexpr E operator&(E LHS, E RHS) { 1570b57cec5SDimitry Andric return static_cast<E>(Underlying(LHS) & Underlying(RHS)); 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1605ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 16181ad6265SDimitry Andric constexpr E operator^(E LHS, E RHS) { 1620b57cec5SDimitry Andric return static_cast<E>(Underlying(LHS) ^ Underlying(RHS)); 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric // |=, &=, and ^= return a reference to LHS, to match the behavior of the 1660b57cec5SDimitry Andric // operators on builtin types. 1670b57cec5SDimitry Andric 1685ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 1690b57cec5SDimitry Andric E &operator|=(E &LHS, E RHS) { 1700b57cec5SDimitry Andric LHS = LHS | RHS; 1710b57cec5SDimitry Andric return LHS; 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1745ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 1750b57cec5SDimitry Andric E &operator&=(E &LHS, E RHS) { 1760b57cec5SDimitry Andric LHS = LHS & RHS; 1770b57cec5SDimitry Andric return LHS; 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric 1805ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 1810b57cec5SDimitry Andric E &operator^=(E &LHS, E RHS) { 1820b57cec5SDimitry Andric LHS = LHS ^ RHS; 1830b57cec5SDimitry Andric return LHS; 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric } // namespace BitmaskEnumDetail 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric // Enable bitmask enums in namespace ::llvm and all nested namespaces. 1890b57cec5SDimitry Andric LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); 1905ffd83dbSDimitry Andric template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>> 1915f757f3fSDimitry Andric constexpr unsigned BitWidth = BitmaskEnumDetail::bitWidth( 1925f757f3fSDimitry Andric uint64_t{llvm::to_underlying(E::LLVM_BITMASK_LARGEST_ENUMERATOR)}); 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric } // namespace llvm 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric #endif 197