Added std::type_info formatter (#3978)

* Added std::type_info formatter;
* Reused std::type_info formatter in std::exception formatters;
* Updated MSVC std::type_info outputting to exclude all class, struct and enum occurences.
This commit is contained in:
Matthias Moulin
2024-05-28 19:57:08 +02:00
committed by GitHub
parent e721046e27
commit 728f9bc388
2 changed files with 101 additions and 56 deletions

View File

@@ -416,36 +416,11 @@ template <typename Char> struct formatter<std::error_code, Char> {
} }
}; };
FMT_EXPORT
template <typename T, typename Char>
struct formatter<
T, Char, // DEPRECATED! Mixing code unit types.
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
private:
bool with_typename_ = false;
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') return it;
if (*it == 't') {
++it;
with_typename_ = FMT_USE_RTTI != 0;
}
return it;
}
template <typename Context>
auto format(const std::exception& ex, Context& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
if (!with_typename_)
return detail::write_bytes<Char>(out, string_view(ex.what()));
#if FMT_USE_RTTI #if FMT_USE_RTTI
const std::type_info& ti = typeid(ex); namespace detail {
template <typename Char, typename OutputIt>
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
# ifdef FMT_HAS_ABI_CXA_DEMANGLE # ifdef FMT_HAS_ABI_CXA_DEMANGLE
int status = 0; int status = 0;
std::size_t size = 0; std::size_t size = 0;
@@ -484,22 +459,85 @@ struct formatter<
} else { } else {
demangled_name_view = string_view(ti.name()); demangled_name_view = string_view(ti.name());
} }
out = detail::write_bytes<Char>(out, demangled_name_view); return detail::write_bytes<Char>(out, demangled_name_view);
# elif FMT_MSC_VERSION # elif FMT_MSC_VERSION
string_view demangled_name_view(ti.name()); const string_view demangled_name(ti.name());
if (demangled_name_view.starts_with("class ")) for (std::size_t i = 0; i < demangled_name.size(); ++i) {
demangled_name_view.remove_prefix(6); auto sub = demangled_name;
else if (demangled_name_view.starts_with("struct ")) sub.remove_prefix(i);
demangled_name_view.remove_prefix(7); if (sub.starts_with("enum ")) {
out = detail::write_bytes<Char>(out, demangled_name_view); i += 4;
continue;
}
if (sub.starts_with("class ") || sub.starts_with("union ")) {
i += 5;
continue;
}
if (sub.starts_with("struct ")) {
i += 6;
continue;
}
if (*sub.begin() != ' ') *out++ = *sub.begin();
}
return out;
# else # else
out = detail::write_bytes<Char>(out, string_view(ti.name()) return detail::write_bytes<Char>(out, string_view(ti.name()));
});
# endif # endif
}
} // namespace detail
FMT_EXPORT
template <typename Char>
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
> {
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename Context>
auto format(const std::type_info& ti, Context& ctx) const
-> decltype(ctx.out()) {
return detail::write_demangled_name<Char>(ctx.out(), ti);
}
};
#endif
FMT_EXPORT
template <typename T, typename Char>
struct formatter<
T, Char, // DEPRECATED! Mixing code unit types.
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
private:
bool with_typename_ = false;
public:
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
-> decltype(ctx.begin()) {
auto it = ctx.begin();
auto end = ctx.end();
if (it == end || *it == '}') return it;
if (*it == 't') {
++it;
with_typename_ = FMT_USE_RTTI != 0;
}
return it;
}
template <typename Context>
auto format(const std::exception& ex, Context& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
#if FMT_USE_RTTI
if (with_typename_) {
out = detail::write_demangled_name<Char>(out, typeid(ex));
*out++ = ':'; *out++ = ':';
*out++ = ' '; *out++ = ' ';
return detail::write_bytes<Char>(out, string_view(ex.what())); }
#endif #endif
return detail::write_bytes<Char>(out, string_view(ex.what()));
} }
}; };

View File

@@ -300,6 +300,13 @@ TEST(std_test, exception) {
#endif #endif
} }
#if FMT_USE_RTTI
TEST(std_test, type_info) {
EXPECT_EQ(fmt::format("{}", typeid(std::runtime_error)),
"std::runtime_error");
}
#endif
TEST(std_test, format_bit_reference) { TEST(std_test, format_bit_reference) {
std::bitset<2> bs(1); std::bitset<2> bs(1);
EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false");