blob: bd6eb832637b1b33f127f7d2094587a395f75ee4 [file] [log] [blame]
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Utility to enable bit operators on enum classes treated as bitfields.
//
// To use define an enum class with valid bitmask values and an underlying type
// then use the macro to enable support:
// enum class MyBitfield : uint32_t {
// kFoo = 1 << 0,
// kBar = 1 << 1,
// };
// IREE_BITFIELD(MyBitfield);
// MyBitfield value = ~(MyBitfield::kFoo | MyBitfield::kBar);
//
// AnyBitSet is provided as a way to quickly test if any of the given bits are
// set:
// if (AnyBitSet(value)) { /* one or more bits are set */ }
//
// If testing for equality it's recommended that AllBitsSet is used to ensure
// that combined values are handled properly:
// if (AllBitsSet(value, MyBitfield::kSomeSetOfFlags)) { /* all bits set */ }
#ifndef IREE_BASE_BITFIELD_H_
#define IREE_BASE_BITFIELD_H_
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/types/span.h"
namespace iree {
#define IREE_BITFIELD(enum_class) \
inline enum_class operator|(enum_class lhs, enum_class rhs) { \
using enum_type = typename std::underlying_type<enum_class>::type; \
return static_cast<enum_class>(static_cast<enum_type>(lhs) | \
static_cast<enum_type>(rhs)); \
} \
inline enum_class& operator|=(enum_class& lhs, enum_class rhs) { \
using enum_type = typename std::underlying_type<enum_class>::type; \
lhs = static_cast<enum_class>(static_cast<enum_type>(lhs) | \
static_cast<enum_type>(rhs)); \
return lhs; \
} \
inline enum_class operator&(enum_class lhs, enum_class rhs) { \
using enum_type = typename std::underlying_type<enum_class>::type; \
return static_cast<enum_class>(static_cast<enum_type>(lhs) & \
static_cast<enum_type>(rhs)); \
} \
inline enum_class& operator&=(enum_class& lhs, enum_class rhs) { \
using enum_type = typename std::underlying_type<enum_class>::type; \
lhs = static_cast<enum_class>(static_cast<enum_type>(lhs) & \
static_cast<enum_type>(rhs)); \
return lhs; \
} \
inline enum_class operator^(enum_class lhs, enum_class rhs) { \
using enum_type = typename std::underlying_type<enum_class>::type; \
return static_cast<enum_class>(static_cast<enum_type>(lhs) ^ \
static_cast<enum_type>(rhs)); \
} \
inline enum_class& operator^=(enum_class& lhs, enum_class rhs) { \
using enum_type = typename std::underlying_type<enum_class>::type; \
lhs = static_cast<enum_class>(static_cast<enum_type>(lhs) ^ \
static_cast<enum_type>(rhs)); \
return lhs; \
} \
inline enum_class operator~(enum_class lhs) { \
using enum_type = typename std::underlying_type<enum_class>::type; \
return static_cast<enum_class>(~static_cast<enum_type>(lhs)); \
} \
inline bool AnyBitSet(enum_class lhs) { \
using enum_type = typename std::underlying_type<enum_class>::type; \
return static_cast<enum_type>(lhs) != 0; \
} \
inline bool AllBitsSet(enum_class lhs, enum_class rhs) { \
return (lhs & rhs) == rhs; \
}
// Appends the formatted contents of the given bitfield value to a stream.
//
// Processes values in the order of the mapping table provided and will only
// use each bit once. Use this to prioritize combined flags over split ones.
template <typename T>
void FormatBitfieldValue(
std::ostringstream* stream, T value,
const absl::Span<const std::pair<T, const char*>> mappings) {
T remaining_bits = value;
int i = 0;
for (const auto& mapping : mappings) {
if ((remaining_bits & mapping.first) == mapping.first) {
if (i > 0) {
*stream << "|";
}
*stream << mapping.second;
remaining_bits &= ~mapping.first;
++i;
}
}
using enum_type = typename std::underlying_type<T>::type;
if (remaining_bits != static_cast<T>(0)) {
if (i > 0) {
*stream << "|";
}
*stream << std::hex << static_cast<enum_type>(remaining_bits) << "h";
}
}
// Returns a string with the formatted contents of the given bitfield value.
//
// Usage:
// MyValue my_value = MyValue::kA | MyValue::kB;
// std::string string_value = FormatBitfieldValue(my_value, {
// {MyValue::kA, "kA"},
// {MyValue::kB, "kB"},
// });
// // string_value contains 'kA|kB'
template <typename T>
std::string FormatBitfieldValue(
T value, absl::Span<const std::pair<T, const char*>> mappings) {
std::ostringstream stream;
FormatBitfieldValue<T>(&stream, value, mappings);
return stream.str();
}
} // namespace iree
#endif // IREE_BASE_BITFIELD_H_