Add translations for various sub-directories
[binutils-gdb.git] / gdbsupport / enum-flags.h
blob71109bb8c9959c16e218f812cf84fae88e12ec4b
1 /* Copyright (C) 2015-2024 Free Software Foundation, Inc.
3 This file is part of GDB.
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.
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.
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/>. */
18 #ifndef GDBSUPPORT_ENUM_FLAGS_H
19 #define GDBSUPPORT_ENUM_FLAGS_H
21 #include "traits.h"
23 /* Type-safe wrapper for enum flags. enum flags are enums where the
24 values are bits that are meant to be ORed together.
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':
30 enum some_flag
32 flag_val1 = 1 << 1,
33 flag_val2 = 1 << 2,
34 flag_val3 = 1 << 3,
35 flag_val4 = 1 << 4,
37 DEF_ENUM_FLAGS_TYPE(enum some_flag, some_flags);
39 some_flags f = flag_val1 | flag_val2;
40 f |= flag_val3;
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:
46 some_flags f = 0;
47 f |= flag_val3 | flag_val4;
49 Note that literal integers other than zero fail to compile:
51 some_flags f = 1; // error
54 /* Use this to mark an enum as flags enum. It defines FLAGS_TYPE as
55 enum_flags wrapper class for ENUM, and enables the global operator
56 overloads for ENUM. */
57 #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type) \
58 using flags_type = enum_flags<enum_type>; \
59 void is_enum_flags_enum_type (enum_type *)
61 /* To enable the global enum_flags operators for enum, declare an
62 "is_enum_flags_enum_type" overload that has exactly one parameter,
63 of type a pointer to that enum class. E.g.,:
65 void is_enum_flags_enum_type (enum some_flag *);
67 The function does not need to be defined, only declared.
68 DEF_ENUM_FLAGS_TYPE declares this.
70 A function declaration is preferred over a traits type, because the
71 former allows calling the DEF_ENUM_FLAGS_TYPE macro inside a
72 namespace to define the corresponding enum flags type in that
73 namespace. The compiler finds the corresponding
74 is_enum_flags_enum_type function via ADL. */
76 namespace enum_flags_detail
79 /* Private type used to support initializing flag types with zero:
81 foo_flags f = 0;
83 but not other integers:
85 foo_flags f = 1;
87 The way this works is that we define an implicit constructor that
88 takes a pointer to this private type. Since nothing can
89 instantiate an object of this type, the only possible pointer to
90 pass to the constructor is the NULL pointer, or, zero. */
91 struct zero_type;
93 /* gdb::Requires trait helpers. */
94 template <typename enum_type>
95 using EnumIsUnsigned
96 = std::is_unsigned<typename std::underlying_type<enum_type>::type>;
98 /* Helper to detect whether an enum has a fixed underlying type. This can be
99 achieved by using a scoped enum (in which case the type is "int") or
100 an explicit underlying type. C-style enums that are unscoped or do not
101 have an explicit underlying type have an implementation-defined underlying
102 type.
104 https://timsong-cpp.github.io/cppwp/n4659/dcl.enum#5
106 We need this trait in order to ensure that operator~ below does NOT
107 operate on old-style enums. This is because we apply operator~ on
108 the value and then cast the result to the enum_type. This is however
109 Undefined Behavior if the result does not fit in the range of possible
110 values for the enum. For enums with fixed underlying type, the entire
111 range of the integer is available. However, for old-style enums, the range
112 is only the smallest bit-field that can hold all the values of the
113 enumeration, typically much smaller than the underlying integer:
115 https://timsong-cpp.github.io/cppwp/n4659/expr.static.cast#10
116 https://timsong-cpp.github.io/cppwp/n4659/dcl.enum#8
118 To implement this, we leverage the fact that, since C++17, enums with
119 fixed underlying type can be list-initialized from an integer:
120 https://timsong-cpp.github.io/cppwp/n4659/dcl.init.list#3.7
122 Old-style enums cannot be initialized like that, leading to ill-formed
123 code.
125 We then use this together with SFINAE to create the desired trait.
128 template <typename enum_type, typename = void>
129 struct EnumHasFixedUnderlyingType : std::false_type
131 static_assert(std::is_enum<enum_type>::value);
134 /* Specialization that is active only if enum_type can be
135 list-initialized from an integer (0). Only enums with fixed
136 underlying type satisfy this property in C++17. */
137 template <typename enum_type>
138 struct EnumHasFixedUnderlyingType<enum_type, std::void_t<decltype(enum_type{0})>> : std::true_type
140 static_assert(std::is_enum<enum_type>::value);
143 template <typename enum_type>
144 using EnumIsSafeForBitwiseComplement = std::conjunction<
145 EnumIsUnsigned<enum_type>,
146 EnumHasFixedUnderlyingType<enum_type>
149 template <typename enum_type>
150 using EnumIsUnsafeForBitwiseComplement = std::negation<EnumIsSafeForBitwiseComplement<enum_type>>;
154 template <typename E>
155 class enum_flags
157 public:
158 using enum_type = E;
159 using underlying_type = typename std::underlying_type<enum_type>::type;
161 /* For to_string. Maps one enumerator of E to a string. */
162 struct string_mapping
164 E flag;
165 const char *str;
168 /* Convenience for to_string implementations, to build a
169 string_mapping array. */
170 #define MAP_ENUM_FLAG(ENUM_FLAG) { ENUM_FLAG, #ENUM_FLAG }
172 public:
173 /* Allow default construction. */
174 constexpr enum_flags ()
175 : m_enum_value ((enum_type) 0)
178 /* The default move/copy ctor/assignment do the right thing. */
180 /* If you get an error saying these two overloads are ambiguous,
181 then you tried to mix values of different enum types. */
182 constexpr enum_flags (enum_type e)
183 : m_enum_value (e)
185 constexpr enum_flags (enum_flags_detail::zero_type *zero)
186 : m_enum_value ((enum_type) 0)
189 enum_flags &operator&= (enum_flags e) &
191 m_enum_value = (enum_type) (m_enum_value & e.m_enum_value);
192 return *this;
194 enum_flags &operator|= (enum_flags e) &
196 m_enum_value = (enum_type) (m_enum_value | e.m_enum_value);
197 return *this;
199 enum_flags &operator^= (enum_flags e) &
201 m_enum_value = (enum_type) (m_enum_value ^ e.m_enum_value);
202 return *this;
205 /* Delete rval versions. */
206 void operator&= (enum_flags e) && = delete;
207 void operator|= (enum_flags e) && = delete;
208 void operator^= (enum_flags e) && = delete;
210 /* Like raw enums, allow conversion to the underlying type. */
211 constexpr operator underlying_type () const
213 return m_enum_value;
216 /* Get the underlying value as a raw enum. */
217 constexpr enum_type raw () const
219 return m_enum_value;
222 /* Binary operations involving some unrelated type (which would be a
223 bug) are implemented as non-members, and deleted. */
225 /* Convert this object to a std::string, using MAPPING as
226 enumerator-to-string mapping array. This is not meant to be
227 called directly. Instead, enum_flags specializations should have
228 their own to_string function wrapping this one, thus hiding the
229 mapping array from callers.
231 Note: this is defined outside the template class so it can use
232 the global operators for enum_type, which are only defined after
233 the template class. */
234 template<size_t N>
235 std::string to_string (const string_mapping (&mapping)[N]) const;
237 private:
238 /* Stored as enum_type because GDB knows to print the bit flags
239 neatly if the enum values look like bit flags. */
240 enum_type m_enum_value;
243 template <typename E>
244 using is_enum_flags_enum_type_t
245 = decltype (is_enum_flags_enum_type (std::declval<E *> ()));
247 /* Global operator overloads. */
249 /* Generate binary operators. */
251 #define ENUM_FLAGS_GEN_BINOP(OPERATOR_OP, OP) \
253 /* Raw enum on both LHS/RHS. Returns raw enum type. */ \
254 template <typename enum_type, \
255 typename = is_enum_flags_enum_type_t<enum_type>> \
256 constexpr enum_type \
257 OPERATOR_OP (enum_type e1, enum_type e2) \
259 using underlying = typename enum_flags<enum_type>::underlying_type; \
260 return (enum_type) (underlying (e1) OP underlying (e2)); \
263 /* enum_flags on the LHS. */ \
264 template <typename enum_type, \
265 typename = is_enum_flags_enum_type_t<enum_type>> \
266 constexpr enum_flags<enum_type> \
267 OPERATOR_OP (enum_flags<enum_type> e1, enum_type e2) \
268 { return e1.raw () OP e2; } \
270 /* enum_flags on the RHS. */ \
271 template <typename enum_type, \
272 typename = is_enum_flags_enum_type_t<enum_type>> \
273 constexpr enum_flags<enum_type> \
274 OPERATOR_OP (enum_type e1, enum_flags<enum_type> e2) \
275 { return e1 OP e2.raw (); } \
277 /* enum_flags on both LHS/RHS. */ \
278 template <typename enum_type, \
279 typename = is_enum_flags_enum_type_t<enum_type>> \
280 constexpr enum_flags<enum_type> \
281 OPERATOR_OP (enum_flags<enum_type> e1, enum_flags<enum_type> e2) \
282 { return e1.raw () OP e2.raw (); } \
284 /* Delete cases involving unrelated types. */ \
286 template <typename enum_type, typename unrelated_type, \
287 typename = is_enum_flags_enum_type_t<enum_type>> \
288 constexpr enum_flags<enum_type> \
289 OPERATOR_OP (enum_type e1, unrelated_type e2) = delete; \
291 template <typename enum_type, typename unrelated_type, \
292 typename = is_enum_flags_enum_type_t<enum_type>> \
293 constexpr enum_flags<enum_type> \
294 OPERATOR_OP (unrelated_type e1, enum_type e2) = delete; \
296 template <typename enum_type, typename unrelated_type, \
297 typename = is_enum_flags_enum_type_t<enum_type>> \
298 constexpr enum_flags<enum_type> \
299 OPERATOR_OP (enum_flags<enum_type> e1, unrelated_type e2) = delete; \
301 template <typename enum_type, typename unrelated_type, \
302 typename = is_enum_flags_enum_type_t<enum_type>> \
303 constexpr enum_flags<enum_type> \
304 OPERATOR_OP (unrelated_type e1, enum_flags<enum_type> e2) = delete;
306 /* Generate non-member compound assignment operators. Only the raw
307 enum versions are defined here. The enum_flags versions are
308 defined as member functions, simply because it's less code that
309 way.
311 Note we delete operators that would allow e.g.,
313 "enum_type | 1" or "enum_type1 | enum_type2"
315 because that would allow a mistake like :
316 enum flags1 { F1_FLAGS1 = 1 };
317 enum flags2 { F2_FLAGS2 = 2 };
318 enum flags1 val;
319 switch (val) {
320 case F1_FLAGS1 | F2_FLAGS2:
323 If you really need to 'or' enumerators of different flag types,
324 cast to integer first.
326 #define ENUM_FLAGS_GEN_COMPOUND_ASSIGN(OPERATOR_OP, OP) \
327 /* lval reference version. */ \
328 template <typename enum_type, \
329 typename = is_enum_flags_enum_type_t<enum_type>> \
330 constexpr enum_type & \
331 OPERATOR_OP (enum_type &e1, enum_type e2) \
332 { return e1 = e1 OP e2; } \
334 /* rval reference version. */ \
335 template <typename enum_type, \
336 typename = is_enum_flags_enum_type_t<enum_type>> \
337 void \
338 OPERATOR_OP (enum_type &&e1, enum_type e2) = delete; \
340 /* Delete compound assignment from unrelated types. */ \
342 template <typename enum_type, typename other_enum_type, \
343 typename = is_enum_flags_enum_type_t<enum_type>> \
344 constexpr enum_type & \
345 OPERATOR_OP (enum_type &e1, other_enum_type e2) = delete; \
347 template <typename enum_type, typename other_enum_type, \
348 typename = is_enum_flags_enum_type_t<enum_type>> \
349 void \
350 OPERATOR_OP (enum_type &&e1, other_enum_type e2) = delete;
352 ENUM_FLAGS_GEN_BINOP (operator|, |)
353 ENUM_FLAGS_GEN_BINOP (operator&, &)
354 ENUM_FLAGS_GEN_BINOP (operator^, ^)
356 ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator|=, |)
357 ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator&=, &)
358 ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator^=, ^)
360 /* Allow comparison with enum_flags, raw enum, and integers, only.
361 The latter case allows "== 0". As side effect, it allows comparing
362 with integer variables too, but that's not a common mistake to
363 make. It's important to disable comparison with unrelated types to
364 prevent accidentally comparing with unrelated enum values, which
365 are convertible to integer, and thus coupled with enum_flags
366 conversion to underlying type too, would trigger the built-in 'bool
367 operator==(unsigned, int)' operator. */
369 #define ENUM_FLAGS_GEN_COMP(OPERATOR_OP, OP) \
371 /* enum_flags OP enum_flags */ \
373 template <typename enum_type> \
374 constexpr bool \
375 OPERATOR_OP (enum_flags<enum_type> lhs, enum_flags<enum_type> rhs) \
376 { return lhs.raw () OP rhs.raw (); } \
378 /* enum_flags OP other */ \
380 template <typename enum_type> \
381 constexpr bool \
382 OPERATOR_OP (enum_flags<enum_type> lhs, enum_type rhs) \
383 { return lhs.raw () OP rhs; } \
385 template <typename enum_type> \
386 constexpr bool \
387 OPERATOR_OP (enum_flags<enum_type> lhs, int rhs) \
388 { return lhs.raw () OP rhs; } \
390 template <typename enum_type, typename U> \
391 constexpr bool \
392 OPERATOR_OP (enum_flags<enum_type> lhs, U rhs) = delete; \
394 /* other OP enum_flags */ \
396 template <typename enum_type> \
397 constexpr bool \
398 OPERATOR_OP (enum_type lhs, enum_flags<enum_type> rhs) \
399 { return lhs OP rhs.raw (); } \
401 template <typename enum_type> \
402 constexpr bool \
403 OPERATOR_OP (int lhs, enum_flags<enum_type> rhs) \
404 { return lhs OP rhs.raw (); } \
406 template <typename enum_type, typename U> \
407 constexpr bool \
408 OPERATOR_OP (U lhs, enum_flags<enum_type> rhs) = delete;
410 ENUM_FLAGS_GEN_COMP (operator==, ==)
411 ENUM_FLAGS_GEN_COMP (operator!=, !=)
413 /* Unary operators for the raw flags enum. */
415 /* We require underlying type to be unsigned when using operator~ --
416 if it were not unsigned, undefined behavior could result. However,
417 asserting this in the class itself would require too many
418 unnecessary changes to usages of otherwise OK enum types. */
419 template <typename enum_type,
420 typename = is_enum_flags_enum_type_t<enum_type>,
421 typename
422 = gdb::Requires<enum_flags_detail::EnumIsSafeForBitwiseComplement<enum_type>>>
423 constexpr enum_type
424 operator~ (enum_type e)
426 using underlying = typename enum_flags<enum_type>::underlying_type;
427 /* Cast to ULONGEST first, to prevent integer promotions from enums
428 with fixed underlying type std::uint8_t or std::uint16_t to
429 signed int. This ensures we apply the bitwise complement on an
430 unsigned type. */
431 return (enum_type)(underlying) ~ULONGEST (e);
434 template <typename enum_type,
435 typename = is_enum_flags_enum_type_t<enum_type>,
436 typename = gdb::Requires<enum_flags_detail::EnumIsUnsafeForBitwiseComplement<enum_type>>>
437 constexpr void operator~ (enum_type e) = delete;
439 template <typename enum_type,
440 typename = is_enum_flags_enum_type_t<enum_type>,
441 typename
442 = gdb::Requires<enum_flags_detail::EnumIsSafeForBitwiseComplement<enum_type>>>
443 constexpr enum_flags<enum_type>
444 operator~ (enum_flags<enum_type> e)
446 using underlying = typename enum_flags<enum_type>::underlying_type;
447 /* Cast to ULONGEST first, to prevent integer promotions from enums
448 with fixed underlying type std::uint8_t or std::uint16_t to
449 signed int. This ensures we apply the bitwise complement on an
450 unsigned type. */
451 return (enum_type)(underlying) ~ULONGEST (e);
454 template <typename enum_type,
455 typename = is_enum_flags_enum_type_t<enum_type>,
456 typename = gdb::Requires<enum_flags_detail::EnumIsUnsafeForBitwiseComplement<enum_type>>>
457 constexpr void operator~ (enum_flags<enum_type> e) = delete;
459 /* Delete operator<< and operator>>. */
461 template <typename enum_type, typename any_type,
462 typename = is_enum_flags_enum_type_t<enum_type>>
463 void operator<< (const enum_type &, const any_type &) = delete;
465 template <typename enum_type, typename any_type,
466 typename = is_enum_flags_enum_type_t<enum_type>>
467 void operator<< (const enum_flags<enum_type> &, const any_type &) = delete;
469 template <typename enum_type, typename any_type,
470 typename = is_enum_flags_enum_type_t<enum_type>>
471 void operator>> (const enum_type &, const any_type &) = delete;
473 template <typename enum_type, typename any_type,
474 typename = is_enum_flags_enum_type_t<enum_type>>
475 void operator>> (const enum_flags<enum_type> &, const any_type &) = delete;
477 template<typename E>
478 template<size_t N>
479 std::string
480 enum_flags<E>::to_string (const string_mapping (&mapping)[N]) const
482 enum_type flags = raw ();
483 std::string res = hex_string (flags);
484 res += " [";
486 bool need_space = false;
487 for (const auto &entry : mapping)
489 if ((flags & entry.flag) != 0)
491 /* Work with an unsigned version of the underlying type,
492 because if enum_type's underlying type is signed, op~
493 won't be defined for it, and, bitwise operations on
494 signed types are implementation defined. */
495 using uns = typename std::make_unsigned<underlying_type>::type;
496 flags &= (enum_type) ~(uns) entry.flag;
498 if (need_space)
499 res += " ";
500 res += entry.str;
502 need_space = true;
506 /* If there were flags not included in the mapping, print them as
507 a hex number. */
508 if (flags != 0)
510 if (need_space)
511 res += " ";
512 res += hex_string (flags);
515 res += "]";
517 return res;
520 #endif /* GDBSUPPORT_ENUM_FLAGS_H */