1*5ba1f45fSchristos /* Copyright (C) 2015-2024 Free Software Foundation, Inc. 28dffb485Schristos 38dffb485Schristos This file is part of GDB. 48dffb485Schristos 58dffb485Schristos This program is free software; you can redistribute it and/or modify 68dffb485Schristos it under the terms of the GNU General Public License as published by 78dffb485Schristos the Free Software Foundation; either version 3 of the License, or 88dffb485Schristos (at your option) any later version. 98dffb485Schristos 108dffb485Schristos This program is distributed in the hope that it will be useful, 118dffb485Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 128dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138dffb485Schristos GNU General Public License for more details. 148dffb485Schristos 158dffb485Schristos You should have received a copy of the GNU General Public License 168dffb485Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 178dffb485Schristos 188dffb485Schristos #ifndef COMMON_ENUM_FLAGS_H 198dffb485Schristos #define COMMON_ENUM_FLAGS_H 208dffb485Schristos 214b169a6bSchristos #include "traits.h" 224b169a6bSchristos 238dffb485Schristos /* Type-safe wrapper for enum flags. enum flags are enums where the 248dffb485Schristos values are bits that are meant to be ORed together. 258dffb485Schristos 268dffb485Schristos This allows writing code like the below, while with raw enums this 278dffb485Schristos would fail to compile without casts to enum type at the assignments 288dffb485Schristos to 'f': 298dffb485Schristos 308dffb485Schristos enum some_flag 318dffb485Schristos { 328dffb485Schristos flag_val1 = 1 << 1, 338dffb485Schristos flag_val2 = 1 << 2, 348dffb485Schristos flag_val3 = 1 << 3, 358dffb485Schristos flag_val4 = 1 << 4, 368dffb485Schristos }; 378dffb485Schristos DEF_ENUM_FLAGS_TYPE(enum some_flag, some_flags); 388dffb485Schristos 398dffb485Schristos some_flags f = flag_val1 | flag_val2; 408dffb485Schristos f |= flag_val3; 418dffb485Schristos 428dffb485Schristos It's also possible to assign literal zero to an enum flags variable 438dffb485Schristos (meaning, no flags), dispensing adding an awkward explicit "no 448dffb485Schristos value" value to the enumeration. For example: 458dffb485Schristos 468dffb485Schristos some_flags f = 0; 478dffb485Schristos f |= flag_val3 | flag_val4; 488dffb485Schristos 498dffb485Schristos Note that literal integers other than zero fail to compile: 508dffb485Schristos 518dffb485Schristos some_flags f = 1; // error 528dffb485Schristos */ 538dffb485Schristos 548dffb485Schristos #ifdef __cplusplus 558dffb485Schristos 564b169a6bSchristos /* Use this to mark an enum as flags enum. It defines FLAGS_TYPE as 578dffb485Schristos enum_flags wrapper class for ENUM, and enables the global operator 588dffb485Schristos overloads for ENUM. */ 598dffb485Schristos #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type) \ 608dffb485Schristos typedef enum_flags<enum_type> flags_type; \ 614b169a6bSchristos void is_enum_flags_enum_type (enum_type *) 628dffb485Schristos 634b169a6bSchristos /* To enable the global enum_flags operators for enum, declare an 644b169a6bSchristos "is_enum_flags_enum_type" overload that has exactly one parameter, 654b169a6bSchristos of type a pointer to that enum class. E.g.,: 664b169a6bSchristos 674b169a6bSchristos void is_enum_flags_enum_type (enum some_flag *); 684b169a6bSchristos 694b169a6bSchristos The function does not need to be defined, only declared. 704b169a6bSchristos DEF_ENUM_FLAGS_TYPE declares this. 714b169a6bSchristos 724b169a6bSchristos A function declaration is preferred over a traits type, because the 734b169a6bSchristos former allows calling the DEF_ENUM_FLAGS_TYPE macro inside a 744b169a6bSchristos namespace to define the corresponding enum flags type in that 754b169a6bSchristos namespace. The compiler finds the corresponding 764b169a6bSchristos is_enum_flags_enum_type function via ADL. */ 774b169a6bSchristos 784b169a6bSchristos /* Note that std::underlying_type<enum_type> is not what we want here, 794b169a6bSchristos since that returns unsigned int even when the enum decays to signed 804b169a6bSchristos int. */ 818dffb485Schristos template<int size, bool sign> class integer_for_size { typedef void type; }; 828dffb485Schristos template<> struct integer_for_size<1, 0> { typedef uint8_t type; }; 838dffb485Schristos template<> struct integer_for_size<2, 0> { typedef uint16_t type; }; 848dffb485Schristos template<> struct integer_for_size<4, 0> { typedef uint32_t type; }; 858dffb485Schristos template<> struct integer_for_size<8, 0> { typedef uint64_t type; }; 868dffb485Schristos template<> struct integer_for_size<1, 1> { typedef int8_t type; }; 878dffb485Schristos template<> struct integer_for_size<2, 1> { typedef int16_t type; }; 888dffb485Schristos template<> struct integer_for_size<4, 1> { typedef int32_t type; }; 898dffb485Schristos template<> struct integer_for_size<8, 1> { typedef int64_t type; }; 908dffb485Schristos 918dffb485Schristos template<typename T> 928dffb485Schristos struct enum_underlying_type 938dffb485Schristos { 944b169a6bSchristos DIAGNOSTIC_PUSH 954b169a6bSchristos DIAGNOSTIC_IGNORE_ENUM_CONSTEXPR_CONVERSION 968dffb485Schristos typedef typename 978dffb485Schristos integer_for_size<sizeof (T), static_cast<bool>(T (-1) < T (0))>::type 988dffb485Schristos type; 994b169a6bSchristos DIAGNOSTIC_POP 1008dffb485Schristos }; 1018dffb485Schristos 1024b169a6bSchristos namespace enum_flags_detail 1038dffb485Schristos { 1048dffb485Schristos 1058dffb485Schristos /* Private type used to support initializing flag types with zero: 1068dffb485Schristos 1078dffb485Schristos foo_flags f = 0; 1088dffb485Schristos 1098dffb485Schristos but not other integers: 1108dffb485Schristos 1118dffb485Schristos foo_flags f = 1; 1128dffb485Schristos 1138dffb485Schristos The way this works is that we define an implicit constructor that 1148dffb485Schristos takes a pointer to this private type. Since nothing can 1158dffb485Schristos instantiate an object of this type, the only possible pointer to 1168dffb485Schristos pass to the constructor is the NULL pointer, or, zero. */ 1178dffb485Schristos struct zero_type; 1188dffb485Schristos 1194b169a6bSchristos /* gdb::Requires trait helpers. */ 1204b169a6bSchristos template <typename enum_type> 1214b169a6bSchristos using EnumIsUnsigned 1224b169a6bSchristos = std::is_unsigned<typename enum_underlying_type<enum_type>::type>; 1234b169a6bSchristos template <typename enum_type> 1244b169a6bSchristos using EnumIsSigned 1254b169a6bSchristos = std::is_signed<typename enum_underlying_type<enum_type>::type>; 1264b169a6bSchristos 1278dffb485Schristos } 1288dffb485Schristos 1294b169a6bSchristos template <typename E> 1304b169a6bSchristos class enum_flags 1314b169a6bSchristos { 1324b169a6bSchristos public: 1334b169a6bSchristos typedef E enum_type; 1344b169a6bSchristos typedef typename enum_underlying_type<enum_type>::type underlying_type; 1354b169a6bSchristos 136*5ba1f45fSchristos /* For to_string. Maps one enumerator of E to a string. */ 137*5ba1f45fSchristos struct string_mapping 138*5ba1f45fSchristos { 139*5ba1f45fSchristos E flag; 140*5ba1f45fSchristos const char *str; 141*5ba1f45fSchristos }; 142*5ba1f45fSchristos 143*5ba1f45fSchristos /* Convenience for to_string implementations, to build a 144*5ba1f45fSchristos string_mapping array. */ 145*5ba1f45fSchristos #define MAP_ENUM_FLAG(ENUM_FLAG) { ENUM_FLAG, #ENUM_FLAG } 146*5ba1f45fSchristos 1478dffb485Schristos public: 1488dffb485Schristos /* Allow default construction. */ 1494b169a6bSchristos constexpr enum_flags () 1508dffb485Schristos : m_enum_value ((enum_type) 0) 1518dffb485Schristos {} 1528dffb485Schristos 1534b169a6bSchristos /* The default move/copy ctor/assignment do the right thing. */ 1544b169a6bSchristos 1558dffb485Schristos /* If you get an error saying these two overloads are ambiguous, 1568dffb485Schristos then you tried to mix values of different enum types. */ 1574b169a6bSchristos constexpr enum_flags (enum_type e) 1588dffb485Schristos : m_enum_value (e) 1598dffb485Schristos {} 1604b169a6bSchristos constexpr enum_flags (enum_flags_detail::zero_type *zero) 1618dffb485Schristos : m_enum_value ((enum_type) 0) 1628dffb485Schristos {} 1638dffb485Schristos 1644b169a6bSchristos enum_flags &operator&= (enum_flags e) & 1658dffb485Schristos { 1664b169a6bSchristos m_enum_value = (enum_type) (m_enum_value & e.m_enum_value); 1678dffb485Schristos return *this; 1688dffb485Schristos } 1694b169a6bSchristos enum_flags &operator|= (enum_flags e) & 1708dffb485Schristos { 1714b169a6bSchristos m_enum_value = (enum_type) (m_enum_value | e.m_enum_value); 1728dffb485Schristos return *this; 1738dffb485Schristos } 1744b169a6bSchristos enum_flags &operator^= (enum_flags e) & 1758dffb485Schristos { 1764b169a6bSchristos m_enum_value = (enum_type) (m_enum_value ^ e.m_enum_value); 1778dffb485Schristos return *this; 1788dffb485Schristos } 1798dffb485Schristos 1804b169a6bSchristos /* Delete rval versions. */ 1814b169a6bSchristos void operator&= (enum_flags e) && = delete; 1824b169a6bSchristos void operator|= (enum_flags e) && = delete; 1834b169a6bSchristos void operator^= (enum_flags e) && = delete; 1844b169a6bSchristos 1854b169a6bSchristos /* Like raw enums, allow conversion to the underlying type. */ 1864b169a6bSchristos constexpr operator underlying_type () const 1878dffb485Schristos { 1888dffb485Schristos return m_enum_value; 1898dffb485Schristos } 1908dffb485Schristos 1914b169a6bSchristos /* Get the underlying value as a raw enum. */ 1924b169a6bSchristos constexpr enum_type raw () const 1938dffb485Schristos { 1944b169a6bSchristos return m_enum_value; 1958dffb485Schristos } 1964b169a6bSchristos 1974b169a6bSchristos /* Binary operations involving some unrelated type (which would be a 1984b169a6bSchristos bug) are implemented as non-members, and deleted. */ 1998dffb485Schristos 200*5ba1f45fSchristos /* Convert this object to a std::string, using MAPPING as 201*5ba1f45fSchristos enumerator-to-string mapping array. This is not meant to be 202*5ba1f45fSchristos called directly. Instead, enum_flags specializations should have 203*5ba1f45fSchristos their own to_string function wrapping this one, thus hiding the 204*5ba1f45fSchristos mapping array from callers. 205*5ba1f45fSchristos 206*5ba1f45fSchristos Note: this is defined outside the template class so it can use 207*5ba1f45fSchristos the global operators for enum_type, which are only defined after 208*5ba1f45fSchristos the template class. */ 209*5ba1f45fSchristos template<size_t N> 210*5ba1f45fSchristos std::string to_string (const string_mapping (&mapping)[N]) const; 211*5ba1f45fSchristos 2128dffb485Schristos private: 2138dffb485Schristos /* Stored as enum_type because GDB knows to print the bit flags 2148dffb485Schristos neatly if the enum values look like bit flags. */ 2158dffb485Schristos enum_type m_enum_value; 2168dffb485Schristos }; 2178dffb485Schristos 2184b169a6bSchristos template <typename E> 2194b169a6bSchristos using is_enum_flags_enum_type_t 2204b169a6bSchristos = decltype (is_enum_flags_enum_type (std::declval<E *> ())); 2214b169a6bSchristos 2228dffb485Schristos /* Global operator overloads. */ 2238dffb485Schristos 2244b169a6bSchristos /* Generate binary operators. */ 2258dffb485Schristos 2264b169a6bSchristos #define ENUM_FLAGS_GEN_BINOP(OPERATOR_OP, OP) \ 2274b169a6bSchristos \ 2284b169a6bSchristos /* Raw enum on both LHS/RHS. Returns raw enum type. */ \ 2294b169a6bSchristos template <typename enum_type, \ 2304b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 2314b169a6bSchristos constexpr enum_type \ 2324b169a6bSchristos OPERATOR_OP (enum_type e1, enum_type e2) \ 2334b169a6bSchristos { \ 2344b169a6bSchristos using underlying = typename enum_flags<enum_type>::underlying_type; \ 2354b169a6bSchristos return (enum_type) (underlying (e1) OP underlying (e2)); \ 2364b169a6bSchristos } \ 2374b169a6bSchristos \ 2384b169a6bSchristos /* enum_flags on the LHS. */ \ 2394b169a6bSchristos template <typename enum_type, \ 2404b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 2414b169a6bSchristos constexpr enum_flags<enum_type> \ 2424b169a6bSchristos OPERATOR_OP (enum_flags<enum_type> e1, enum_type e2) \ 2434b169a6bSchristos { return e1.raw () OP e2; } \ 2444b169a6bSchristos \ 2454b169a6bSchristos /* enum_flags on the RHS. */ \ 2464b169a6bSchristos template <typename enum_type, \ 2474b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 2484b169a6bSchristos constexpr enum_flags<enum_type> \ 2494b169a6bSchristos OPERATOR_OP (enum_type e1, enum_flags<enum_type> e2) \ 2504b169a6bSchristos { return e1 OP e2.raw (); } \ 2514b169a6bSchristos \ 2524b169a6bSchristos /* enum_flags on both LHS/RHS. */ \ 2534b169a6bSchristos template <typename enum_type, \ 2544b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 2554b169a6bSchristos constexpr enum_flags<enum_type> \ 2564b169a6bSchristos OPERATOR_OP (enum_flags<enum_type> e1, enum_flags<enum_type> e2) \ 2574b169a6bSchristos { return e1.raw () OP e2.raw (); } \ 2584b169a6bSchristos \ 2594b169a6bSchristos /* Delete cases involving unrelated types. */ \ 2604b169a6bSchristos \ 2614b169a6bSchristos template <typename enum_type, typename unrelated_type, \ 2624b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 2634b169a6bSchristos constexpr enum_flags<enum_type> \ 2644b169a6bSchristos OPERATOR_OP (enum_type e1, unrelated_type e2) = delete; \ 2654b169a6bSchristos \ 2664b169a6bSchristos template <typename enum_type, typename unrelated_type, \ 2674b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 2684b169a6bSchristos constexpr enum_flags<enum_type> \ 2694b169a6bSchristos OPERATOR_OP (unrelated_type e1, enum_type e2) = delete; \ 2704b169a6bSchristos \ 2714b169a6bSchristos template <typename enum_type, typename unrelated_type, \ 2724b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 2734b169a6bSchristos constexpr enum_flags<enum_type> \ 2744b169a6bSchristos OPERATOR_OP (enum_flags<enum_type> e1, unrelated_type e2) = delete; \ 2754b169a6bSchristos \ 2764b169a6bSchristos template <typename enum_type, typename unrelated_type, \ 2774b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 2784b169a6bSchristos constexpr enum_flags<enum_type> \ 2794b169a6bSchristos OPERATOR_OP (unrelated_type e1, enum_flags<enum_type> e2) = delete; 2808dffb485Schristos 2814b169a6bSchristos /* Generate non-member compound assignment operators. Only the raw 2824b169a6bSchristos enum versions are defined here. The enum_flags versions are 2834b169a6bSchristos defined as member functions, simply because it's less code that 2844b169a6bSchristos way. 2858dffb485Schristos 2864b169a6bSchristos Note we delete operators that would allow e.g., 2874b169a6bSchristos 2884b169a6bSchristos "enum_type | 1" or "enum_type1 | enum_type2" 2894b169a6bSchristos 2904b169a6bSchristos because that would allow a mistake like : 2914b169a6bSchristos enum flags1 { F1_FLAGS1 = 1 }; 2924b169a6bSchristos enum flags2 { F2_FLAGS2 = 2 }; 2934b169a6bSchristos enum flags1 val; 2944b169a6bSchristos switch (val) { 2954b169a6bSchristos case F1_FLAGS1 | F2_FLAGS2: 2964b169a6bSchristos ... 2974b169a6bSchristos 2984b169a6bSchristos If you really need to 'or' enumerators of different flag types, 2994b169a6bSchristos cast to integer first. 3004b169a6bSchristos */ 3014b169a6bSchristos #define ENUM_FLAGS_GEN_COMPOUND_ASSIGN(OPERATOR_OP, OP) \ 3024b169a6bSchristos /* lval reference version. */ \ 3034b169a6bSchristos template <typename enum_type, \ 3044b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 3054b169a6bSchristos constexpr enum_type & \ 3064b169a6bSchristos OPERATOR_OP (enum_type &e1, enum_type e2) \ 3074b169a6bSchristos { return e1 = e1 OP e2; } \ 3084b169a6bSchristos \ 3094b169a6bSchristos /* rval reference version. */ \ 3104b169a6bSchristos template <typename enum_type, \ 3114b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 3124b169a6bSchristos void \ 3134b169a6bSchristos OPERATOR_OP (enum_type &&e1, enum_type e2) = delete; \ 3144b169a6bSchristos \ 3154b169a6bSchristos /* Delete compound assignment from unrelated types. */ \ 3164b169a6bSchristos \ 3174b169a6bSchristos template <typename enum_type, typename other_enum_type, \ 3184b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 3194b169a6bSchristos constexpr enum_type & \ 3204b169a6bSchristos OPERATOR_OP (enum_type &e1, other_enum_type e2) = delete; \ 3214b169a6bSchristos \ 3224b169a6bSchristos template <typename enum_type, typename other_enum_type, \ 3234b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> \ 3244b169a6bSchristos void \ 3254b169a6bSchristos OPERATOR_OP (enum_type &&e1, other_enum_type e2) = delete; 3264b169a6bSchristos 3274b169a6bSchristos ENUM_FLAGS_GEN_BINOP (operator|, |) 3284b169a6bSchristos ENUM_FLAGS_GEN_BINOP (operator&, &) 3294b169a6bSchristos ENUM_FLAGS_GEN_BINOP (operator^, ^) 3304b169a6bSchristos 3314b169a6bSchristos ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator|=, |) 3324b169a6bSchristos ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator&=, &) 3334b169a6bSchristos ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator^=, ^) 3344b169a6bSchristos 3354b169a6bSchristos /* Allow comparison with enum_flags, raw enum, and integers, only. 3364b169a6bSchristos The latter case allows "== 0". As side effect, it allows comparing 3374b169a6bSchristos with integer variables too, but that's not a common mistake to 3384b169a6bSchristos make. It's important to disable comparison with unrelated types to 3394b169a6bSchristos prevent accidentally comparing with unrelated enum values, which 3404b169a6bSchristos are convertible to integer, and thus coupled with enum_flags 341*5ba1f45fSchristos conversion to underlying type too, would trigger the built-in 'bool 3424b169a6bSchristos operator==(unsigned, int)' operator. */ 3434b169a6bSchristos 3444b169a6bSchristos #define ENUM_FLAGS_GEN_COMP(OPERATOR_OP, OP) \ 3454b169a6bSchristos \ 3464b169a6bSchristos /* enum_flags OP enum_flags */ \ 3474b169a6bSchristos \ 3484b169a6bSchristos template <typename enum_type> \ 3494b169a6bSchristos constexpr bool \ 3504b169a6bSchristos OPERATOR_OP (enum_flags<enum_type> lhs, enum_flags<enum_type> rhs) \ 3514b169a6bSchristos { return lhs.raw () OP rhs.raw (); } \ 3524b169a6bSchristos \ 3534b169a6bSchristos /* enum_flags OP other */ \ 3544b169a6bSchristos \ 3554b169a6bSchristos template <typename enum_type> \ 3564b169a6bSchristos constexpr bool \ 3574b169a6bSchristos OPERATOR_OP (enum_flags<enum_type> lhs, enum_type rhs) \ 3584b169a6bSchristos { return lhs.raw () OP rhs; } \ 3594b169a6bSchristos \ 3604b169a6bSchristos template <typename enum_type> \ 3614b169a6bSchristos constexpr bool \ 3624b169a6bSchristos OPERATOR_OP (enum_flags<enum_type> lhs, int rhs) \ 3634b169a6bSchristos { return lhs.raw () OP rhs; } \ 3644b169a6bSchristos \ 3654b169a6bSchristos template <typename enum_type, typename U> \ 3664b169a6bSchristos constexpr bool \ 3674b169a6bSchristos OPERATOR_OP (enum_flags<enum_type> lhs, U rhs) = delete; \ 3684b169a6bSchristos \ 3694b169a6bSchristos /* other OP enum_flags */ \ 3704b169a6bSchristos \ 3714b169a6bSchristos template <typename enum_type> \ 3724b169a6bSchristos constexpr bool \ 3734b169a6bSchristos OPERATOR_OP (enum_type lhs, enum_flags<enum_type> rhs) \ 3744b169a6bSchristos { return lhs OP rhs.raw (); } \ 3754b169a6bSchristos \ 3764b169a6bSchristos template <typename enum_type> \ 3774b169a6bSchristos constexpr bool \ 3784b169a6bSchristos OPERATOR_OP (int lhs, enum_flags<enum_type> rhs) \ 3794b169a6bSchristos { return lhs OP rhs.raw (); } \ 3804b169a6bSchristos \ 3814b169a6bSchristos template <typename enum_type, typename U> \ 3824b169a6bSchristos constexpr bool \ 3834b169a6bSchristos OPERATOR_OP (U lhs, enum_flags<enum_type> rhs) = delete; 3844b169a6bSchristos 3854b169a6bSchristos ENUM_FLAGS_GEN_COMP (operator==, ==) 3864b169a6bSchristos ENUM_FLAGS_GEN_COMP (operator!=, !=) 3874b169a6bSchristos 3884b169a6bSchristos /* Unary operators for the raw flags enum. */ 3894b169a6bSchristos 3904b169a6bSchristos /* We require underlying type to be unsigned when using operator~ -- 3914b169a6bSchristos if it were not unsigned, undefined behavior could result. However, 3924b169a6bSchristos asserting this in the class itself would require too many 3934b169a6bSchristos unnecessary changes to usages of otherwise OK enum types. */ 3944b169a6bSchristos template <typename enum_type, 3954b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>, 3964b169a6bSchristos typename 3974b169a6bSchristos = gdb::Requires<enum_flags_detail::EnumIsUnsigned<enum_type>>> 3984b169a6bSchristos constexpr enum_type 3998dffb485Schristos operator~ (enum_type e) 4008dffb485Schristos { 4014b169a6bSchristos using underlying = typename enum_flags<enum_type>::underlying_type; 4024b169a6bSchristos return (enum_type) ~underlying (e); 4038dffb485Schristos } 4048dffb485Schristos 4054b169a6bSchristos template <typename enum_type, 4064b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>, 4074b169a6bSchristos typename = gdb::Requires<enum_flags_detail::EnumIsSigned<enum_type>>> 4084b169a6bSchristos constexpr void operator~ (enum_type e) = delete; 4094b169a6bSchristos 4104b169a6bSchristos template <typename enum_type, 4114b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>, 4124b169a6bSchristos typename 4134b169a6bSchristos = gdb::Requires<enum_flags_detail::EnumIsUnsigned<enum_type>>> 4144b169a6bSchristos constexpr enum_flags<enum_type> 4154b169a6bSchristos operator~ (enum_flags<enum_type> e) 4164b169a6bSchristos { 4174b169a6bSchristos using underlying = typename enum_flags<enum_type>::underlying_type; 4184b169a6bSchristos return (enum_type) ~underlying (e); 4194b169a6bSchristos } 4204b169a6bSchristos 4214b169a6bSchristos template <typename enum_type, 4224b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>, 4234b169a6bSchristos typename = gdb::Requires<enum_flags_detail::EnumIsSigned<enum_type>>> 4244b169a6bSchristos constexpr void operator~ (enum_flags<enum_type> e) = delete; 4254b169a6bSchristos 4264b169a6bSchristos /* Delete operator<< and operator>>. */ 4274b169a6bSchristos 4284b169a6bSchristos template <typename enum_type, typename any_type, 4294b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> 4304b169a6bSchristos void operator<< (const enum_type &, const any_type &) = delete; 4314b169a6bSchristos 4324b169a6bSchristos template <typename enum_type, typename any_type, 4334b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> 4344b169a6bSchristos void operator<< (const enum_flags<enum_type> &, const any_type &) = delete; 4354b169a6bSchristos 4364b169a6bSchristos template <typename enum_type, typename any_type, 4374b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> 4384b169a6bSchristos void operator>> (const enum_type &, const any_type &) = delete; 4394b169a6bSchristos 4404b169a6bSchristos template <typename enum_type, typename any_type, 4414b169a6bSchristos typename = is_enum_flags_enum_type_t<enum_type>> 4424b169a6bSchristos void operator>> (const enum_flags<enum_type> &, const any_type &) = delete; 4434b169a6bSchristos 444*5ba1f45fSchristos template<typename E> 445*5ba1f45fSchristos template<size_t N> 446*5ba1f45fSchristos std::string 447*5ba1f45fSchristos enum_flags<E>::to_string (const string_mapping (&mapping)[N]) const 448*5ba1f45fSchristos { 449*5ba1f45fSchristos enum_type flags = raw (); 450*5ba1f45fSchristos std::string res = hex_string (flags); 451*5ba1f45fSchristos res += " ["; 452*5ba1f45fSchristos 453*5ba1f45fSchristos bool need_space = false; 454*5ba1f45fSchristos for (const auto &entry : mapping) 455*5ba1f45fSchristos { 456*5ba1f45fSchristos if ((flags & entry.flag) != 0) 457*5ba1f45fSchristos { 458*5ba1f45fSchristos /* Work with an unsigned version of the underlying type, 459*5ba1f45fSchristos because if enum_type's underlying type is signed, op~ 460*5ba1f45fSchristos won't be defined for it, and, bitwise operations on 461*5ba1f45fSchristos signed types are implementation defined. */ 462*5ba1f45fSchristos using uns = typename std::make_unsigned<underlying_type>::type; 463*5ba1f45fSchristos flags &= (enum_type) ~(uns) entry.flag; 464*5ba1f45fSchristos 465*5ba1f45fSchristos if (need_space) 466*5ba1f45fSchristos res += " "; 467*5ba1f45fSchristos res += entry.str; 468*5ba1f45fSchristos 469*5ba1f45fSchristos need_space = true; 470*5ba1f45fSchristos } 471*5ba1f45fSchristos } 472*5ba1f45fSchristos 473*5ba1f45fSchristos /* If there were flags not included in the mapping, print them as 474*5ba1f45fSchristos a hex number. */ 475*5ba1f45fSchristos if (flags != 0) 476*5ba1f45fSchristos { 477*5ba1f45fSchristos if (need_space) 478*5ba1f45fSchristos res += " "; 479*5ba1f45fSchristos res += hex_string (flags); 480*5ba1f45fSchristos } 481*5ba1f45fSchristos 482*5ba1f45fSchristos res += "]"; 483*5ba1f45fSchristos 484*5ba1f45fSchristos return res; 485*5ba1f45fSchristos } 486*5ba1f45fSchristos 4878dffb485Schristos #else /* __cplusplus */ 4888dffb485Schristos 4898dffb485Schristos /* In C, the flags type is just a typedef for the enum type. */ 4908dffb485Schristos 4918dffb485Schristos #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type) \ 4928dffb485Schristos typedef enum_type flags_type 4938dffb485Schristos 4948dffb485Schristos #endif /* __cplusplus */ 4958dffb485Schristos 4968dffb485Schristos #endif /* COMMON_ENUM_FLAGS_H */ 497