forked from Imagelibrary/binutils-gdb
enum_flags to_string
This commit introduces shared infrastructure that can be used to
implement enum_flags -> to_string functions. With this, if we want to
support converting a given enum_flags specialization to string, we
just need to implement a function that provides the enumerator->string
mapping, like so:
enum some_flag
{
SOME_FLAG1 = 1 << 0,
SOME_FLAG2 = 1 << 1,
SOME_FLAG3 = 1 << 2,
};
DEF_ENUM_FLAGS_TYPE (some_flag, some_flags);
static std::string
to_string (some_flags flags)
{
static constexpr some_flags::string_mapping mapping[] = {
MAP_ENUM_FLAG (SOME_FLAG1),
MAP_ENUM_FLAG (SOME_FLAG2),
MAP_ENUM_FLAG (SOME_FLAG3),
};
return flags.to_string (mapping);
}
.. and then to_string(SOME_FLAG2 | SOME_FLAG3) produces a string like
"0x6 [SOME_FLAG2 SOME_FLAG3]".
If we happen to forget to update the mapping array when we introduce a
new enumerator, then the string representation will pretty-print the
flags it knows about, and then the leftover flags in hex (one single
number). For example, if we had missed mapping SOME_FLAG2 above, we'd
end up with:
to_string(SOME_FLAG2 | SOME_FLAG3) => "0x6 [SOME_FLAG2 0x4]");
Other than in the unit tests included, no actual usage of the
functionality is added in this commit.
Approved-By: Simon Marchi <simon.marchi@efficios.com>
Change-Id: I835de43c33d13bc0c95132f42c3f97318b875779
This commit is contained in:
committed by
Simon Marchi
parent
c121e82c39
commit
8c4f70ffe7
@@ -130,6 +130,17 @@ public:
|
||||
typedef E enum_type;
|
||||
typedef typename enum_underlying_type<enum_type>::type underlying_type;
|
||||
|
||||
/* For to_string. Maps one enumerator of E to a string. */
|
||||
struct string_mapping
|
||||
{
|
||||
E flag;
|
||||
const char *str;
|
||||
};
|
||||
|
||||
/* Convenience for to_string implementations, to build a
|
||||
string_mapping array. */
|
||||
#define MAP_ENUM_FLAG(ENUM_FLAG) { ENUM_FLAG, #ENUM_FLAG }
|
||||
|
||||
public:
|
||||
/* Allow default construction. */
|
||||
constexpr enum_flags ()
|
||||
@@ -183,6 +194,18 @@ public:
|
||||
/* Binary operations involving some unrelated type (which would be a
|
||||
bug) are implemented as non-members, and deleted. */
|
||||
|
||||
/* Convert this object to a std::string, using MAPPING as
|
||||
enumerator-to-string mapping array. This is not meant to be
|
||||
called directly. Instead, enum_flags specializations should have
|
||||
their own to_string function wrapping this one, thus hidding the
|
||||
mapping array from callers.
|
||||
|
||||
Note: this is defined outside the template class so it can use
|
||||
the global operators for enum_type, which are only defined after
|
||||
the template class. */
|
||||
template<size_t N>
|
||||
std::string to_string (const string_mapping (&mapping)[N]) const;
|
||||
|
||||
private:
|
||||
/* Stored as enum_type because GDB knows to print the bit flags
|
||||
neatly if the enum values look like bit flags. */
|
||||
@@ -415,6 +438,49 @@ 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 E>
|
||||
template<size_t N>
|
||||
std::string
|
||||
enum_flags<E>::to_string (const string_mapping (&mapping)[N]) const
|
||||
{
|
||||
enum_type flags = raw ();
|
||||
std::string res = hex_string (flags);
|
||||
res += " [";
|
||||
|
||||
bool need_space = false;
|
||||
for (const auto &entry : mapping)
|
||||
{
|
||||
if ((flags & entry.flag) != 0)
|
||||
{
|
||||
/* Work with an unsigned version of the underlying type,
|
||||
because if enum_type's underlying type is signed, op~
|
||||
won't be defined for it, and, bitwise operations on
|
||||
signed types are implementation defined. */
|
||||
using uns = typename std::make_unsigned<underlying_type>::type;
|
||||
flags &= (enum_type) ~(uns) entry.flag;
|
||||
|
||||
if (need_space)
|
||||
res += " ";
|
||||
res += entry.str;
|
||||
|
||||
need_space = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there were flags not included in the mapping, print them as
|
||||
a hex number. */
|
||||
if (flags != 0)
|
||||
{
|
||||
if (need_space)
|
||||
res += " ";
|
||||
res += hex_string (flags);
|
||||
}
|
||||
|
||||
res += "]";
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#else /* __cplusplus */
|
||||
|
||||
/* In C, the flags type is just a typedef for the enum type. */
|
||||
|
||||
Reference in New Issue
Block a user