xref: /netbsd-src/external/gpl3/gdb/dist/gdbsupport/enum-flags.h (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
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