GDBserver
enum-flags.h
Go to the documentation of this file.
1 /* Copyright (C) 2015-2018 Free Software Foundation, Inc.
2 
3  This file is part of GDB.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 
18 #ifndef COMMON_ENUM_FLAGS_H
19 #define COMMON_ENUM_FLAGS_H
20 
21 /* Type-safe wrapper for enum flags. enum flags are enums where the
22  values are bits that are meant to be ORed together.
23 
24  This allows writing code like the below, while with raw enums this
25  would fail to compile without casts to enum type at the assignments
26  to 'f':
27 
28  enum some_flag
29  {
30  flag_val1 = 1 << 1,
31  flag_val2 = 1 << 2,
32  flag_val3 = 1 << 3,
33  flag_val4 = 1 << 4,
34  };
35  DEF_ENUM_FLAGS_TYPE(enum some_flag, some_flags)
36 
37  some_flags f = flag_val1 | flag_val2;
38  f |= flag_val3;
39 
40  It's also possible to assign literal zero to an enum flags variable
41  (meaning, no flags), dispensing adding an awkward explicit "no
42  value" value to the enumeration. For example:
43 
44  some_flags f = 0;
45  f |= flag_val3 | flag_val4;
46 
47  Note that literal integers other than zero fail to compile:
48 
49  some_flags f = 1; // error
50 */
51 
52 #ifdef __cplusplus
53 
54 /* Traits type used to prevent the global operator overloads from
55  instantiating for non-flag enums. */
56 template<typename T> struct enum_flags_type {};
57 
58 /* Use this to mark an enum as flags enum. It defines FLAGS as
59  enum_flags wrapper class for ENUM, and enables the global operator
60  overloads for ENUM. */
61 #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type) \
62  typedef enum_flags<enum_type> flags_type; \
63  template<> \
64  struct enum_flags_type<enum_type> \
65  { \
66  typedef enum_flags<enum_type> type; \
67  }
68 
69 /* Until we can rely on std::underlying type being universally
70  available (C++11), roll our own for enums. */
71 template<int size, bool sign> class integer_for_size { typedef void type; };
72 template<> struct integer_for_size<1, 0> { typedef uint8_t type; };
73 template<> struct integer_for_size<2, 0> { typedef uint16_t type; };
74 template<> struct integer_for_size<4, 0> { typedef uint32_t type; };
75 template<> struct integer_for_size<8, 0> { typedef uint64_t type; };
76 template<> struct integer_for_size<1, 1> { typedef int8_t type; };
77 template<> struct integer_for_size<2, 1> { typedef int16_t type; };
78 template<> struct integer_for_size<4, 1> { typedef int32_t type; };
79 template<> struct integer_for_size<8, 1> { typedef int64_t type; };
80 
81 template<typename T>
82 struct enum_underlying_type
83 {
84  typedef typename
85  integer_for_size<sizeof (T), static_cast<bool>(T (-1) < T (0))>::type
86  type;
87 };
88 
89 template <typename E>
90 class enum_flags
91 {
92 public:
93  typedef E enum_type;
94  typedef typename enum_underlying_type<enum_type>::type underlying_type;
95 
96 private:
97  /* Private type used to support initializing flag types with zero:
98 
99  foo_flags f = 0;
100 
101  but not other integers:
102 
103  foo_flags f = 1;
104 
105  The way this works is that we define an implicit constructor that
106  takes a pointer to this private type. Since nothing can
107  instantiate an object of this type, the only possible pointer to
108  pass to the constructor is the NULL pointer, or, zero. */
109  struct zero_type;
110 
111  underlying_type
112  underlying_value () const
113  {
114  return m_enum_value;
115  }
116 
117 public:
118  /* Allow default construction. */
119  enum_flags ()
120  : m_enum_value ((enum_type) 0)
121  {}
122 
123  /* If you get an error saying these two overloads are ambiguous,
124  then you tried to mix values of different enum types. */
125  enum_flags (enum_type e)
126  : m_enum_value (e)
127  {}
128  enum_flags (struct enum_flags::zero_type *zero)
129  : m_enum_value ((enum_type) 0)
130  {}
131 
132  enum_flags &operator&= (enum_type e)
133  {
134  m_enum_value = (enum_type) (underlying_value () & e);
135  return *this;
136  }
137  enum_flags &operator|= (enum_type e)
138  {
139  m_enum_value = (enum_type) (underlying_value () | e);
140  return *this;
141  }
142  enum_flags &operator^= (enum_type e)
143  {
144  m_enum_value = (enum_type) (underlying_value () ^ e);
145  return *this;
146  }
147 
148  operator enum_type () const
149  {
150  return m_enum_value;
151  }
152 
153  enum_flags operator& (enum_type e) const
154  {
155  return (enum_type) (underlying_value () & e);
156  }
157  enum_flags operator| (enum_type e) const
158  {
159  return (enum_type) (underlying_value () | e);
160  }
161  enum_flags operator^ (enum_type e) const
162  {
163  return (enum_type) (underlying_value () ^ e);
164  }
165  enum_flags operator~ () const
166  {
167  return (enum_type) ~underlying_value ();
168  }
169 
170 private:
171  /* Stored as enum_type because GDB knows to print the bit flags
172  neatly if the enum values look like bit flags. */
173  enum_type m_enum_value;
174 };
175 
176 /* Global operator overloads. */
177 
178 template <typename enum_type>
179 typename enum_flags_type<enum_type>::type
180 operator& (enum_type e1, enum_type e2)
181 {
182  return enum_flags<enum_type> (e1) & e2;
183 }
184 
185 template <typename enum_type>
186 typename enum_flags_type<enum_type>::type
187 operator| (enum_type e1, enum_type e2)
188 {
189  return enum_flags<enum_type> (e1) | e2;
190 }
191 
192 template <typename enum_type>
193 typename enum_flags_type<enum_type>::type
194 operator^ (enum_type e1, enum_type e2)
195 {
196  return enum_flags<enum_type> (e1) ^ e2;
197 }
198 
199 template <typename enum_type>
200 typename enum_flags_type<enum_type>::type
201 operator~ (enum_type e)
202 {
203  return ~enum_flags<enum_type> (e);
204 }
205 
206 #else /* __cplusplus */
207 
208 /* In C, the flags type is just a typedef for the enum type. */
209 
210 #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type) \
211  typedef enum_type flags_type
212 
213 #endif /* __cplusplus */
214 
215 #endif /* COMMON_ENUM_FLAGS_H */