|  | /* Copyright (C) 2015-2022 Free Software Foundation, Inc. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #ifndef COMMON_ENUM_FLAGS_H | 
|  | #define COMMON_ENUM_FLAGS_H | 
|  |  | 
|  | #include "traits.h" | 
|  |  | 
|  | /* Type-safe wrapper for enum flags.  enum flags are enums where the | 
|  | values are bits that are meant to be ORed together. | 
|  |  | 
|  | This allows writing code like the below, while with raw enums this | 
|  | would fail to compile without casts to enum type at the assignments | 
|  | to 'f': | 
|  |  | 
|  | enum some_flag | 
|  | { | 
|  | flag_val1 = 1 << 1, | 
|  | flag_val2 = 1 << 2, | 
|  | flag_val3 = 1 << 3, | 
|  | flag_val4 = 1 << 4, | 
|  | }; | 
|  | DEF_ENUM_FLAGS_TYPE(enum some_flag, some_flags); | 
|  |  | 
|  | some_flags f = flag_val1 | flag_val2; | 
|  | f |= flag_val3; | 
|  |  | 
|  | It's also possible to assign literal zero to an enum flags variable | 
|  | (meaning, no flags), dispensing adding an awkward explicit "no | 
|  | value" value to the enumeration.  For example: | 
|  |  | 
|  | some_flags f = 0; | 
|  | f |= flag_val3 | flag_val4; | 
|  |  | 
|  | Note that literal integers other than zero fail to compile: | 
|  |  | 
|  | some_flags f = 1; // error | 
|  | */ | 
|  |  | 
|  | #ifdef __cplusplus | 
|  |  | 
|  | /* Use this to mark an enum as flags enum.  It defines FLAGS_TYPE as | 
|  | enum_flags wrapper class for ENUM, and enables the global operator | 
|  | overloads for ENUM.  */ | 
|  | #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type)	\ | 
|  | typedef enum_flags<enum_type> flags_type;		\ | 
|  | void is_enum_flags_enum_type (enum_type *) | 
|  |  | 
|  | /* To enable the global enum_flags operators for enum, declare an | 
|  | "is_enum_flags_enum_type" overload that has exactly one parameter, | 
|  | of type a pointer to that enum class.  E.g.,: | 
|  |  | 
|  | void is_enum_flags_enum_type (enum some_flag *); | 
|  |  | 
|  | The function does not need to be defined, only declared. | 
|  | DEF_ENUM_FLAGS_TYPE declares this. | 
|  |  | 
|  | A function declaration is preferred over a traits type, because the | 
|  | former allows calling the DEF_ENUM_FLAGS_TYPE macro inside a | 
|  | namespace to define the corresponding enum flags type in that | 
|  | namespace.  The compiler finds the corresponding | 
|  | is_enum_flags_enum_type function via ADL.  */ | 
|  |  | 
|  | /* Note that std::underlying_type<enum_type> is not what we want here, | 
|  | since that returns unsigned int even when the enum decays to signed | 
|  | int.  */ | 
|  | template<int size, bool sign> class integer_for_size { typedef void type; }; | 
|  | template<> struct integer_for_size<1, 0> { typedef uint8_t type; }; | 
|  | template<> struct integer_for_size<2, 0> { typedef uint16_t type; }; | 
|  | template<> struct integer_for_size<4, 0> { typedef uint32_t type; }; | 
|  | template<> struct integer_for_size<8, 0> { typedef uint64_t type; }; | 
|  | template<> struct integer_for_size<1, 1> { typedef int8_t type; }; | 
|  | template<> struct integer_for_size<2, 1> { typedef int16_t type; }; | 
|  | template<> struct integer_for_size<4, 1> { typedef int32_t type; }; | 
|  | template<> struct integer_for_size<8, 1> { typedef int64_t type; }; | 
|  |  | 
|  | template<typename T> | 
|  | struct enum_underlying_type | 
|  | { | 
|  | typedef typename | 
|  | integer_for_size<sizeof (T), static_cast<bool>(T (-1) < T (0))>::type | 
|  | type; | 
|  | }; | 
|  |  | 
|  | namespace enum_flags_detail | 
|  | { | 
|  |  | 
|  | /* Private type used to support initializing flag types with zero: | 
|  |  | 
|  | foo_flags f = 0; | 
|  |  | 
|  | but not other integers: | 
|  |  | 
|  | foo_flags f = 1; | 
|  |  | 
|  | The way this works is that we define an implicit constructor that | 
|  | takes a pointer to this private type.  Since nothing can | 
|  | instantiate an object of this type, the only possible pointer to | 
|  | pass to the constructor is the NULL pointer, or, zero.  */ | 
|  | struct zero_type; | 
|  |  | 
|  | /* gdb::Requires trait helpers.  */ | 
|  | template <typename enum_type> | 
|  | using EnumIsUnsigned | 
|  | = std::is_unsigned<typename enum_underlying_type<enum_type>::type>; | 
|  | template <typename enum_type> | 
|  | using EnumIsSigned | 
|  | = std::is_signed<typename enum_underlying_type<enum_type>::type>; | 
|  |  | 
|  | } | 
|  |  | 
|  | template <typename E> | 
|  | class enum_flags | 
|  | { | 
|  | public: | 
|  | typedef E enum_type; | 
|  | typedef typename enum_underlying_type<enum_type>::type underlying_type; | 
|  |  | 
|  | public: | 
|  | /* Allow default construction.  */ | 
|  | constexpr enum_flags () | 
|  | : m_enum_value ((enum_type) 0) | 
|  | {} | 
|  |  | 
|  | /* The default move/copy ctor/assignment do the right thing.  */ | 
|  |  | 
|  | /* If you get an error saying these two overloads are ambiguous, | 
|  | then you tried to mix values of different enum types.  */ | 
|  | constexpr enum_flags (enum_type e) | 
|  | : m_enum_value (e) | 
|  | {} | 
|  | constexpr enum_flags (enum_flags_detail::zero_type *zero) | 
|  | : m_enum_value ((enum_type) 0) | 
|  | {} | 
|  |  | 
|  | enum_flags &operator&= (enum_flags e) & | 
|  | { | 
|  | m_enum_value = (enum_type) (m_enum_value & e.m_enum_value); | 
|  | return *this; | 
|  | } | 
|  | enum_flags &operator|= (enum_flags e) & | 
|  | { | 
|  | m_enum_value = (enum_type) (m_enum_value | e.m_enum_value); | 
|  | return *this; | 
|  | } | 
|  | enum_flags &operator^= (enum_flags e) & | 
|  | { | 
|  | m_enum_value = (enum_type) (m_enum_value ^ e.m_enum_value); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | /* Delete rval versions.  */ | 
|  | void operator&= (enum_flags e) && = delete; | 
|  | void operator|= (enum_flags e) && = delete; | 
|  | void operator^= (enum_flags e) && = delete; | 
|  |  | 
|  | /* Like raw enums, allow conversion to the underlying type.  */ | 
|  | constexpr operator underlying_type () const | 
|  | { | 
|  | return m_enum_value; | 
|  | } | 
|  |  | 
|  | /* Get the underlying value as a raw enum.  */ | 
|  | constexpr enum_type raw () const | 
|  | { | 
|  | return m_enum_value; | 
|  | } | 
|  |  | 
|  | /* Binary operations involving some unrelated type (which would be a | 
|  | bug) are implemented as non-members, and deleted.  */ | 
|  |  | 
|  | private: | 
|  | /* Stored as enum_type because GDB knows to print the bit flags | 
|  | neatly if the enum values look like bit flags.  */ | 
|  | enum_type m_enum_value; | 
|  | }; | 
|  |  | 
|  | template <typename E> | 
|  | using is_enum_flags_enum_type_t | 
|  | = decltype (is_enum_flags_enum_type (std::declval<E *> ())); | 
|  |  | 
|  | /* Global operator overloads.  */ | 
|  |  | 
|  | /* Generate binary operators.  */ | 
|  |  | 
|  | #define ENUM_FLAGS_GEN_BINOP(OPERATOR_OP, OP)				\ | 
|  | \ | 
|  | /* Raw enum on both LHS/RHS.  Returns raw enum type.  */		\ | 
|  | template <typename enum_type,						\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_type							\ | 
|  | OPERATOR_OP (enum_type e1, enum_type e2)				\ | 
|  | {									\ | 
|  | using underlying = typename enum_flags<enum_type>::underlying_type;	\ | 
|  | return (enum_type) (underlying (e1) OP underlying (e2));		\ | 
|  | }									\ | 
|  | \ | 
|  | /* enum_flags on the LHS.  */						\ | 
|  | template <typename enum_type,						\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_flags<enum_type>					\ | 
|  | OPERATOR_OP (enum_flags<enum_type> e1, enum_type e2)			\ | 
|  | { return e1.raw () OP e2; }						\ | 
|  | \ | 
|  | /* enum_flags on the RHS.  */						\ | 
|  | template <typename enum_type,						\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_flags<enum_type>					\ | 
|  | OPERATOR_OP (enum_type e1, enum_flags<enum_type> e2)			\ | 
|  | { return e1 OP e2.raw (); }						\ | 
|  | \ | 
|  | /* enum_flags on both LHS/RHS.  */					\ | 
|  | template <typename enum_type,						\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_flags<enum_type>					\ | 
|  | OPERATOR_OP (enum_flags<enum_type> e1, enum_flags<enum_type> e2)	\ | 
|  | { return e1.raw () OP e2.raw (); }					\ | 
|  | \ | 
|  | /* Delete cases involving unrelated types.  */			\ | 
|  | \ | 
|  | template <typename enum_type, typename unrelated_type,		\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_flags<enum_type>					\ | 
|  | OPERATOR_OP (enum_type e1, unrelated_type e2) = delete;		\ | 
|  | \ | 
|  | template <typename enum_type, typename unrelated_type,		\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_flags<enum_type>					\ | 
|  | OPERATOR_OP (unrelated_type e1, enum_type e2) = delete;		\ | 
|  | \ | 
|  | template <typename enum_type, typename unrelated_type,		\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_flags<enum_type>					\ | 
|  | OPERATOR_OP (enum_flags<enum_type> e1, unrelated_type e2) = delete;	\ | 
|  | \ | 
|  | template <typename enum_type, typename unrelated_type,		\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_flags<enum_type>					\ | 
|  | OPERATOR_OP (unrelated_type e1, enum_flags<enum_type> e2) = delete; | 
|  |  | 
|  | /* Generate non-member compound assignment operators.  Only the raw | 
|  | enum versions are defined here.  The enum_flags versions are | 
|  | defined as member functions, simply because it's less code that | 
|  | way. | 
|  |  | 
|  | Note we delete operators that would allow e.g., | 
|  |  | 
|  | "enum_type | 1" or "enum_type1 | enum_type2" | 
|  |  | 
|  | because that would allow a mistake like : | 
|  | enum flags1 { F1_FLAGS1 = 1 }; | 
|  | enum flags2 { F2_FLAGS2 = 2 }; | 
|  | enum flags1 val; | 
|  | switch (val) { | 
|  | case F1_FLAGS1 | F2_FLAGS2: | 
|  | ... | 
|  |  | 
|  | If you really need to 'or' enumerators of different flag types, | 
|  | cast to integer first. | 
|  | */ | 
|  | #define ENUM_FLAGS_GEN_COMPOUND_ASSIGN(OPERATOR_OP, OP)			\ | 
|  | /* lval reference version.  */					\ | 
|  | template <typename enum_type,						\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_type &							\ | 
|  | OPERATOR_OP (enum_type &e1, enum_type e2)				\ | 
|  | { return e1 = e1 OP e2; }						\ | 
|  | \ | 
|  | /* rval reference version.  */					\ | 
|  | template <typename enum_type,						\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | void									\ | 
|  | OPERATOR_OP (enum_type &&e1, enum_type e2) = delete;			\ | 
|  | \ | 
|  | /* Delete compound assignment from unrelated types.  */		\ | 
|  | \ | 
|  | template <typename enum_type, typename other_enum_type,		\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | constexpr enum_type &							\ | 
|  | OPERATOR_OP (enum_type &e1, other_enum_type e2) = delete;		\ | 
|  | \ | 
|  | template <typename enum_type, typename other_enum_type,		\ | 
|  | typename = is_enum_flags_enum_type_t<enum_type>>		\ | 
|  | void									\ | 
|  | OPERATOR_OP (enum_type &&e1, other_enum_type e2) = delete; | 
|  |  | 
|  | ENUM_FLAGS_GEN_BINOP (operator|, |) | 
|  | ENUM_FLAGS_GEN_BINOP (operator&, &) | 
|  | ENUM_FLAGS_GEN_BINOP (operator^, ^) | 
|  |  | 
|  | ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator|=, |) | 
|  | ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator&=, &) | 
|  | ENUM_FLAGS_GEN_COMPOUND_ASSIGN (operator^=, ^) | 
|  |  | 
|  | /* Allow comparison with enum_flags, raw enum, and integers, only. | 
|  | The latter case allows "== 0".  As side effect, it allows comparing | 
|  | with integer variables too, but that's not a common mistake to | 
|  | make.  It's important to disable comparison with unrelated types to | 
|  | prevent accidentally comparing with unrelated enum values, which | 
|  | are convertible to integer, and thus coupled with enum_flags | 
|  | convertion to underlying type too, would trigger the built-in 'bool | 
|  | operator==(unsigned, int)' operator.  */ | 
|  |  | 
|  | #define ENUM_FLAGS_GEN_COMP(OPERATOR_OP, OP)				\ | 
|  | \ | 
|  | /* enum_flags OP enum_flags */					\ | 
|  | \ | 
|  | template <typename enum_type>						\ | 
|  | constexpr bool							\ | 
|  | OPERATOR_OP (enum_flags<enum_type> lhs, enum_flags<enum_type> rhs)	\ | 
|  | { return lhs.raw () OP rhs.raw (); }					\ | 
|  | \ | 
|  | /* enum_flags OP other */						\ | 
|  | \ | 
|  | template <typename enum_type>						\ | 
|  | constexpr bool							\ | 
|  | OPERATOR_OP (enum_flags<enum_type> lhs, enum_type rhs)		\ | 
|  | { return lhs.raw () OP rhs; }						\ | 
|  | \ | 
|  | template <typename enum_type>						\ | 
|  | constexpr bool							\ | 
|  | OPERATOR_OP (enum_flags<enum_type> lhs, int rhs)			\ | 
|  | { return lhs.raw () OP rhs; }						\ | 
|  | \ | 
|  | template <typename enum_type, typename U>				\ | 
|  | constexpr bool							\ | 
|  | OPERATOR_OP (enum_flags<enum_type> lhs, U rhs) = delete;		\ | 
|  | \ | 
|  | /* other OP enum_flags */						\ | 
|  | \ | 
|  | template <typename enum_type>						\ | 
|  | constexpr bool							\ | 
|  | OPERATOR_OP (enum_type lhs, enum_flags<enum_type> rhs)		\ | 
|  | { return lhs OP rhs.raw (); }						\ | 
|  | \ | 
|  | template <typename enum_type>						\ | 
|  | constexpr bool							\ | 
|  | OPERATOR_OP (int lhs, enum_flags<enum_type> rhs)			\ | 
|  | { return lhs OP rhs.raw (); }						\ | 
|  | \ | 
|  | template <typename enum_type, typename U>				\ | 
|  | constexpr bool							\ | 
|  | OPERATOR_OP (U lhs, enum_flags<enum_type> rhs) = delete; | 
|  |  | 
|  | ENUM_FLAGS_GEN_COMP (operator==, ==) | 
|  | ENUM_FLAGS_GEN_COMP (operator!=, !=) | 
|  |  | 
|  | /* Unary operators for the raw flags enum.  */ | 
|  |  | 
|  | /* We require underlying type to be unsigned when using operator~ -- | 
|  | if it were not unsigned, undefined behavior could result.  However, | 
|  | asserting this in the class itself would require too many | 
|  | unnecessary changes to usages of otherwise OK enum types.  */ | 
|  | template <typename enum_type, | 
|  | typename = is_enum_flags_enum_type_t<enum_type>, | 
|  | typename | 
|  | = gdb::Requires<enum_flags_detail::EnumIsUnsigned<enum_type>>> | 
|  | constexpr enum_type | 
|  | operator~ (enum_type e) | 
|  | { | 
|  | using underlying = typename enum_flags<enum_type>::underlying_type; | 
|  | return (enum_type) ~underlying (e); | 
|  | } | 
|  |  | 
|  | template <typename enum_type, | 
|  | typename = is_enum_flags_enum_type_t<enum_type>, | 
|  | typename = gdb::Requires<enum_flags_detail::EnumIsSigned<enum_type>>> | 
|  | constexpr void operator~ (enum_type e) = delete; | 
|  |  | 
|  | template <typename enum_type, | 
|  | typename = is_enum_flags_enum_type_t<enum_type>, | 
|  | typename | 
|  | = gdb::Requires<enum_flags_detail::EnumIsUnsigned<enum_type>>> | 
|  | constexpr enum_flags<enum_type> | 
|  | operator~ (enum_flags<enum_type> e) | 
|  | { | 
|  | using underlying = typename enum_flags<enum_type>::underlying_type; | 
|  | return (enum_type) ~underlying (e); | 
|  | } | 
|  |  | 
|  | template <typename enum_type, | 
|  | typename = is_enum_flags_enum_type_t<enum_type>, | 
|  | typename = gdb::Requires<enum_flags_detail::EnumIsSigned<enum_type>>> | 
|  | constexpr void operator~ (enum_flags<enum_type> e) = delete; | 
|  |  | 
|  | /* Delete operator<< and operator>>.  */ | 
|  |  | 
|  | template <typename enum_type, typename any_type, | 
|  | typename = is_enum_flags_enum_type_t<enum_type>> | 
|  | void operator<< (const enum_type &, const any_type &) = delete; | 
|  |  | 
|  | template <typename enum_type, typename any_type, | 
|  | typename = is_enum_flags_enum_type_t<enum_type>> | 
|  | void operator<< (const enum_flags<enum_type> &, const any_type &) = delete; | 
|  |  | 
|  | template <typename enum_type, typename any_type, | 
|  | typename = is_enum_flags_enum_type_t<enum_type>> | 
|  | void operator>> (const enum_type &, const any_type &) = delete; | 
|  |  | 
|  | template <typename enum_type, typename any_type, | 
|  | typename = is_enum_flags_enum_type_t<enum_type>> | 
|  | void operator>> (const enum_flags<enum_type> &, const any_type &) = delete; | 
|  |  | 
|  | #else /* __cplusplus */ | 
|  |  | 
|  | /* In C, the flags type is just a typedef for the enum type.  */ | 
|  |  | 
|  | #define DEF_ENUM_FLAGS_TYPE(enum_type, flags_type) \ | 
|  | typedef enum_type flags_type | 
|  |  | 
|  | #endif /* __cplusplus */ | 
|  |  | 
|  | #endif /* COMMON_ENUM_FLAGS_H */ |