[libc] Switch to using the generic `<gpuintrin.h>` implementations (#121810)
[llvm-project.git] / compiler-rt / lib / orc / bitmask_enum.h
blob77f4ca6b0fd691584f8d48e038120be750e691ec
1 //===---- bitmask_enum.h - Enable bitmask operations on enums ---*- 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 // This file is a part of the ORC runtime support library.
11 //===----------------------------------------------------------------------===//
13 #ifndef ORC_RT_BITMASK_ENUM_H
14 #define ORC_RT_BITMASK_ENUM_H
16 #include "stl_extras.h"
18 #include <cassert>
19 #include <type_traits>
21 namespace orc_rt {
23 /// ORC_RT_MARK_AS_BITMASK_ENUM lets you opt in an individual enum type so you
24 /// can perform bitwise operations on it without putting static_cast everywhere.
25 ///
26 /// \code
27 /// enum MyEnum {
28 /// E1 = 1, E2 = 2, E3 = 4, E4 = 8,
29 /// ORC_RT_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4)
30 /// };
31 ///
32 /// void Foo() {
33 /// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast!
34 /// }
35 /// \endcode
36 ///
37 /// Normally when you do a bitwise operation on an enum value, you get back an
38 /// instance of the underlying type (e.g. int). But using this macro, bitwise
39 /// ops on your enum will return you back instances of the enum. This is
40 /// particularly useful for enums which represent a combination of flags.
41 ///
42 /// The parameter to ORC_RT_MARK_AS_BITMASK_ENUM should be the largest
43 /// individual value in your enum.
44 ///
45 /// All of the enum's values must be non-negative.
46 #define ORC_RT_MARK_AS_BITMASK_ENUM(LargestValue) \
47 ORC_RT_BITMASK_LARGEST_ENUMERATOR = LargestValue
49 /// ORC_RT_DECLARE_ENUM_AS_BITMASK can be used to declare an enum type as a bit
50 /// set, so that bitwise operation on such enum does not require static_cast.
51 ///
52 /// \code
53 /// enum MyEnum { E1 = 1, E2 = 2, E3 = 4, E4 = 8 };
54 /// ORC_RT_DECLARE_ENUM_AS_BITMASK(MyEnum, E4);
55 ///
56 /// void Foo() {
57 /// MyEnum A = (E1 | E2) & E3 ^ ~E4; // No static_cast
58 /// }
59 /// \endcode
60 ///
61 /// The second parameter to ORC_RT_DECLARE_ENUM_AS_BITMASK specifies the largest
62 /// bit value of the enum type.
63 ///
64 /// ORC_RT_DECLARE_ENUM_AS_BITMASK should be used in __orc_rt namespace.
65 ///
66 /// This a non-intrusive alternative for ORC_RT_MARK_AS_BITMASK_ENUM. It allows
67 /// declaring more than one non-scoped enumerations as bitmask types in the same
68 /// scope. Otherwise it provides the same functionality as
69 /// ORC_RT_MARK_AS_BITMASK_ENUM.
70 #define ORC_RT_DECLARE_ENUM_AS_BITMASK(Enum, LargestValue) \
71 template <> struct is_bitmask_enum<Enum> : std::true_type {}; \
72 template <> struct largest_bitmask_enum_bit<Enum> { \
73 static constexpr std::underlying_type_t<Enum> value = LargestValue; \
76 /// Traits class to determine whether an enum has been declared as a bitwise
77 /// enum via ORC_RT_DECLARE_ENUM_AS_BITMASK.
78 template <typename E, typename Enable = void>
79 struct is_bitmask_enum : std::false_type {};
81 template <typename E>
82 struct is_bitmask_enum<
83 E, std::enable_if_t<sizeof(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR) >= 0>>
84 : std::true_type {};
86 template <typename E>
87 inline constexpr bool is_bitmask_enum_v = is_bitmask_enum<E>::value;
89 /// Traits class to deermine bitmask enum largest bit.
90 template <typename E, typename Enable = void> struct largest_bitmask_enum_bit;
92 template <typename E>
93 struct largest_bitmask_enum_bit<
94 E, std::enable_if_t<sizeof(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR) >= 0>> {
95 using UnderlyingTy = std::underlying_type_t<E>;
96 static constexpr UnderlyingTy value =
97 static_cast<UnderlyingTy>(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR);
100 template <typename E> constexpr std::underlying_type_t<E> Mask() {
101 return bit_ceil(largest_bitmask_enum_bit<E>::value) - 1;
104 template <typename E> constexpr std::underlying_type_t<E> Underlying(E Val) {
105 auto U = static_cast<std::underlying_type_t<E>>(Val);
106 assert(U >= 0 && "Negative enum values are not allowed");
107 assert(U <= Mask<E>() && "Enum value too large (or langest val too small");
108 return U;
111 template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
112 constexpr E operator~(E Val) {
113 return static_cast<E>(~Underlying(Val) & Mask<E>());
116 template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
117 constexpr E operator|(E LHS, E RHS) {
118 return static_cast<E>(Underlying(LHS) | Underlying(RHS));
121 template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
122 constexpr E operator&(E LHS, E RHS) {
123 return static_cast<E>(Underlying(LHS) & Underlying(RHS));
126 template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
127 constexpr E operator^(E LHS, E RHS) {
128 return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));
131 template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
132 E &operator|=(E &LHS, E RHS) {
133 LHS = LHS | RHS;
134 return LHS;
137 template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
138 E &operator&=(E &LHS, E RHS) {
139 LHS = LHS & RHS;
140 return LHS;
143 template <typename E, typename = std::enable_if_t<is_bitmask_enum_v<E>>>
144 E &operator^=(E &LHS, E RHS) {
145 LHS = LHS ^ RHS;
146 return LHS;
149 } // namespace orc_rt
151 #endif // ORC_RT_BITMASK_ENUM_H