Skip to content

Commit baaf111

Browse files
[BitmaskEnum] Add support for shift operators. (#118007)
For enums that describe a bitmask where successive bits within that mask describe some enum value (as described in the same enum), it is useful to support operator<< and operator>> as well. For example: ``` enum class E : unsigned { // 2 bits per option OptionA = 0, OptionB = 1, OptionC = 2, OptionD = 3, OptionMask = 3, // Given 3 values in the bitmask X, Y and Z, each is 2 bits in size // and represents a choice of OptionA..OptionD. ShiftX = 0, ShiftY = 2, ShiftZ = 4, }; // The mask can be encoded with: E mask; mask |= getOptionFor(X) << E::ShiftX; mask |= getOptionFor(Y) << E::ShiftY; mask |= getOptionFor(Z) << E::ShiftZ; // And to extract a value: E OptionForX = (mask >> E::ShiftX) & E::OptionMask; E OptionForY = (mask >> E::ShiftY) & E::OptionMask; E OptionForZ = (mask >> E::ShiftZ) & E::OptionMask; ```
1 parent 55dd475 commit baaf111

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

llvm/include/llvm/ADT/BitmaskEnum.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,13 @@
8585
using ::llvm::BitmaskEnumDetail::operator|; \
8686
using ::llvm::BitmaskEnumDetail::operator&; \
8787
using ::llvm::BitmaskEnumDetail::operator^; \
88+
using ::llvm::BitmaskEnumDetail::operator<<; \
89+
using ::llvm::BitmaskEnumDetail::operator>>; \
8890
using ::llvm::BitmaskEnumDetail::operator|=; \
8991
using ::llvm::BitmaskEnumDetail::operator&=; \
9092
using ::llvm::BitmaskEnumDetail::operator^=; \
93+
using ::llvm::BitmaskEnumDetail::operator<<=; \
94+
using ::llvm::BitmaskEnumDetail::operator>>=; \
9195
/* Force a semicolon at the end of this macro. */ \
9296
using ::llvm::BitmaskEnumDetail::any
9397

@@ -162,6 +166,16 @@ constexpr E operator^(E LHS, E RHS) {
162166
return static_cast<E>(Underlying(LHS) ^ Underlying(RHS));
163167
}
164168

169+
template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
170+
constexpr E operator<<(E LHS, E RHS) {
171+
return static_cast<E>(Underlying(LHS) << Underlying(RHS));
172+
}
173+
174+
template <typename E, typename = std::enable_if_t<is_bitmask_enum<E>::value>>
175+
constexpr E operator>>(E LHS, E RHS) {
176+
return static_cast<E>(Underlying(LHS) >> Underlying(RHS));
177+
}
178+
165179
// |=, &=, and ^= return a reference to LHS, to match the behavior of the
166180
// operators on builtin types.
167181

@@ -183,6 +197,18 @@ E &operator^=(E &LHS, E RHS) {
183197
return LHS;
184198
}
185199

200+
template <typename e, typename = std::enable_if_t<is_bitmask_enum<e>::value>>
201+
e &operator<<=(e &lhs, e rhs) {
202+
lhs = lhs << rhs;
203+
return lhs;
204+
}
205+
206+
template <typename e, typename = std::enable_if_t<is_bitmask_enum<e>::value>>
207+
e &operator>>=(e &lhs, e rhs) {
208+
lhs = lhs >> rhs;
209+
return lhs;
210+
}
211+
186212
} // namespace BitmaskEnumDetail
187213

188214
// Enable bitmask enums in namespace ::llvm and all nested namespaces.

llvm/unittests/ADT/BitmaskEnumTest.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,22 @@ TEST(BitmaskEnumTest, BitwiseXorEquals) {
130130
EXPECT_EQ(V3, f2);
131131
}
132132

133+
TEST(BitmaskEnumTest, BitwiseShift) {
134+
Flags f = (F1 << F1);
135+
EXPECT_EQ(f, F2);
136+
137+
Flags f2 = F1;
138+
f2 <<= F1;
139+
EXPECT_EQ(f2, F2);
140+
141+
Flags f3 = (F1 >> F1);
142+
EXPECT_EQ(f3, F0);
143+
144+
Flags f4 = F1;
145+
f4 >>= F1;
146+
EXPECT_EQ(f4, F0);
147+
}
148+
133149
TEST(BitmaskEnumTest, ConstantExpression) {
134150
constexpr Flags f1 = ~F1;
135151
constexpr Flags f2 = F1 | F2;

0 commit comments

Comments
 (0)