1 /* Copyright (C) 2015-2021 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 #include "traits.h"
22 
23 /* Type-safe wrapper for enum flags.  enum flags are enums where the
24    values are bits that are meant to be ORed together.
25 
26    This allows writing code like the below, while with raw enums this
27    would fail to compile without casts to enum type at the assignments
28    to 'f':
29 
30     enum some_flag
31     {
32        flag_val1 = 1 << 1,
33        flag_val2 = 1 << 2,
34        flag_val3 = 1 << 3,
35        flag_val4 = 1 << 4,
36     };
37     DEF_ENUM_FLAGS_TYPE(enum some_flag, some_flags);
38 
39     some_flags f = flag_val1 | flag_val2;
40     f |= flag_val3;
41 
42    It's also possible to assign literal zero to an enum flags variable
43    (meaning, no flags), dispensing adding an awkward explicit "no
44    value" value to the enumeration.  For example:
45 
46     some_flags f = 0;
47     f |= flag_val3 | flag_val4;
48 
49    Note that literal integers other than zero fail to compile:
50 
51     some_flags f = 1; // error
52 */
53 
54 #ifdef __cplusplus
55 
56 /* Use this to mark an enum as flags enum.  It defines FLAGS_TYPE as
57    enum_flags wrapper class for ENUM, and enables the global operator
58    overloads for ENUM.  */
59 #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type)	\
60   typedef enum_flags<enum_type> flags_type;		\
61   void is_enum_flags_enum_type (enum_type *)
62 
63 /* To enable the global enum_flags operators for enum, declare an
64    "is_enum_flags_enum_type" overload that has exactly one parameter,
65    of type a pointer to that enum class.  E.g.,:
66 
67      void is_enum_flags_enum_type (enum some_flag *);
68 
69    The function does not need to be defined, only declared.
70    DEF_ENUM_FLAGS_TYPE declares this.
71 
72    A function declaration is preferred over a traits type, because the
73    former allows calling the DEF_ENUM_FLAGS_TYPE macro inside a
74    namespace to define the corresponding enum flags type in that
75    namespace.  The compiler finds the corresponding
76    is_enum_flags_enum_type function via ADL.  */
77 
78 /* Note that std::underlying_type<enum_type> is not what we want here,
79    since that returns unsigned int even when the enum decays to signed
80    int.  */
81 template<int size, bool sign> class integer_for_size { typedef void type; };
82 template<> struct integer_for_size<1, 0> { typedef uint8_t type; };
83 template<> struct integer_for_size<2, 0> { typedef uint16_t type; };
84 template<> struct integer_for_size<4, 0> { typedef uint32_t type; };
85 template<> struct integer_for_size<8, 0> { typedef uint64_t type; };
86 template<> struct integer_for_size<1, 1> { typedef int8_t type; };
87 template<> struct integer_for_size<2, 1> { typedef int16_t type; };
88 template<> struct integer_for_size<4, 1> { typedef int32_t type; };
89 template<> struct integer_for_size<8, 1> { typedef int64_t type; };
90 
91 template<typename T>
92 struct enum_underlying_type
93 {
94   typedef typename
95     integer_for_size<sizeof (T), static_cast<bool>(T (-1) < T (0))>::type
96     type;
97 };
98 
99 namespace enum_flags_detail
100 {
101 
102 /* Private type used to support initializing flag types with zero:
103 
104    foo_flags f = 0;
105 
106    but not other integers:
107 
108    foo_flags f = 1;
109 
110    The way this works is that we define an implicit constructor that
111    takes a pointer to this private type.  Since nothing can
112    instantiate an object of this type, the only possible pointer to
113    pass to the constructor is the NULL pointer, or, zero.  */
114 struct zero_type;
115 
116 /* gdb::Requires trait helpers.  */
117 template <typename enum_type>
118 using EnumIsUnsigned
119   = std::is_unsigned<typename enum_underlying_type<enum_type>::type>;
120 template <typename enum_type>
121 using EnumIsSigned
122   = std::is_signed<typename enum_underlying_type<enum_type>::type>;
123 
124 }
125 
126 template <typename E>
127 class enum_flags
128 {
129 public:
130   typedef E enum_type;
131   typedef typename enum_underlying_type<enum_type>::type underlying_type;
132 
133 public:
134   /* Allow default construction.  */
135   constexpr enum_flags ()
136     : m_enum_value ((enum_type) 0)
137   {}
138 
139   /* The default move/copy ctor/assignment do the right thing.  */
140 
141   /* If you get an error saying these two overloads are ambiguous,
142      then you tried to mix values of different enum types.  */
143   constexpr enum_flags (enum_type e)
144     : m_enum_value (e)
145   {}
146   constexpr enum_flags (enum_flags_detail::zero_type *zero)
147     : m_enum_value ((enum_type) 0)
148   {}
149 
150   enum_flags &operator&= (enum_flags e) &
151   {
152     m_enum_value = (enum_type) (m_enum_value & e.m_enum_value);
153     return *this;
154   }
155   enum_flags &operator|= (enum_flags e) &
156   {
157     m_enum_value = (enum_type) (m_enum_value | e.m_enum_value);
158     return *this;
159   }
160   enum_flags &operator^= (enum_flags e) &
161   {
162     m_enum_value = (enum_type) (m_enum_value ^ e.m_enum_value);
163     return *this;
164   }
165 
166   /* Delete rval versions.  */
167   void operator&= (enum_flags e) && = delete;
168   void operator|= (enum_flags e) && = delete;
169   void operator^= (enum_flags e) && = delete;
170 
171   /* Like raw enums, allow conversion to the underlying type.  */
172   constexpr operator underlying_type () const
173   {
174     return m_enum_value;
175   }
176 
177   /* Get the underlying value as a raw enum.  */
178   constexpr enum_type raw () const
179   {
180     return m_enum_value;
181   }
182 
183   /* Binary operations involving some unrelated type (which would be a
184      bug) are implemented as non-members, and deleted.  */
185 
186 private:
187   /* Stored as enum_type because GDB knows to print the bit flags
188      neatly if the enum values look like bit flags.  */
189   enum_type m_enum_value;
190 };
191 
192 template <typename E>
193 using is_enum_flags_enum_type_t
194   = decltype (is_enum_flags_enum_type (std::declval<E *> ()));
195 
196 /* Global operator overloads.  */
197 
198 /* Generate binary operators.  */
199 
200 #define ENUM_FLAGS_GEN_BINOP(OPERATOR_OP, OP)				\
201 									\
202   /* Raw enum on both LHS/RHS.  Returns raw enum type.  */		\
203   template <typename enum_type,						\
204 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
205   constexpr enum_type							\
206   OPERATOR_OP (enum_type e1, enum_type e2)				\
207   {									\
208     using underlying = typename enum_flags<enum_type>::underlying_type;	\
209     return (enum_type) (underlying (e1) OP underlying (e2));		\
210   }									\
211 									\
212   /* enum_flags on the LHS.  */						\
213   template <typename enum_type,						\
214 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
215   constexpr enum_flags<enum_type>					\
216   OPERATOR_OP (enum_flags<enum_type> e1, enum_type e2)			\
217   { return e1.raw () OP e2; }						\
218 									\
219   /* enum_flags on the RHS.  */						\
220   template <typename enum_type,						\
221 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
222   constexpr enum_flags<enum_type>					\
223   OPERATOR_OP (enum_type e1, enum_flags<enum_type> e2)			\
224   { return e1 OP e2.raw (); }						\
225 									\
226   /* enum_flags on both LHS/RHS.  */					\
227   template <typename enum_type,						\
228 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
229   constexpr enum_flags<enum_type>					\
230   OPERATOR_OP (enum_flags<enum_type> e1, enum_flags<enum_type> e2)	\
231   { return e1.raw () OP e2.raw (); }					\
232 									\
233   /* Delete cases involving unrelated types.  */			\
234 									\
235   template <typename enum_type, typename unrelated_type,		\
236 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
237   constexpr enum_flags<enum_type>					\
238   OPERATOR_OP (enum_type e1, unrelated_type e2) = delete;		\
239 									\
240   template <typename enum_type, typename unrelated_type,		\
241 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
242   constexpr enum_flags<enum_type>					\
243   OPERATOR_OP (unrelated_type e1, enum_type e2) = delete;		\
244 									\
245   template <typename enum_type, typename unrelated_type,		\
246 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
247   constexpr enum_flags<enum_type>					\
248   OPERATOR_OP (enum_flags<enum_type> e1, unrelated_type e2) = delete;	\
249 									\
250   template <typename enum_type, typename unrelated_type,		\
251 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
252   constexpr enum_flags<enum_type>					\
253   OPERATOR_OP (unrelated_type e1, enum_flags<enum_type> e2) = delete;
254 
255 /* Generate non-member compound assignment operators.  Only the raw
256    enum versions are defined here.  The enum_flags versions are
257    defined as member functions, simply because it's less code that
258    way.
259 
260    Note we delete operators that would allow e.g.,
261 
262      "enum_type | 1" or "enum_type1 | enum_type2"
263 
264    because that would allow a mistake like :
265      enum flags1 { F1_FLAGS1 = 1 };
266      enum flags2 { F2_FLAGS2 = 2 };
267      enum flags1 val;
268      switch (val) {
269        case F1_FLAGS1 | F2_FLAGS2:
270      ...
271 
272    If you really need to 'or' enumerators of different flag types,
273    cast to integer first.
274 */
275 #define ENUM_FLAGS_GEN_COMPOUND_ASSIGN(OPERATOR_OP, OP)			\
276   /* lval reference version.  */					\
277   template <typename enum_type,						\
278 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
279   constexpr enum_type &							\
280   OPERATOR_OP (enum_type &e1, enum_type e2)				\
281   { return e1 = e1 OP e2; }						\
282 									\
283   /* rval reference version.  */					\
284   template <typename enum_type,						\
285 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
286   void									\
287   OPERATOR_OP (enum_type &&e1, enum_type e2) = delete;			\
288 									\
289   /* Delete compound assignment from unrelated types.  */		\
290 									\
291   template <typename enum_type, typename other_enum_type,		\
292 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
293   constexpr enum_type &							\
294   OPERATOR_OP (enum_type &e1, other_enum_type e2) = delete;		\
295 									\
296   template <typename enum_type, typename other_enum_type,		\
297 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
298   void									\
299   OPERATOR_OP (enum_type &&e1, other_enum_type e2) = delete;
300 
301 ENUM_FLAGS_GEN_BINOP (operator|, |)
302 ENUM_FLAGS_GEN_BINOP (operator&, &)
303 ENUM_FLAGS_GEN_BINOP (operator^, ^)
304 
305 ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator|=, |)
306 ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator&=, &)
307 ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator^=, ^)
308 
309 /* Allow comparison with enum_flags, raw enum, and integers, only.
310    The latter case allows "== 0".  As side effect, it allows comparing
311    with integer variables too, but that's not a common mistake to
312    make.  It's important to disable comparison with unrelated types to
313    prevent accidentally comparing with unrelated enum values, which
314    are convertible to integer, and thus coupled with enum_flags
315    convertion to underlying type too, would trigger the built-in 'bool
316    operator==(unsigned, int)' operator.  */
317 
318 #define ENUM_FLAGS_GEN_COMP(OPERATOR_OP, OP)				\
319 									\
320   /* enum_flags OP enum_flags */					\
321 									\
322   template <typename enum_type>						\
323   constexpr bool							\
324   OPERATOR_OP (enum_flags<enum_type> lhs, enum_flags<enum_type> rhs)	\
325   { return lhs.raw () OP rhs.raw (); }					\
326 									\
327   /* enum_flags OP other */						\
328 									\
329   template <typename enum_type>						\
330   constexpr bool							\
331   OPERATOR_OP (enum_flags<enum_type> lhs, enum_type rhs)		\
332   { return lhs.raw () OP rhs; }						\
333 									\
334   template <typename enum_type>						\
335   constexpr bool							\
336   OPERATOR_OP (enum_flags<enum_type> lhs, int rhs)			\
337   { return lhs.raw () OP rhs; }						\
338 									\
339   template <typename enum_type, typename U>				\
340   constexpr bool							\
341   OPERATOR_OP (enum_flags<enum_type> lhs, U rhs) = delete;		\
342 									\
343   /* other OP enum_flags */						\
344 									\
345   template <typename enum_type>						\
346   constexpr bool							\
347   OPERATOR_OP (enum_type lhs, enum_flags<enum_type> rhs)		\
348   { return lhs OP rhs.raw (); }						\
349 									\
350   template <typename enum_type>						\
351   constexpr bool							\
352   OPERATOR_OP (int lhs, enum_flags<enum_type> rhs)			\
353   { return lhs OP rhs.raw (); }						\
354 									\
355   template <typename enum_type, typename U>				\
356   constexpr bool							\
357   OPERATOR_OP (U lhs, enum_flags<enum_type> rhs) = delete;
358 
359 ENUM_FLAGS_GEN_COMP (operator==, ==)
360 ENUM_FLAGS_GEN_COMP (operator!=, !=)
361 
362 /* Unary operators for the raw flags enum.  */
363 
364 /* We require underlying type to be unsigned when using operator~ --
365    if it were not unsigned, undefined behavior could result.  However,
366    asserting this in the class itself would require too many
367    unnecessary changes to usages of otherwise OK enum types.  */
368 template <typename enum_type,
369 	  typename = is_enum_flags_enum_type_t<enum_type>,
370 	  typename
371 	    = gdb::Requires<enum_flags_detail::EnumIsUnsigned<enum_type>>>
372 constexpr enum_type
373 operator~ (enum_type e)
374 {
375   using underlying = typename enum_flags<enum_type>::underlying_type;
376   return (enum_type) ~underlying (e);
377 }
378 
379 template <typename enum_type,
380 	  typename = is_enum_flags_enum_type_t<enum_type>,
381 	  typename = gdb::Requires<enum_flags_detail::EnumIsSigned<enum_type>>>
382 constexpr void operator~ (enum_type e) = delete;
383 
384 template <typename enum_type,
385 	  typename = is_enum_flags_enum_type_t<enum_type>,
386 	  typename
387 	    = gdb::Requires<enum_flags_detail::EnumIsUnsigned<enum_type>>>
388 constexpr enum_flags<enum_type>
389 operator~ (enum_flags<enum_type> e)
390 {
391   using underlying = typename enum_flags<enum_type>::underlying_type;
392   return (enum_type) ~underlying (e);
393 }
394 
395 template <typename enum_type,
396 	  typename = is_enum_flags_enum_type_t<enum_type>,
397 	  typename = gdb::Requires<enum_flags_detail::EnumIsSigned<enum_type>>>
398 constexpr void operator~ (enum_flags<enum_type> e) = delete;
399 
400 /* Delete operator<< and operator>>.  */
401 
402 template <typename enum_type, typename any_type,
403 	  typename = is_enum_flags_enum_type_t<enum_type>>
404 void operator<< (const enum_type &, const any_type &) = delete;
405 
406 template <typename enum_type, typename any_type,
407 	  typename = is_enum_flags_enum_type_t<enum_type>>
408 void operator<< (const enum_flags<enum_type> &, const any_type &) = delete;
409 
410 template <typename enum_type, typename any_type,
411 	  typename = is_enum_flags_enum_type_t<enum_type>>
412 void operator>> (const enum_type &, const any_type &) = delete;
413 
414 template <typename enum_type, typename any_type,
415 	  typename = is_enum_flags_enum_type_t<enum_type>>
416 void operator>> (const enum_flags<enum_type> &, const any_type &) = delete;
417 
418 #else /* __cplusplus */
419 
420 /* In C, the flags type is just a typedef for the enum type.  */
421 
422 #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type) \
423   typedef enum_type flags_type
424 
425 #endif /* __cplusplus */
426 
427 #endif /* COMMON_ENUM_FLAGS_H */
428