1 //===---- bitmask_enum.h - Enable bitmask operations on enums ---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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"
19 #include <type_traits>
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.
28 /// E1 = 1, E2 = 2, E3 = 4, E4 = 8,
29 /// ORC_RT_MARK_AS_BITMASK_ENUM(/* LargestValue = */ E4)
33 /// MyEnum A = (E1 | E2) & E3 ^ ~E4; // Look, ma: No static_cast!
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.
42 /// The parameter to ORC_RT_MARK_AS_BITMASK_ENUM should be the largest
43 /// individual value in your enum.
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.
53 /// enum MyEnum { E1 = 1, E2 = 2, E3 = 4, E4 = 8 };
54 /// ORC_RT_DECLARE_ENUM_AS_BITMASK(MyEnum, E4);
57 /// MyEnum A = (E1 | E2) & E3 ^ ~E4; // No static_cast
61 /// The second parameter to ORC_RT_DECLARE_ENUM_AS_BITMASK specifies the largest
62 /// bit value of the enum type.
64 /// ORC_RT_DECLARE_ENUM_AS_BITMASK should be used in __orc_rt namespace.
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
{};
82 struct is_bitmask_enum
<
83 E
, std::enable_if_t
<sizeof(E::ORC_RT_BITMASK_LARGEST_ENUMERATOR
) >= 0>>
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
;
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");
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
) {
137 template <typename E
, typename
= std::enable_if_t
<is_bitmask_enum_v
<E
>>>
138 E
&operator&=(E
&LHS
, E RHS
) {
143 template <typename E
, typename
= std::enable_if_t
<is_bitmask_enum_v
<E
>>>
144 E
&operator^=(E
&LHS
, E RHS
) {
149 } // namespace orc_rt
151 #endif // ORC_RT_BITMASK_ENUM_H