mirror of
https://github.com/fmtlib/fmt.git
synced 2026-10-28 18:07:37 +08:00
Compare commits
5 Commits
4a07e01473
...
cb16448e44
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb16448e44 | ||
|
|
0fe44d56d0 | ||
|
|
f87a75e152 | ||
|
|
2e60743c67 | ||
|
|
adb4f149c0 |
@ -1673,20 +1673,16 @@ struct duration_formatter {
|
||||
negative = true;
|
||||
}
|
||||
|
||||
// this may overflow and/or the result may not fit in the
|
||||
// target type.
|
||||
// might need checked conversion (rep!=Rep)
|
||||
s = detail::duration_cast<seconds>(std::chrono::duration<rep, Period>(val));
|
||||
}
|
||||
|
||||
// returns true if nan or inf, writes to out.
|
||||
auto handle_nan_inf() -> bool {
|
||||
// If val is NaN or infinite, writes it to out and returns true.
|
||||
auto write_if_nonfinite() -> bool {
|
||||
if (isfinite(val)) return false;
|
||||
if (isnan(val)) {
|
||||
write_nan();
|
||||
return true;
|
||||
}
|
||||
// must be +-inf
|
||||
write_sign();
|
||||
std::copy_n("inf", 3, out);
|
||||
return true;
|
||||
@ -1774,12 +1770,12 @@ struct duration_formatter {
|
||||
void on_day_of_month(numeric_system, pad_type) {}
|
||||
|
||||
void on_day_of_year(pad_type) {
|
||||
if (handle_nan_inf()) return;
|
||||
if (write_if_nonfinite()) return;
|
||||
write(days(), 0);
|
||||
}
|
||||
|
||||
void on_24_hour(numeric_system ns, pad_type pad) {
|
||||
if (handle_nan_inf()) return;
|
||||
if (write_if_nonfinite()) return;
|
||||
|
||||
if (ns == numeric_system::standard) return write(hour(), 2, pad);
|
||||
auto time = tm();
|
||||
@ -1788,7 +1784,7 @@ struct duration_formatter {
|
||||
}
|
||||
|
||||
void on_12_hour(numeric_system ns, pad_type pad) {
|
||||
if (handle_nan_inf()) return;
|
||||
if (write_if_nonfinite()) return;
|
||||
|
||||
if (ns == numeric_system::standard) return write(hour12(), 2, pad);
|
||||
auto time = tm();
|
||||
@ -1797,7 +1793,7 @@ struct duration_formatter {
|
||||
}
|
||||
|
||||
void on_minute(numeric_system ns, pad_type pad) {
|
||||
if (handle_nan_inf()) return;
|
||||
if (write_if_nonfinite()) return;
|
||||
|
||||
if (ns == numeric_system::standard) return write(minute(), 2, pad);
|
||||
auto time = tm();
|
||||
@ -1806,7 +1802,7 @@ struct duration_formatter {
|
||||
}
|
||||
|
||||
void on_second(numeric_system ns, pad_type pad) {
|
||||
if (handle_nan_inf()) return;
|
||||
if (write_if_nonfinite()) return;
|
||||
|
||||
if (ns == numeric_system::standard) {
|
||||
if (std::is_floating_point<rep>::value) {
|
||||
@ -1830,14 +1826,14 @@ struct duration_formatter {
|
||||
}
|
||||
|
||||
void on_12_hour_time() {
|
||||
if (handle_nan_inf()) return;
|
||||
if (write_if_nonfinite()) return;
|
||||
format_tm(time(), &tm_writer_type::on_12_hour_time);
|
||||
}
|
||||
|
||||
void on_24_hour_time() {
|
||||
if (handle_nan_inf()) {
|
||||
if (write_if_nonfinite()) {
|
||||
*out++ = ':';
|
||||
handle_nan_inf();
|
||||
write_if_nonfinite();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1849,17 +1845,17 @@ struct duration_formatter {
|
||||
void on_iso_time() {
|
||||
on_24_hour_time();
|
||||
*out++ = ':';
|
||||
if (handle_nan_inf()) return;
|
||||
if (write_if_nonfinite()) return;
|
||||
on_second(numeric_system::standard, pad_type::zero);
|
||||
}
|
||||
|
||||
void on_am_pm() {
|
||||
if (handle_nan_inf()) return;
|
||||
if (write_if_nonfinite()) return;
|
||||
format_tm(time(), &tm_writer_type::on_am_pm);
|
||||
}
|
||||
|
||||
void on_duration_value() {
|
||||
if (handle_nan_inf()) return;
|
||||
if (write_if_nonfinite()) return;
|
||||
write_sign();
|
||||
out = format_duration_value<Char>(out, val, precision);
|
||||
}
|
||||
|
||||
@ -175,7 +175,8 @@ template <typename Char, typename V, int N> struct field {
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&... args) const -> OutputIt {
|
||||
const V& arg = get_arg_checked<V, N>(args...);
|
||||
if constexpr (std::is_convertible<V, basic_string_view<Char>>::value) {
|
||||
if constexpr (std::is_convertible<V, basic_string_view<Char>>::value &&
|
||||
!std::is_same<V, nullptr_t>::value) {
|
||||
auto s = basic_string_view<Char>(arg);
|
||||
return copy<Char>(s.begin(), s.end(), out);
|
||||
} else if constexpr (use_format_as<V>::value) {
|
||||
|
||||
@ -3920,6 +3920,11 @@ auto write(OutputIt out, const T* value, const format_specs& specs = {},
|
||||
return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
auto write(OutputIt out, nullptr_t) -> OutputIt {
|
||||
return write<Char>(out, static_cast<const void*>(nullptr));
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt, typename T,
|
||||
FMT_ENABLE_IF(mapped_type_constant<T, Char>::value ==
|
||||
type::custom_type &&
|
||||
|
||||
@ -102,19 +102,19 @@ template <int N> struct ubitint {};
|
||||
#if FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
template <typename Char, typename PathChar>
|
||||
auto get_path_string(const std::filesystem::path& p,
|
||||
const std::basic_string<PathChar>& native) {
|
||||
auto get_path_string(const std::basic_string<PathChar>& native) {
|
||||
if constexpr (std::is_same_v<Char, char> &&
|
||||
std::is_same_v<PathChar, wchar_t>) {
|
||||
return to_utf8<wchar_t>(native, to_utf8_error_policy::wtf);
|
||||
} else if constexpr (std::is_same_v<Char, PathChar>) {
|
||||
return native;
|
||||
} else {
|
||||
return p.string<Char>();
|
||||
return std::filesystem::path(native).string<Char>();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Char, typename PathChar>
|
||||
void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||
const std::filesystem::path& p,
|
||||
const std::basic_string<PathChar>& native) {
|
||||
if constexpr (std::is_same_v<Char, char> &&
|
||||
std::is_same_v<PathChar, wchar_t>) {
|
||||
@ -126,7 +126,8 @@ void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||
write_escaped_string<std::filesystem::path::value_type>(
|
||||
std::back_inserter(quoted), native);
|
||||
} else {
|
||||
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
|
||||
write_escaped_string<Char>(std::back_inserter(quoted),
|
||||
std::filesystem::path(native).string<Char>());
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,11 +338,11 @@ template <typename Char> struct formatter<std::filesystem::path, Char> {
|
||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||
ctx);
|
||||
if (!debug_) {
|
||||
auto s = detail::get_path_string<Char>(p, path_string);
|
||||
auto s = detail::get_path_string<Char>(path_string);
|
||||
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
||||
}
|
||||
auto quoted = basic_memory_buffer<Char>();
|
||||
detail::write_escaped_path(quoted, p, path_string);
|
||||
detail::write_escaped_path(quoted, path_string);
|
||||
return detail::write(ctx.out(),
|
||||
basic_string_view<Char>(quoted.data(), quoted.size()),
|
||||
specs);
|
||||
|
||||
@ -755,33 +755,15 @@ TEST(chrono_test, special_durations) {
|
||||
"01.234");
|
||||
}
|
||||
|
||||
TEST(chrono_test, negative_floating_duration_sign) {
|
||||
auto d = std::chrono::duration<double>(-61.25);
|
||||
EXPECT_EQ(fmt::format("{:%S %M}", d), "-01.250000 01");
|
||||
EXPECT_EQ(fmt::format("{:%S %S}", d), "-01.250000 01.250000");
|
||||
EXPECT_EQ(fmt::format("{:%S %Q}", d), "-01.250000 61.25");
|
||||
EXPECT_EQ(fmt::format("{:%Q %S}", d), "-61.25 01.250000");
|
||||
EXPECT_EQ(fmt::format("{:%S %Q}", -d), "01.250000 61.25");
|
||||
EXPECT_EQ(fmt::format("{:%S %Q}", std::chrono::duration<float>(-1)), "-01 1");
|
||||
EXPECT_EQ(fmt::format("{:%S %Q}", std::chrono::duration<long double>(-1)),
|
||||
"-01 1");
|
||||
}
|
||||
|
||||
TEST(chrono_test, negative_infinite_duration_sign) {
|
||||
auto inf = std::numeric_limits<double>::infinity();
|
||||
auto d = std::chrono::duration<double>(-inf);
|
||||
EXPECT_EQ(fmt::format("{:%Q}", d), "-inf");
|
||||
EXPECT_EQ(fmt::format("{:%S}", d), "-inf");
|
||||
EXPECT_EQ(fmt::format("{:%H}", d), "-inf");
|
||||
EXPECT_EQ(fmt::format("{:%j}", d), "-inf");
|
||||
EXPECT_EQ(fmt::format("{:%R}", d), "-inf:inf");
|
||||
EXPECT_EQ(fmt::format("{:%T}", d), "-inf:inf:inf");
|
||||
EXPECT_EQ(fmt::format("{:%S %Q}", d), "-inf inf");
|
||||
EXPECT_EQ(fmt::format("{:>6%Q}", d), " -inf");
|
||||
EXPECT_EQ(fmt::format("{:%Q %S}", -d), "inf inf");
|
||||
EXPECT_EQ(fmt::format("{:%Q}", std::chrono::duration<float>(-inf)), "-inf");
|
||||
EXPECT_EQ(fmt::format("{:%Q}", std::chrono::duration<long double>(-inf)),
|
||||
"-inf");
|
||||
TEST(chrono_test, floating_duration_sign) {
|
||||
EXPECT_EQ(fmt::format("{:%S %M}", std::chrono::duration<double>(-61.25)),
|
||||
"-01.250000 01");
|
||||
auto inf =
|
||||
std::chrono::duration<double>(std::numeric_limits<double>::infinity());
|
||||
EXPECT_EQ(fmt::format("{:%Q}", inf), "inf");
|
||||
EXPECT_EQ(fmt::format("{:%Q}", -inf), "-inf");
|
||||
EXPECT_EQ(fmt::format("{:%S}", -inf), "-inf");
|
||||
EXPECT_EQ(fmt::format("{:%R}", -inf), "-inf:inf");
|
||||
}
|
||||
|
||||
TEST(chrono_test, unsigned_duration) {
|
||||
|
||||
@ -76,6 +76,7 @@ TEST(compile_test, format_default) {
|
||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo"));
|
||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo")));
|
||||
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), test_formattable()));
|
||||
EXPECT_EQ("0x0", fmt::format(FMT_COMPILE("{}"), nullptr));
|
||||
auto t = std::chrono::system_clock::now();
|
||||
EXPECT_EQ(fmt::format("{}", t), fmt::format(FMT_COMPILE("{}"), t));
|
||||
}
|
||||
@ -314,6 +315,7 @@ TEST(compile_test, static_format_high_precision) {
|
||||
TEST(compile_test, text_and_arg) {
|
||||
EXPECT_EQ(">>>42<<<", fmt::format(FMT_COMPILE(">>>{}<<<"), 42));
|
||||
EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42));
|
||||
EXPECT_EQ("0x0!", fmt::format(FMT_COMPILE("{}!"), nullptr));
|
||||
}
|
||||
|
||||
TEST(compile_test, unknown_format_fallback) {
|
||||
|
||||
@ -2339,6 +2339,7 @@ FMT_END_NAMESPACE
|
||||
TEST(format_test, to_string) {
|
||||
EXPECT_EQ(fmt::to_string(42), "42");
|
||||
EXPECT_EQ(fmt::to_string(reinterpret_cast<void*>(0x1234)), "0x1234");
|
||||
EXPECT_EQ(fmt::to_string(nullptr), "0x0");
|
||||
EXPECT_EQ(fmt::to_string(adl_test::fmt::detail::foo()), "foo");
|
||||
EXPECT_EQ(fmt::to_string(foo), "0");
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
#include "fmt/os.h" // fmt::system_category
|
||||
#include "fmt/ranges.h"
|
||||
#include "fmt/xchar.h"
|
||||
#include "gtest-extra.h" // StartsWith
|
||||
|
||||
#ifdef __cpp_lib_filesystem
|
||||
@ -32,9 +33,18 @@ TEST(std_test, path) {
|
||||
EXPECT_EQ(fmt::format("{:?}", path("foo\"bar")), "\"foo\\\"bar\"");
|
||||
|
||||
EXPECT_EQ(fmt::format("{:g}", path("/usr/bin")), "/usr/bin");
|
||||
|
||||
// libstdc++ collapses repeated separators in the generic format.
|
||||
const path repeated = "a//b";
|
||||
EXPECT_EQ(fmt::format("{:g}", repeated), repeated.generic_string());
|
||||
EXPECT_EQ(fmt::format(L"{:g}", repeated), repeated.generic_wstring());
|
||||
EXPECT_EQ(fmt::format(L"{:?g}", repeated),
|
||||
L"\"" + repeated.generic_wstring() + L"\"");
|
||||
# ifdef _WIN32
|
||||
EXPECT_EQ(fmt::format("{}", path("C:\\foo")), "C:\\foo");
|
||||
EXPECT_EQ(fmt::format("{:g}", path("C:\\foo")), "C:/foo");
|
||||
EXPECT_EQ(fmt::format(L"{}", path(L"C:\\foo")), L"C:\\foo");
|
||||
EXPECT_EQ(fmt::format(L"{:g}", path(L"C:\\foo")), L"C:/foo");
|
||||
|
||||
EXPECT_EQ(fmt::format("{}", path(L"\x0428\x0447\x0443\x0447\x044B\x043D\x0448"
|
||||
L"\x0447\x044B\x043D\x0430")),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user