Path: blob/main/contrib/llvm-project/compiler-rt/lib/orc/bitmask_enum.h
39566 views
//===---- bitmask_enum.h - Enable bitmask operations on enums ---*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of the ORC runtime support library.9//10//===----------------------------------------------------------------------===//1112#ifndef ORC_RT_BITMASK_ENUM_H13#define ORC_RT_BITMASK_ENUM_H1415#include "stl_extras.h"1617#include <cassert>18#include <type_traits>1920namespace __orc_rt {2122/// ORC_RT_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you23/// can perform bitwise operations on it without putting static_cast everywhere.24///25/// \code26/// enum MyEnum {27/// E1 = 1, E2 = 2, E3 = 4, E4 = 8,28/// ORC_RT_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4)29/// };30///31/// void Foo() {32/// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast!33/// }34/// \endcode35///36/// Normally when you do a bitwise operation on an enum value, you get back an37/// instance of the underlying type (e.g. int). But using this macro, bitwise38/// ops on your enum will return you back instances of the enum. This is39/// particularly useful for enums which represent a combination of flags.40///41/// The parameter to ORC_RT_MARK_AS_BITMASK_ENUM should be the largest42/// individual value in your enum.43///44/// All of the enum's values must be non-negative.45#define ORC_RT_MARK_AS_BITMASK_ENUM(LargestValue) \46ORC_RT_BITMASK_LARGEST_ENUMERATOR = LargestValue4748/// ORC_RT_DECLARE_ENUM_AS_BITMASK can be used to declare an enum type as a bit49/// set, so that bitwise operation on such enum does not require static_cast.50///51/// \code52/// enum MyEnum { E1 = 1, E2 = 2, E3 = 4, E4 = 8 };53/// ORC_RT_DECLARE_ENUM_AS_BITMASK(MyEnum, E4);54///55/// void Foo() {56/// MyEnum A = (E1 | E2) & E3 ^ ~E4; // No static_cast57/// }58/// \endcode59///60/// The second parameter to ORC_RT_DECLARE_ENUM_AS_BITMASK specifies the largest61/// bit value of the enum type.62///63/// ORC_RT_DECLARE_ENUM_AS_BITMASK should be used in __orc_rt namespace.64///65/// This a non-intrusive alternative for ORC_RT_MARK_AS_BITMASK_ENUM. It allows66/// declaring more than one non-scoped enumerations as bitmask types in the same67/// scope. Otherwise it provides the same functionality as68/// ORC_RT_MARK_AS_BITMASK_ENUM.69#define ORC_RT_DECLARE_ENUM_AS_BITMASK(Enum, LargestValue) \70template <> struct is_bitmask_enum<Enum> : std::true_type {}; \71template <> struct largest_bitmask_enum_bit<Enum> { \72static constexpr std::underlying_type_t<Enum> value = LargestValue; \73}7475/// Traits class to determine whether an enum has been declared as a bitwise76/// enum via ORC_RT_DECLARE_ENUM_AS_BITMASK.77template <typename E, typename Enable = void>78struct is_bitmask_enum : std::false_type {};7980template <typename E>81struct is_bitmask_enum<82E, std::enable_if_t<sizeof(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR) >= 0>>83: std::true_type {};8485template <typename E>86inline constexpr bool is_bitmask_enum_v = is_bitmask_enum<E>::value;8788/// Traits class to deermine bitmask enum largest bit.89template <typename E, typename Enable = void> struct largest_bitmask_enum_bit;9091template <typename E>92struct largest_bitmask_enum_bit<93E, std::enable_if_t<sizeof(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR) >= 0>> {94using UnderlyingTy = std::underlying_type_t<E>;95static constexpr UnderlyingTy value =96static_cast<UnderlyingTy>(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR);97};9899template <typename E> constexpr std::underlying_type_t<E> Mask() {100return bit_ceil(largest_bitmask_enum_bit<E>::value) - 1;101}102103template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) {104auto U = static_cast<std::underlying_type_t<E>>(Val);105assert(U >= 0 && "Negative enum values are not allowed");106assert(U <= Mask<E>() && "Enum value too large (or langest val too small");107return U;108}109110template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>111constexpr E operator~(E Val) {112return static_cast<E>(~Underlying(Val) & Mask<E>());113}114115template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>116constexpr E operator|(E LHS, E RHS) {117return static_cast<E>(Underlying(LHS) | Underlying(RHS));118}119120template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>121constexpr E operator&(E LHS, E RHS) {122return static_cast<E>(Underlying(LHS) & Underlying(RHS));123}124125template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>126constexpr E operator^(E LHS, E RHS) {127return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));128}129130template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>131E &operator|=(E &LHS, E RHS) {132LHS = LHS | RHS;133return LHS;134}135136template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>137E &operator&=(E &LHS, E RHS) {138LHS = LHS & RHS;139return LHS;140}141142template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>143E &operator^=(E &LHS, E RHS) {144LHS = LHS ^ RHS;145return LHS;146}147148} // end namespace __orc_rt149150#endif // ORC_RT_BITMASK_ENUM_H151152153