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