Skip to content

Commit 241ebe1

Browse files
committed
Added std::type_info formatter
* 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.
1 parent 1768bf9 commit 241ebe1

File tree

2 files changed

+99
-56
lines changed

2 files changed

+99
-56
lines changed

Diff for: include/fmt/std.h

+94-56
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,95 @@ template <typename Char> struct formatter<std::error_code, Char> {
416416
}
417417
};
418418

419+
#if FMT_USE_RTTI
420+
namespace detail {
421+
422+
template <typename Char, typename OutputIt>
423+
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
424+
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
425+
int status = 0;
426+
std::size_t size = 0;
427+
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
428+
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
429+
430+
string_view demangled_name_view;
431+
if (demangled_name_ptr) {
432+
demangled_name_view = demangled_name_ptr.get();
433+
434+
// Normalization of stdlib inline namespace names.
435+
// libc++ inline namespaces.
436+
// std::__1::* -> std::*
437+
// std::__1::__fs::* -> std::*
438+
// libstdc++ inline namespaces.
439+
// std::__cxx11::* -> std::*
440+
// std::filesystem::__cxx11::* -> std::filesystem::*
441+
if (demangled_name_view.starts_with("std::")) {
442+
char* begin = demangled_name_ptr.get();
443+
char* to = begin + 5; // std::
444+
for (char *from = to, *end = begin + demangled_name_view.size();
445+
from < end;) {
446+
// This is safe, because demangled_name is NUL-terminated.
447+
if (from[0] == '_' && from[1] == '_') {
448+
char* next = from + 1;
449+
while (next < end && *next != ':') next++;
450+
if (next[0] == ':' && next[1] == ':') {
451+
from = next + 2;
452+
continue;
453+
}
454+
}
455+
*to++ = *from++;
456+
}
457+
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
458+
}
459+
} else {
460+
demangled_name_view = string_view(ti.name());
461+
}
462+
return detail::write_bytes<Char>(out, demangled_name_view);
463+
# elif FMT_MSC_VERSION
464+
const string_view demangled_name(ti.name());
465+
for (std::size_t i = 0; i < demangled_name.size(); ++i) {
466+
auto sub = demangled_name;
467+
sub.remove_prefix(i);
468+
if (sub.starts_with("enum ")) {
469+
i += 4;
470+
continue;
471+
}
472+
if (sub.starts_with("class ") || sub.starts_with("union ")) {
473+
i += 5;
474+
continue;
475+
}
476+
if (sub.starts_with("struct ")) {
477+
i += 6;
478+
continue;
479+
}
480+
if (*sub.begin() != ' ') *out++ = *sub.begin();
481+
}
482+
return out;
483+
# else
484+
return detail::write_bytes<Char>(out, string_view(ti.name()));
485+
# endif
486+
}
487+
488+
} // namespace detail
489+
490+
FMT_EXPORT
491+
template <typename Char>
492+
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
493+
> {
494+
public:
495+
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
496+
-> decltype(ctx.begin()) {
497+
return ctx.begin();
498+
}
499+
500+
template <typename Context>
501+
auto format(const std::type_info& ti, Context& ctx) const
502+
-> decltype(ctx.out()) {
503+
return detail::write_demangled_name<Char>(ctx.out(), ti);
504+
}
505+
};
506+
#endif
507+
419508
FMT_EXPORT
420509
template <typename T, typename Char>
421510
struct formatter<
@@ -441,65 +530,14 @@ struct formatter<
441530
auto format(const std::exception& ex, Context& ctx) const
442531
-> decltype(ctx.out()) {
443532
auto out = ctx.out();
444-
if (!with_typename_)
445-
return detail::write_bytes<Char>(out, string_view(ex.what()));
446-
447533
#if FMT_USE_RTTI
448-
const std::type_info& ti = typeid(ex);
449-
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
450-
int status = 0;
451-
std::size_t size = 0;
452-
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
453-
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
454-
455-
string_view demangled_name_view;
456-
if (demangled_name_ptr) {
457-
demangled_name_view = demangled_name_ptr.get();
458-
459-
// Normalization of stdlib inline namespace names.
460-
// libc++ inline namespaces.
461-
// std::__1::* -> std::*
462-
// std::__1::__fs::* -> std::*
463-
// libstdc++ inline namespaces.
464-
// std::__cxx11::* -> std::*
465-
// std::filesystem::__cxx11::* -> std::filesystem::*
466-
if (demangled_name_view.starts_with("std::")) {
467-
char* begin = demangled_name_ptr.get();
468-
char* to = begin + 5; // std::
469-
for (char *from = to, *end = begin + demangled_name_view.size();
470-
from < end;) {
471-
// This is safe, because demangled_name is NUL-terminated.
472-
if (from[0] == '_' && from[1] == '_') {
473-
char* next = from + 1;
474-
while (next < end && *next != ':') next++;
475-
if (next[0] == ':' && next[1] == ':') {
476-
from = next + 2;
477-
continue;
478-
}
479-
}
480-
*to++ = *from++;
481-
}
482-
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
483-
}
484-
} else {
485-
demangled_name_view = string_view(ti.name());
534+
if (with_typename_) {
535+
out = detail::write_demangled_name<Char>(out, typeid(ex));
536+
*out++ = ':';
537+
*out++ = ' ';
486538
}
487-
out = detail::write_bytes<Char>(out, demangled_name_view);
488-
# elif FMT_MSC_VERSION
489-
string_view demangled_name_view(ti.name());
490-
if (demangled_name_view.starts_with("class "))
491-
demangled_name_view.remove_prefix(6);
492-
else if (demangled_name_view.starts_with("struct "))
493-
demangled_name_view.remove_prefix(7);
494-
out = detail::write_bytes<Char>(out, demangled_name_view);
495-
# else
496-
out = detail::write_bytes<Char>(out, string_view(ti.name())
497-
});
498-
# endif
499-
*out++ = ':';
500-
*out++ = ' ';
501-
return detail::write_bytes<Char>(out, string_view(ex.what()));
502539
#endif
540+
return detail::write_bytes<Char>(out, string_view(ex.what()));
503541
}
504542
};
505543

Diff for: test/std-test.cc

+5
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,11 @@ TEST(std_test, exception) {
300300
#endif
301301
}
302302

303+
TEST(std_test, type_info) {
304+
EXPECT_EQ(fmt::format("{}", typeid(std::runtime_error)),
305+
"std::runtime_error");
306+
}
307+
303308
TEST(std_test, format_bit_reference) {
304309
std::bitset<2> bs(1);
305310
EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false");

0 commit comments

Comments
 (0)