You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
4.1 KiB
130 lines
4.1 KiB
// Copyright 2017 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef LIBBRILLO_BRILLO_ENUM_FLAGS_H_
|
|
#define LIBBRILLO_BRILLO_ENUM_FLAGS_H_
|
|
|
|
#include <type_traits>
|
|
|
|
// This is a helper for generating type-safe bitwise operators for flags that
|
|
// are defined by an enumeration. By default, when a bitwise operation is
|
|
// performed on two enumerators of an enumeration, the result is the base type
|
|
// (int), not a value of the enumeration:
|
|
//
|
|
// enum SomeEnumOfFlags {
|
|
// ONE = 1,
|
|
// TWO = 2,
|
|
// THREE = 4,
|
|
// // etc.
|
|
// };
|
|
//
|
|
// SomeEnumOfFlags flags = static_cast<SomeEnumOfFlags>(ONE | TWO);
|
|
//
|
|
// By enabling these operators for an enum type:
|
|
//
|
|
// DECLARE_FLAGS_ENUM(SomeEnumOfFlags);
|
|
//
|
|
// The syntax is simplified to:
|
|
//
|
|
// SomeEnumOfFlags flags = ONE | TWO;
|
|
//
|
|
// But the following still does not compile without using a cast (as is
|
|
// expected):
|
|
//
|
|
// SomeEnumOfFlags flags = ONE | 2;
|
|
|
|
// This is the macro used to declare that an enum type |ENUM| should have bit-
|
|
// wise operators defined for it.
|
|
#define DECLARE_FLAGS_ENUM(ENUM) \
|
|
template <typename> struct EnumFlagTraitType; \
|
|
template <> struct EnumFlagTraitType<ENUM> { using EnumFlagType = ENUM; }; \
|
|
EnumFlagTraitType<ENUM> GetEnumFlagTraitType(ENUM) __attribute__((used));
|
|
|
|
|
|
// Setup the templates used to declare that the operators should exist for a
|
|
// given type T.
|
|
|
|
namespace enum_details {
|
|
|
|
template <typename T>
|
|
using FlagEnumTraits = decltype(GetEnumFlagTraitType(std::declval<T>()));
|
|
|
|
template <typename T>
|
|
using Void = void;
|
|
|
|
template <typename T, typename = void>
|
|
struct IsFlagEnum : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct IsFlagEnum<T, Void<typename FlagEnumTraits<T>::EnumFlagType>>
|
|
: std::true_type {};
|
|
|
|
} // namespace enum_details
|
|
|
|
// The operators themselves, conditional on having been declared that they are
|
|
// flag-style enums.
|
|
|
|
// T operator~(T&)
|
|
template <typename T>
|
|
constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
|
|
operator~(const T& l) {
|
|
return static_cast<T>(
|
|
~static_cast<typename std::underlying_type<T>::type>(l));
|
|
}
|
|
|
|
// T operator|(T&, T&)
|
|
template <typename T>
|
|
constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
|
|
operator|(const T& l, const T& r) {
|
|
return static_cast<T>(
|
|
static_cast<typename std::underlying_type<T>::type>(l) |
|
|
static_cast<typename std::underlying_type<T>::type>(r));
|
|
}
|
|
|
|
// T operator&(T&, T&)
|
|
template <typename T>
|
|
constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
|
|
operator&(const T& l, const T& r) {
|
|
return static_cast<T>(
|
|
static_cast<typename std::underlying_type<T>::type>(l) &
|
|
static_cast<typename std::underlying_type<T>::type>(r));
|
|
}
|
|
|
|
// T operator^(T&, T&)
|
|
template <typename T>
|
|
constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
|
|
operator^(const T& l, const T& r) {
|
|
return static_cast<T>(static_cast<typename std::underlying_type<T>::type>(l) ^
|
|
static_cast<typename std::underlying_type<T>::type>(r));
|
|
}
|
|
|
|
// T operator|=(T&, T&)
|
|
template <typename T>
|
|
constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
|
|
operator|=(T& l, const T& r) {
|
|
return l = static_cast<T>(
|
|
static_cast<typename std::underlying_type<T>::type>(l) |
|
|
static_cast<typename std::underlying_type<T>::type>(r));
|
|
}
|
|
|
|
// T operator&=(T&, T&)
|
|
template <typename T>
|
|
constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
|
|
operator&=(T& l, const T& r) {
|
|
return l = static_cast<T>(
|
|
static_cast<typename std::underlying_type<T>::type>(l) &
|
|
static_cast<typename std::underlying_type<T>::type>(r));
|
|
}
|
|
|
|
// T operator^=(T&, T&)
|
|
template <typename T>
|
|
constexpr typename std::enable_if<enum_details::IsFlagEnum<T>::value, T>::type
|
|
operator^=(T& l, const T& r) {
|
|
return l = static_cast<T>(
|
|
static_cast<typename std::underlying_type<T>::type>(l) ^
|
|
static_cast<typename std::underlying_type<T>::type>(r));
|
|
}
|
|
|
|
#endif // LIBBRILLO_BRILLO_ENUM_FLAGS_H_
|