Home | History | Annotate | Line # | Download | only in gdbsupport
      1  1.1.1.3  christos /* Copyright (C) 2015-2024 Free Software Foundation, Inc.
      2      1.1  christos 
      3      1.1  christos    This file is part of GDB.
      4      1.1  christos 
      5      1.1  christos    This program is free software; you can redistribute it and/or modify
      6      1.1  christos    it under the terms of the GNU General Public License as published by
      7      1.1  christos    the Free Software Foundation; either version 3 of the License, or
      8      1.1  christos    (at your option) any later version.
      9      1.1  christos 
     10      1.1  christos    This program is distributed in the hope that it will be useful,
     11      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13      1.1  christos    GNU General Public License for more details.
     14      1.1  christos 
     15      1.1  christos    You should have received a copy of the GNU General Public License
     16      1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     17      1.1  christos 
     18  1.1.1.4  christos #ifndef GDBSUPPORT_ENUM_FLAGS_H
     19  1.1.1.4  christos #define GDBSUPPORT_ENUM_FLAGS_H
     20      1.1  christos 
     21  1.1.1.2  christos #include "traits.h"
     22  1.1.1.2  christos 
     23      1.1  christos /* Type-safe wrapper for enum flags.  enum flags are enums where the
     24      1.1  christos    values are bits that are meant to be ORed together.
     25      1.1  christos 
     26      1.1  christos    This allows writing code like the below, while with raw enums this
     27      1.1  christos    would fail to compile without casts to enum type at the assignments
     28      1.1  christos    to 'f':
     29      1.1  christos 
     30      1.1  christos     enum some_flag
     31      1.1  christos     {
     32      1.1  christos        flag_val1 = 1 << 1,
     33      1.1  christos        flag_val2 = 1 << 2,
     34      1.1  christos        flag_val3 = 1 << 3,
     35      1.1  christos        flag_val4 = 1 << 4,
     36      1.1  christos     };
     37      1.1  christos     DEF_ENUM_FLAGS_TYPE(enum some_flag, some_flags);
     38      1.1  christos 
     39      1.1  christos     some_flags f = flag_val1 | flag_val2;
     40      1.1  christos     f |= flag_val3;
     41      1.1  christos 
     42      1.1  christos    It's also possible to assign literal zero to an enum flags variable
     43      1.1  christos    (meaning, no flags), dispensing adding an awkward explicit "no
     44      1.1  christos    value" value to the enumeration.  For example:
     45      1.1  christos 
     46      1.1  christos     some_flags f = 0;
     47      1.1  christos     f |= flag_val3 | flag_val4;
     48      1.1  christos 
     49      1.1  christos    Note that literal integers other than zero fail to compile:
     50      1.1  christos 
     51      1.1  christos     some_flags f = 1; // error
     52      1.1  christos */
     53      1.1  christos 
     54  1.1.1.2  christos /* Use this to mark an enum as flags enum.  It defines FLAGS_TYPE as
     55      1.1  christos    enum_flags wrapper class for ENUM, and enables the global operator
     56      1.1  christos    overloads for ENUM.  */
     57      1.1  christos #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type)	\
     58  1.1.1.4  christos   using flags_type = enum_flags<enum_type>;		\
     59  1.1.1.2  christos   void is_enum_flags_enum_type (enum_type *)
     60      1.1  christos 
     61  1.1.1.2  christos /* To enable the global enum_flags operators for enum, declare an
     62  1.1.1.2  christos    "is_enum_flags_enum_type" overload that has exactly one parameter,
     63  1.1.1.2  christos    of type a pointer to that enum class.  E.g.,:
     64  1.1.1.2  christos 
     65  1.1.1.2  christos      void is_enum_flags_enum_type (enum some_flag *);
     66  1.1.1.2  christos 
     67  1.1.1.2  christos    The function does not need to be defined, only declared.
     68  1.1.1.2  christos    DEF_ENUM_FLAGS_TYPE declares this.
     69  1.1.1.2  christos 
     70  1.1.1.2  christos    A function declaration is preferred over a traits type, because the
     71  1.1.1.2  christos    former allows calling the DEF_ENUM_FLAGS_TYPE macro inside a
     72  1.1.1.2  christos    namespace to define the corresponding enum flags type in that
     73  1.1.1.2  christos    namespace.  The compiler finds the corresponding
     74  1.1.1.2  christos    is_enum_flags_enum_type function via ADL.  */
     75  1.1.1.2  christos 
     76  1.1.1.2  christos namespace enum_flags_detail
     77      1.1  christos {
     78      1.1  christos 
     79  1.1.1.2  christos /* Private type used to support initializing flag types with zero:
     80      1.1  christos 
     81  1.1.1.2  christos    foo_flags f = 0;
     82      1.1  christos 
     83  1.1.1.2  christos    but not other integers:
     84      1.1  christos 
     85  1.1.1.2  christos    foo_flags f = 1;
     86      1.1  christos 
     87  1.1.1.2  christos    The way this works is that we define an implicit constructor that
     88  1.1.1.2  christos    takes a pointer to this private type.  Since nothing can
     89  1.1.1.2  christos    instantiate an object of this type, the only possible pointer to
     90  1.1.1.2  christos    pass to the constructor is the NULL pointer, or, zero.  */
     91  1.1.1.2  christos struct zero_type;
     92      1.1  christos 
     93  1.1.1.2  christos /* gdb::Requires trait helpers.  */
     94  1.1.1.2  christos template <typename enum_type>
     95  1.1.1.2  christos using EnumIsUnsigned
     96  1.1.1.4  christos   = std::is_unsigned<typename std::underlying_type<enum_type>::type>;
     97  1.1.1.4  christos 
     98  1.1.1.4  christos /* Helper to detect whether an enum has a fixed underlying type. This can be
     99  1.1.1.4  christos    achieved by using a scoped enum (in which case the type is "int") or
    100  1.1.1.4  christos    an explicit underlying type. C-style enums that are unscoped or do not
    101  1.1.1.4  christos    have an explicit underlying type have an implementation-defined underlying
    102  1.1.1.4  christos    type.
    103  1.1.1.4  christos 
    104  1.1.1.4  christos    https://timsong-cpp.github.io/cppwp/n4659/dcl.enum#5
    105  1.1.1.4  christos 
    106  1.1.1.4  christos    We need this trait in order to ensure that operator~ below does NOT
    107  1.1.1.4  christos    operate on old-style enums. This is because we apply operator~ on
    108  1.1.1.4  christos    the value and then cast the result to the enum_type. This is however
    109  1.1.1.4  christos    Undefined Behavior if the result does not fit in the range of possible
    110  1.1.1.4  christos    values for the enum. For enums with fixed underlying type, the entire
    111  1.1.1.4  christos    range of the integer is available. However, for old-style enums, the range
    112  1.1.1.4  christos    is only the smallest bit-field that can hold all the values of the
    113  1.1.1.4  christos    enumeration, typically much smaller than the underlying integer:
    114  1.1.1.4  christos 
    115  1.1.1.4  christos    https://timsong-cpp.github.io/cppwp/n4659/expr.static.cast#10
    116  1.1.1.4  christos    https://timsong-cpp.github.io/cppwp/n4659/dcl.enum#8
    117  1.1.1.4  christos 
    118  1.1.1.4  christos    To implement this, we leverage the fact that, since C++17, enums with
    119  1.1.1.4  christos    fixed underlying type can be list-initialized from an integer:
    120  1.1.1.4  christos    https://timsong-cpp.github.io/cppwp/n4659/dcl.init.list#3.7
    121  1.1.1.4  christos 
    122  1.1.1.4  christos    Old-style enums cannot be initialized like that, leading to ill-formed
    123  1.1.1.4  christos    code.
    124  1.1.1.4  christos 
    125  1.1.1.4  christos    We then use this together with SFINAE to create the desired trait.
    126  1.1.1.4  christos 
    127  1.1.1.4  christos */
    128  1.1.1.4  christos template <typename enum_type, typename = void>
    129  1.1.1.4  christos struct EnumHasFixedUnderlyingType : std::false_type
    130  1.1.1.4  christos {
    131  1.1.1.4  christos   static_assert(std::is_enum<enum_type>::value);
    132  1.1.1.4  christos };
    133  1.1.1.4  christos 
    134  1.1.1.4  christos /* Specialization that is active only if enum_type can be
    135  1.1.1.4  christos    list-initialized from an integer (0).  Only enums with fixed
    136  1.1.1.4  christos    underlying type satisfy this property in C++17.  */
    137  1.1.1.4  christos template <typename enum_type>
    138  1.1.1.4  christos struct EnumHasFixedUnderlyingType<enum_type, std::void_t<decltype(enum_type{0})>> : std::true_type
    139  1.1.1.4  christos {
    140  1.1.1.4  christos   static_assert(std::is_enum<enum_type>::value);
    141  1.1.1.4  christos };
    142  1.1.1.4  christos 
    143  1.1.1.2  christos template <typename enum_type>
    144  1.1.1.4  christos using EnumIsSafeForBitwiseComplement = std::conjunction<
    145  1.1.1.4  christos   EnumIsUnsigned<enum_type>,
    146  1.1.1.4  christos   EnumHasFixedUnderlyingType<enum_type>
    147  1.1.1.4  christos >;
    148  1.1.1.4  christos 
    149  1.1.1.4  christos template <typename enum_type>
    150  1.1.1.4  christos using EnumIsUnsafeForBitwiseComplement = std::negation<EnumIsSafeForBitwiseComplement<enum_type>>;
    151  1.1.1.2  christos 
    152  1.1.1.2  christos }
    153  1.1.1.2  christos 
    154  1.1.1.2  christos template <typename E>
    155  1.1.1.2  christos class enum_flags
    156  1.1.1.2  christos {
    157  1.1.1.2  christos public:
    158  1.1.1.4  christos   using enum_type = E;
    159  1.1.1.4  christos   using underlying_type = typename std::underlying_type<enum_type>::type;
    160      1.1  christos 
    161  1.1.1.3  christos   /* For to_string.  Maps one enumerator of E to a string.  */
    162  1.1.1.3  christos   struct string_mapping
    163  1.1.1.3  christos   {
    164  1.1.1.3  christos     E flag;
    165  1.1.1.3  christos     const char *str;
    166  1.1.1.3  christos   };
    167  1.1.1.3  christos 
    168  1.1.1.3  christos   /* Convenience for to_string implementations, to build a
    169  1.1.1.3  christos      string_mapping array.  */
    170  1.1.1.3  christos #define MAP_ENUM_FLAG(ENUM_FLAG) { ENUM_FLAG, #ENUM_FLAG }
    171  1.1.1.3  christos 
    172      1.1  christos public:
    173      1.1  christos   /* Allow default construction.  */
    174  1.1.1.2  christos   constexpr enum_flags ()
    175      1.1  christos     : m_enum_value ((enum_type) 0)
    176      1.1  christos   {}
    177      1.1  christos 
    178  1.1.1.2  christos   /* The default move/copy ctor/assignment do the right thing.  */
    179  1.1.1.2  christos 
    180      1.1  christos   /* If you get an error saying these two overloads are ambiguous,
    181      1.1  christos      then you tried to mix values of different enum types.  */
    182  1.1.1.2  christos   constexpr enum_flags (enum_type e)
    183      1.1  christos     : m_enum_value (e)
    184      1.1  christos   {}
    185  1.1.1.2  christos   constexpr enum_flags (enum_flags_detail::zero_type *zero)
    186      1.1  christos     : m_enum_value ((enum_type) 0)
    187      1.1  christos   {}
    188      1.1  christos 
    189  1.1.1.2  christos   enum_flags &operator&= (enum_flags e) &
    190      1.1  christos   {
    191  1.1.1.2  christos     m_enum_value = (enum_type) (m_enum_value & e.m_enum_value);
    192      1.1  christos     return *this;
    193      1.1  christos   }
    194  1.1.1.2  christos   enum_flags &operator|= (enum_flags e) &
    195      1.1  christos   {
    196  1.1.1.2  christos     m_enum_value = (enum_type) (m_enum_value | e.m_enum_value);
    197      1.1  christos     return *this;
    198      1.1  christos   }
    199  1.1.1.2  christos   enum_flags &operator^= (enum_flags e) &
    200      1.1  christos   {
    201  1.1.1.2  christos     m_enum_value = (enum_type) (m_enum_value ^ e.m_enum_value);
    202      1.1  christos     return *this;
    203      1.1  christos   }
    204      1.1  christos 
    205  1.1.1.2  christos   /* Delete rval versions.  */
    206  1.1.1.2  christos   void operator&= (enum_flags e) && = delete;
    207  1.1.1.2  christos   void operator|= (enum_flags e) && = delete;
    208  1.1.1.2  christos   void operator^= (enum_flags e) && = delete;
    209  1.1.1.2  christos 
    210  1.1.1.2  christos   /* Like raw enums, allow conversion to the underlying type.  */
    211  1.1.1.2  christos   constexpr operator underlying_type () const
    212      1.1  christos   {
    213      1.1  christos     return m_enum_value;
    214      1.1  christos   }
    215      1.1  christos 
    216  1.1.1.2  christos   /* Get the underlying value as a raw enum.  */
    217  1.1.1.2  christos   constexpr enum_type raw () const
    218      1.1  christos   {
    219  1.1.1.2  christos     return m_enum_value;
    220      1.1  christos   }
    221      1.1  christos 
    222  1.1.1.2  christos   /* Binary operations involving some unrelated type (which would be a
    223  1.1.1.2  christos      bug) are implemented as non-members, and deleted.  */
    224  1.1.1.2  christos 
    225  1.1.1.3  christos   /* Convert this object to a std::string, using MAPPING as
    226  1.1.1.3  christos      enumerator-to-string mapping array.  This is not meant to be
    227  1.1.1.3  christos      called directly.  Instead, enum_flags specializations should have
    228  1.1.1.3  christos      their own to_string function wrapping this one, thus hiding the
    229  1.1.1.3  christos      mapping array from callers.
    230  1.1.1.3  christos 
    231  1.1.1.3  christos      Note: this is defined outside the template class so it can use
    232  1.1.1.3  christos      the global operators for enum_type, which are only defined after
    233  1.1.1.3  christos      the template class.  */
    234  1.1.1.3  christos   template<size_t N>
    235  1.1.1.3  christos   std::string to_string (const string_mapping (&mapping)[N]) const;
    236  1.1.1.3  christos 
    237      1.1  christos private:
    238      1.1  christos   /* Stored as enum_type because GDB knows to print the bit flags
    239      1.1  christos      neatly if the enum values look like bit flags.  */
    240      1.1  christos   enum_type m_enum_value;
    241      1.1  christos };
    242      1.1  christos 
    243  1.1.1.2  christos template <typename E>
    244  1.1.1.2  christos using is_enum_flags_enum_type_t
    245  1.1.1.2  christos   = decltype (is_enum_flags_enum_type (std::declval<E *> ()));
    246  1.1.1.2  christos 
    247      1.1  christos /* Global operator overloads.  */
    248      1.1  christos 
    249  1.1.1.2  christos /* Generate binary operators.  */
    250      1.1  christos 
    251  1.1.1.2  christos #define ENUM_FLAGS_GEN_BINOP(OPERATOR_OP, OP)				\
    252  1.1.1.2  christos 									\
    253  1.1.1.2  christos   /* Raw enum on both LHS/RHS.  Returns raw enum type.  */		\
    254  1.1.1.2  christos   template <typename enum_type,						\
    255  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    256  1.1.1.2  christos   constexpr enum_type							\
    257  1.1.1.2  christos   OPERATOR_OP (enum_type e1, enum_type e2)				\
    258  1.1.1.2  christos   {									\
    259  1.1.1.2  christos     using underlying = typename enum_flags<enum_type>::underlying_type;	\
    260  1.1.1.2  christos     return (enum_type) (underlying (e1) OP underlying (e2));		\
    261  1.1.1.2  christos   }									\
    262  1.1.1.2  christos 									\
    263  1.1.1.2  christos   /* enum_flags on the LHS.  */						\
    264  1.1.1.2  christos   template <typename enum_type,						\
    265  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    266  1.1.1.2  christos   constexpr enum_flags<enum_type>					\
    267  1.1.1.2  christos   OPERATOR_OP (enum_flags<enum_type> e1, enum_type e2)			\
    268  1.1.1.2  christos   { return e1.raw () OP e2; }						\
    269  1.1.1.2  christos 									\
    270  1.1.1.2  christos   /* enum_flags on the RHS.  */						\
    271  1.1.1.2  christos   template <typename enum_type,						\
    272  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    273  1.1.1.2  christos   constexpr enum_flags<enum_type>					\
    274  1.1.1.2  christos   OPERATOR_OP (enum_type e1, enum_flags<enum_type> e2)			\
    275  1.1.1.2  christos   { return e1 OP e2.raw (); }						\
    276  1.1.1.2  christos 									\
    277  1.1.1.2  christos   /* enum_flags on both LHS/RHS.  */					\
    278  1.1.1.2  christos   template <typename enum_type,						\
    279  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    280  1.1.1.2  christos   constexpr enum_flags<enum_type>					\
    281  1.1.1.2  christos   OPERATOR_OP (enum_flags<enum_type> e1, enum_flags<enum_type> e2)	\
    282  1.1.1.2  christos   { return e1.raw () OP e2.raw (); }					\
    283  1.1.1.2  christos 									\
    284  1.1.1.2  christos   /* Delete cases involving unrelated types.  */			\
    285  1.1.1.2  christos 									\
    286  1.1.1.2  christos   template <typename enum_type, typename unrelated_type,		\
    287  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    288  1.1.1.2  christos   constexpr enum_flags<enum_type>					\
    289  1.1.1.2  christos   OPERATOR_OP (enum_type e1, unrelated_type e2) = delete;		\
    290  1.1.1.2  christos 									\
    291  1.1.1.2  christos   template <typename enum_type, typename unrelated_type,		\
    292  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    293  1.1.1.2  christos   constexpr enum_flags<enum_type>					\
    294  1.1.1.2  christos   OPERATOR_OP (unrelated_type e1, enum_type e2) = delete;		\
    295  1.1.1.2  christos 									\
    296  1.1.1.2  christos   template <typename enum_type, typename unrelated_type,		\
    297  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    298  1.1.1.2  christos   constexpr enum_flags<enum_type>					\
    299  1.1.1.2  christos   OPERATOR_OP (enum_flags<enum_type> e1, unrelated_type e2) = delete;	\
    300  1.1.1.2  christos 									\
    301  1.1.1.2  christos   template <typename enum_type, typename unrelated_type,		\
    302  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    303  1.1.1.2  christos   constexpr enum_flags<enum_type>					\
    304  1.1.1.2  christos   OPERATOR_OP (unrelated_type e1, enum_flags<enum_type> e2) = delete;
    305  1.1.1.2  christos 
    306  1.1.1.2  christos /* Generate non-member compound assignment operators.  Only the raw
    307  1.1.1.2  christos    enum versions are defined here.  The enum_flags versions are
    308  1.1.1.2  christos    defined as member functions, simply because it's less code that
    309  1.1.1.2  christos    way.
    310  1.1.1.2  christos 
    311  1.1.1.2  christos    Note we delete operators that would allow e.g.,
    312  1.1.1.2  christos 
    313  1.1.1.2  christos      "enum_type | 1" or "enum_type1 | enum_type2"
    314  1.1.1.2  christos 
    315  1.1.1.2  christos    because that would allow a mistake like :
    316  1.1.1.2  christos      enum flags1 { F1_FLAGS1 = 1 };
    317  1.1.1.2  christos      enum flags2 { F2_FLAGS2 = 2 };
    318  1.1.1.2  christos      enum flags1 val;
    319  1.1.1.2  christos      switch (val) {
    320  1.1.1.2  christos        case F1_FLAGS1 | F2_FLAGS2:
    321  1.1.1.2  christos      ...
    322      1.1  christos 
    323  1.1.1.2  christos    If you really need to 'or' enumerators of different flag types,
    324  1.1.1.2  christos    cast to integer first.
    325  1.1.1.2  christos */
    326  1.1.1.2  christos #define ENUM_FLAGS_GEN_COMPOUND_ASSIGN(OPERATOR_OP, OP)			\
    327  1.1.1.2  christos   /* lval reference version.  */					\
    328  1.1.1.2  christos   template <typename enum_type,						\
    329  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    330  1.1.1.2  christos   constexpr enum_type &							\
    331  1.1.1.2  christos   OPERATOR_OP (enum_type &e1, enum_type e2)				\
    332  1.1.1.2  christos   { return e1 = e1 OP e2; }						\
    333  1.1.1.2  christos 									\
    334  1.1.1.2  christos   /* rval reference version.  */					\
    335  1.1.1.2  christos   template <typename enum_type,						\
    336  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    337  1.1.1.2  christos   void									\
    338  1.1.1.2  christos   OPERATOR_OP (enum_type &&e1, enum_type e2) = delete;			\
    339  1.1.1.2  christos 									\
    340  1.1.1.2  christos   /* Delete compound assignment from unrelated types.  */		\
    341  1.1.1.2  christos 									\
    342  1.1.1.2  christos   template <typename enum_type, typename other_enum_type,		\
    343  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    344  1.1.1.2  christos   constexpr enum_type &							\
    345  1.1.1.2  christos   OPERATOR_OP (enum_type &e1, other_enum_type e2) = delete;		\
    346  1.1.1.2  christos 									\
    347  1.1.1.2  christos   template <typename enum_type, typename other_enum_type,		\
    348  1.1.1.2  christos 	    typename = is_enum_flags_enum_type_t<enum_type>>		\
    349  1.1.1.2  christos   void									\
    350  1.1.1.2  christos   OPERATOR_OP (enum_type &&e1, other_enum_type e2) = delete;
    351  1.1.1.2  christos 
    352  1.1.1.2  christos ENUM_FLAGS_GEN_BINOP (operator|, |)
    353  1.1.1.2  christos ENUM_FLAGS_GEN_BINOP (operator&, &)
    354  1.1.1.2  christos ENUM_FLAGS_GEN_BINOP (operator^, ^)
    355  1.1.1.2  christos 
    356  1.1.1.2  christos ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator|=, |)
    357  1.1.1.2  christos ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator&=, &)
    358  1.1.1.2  christos ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator^=, ^)
    359  1.1.1.2  christos 
    360  1.1.1.2  christos /* Allow comparison with enum_flags, raw enum, and integers, only.
    361  1.1.1.2  christos    The latter case allows "== 0".  As side effect, it allows comparing
    362  1.1.1.2  christos    with integer variables too, but that's not a common mistake to
    363  1.1.1.2  christos    make.  It's important to disable comparison with unrelated types to
    364  1.1.1.2  christos    prevent accidentally comparing with unrelated enum values, which
    365  1.1.1.2  christos    are convertible to integer, and thus coupled with enum_flags
    366  1.1.1.3  christos    conversion to underlying type too, would trigger the built-in 'bool
    367  1.1.1.2  christos    operator==(unsigned, int)' operator.  */
    368  1.1.1.2  christos 
    369  1.1.1.2  christos #define ENUM_FLAGS_GEN_COMP(OPERATOR_OP, OP)				\
    370  1.1.1.2  christos 									\
    371  1.1.1.2  christos   /* enum_flags OP enum_flags */					\
    372  1.1.1.2  christos 									\
    373  1.1.1.2  christos   template <typename enum_type>						\
    374  1.1.1.2  christos   constexpr bool							\
    375  1.1.1.2  christos   OPERATOR_OP (enum_flags<enum_type> lhs, enum_flags<enum_type> rhs)	\
    376  1.1.1.2  christos   { return lhs.raw () OP rhs.raw (); }					\
    377  1.1.1.2  christos 									\
    378  1.1.1.2  christos   /* enum_flags OP other */						\
    379  1.1.1.2  christos 									\
    380  1.1.1.2  christos   template <typename enum_type>						\
    381  1.1.1.2  christos   constexpr bool							\
    382  1.1.1.2  christos   OPERATOR_OP (enum_flags<enum_type> lhs, enum_type rhs)		\
    383  1.1.1.2  christos   { return lhs.raw () OP rhs; }						\
    384  1.1.1.2  christos 									\
    385  1.1.1.2  christos   template <typename enum_type>						\
    386  1.1.1.2  christos   constexpr bool							\
    387  1.1.1.2  christos   OPERATOR_OP (enum_flags<enum_type> lhs, int rhs)			\
    388  1.1.1.2  christos   { return lhs.raw () OP rhs; }						\
    389  1.1.1.2  christos 									\
    390  1.1.1.2  christos   template <typename enum_type, typename U>				\
    391  1.1.1.2  christos   constexpr bool							\
    392  1.1.1.2  christos   OPERATOR_OP (enum_flags<enum_type> lhs, U rhs) = delete;		\
    393  1.1.1.2  christos 									\
    394  1.1.1.2  christos   /* other OP enum_flags */						\
    395  1.1.1.2  christos 									\
    396  1.1.1.2  christos   template <typename enum_type>						\
    397  1.1.1.2  christos   constexpr bool							\
    398  1.1.1.2  christos   OPERATOR_OP (enum_type lhs, enum_flags<enum_type> rhs)		\
    399  1.1.1.2  christos   { return lhs OP rhs.raw (); }						\
    400  1.1.1.2  christos 									\
    401  1.1.1.2  christos   template <typename enum_type>						\
    402  1.1.1.2  christos   constexpr bool							\
    403  1.1.1.2  christos   OPERATOR_OP (int lhs, enum_flags<enum_type> rhs)			\
    404  1.1.1.2  christos   { return lhs OP rhs.raw (); }						\
    405  1.1.1.2  christos 									\
    406  1.1.1.2  christos   template <typename enum_type, typename U>				\
    407  1.1.1.2  christos   constexpr bool							\
    408  1.1.1.2  christos   OPERATOR_OP (U lhs, enum_flags<enum_type> rhs) = delete;
    409  1.1.1.2  christos 
    410  1.1.1.2  christos ENUM_FLAGS_GEN_COMP (operator==, ==)
    411  1.1.1.2  christos ENUM_FLAGS_GEN_COMP (operator!=, !=)
    412  1.1.1.2  christos 
    413  1.1.1.2  christos /* Unary operators for the raw flags enum.  */
    414  1.1.1.2  christos 
    415  1.1.1.2  christos /* We require underlying type to be unsigned when using operator~ --
    416  1.1.1.2  christos    if it were not unsigned, undefined behavior could result.  However,
    417  1.1.1.2  christos    asserting this in the class itself would require too many
    418  1.1.1.2  christos    unnecessary changes to usages of otherwise OK enum types.  */
    419  1.1.1.2  christos template <typename enum_type,
    420  1.1.1.2  christos 	  typename = is_enum_flags_enum_type_t<enum_type>,
    421  1.1.1.2  christos 	  typename
    422  1.1.1.4  christos 	    = gdb::Requires<enum_flags_detail::EnumIsSafeForBitwiseComplement<enum_type>>>
    423  1.1.1.2  christos constexpr enum_type
    424  1.1.1.2  christos operator~ (enum_type e)
    425      1.1  christos {
    426  1.1.1.2  christos   using underlying = typename enum_flags<enum_type>::underlying_type;
    427  1.1.1.4  christos   /* Cast to ULONGEST first, to prevent integer promotions from enums
    428  1.1.1.4  christos      with fixed underlying type std::uint8_t or std::uint16_t to
    429  1.1.1.4  christos      signed int.  This ensures we apply the bitwise complement on an
    430  1.1.1.4  christos      unsigned type.  */
    431  1.1.1.4  christos   return (enum_type)(underlying) ~ULONGEST (e);
    432      1.1  christos }
    433      1.1  christos 
    434  1.1.1.2  christos template <typename enum_type,
    435  1.1.1.2  christos 	  typename = is_enum_flags_enum_type_t<enum_type>,
    436  1.1.1.4  christos 	  typename = gdb::Requires<enum_flags_detail::EnumIsUnsafeForBitwiseComplement<enum_type>>>
    437  1.1.1.2  christos constexpr void operator~ (enum_type e) = delete;
    438  1.1.1.2  christos 
    439  1.1.1.2  christos template <typename enum_type,
    440  1.1.1.2  christos 	  typename = is_enum_flags_enum_type_t<enum_type>,
    441  1.1.1.2  christos 	  typename
    442  1.1.1.4  christos 	    = gdb::Requires<enum_flags_detail::EnumIsSafeForBitwiseComplement<enum_type>>>
    443  1.1.1.2  christos constexpr enum_flags<enum_type>
    444  1.1.1.2  christos operator~ (enum_flags<enum_type> e)
    445      1.1  christos {
    446  1.1.1.2  christos   using underlying = typename enum_flags<enum_type>::underlying_type;
    447  1.1.1.4  christos   /* Cast to ULONGEST first, to prevent integer promotions from enums
    448  1.1.1.4  christos      with fixed underlying type std::uint8_t or std::uint16_t to
    449  1.1.1.4  christos      signed int.  This ensures we apply the bitwise complement on an
    450  1.1.1.4  christos      unsigned type.  */
    451  1.1.1.4  christos   return (enum_type)(underlying) ~ULONGEST (e);
    452      1.1  christos }
    453      1.1  christos 
    454  1.1.1.2  christos template <typename enum_type,
    455  1.1.1.2  christos 	  typename = is_enum_flags_enum_type_t<enum_type>,
    456  1.1.1.4  christos 	  typename = gdb::Requires<enum_flags_detail::EnumIsUnsafeForBitwiseComplement<enum_type>>>
    457  1.1.1.2  christos constexpr void operator~ (enum_flags<enum_type> e) = delete;
    458  1.1.1.2  christos 
    459  1.1.1.2  christos /* Delete operator<< and operator>>.  */
    460  1.1.1.2  christos 
    461  1.1.1.2  christos template <typename enum_type, typename any_type,
    462  1.1.1.2  christos 	  typename = is_enum_flags_enum_type_t<enum_type>>
    463  1.1.1.2  christos void operator<< (const enum_type &, const any_type &) = delete;
    464  1.1.1.2  christos 
    465  1.1.1.2  christos template <typename enum_type, typename any_type,
    466  1.1.1.2  christos 	  typename = is_enum_flags_enum_type_t<enum_type>>
    467  1.1.1.2  christos void operator<< (const enum_flags<enum_type> &, const any_type &) = delete;
    468  1.1.1.2  christos 
    469  1.1.1.2  christos template <typename enum_type, typename any_type,
    470  1.1.1.2  christos 	  typename = is_enum_flags_enum_type_t<enum_type>>
    471  1.1.1.2  christos void operator>> (const enum_type &, const any_type &) = delete;
    472  1.1.1.2  christos 
    473  1.1.1.2  christos template <typename enum_type, typename any_type,
    474  1.1.1.2  christos 	  typename = is_enum_flags_enum_type_t<enum_type>>
    475  1.1.1.2  christos void operator>> (const enum_flags<enum_type> &, const any_type &) = delete;
    476  1.1.1.2  christos 
    477  1.1.1.3  christos template<typename E>
    478  1.1.1.3  christos template<size_t N>
    479  1.1.1.3  christos std::string
    480  1.1.1.3  christos enum_flags<E>::to_string (const string_mapping (&mapping)[N]) const
    481  1.1.1.3  christos {
    482  1.1.1.3  christos   enum_type flags = raw ();
    483  1.1.1.3  christos   std::string res = hex_string (flags);
    484  1.1.1.3  christos   res += " [";
    485  1.1.1.3  christos 
    486  1.1.1.3  christos   bool need_space = false;
    487  1.1.1.3  christos   for (const auto &entry : mapping)
    488  1.1.1.3  christos     {
    489  1.1.1.3  christos       if ((flags & entry.flag) != 0)
    490  1.1.1.3  christos 	{
    491  1.1.1.3  christos 	  /* Work with an unsigned version of the underlying type,
    492  1.1.1.3  christos 	     because if enum_type's underlying type is signed, op~
    493  1.1.1.3  christos 	     won't be defined for it, and, bitwise operations on
    494  1.1.1.3  christos 	     signed types are implementation defined.  */
    495  1.1.1.3  christos 	  using uns = typename std::make_unsigned<underlying_type>::type;
    496  1.1.1.3  christos 	  flags &= (enum_type) ~(uns) entry.flag;
    497  1.1.1.3  christos 
    498  1.1.1.3  christos 	  if (need_space)
    499  1.1.1.3  christos 	    res += " ";
    500  1.1.1.3  christos 	  res += entry.str;
    501  1.1.1.3  christos 
    502  1.1.1.3  christos 	  need_space = true;
    503  1.1.1.3  christos 	}
    504  1.1.1.3  christos     }
    505  1.1.1.3  christos 
    506  1.1.1.3  christos   /* If there were flags not included in the mapping, print them as
    507  1.1.1.3  christos      a hex number.  */
    508  1.1.1.3  christos   if (flags != 0)
    509  1.1.1.3  christos     {
    510  1.1.1.3  christos       if (need_space)
    511  1.1.1.3  christos 	res += " ";
    512  1.1.1.3  christos       res += hex_string (flags);
    513  1.1.1.3  christos     }
    514  1.1.1.3  christos 
    515  1.1.1.3  christos   res += "]";
    516  1.1.1.3  christos 
    517  1.1.1.3  christos   return res;
    518  1.1.1.3  christos }
    519  1.1.1.3  christos 
    520  1.1.1.4  christos #endif /* GDBSUPPORT_ENUM_FLAGS_H */
    521