diff --git a/include/fmt/std.h b/include/fmt/std.h index 01a61cee61fb..0b933c08cffd 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -634,30 +634,55 @@ FMT_EXPORT template struct formatter, Char> : nested_formatter { private: + bool compat_iostreams_ = false; // Functor because C++11 doesn't support generic lambdas. struct writer { const formatter, Char>* f; const std::complex& c; + const bool compat_iostreams; template FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt { - if (c.real() != 0) { - auto format_full = detail::string_literal{}; - return fmt::format_to(out, basic_string_view(format_full), - f->nested(c.real()), f->nested(c.imag())); + if (c.real() != 0 || compat_iostreams) { + auto format_full_ = detail::string_literal{}; + auto format_neg_ = detail::string_literal{}; + auto pformat_full_ = detail::string_literal{}; + if (compat_iostreams) + return fmt::format_to(out, basic_string_view(pformat_full_), + f->nested(c.real()), f->nested(c.imag())); + else if (c.imag() >= 0 /* check format_specs.sign */) + return fmt::format_to(out, basic_string_view(format_full_), + f->nested(c.real()), f->nested(c.imag())); + else + return fmt::format_to(out, basic_string_view(format_neg_), + f->nested(c.real()), f->nested(c.imag())); } - auto format_imag = detail::string_literal{}; - return fmt::format_to(out, basic_string_view(format_imag), + auto format_imag_ = detail::string_literal{}; + return fmt::format_to(out, basic_string_view(format_imag_), f->nested(c.imag())); } }; public: + FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) + -> decltype(ctx.begin()) { + auto it = ctx.begin(); + auto end = ctx.end(); + if (it != end && *it == 'p') { + ++it; + compat_iostreams_ = 1; + ctx.advance_to(it); + } + return nested_formatter::parse(ctx); + } + template auto format(const std::complex& c, FormatContext& ctx) const -> decltype(ctx.out()) { - return this->write_padded(ctx, writer{this, c}); + return this->write_padded(ctx, writer{this, c, compat_iostreams_}); } }; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6f7214a8ff89..d8d638f1c80b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -163,6 +163,7 @@ if (FMT_PEDANTIC) endif () if (HAVE_FNO_EXCEPTIONS_FLAG) add_library(noexception-test ../src/format.cc noexception-test.cc) + target_compile_features(noexception-test PUBLIC cxx_std_11) target_include_directories( noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_options(noexception-test PRIVATE -fno-exceptions) @@ -171,6 +172,7 @@ if (FMT_PEDANTIC) # Test that the library compiles without locale. add_library(nolocale-test ../src/format.cc) + target_compile_features(nolocale-test PUBLIC cxx_std_11) target_include_directories( nolocale-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_definitions( diff --git a/test/std-test.cc b/test/std-test.cc index 17c95cfe57ed..4d707774dd92 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -67,9 +67,35 @@ TEST(std_test, thread_id) { TEST(std_test, complex) { EXPECT_EQ(fmt::format("{}", std::complex(1, 2.2)), "(1+2.2i)"); + EXPECT_EQ(fmt::format("{}", std::complex(1, -2.2)), "(1-2.2i)"); EXPECT_EQ(fmt::format("{}", std::complex(0, 2.2)), "2.2i"); + EXPECT_EQ(fmt::format("{}", std::complex(0, -2.2)), "-2.2i"); + EXPECT_EQ(fmt::format("{:+}", std::complex(0, 2.2)), "+2.2i"); + EXPECT_EQ(fmt::format("{:+}", std::complex(0, -2.2)), "-2.2i"); + EXPECT_EQ(fmt::format("{:+}", std::complex(1, -2.2)), "(+1-2.2i)"); + //EXPECT_EQ(fmt::format("{:+}", std::complex(1, 2.2)), "(+1+2.2i)"); // TODO + //EXPECT_EQ(fmt::format("{: }", std::complex(1, 2.2)), "( 1+2.2i)"); // TODO + EXPECT_EQ(fmt::format("{: }", std::complex(1, -2.2)), "( 1-2.2i)"); EXPECT_EQ(fmt::format("{:>20.2f}", std::complex(1, 2.2)), " (1.00+2.20i)"); + EXPECT_EQ(fmt::format("{:<20.2f}", std::complex(1, 2.2)), + "(1.00+2.20i) "); + EXPECT_EQ(fmt::format("{:<20.2f}", std::complex(1, -2.2)), + "(1.00-2.20i) "); + // :p + EXPECT_EQ(fmt::format("{:>p}", std::complex(1, 2.2)), "(1,2.2)"); + EXPECT_EQ(fmt::format("{:>p}", std::complex(1, -2.2)), "(1,-2.2)"); + EXPECT_EQ(fmt::format("{:>p}", std::complex(0, 2.2)), "(0,2.2)"); + EXPECT_EQ(fmt::format("{:>p}", std::complex(2.2, 0)), "(2.2,0)"); + EXPECT_EQ(fmt::format("{:>p}", std::complex(0, 0)), "(0,0)"); + // :p + format + align + EXPECT_EQ(fmt::format("{:p<20.2f}", std::complex(1, 2.2)), + "(1.00,2.20) "); + EXPECT_EQ(fmt::format("{:p+<20.2f}", std::complex(1, 2.2)), + "(1.00,2.20) "); + // TODO + // * + // i or j } #ifdef __cpp_lib_source_location