aboutsummaryrefslogtreecommitdiffstats
path: root/brillo/enum_flags.h
blob: 9630dd0e8beed7d84387fc565764c3b6000a6030 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// 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_