| // 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_ |