mirror of
https://github.com/fmtlib/fmt.git
synced 2026-07-30 16:26:27 +08:00
Merge b059132e13d045c8f8217649cc8517e2eac846d7 into 17500e457b198c37c4374d142fa7a1d36e4651fe
This commit is contained in:
commit
630aafeb70
@ -620,6 +620,8 @@ struct formatter<
|
|||||||
T, char,
|
T, char,
|
||||||
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
|
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
|
||||||
private:
|
private:
|
||||||
|
format_specs specs_;
|
||||||
|
detail::arg_ref<char> width_ref_;
|
||||||
bool with_typename_ = false;
|
bool with_typename_ = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -627,7 +629,14 @@ struct formatter<
|
|||||||
auto it = ctx.begin();
|
auto it = ctx.begin();
|
||||||
auto end = ctx.end();
|
auto end = ctx.end();
|
||||||
if (it == end || *it == '}') return it;
|
if (it == end || *it == '}') return it;
|
||||||
if (*it == 't') {
|
|
||||||
|
it = detail::parse_align(it, end, specs_);
|
||||||
|
if (it == end) return it;
|
||||||
|
|
||||||
|
char c = *it;
|
||||||
|
if ((c >= '0' && c <= '9') || c == '{')
|
||||||
|
it = detail::parse_width(it, end, specs_, width_ref_, ctx);
|
||||||
|
if (it != end && *it == 't') {
|
||||||
++it;
|
++it;
|
||||||
with_typename_ = FMT_USE_RTTI != 0;
|
with_typename_ = FMT_USE_RTTI != 0;
|
||||||
}
|
}
|
||||||
@ -637,7 +646,20 @@ struct formatter<
|
|||||||
template <typename Context>
|
template <typename Context>
|
||||||
auto format(const std::exception& ex, Context& ctx) const
|
auto format(const std::exception& ex, Context& ctx) const
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
return write(ctx.out(), ex);
|
auto buf = memory_buffer();
|
||||||
|
write(appender(buf), ex);
|
||||||
|
return write_padded(ctx, string_view(buf.data(), buf.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Applies the parsed fill/align/width to an already-formatted message.
|
||||||
|
template <typename Context>
|
||||||
|
auto write_padded(Context& ctx, string_view message) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto specs = specs_;
|
||||||
|
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||||
|
ctx);
|
||||||
|
return detail::write(ctx.out(), message, specs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -675,13 +697,13 @@ template <> struct formatter<std::exception_ptr> : formatter<std::exception> {
|
|||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const std::exception_ptr& ep, FormatContext& ctx) const
|
auto format(const std::exception_ptr& ep, FormatContext& ctx) const
|
||||||
-> decltype(ctx.out()) {
|
-> decltype(ctx.out()) {
|
||||||
if (!ep) return detail::write(ctx.out(), string_view("none"));
|
if (!ep) return this->write_padded(ctx, string_view("none"));
|
||||||
try {
|
try {
|
||||||
std::rethrow_exception(ep);
|
std::rethrow_exception(ep);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
return formatter<std::exception>::format(e, ctx);
|
return formatter<std::exception>::format(e, ctx);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return detail::write(ctx.out(), string_view("unknown exception"));
|
return this->write_padded(ctx, string_view("unknown exception"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -465,6 +465,43 @@ TEST(std_test, exception_ptr) {
|
|||||||
#endif // FMT_USE_RTTI
|
#endif // FMT_USE_RTTI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(std_test, exception_align) {
|
||||||
|
// The exception formatter supports standard width, fill and alignment.
|
||||||
|
auto ex = std::runtime_error("boom");
|
||||||
|
EXPECT_EQ(fmt::format("{:>8}", ex), " boom");
|
||||||
|
EXPECT_EQ(fmt::format("{:<8}", ex), "boom ");
|
||||||
|
EXPECT_EQ(fmt::format("{:^8}", ex), " boom ");
|
||||||
|
EXPECT_EQ(fmt::format("{:*>8}", ex), "****boom");
|
||||||
|
EXPECT_EQ(fmt::format("{:{}}", ex, 8), "boom ");
|
||||||
|
// A width smaller than the message leaves the message untouched.
|
||||||
|
EXPECT_EQ(fmt::format("{:>2}", ex), "boom");
|
||||||
|
|
||||||
|
#if FMT_USE_RTTI
|
||||||
|
// Alignment combines with the 't' (type name) presentation type.
|
||||||
|
try {
|
||||||
|
using namespace my_ns1::my_ns2;
|
||||||
|
throw my_exception("oops");
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
auto base = fmt::format("{:t}", e);
|
||||||
|
auto padded = fmt::format("{:*<40t}", e);
|
||||||
|
EXPECT_EQ(padded.size(), 40u);
|
||||||
|
EXPECT_EQ(padded.substr(0, base.size()), base);
|
||||||
|
EXPECT_EQ(padded.substr(base.size()), std::string(40 - base.size(), '*'));
|
||||||
|
}
|
||||||
|
#endif // FMT_USE_RTTI
|
||||||
|
|
||||||
|
// exception_ptr honors the same specifiers, for both the empty ("none")
|
||||||
|
// and the non-empty case.
|
||||||
|
std::exception_ptr enull = nullptr;
|
||||||
|
EXPECT_EQ(fmt::format("{:>8}", enull), " none");
|
||||||
|
std::exception_ptr ep;
|
||||||
|
try {
|
||||||
|
throw std::runtime_error("bang");
|
||||||
|
} catch (...) {
|
||||||
|
ep = std::current_exception();
|
||||||
|
}
|
||||||
|
EXPECT_EQ(fmt::format("{:>8}", ep), " bang");
|
||||||
|
}
|
||||||
#if FMT_USE_RTTI
|
#if FMT_USE_RTTI
|
||||||
TEST(std_test, type_info) {
|
TEST(std_test, type_info) {
|
||||||
EXPECT_EQ(fmt::format("{}", typeid(std::runtime_error)),
|
EXPECT_EQ(fmt::format("{}", typeid(std::runtime_error)),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user