Skip to content

Commit 212266e

Browse files
committed
Add std::complex formatter
Signed-off-by: Vladislav Shchapov <[email protected]>
1 parent ba61161 commit 212266e

File tree

3 files changed

+53
-43
lines changed

3 files changed

+53
-43
lines changed

include/fmt/std.h

+40
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <atomic>
1212
#include <bitset>
13+
#include <complex>
1314
#include <cstdlib>
1415
#include <exception>
1516
#include <memory>
@@ -585,5 +586,44 @@ struct formatter<std::atomic_flag, Char> : formatter<bool, Char> {
585586
};
586587
#endif // __cpp_lib_atomic_flag_test
587588

589+
FMT_EXPORT
590+
template <typename F, typename Char>
591+
struct formatter<std::complex<F>, Char> : nested_formatter<F, Char> {
592+
private:
593+
// Functor because C++11 doesn't support generic lambdas.
594+
struct writer {
595+
const formatter<std::complex<F>, Char>* f;
596+
const std::complex<F>& c;
597+
598+
template <typename Char2, typename OutputIt,
599+
FMT_ENABLE_IF(std::is_same<Char2, char>::value)>
600+
FMT_CONSTEXPR auto impl(OutputIt out) -> OutputIt {
601+
return fmt::format_to(out, "({},{})", f->nested(c.real()),
602+
f->nested(c.imag()));
603+
}
604+
605+
template <typename Char2, typename OutputIt,
606+
FMT_ENABLE_IF(!std::is_same<Char2, char>::value)>
607+
FMT_CONSTEXPR auto impl(OutputIt out) -> OutputIt {
608+
auto format =
609+
detail::string_literal<Char2, '(', '{', '}', ',', '{', '}', ')'>{};
610+
return fmt::format_to(out, basic_string_view<Char>(format),
611+
f->nested(c.real()), f->nested(c.imag()));
612+
}
613+
614+
template <typename OutputIt>
615+
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
616+
return impl<Char>(out);
617+
}
618+
};
619+
620+
public:
621+
template <typename FormatContext>
622+
auto format(const std::complex<F>& c, FormatContext& ctx) const
623+
-> decltype(ctx.out()) {
624+
return this->write_padded(ctx, writer{this, c});
625+
}
626+
};
627+
588628
FMT_END_NAMESPACE
589629
#endif // FMT_STD_H_

test/std-test.cc

+6
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ TEST(std_test, thread_id) {
6565
EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty());
6666
}
6767

68+
TEST(std_test, complex) {
69+
EXPECT_EQ(fmt::format("{}", std::complex<double>(1, 2.2)), "(1,2.2)");
70+
EXPECT_EQ(fmt::format("{:>20.2f}", std::complex<double>(1, 2.2)),
71+
" (1.00,2.20)");
72+
}
73+
6874
#ifdef __cpp_lib_source_location
6975
TEST(std_test, source_location) {
7076
std::source_location loc = std::source_location::current();

test/xchar-test.cc

+7-43
Original file line numberDiff line numberDiff line change
@@ -562,49 +562,6 @@ TEST(locale_test, int_formatter) {
562562
EXPECT_EQ(fmt::to_string(buf), "12,345");
563563
}
564564

565-
FMT_BEGIN_NAMESPACE
566-
template <class charT> struct formatter<std::complex<double>, charT> {
567-
private:
568-
detail::dynamic_format_specs<char> specs_;
569-
570-
public:
571-
FMT_CONSTEXPR typename basic_format_parse_context<charT>::iterator parse(
572-
basic_format_parse_context<charT>& ctx) {
573-
auto end = parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
574-
detail::type::float_type);
575-
detail::parse_float_type_spec(specs_);
576-
return end;
577-
}
578-
579-
template <class FormatContext>
580-
typename FormatContext::iterator format(const std::complex<double>& c,
581-
FormatContext& ctx) const {
582-
auto specs = specs_;
583-
detail::handle_dynamic_spec<detail::precision_checker>(
584-
specs.precision, specs.precision_ref, ctx);
585-
auto fspecs = std::string();
586-
if (specs.precision > 0) fspecs = fmt::format(".{}", specs.precision);
587-
if (specs.type == presentation_type::fixed) fspecs += 'f';
588-
auto real = fmt::format(ctx.locale().template get<std::locale>(),
589-
fmt::runtime("{:" + fspecs + "}"), c.real());
590-
auto imag = fmt::format(ctx.locale().template get<std::locale>(),
591-
fmt::runtime("{:" + fspecs + "}"), c.imag());
592-
auto fill_align_width = std::string();
593-
if (specs.width > 0) fill_align_width = fmt::format(">{}", specs.width);
594-
return fmt::format_to(ctx.out(), runtime("{:" + fill_align_width + "}"),
595-
c.real() != 0 ? fmt::format("({}+{}i)", real, imag)
596-
: fmt::format("{}i", imag));
597-
}
598-
};
599-
FMT_END_NAMESPACE
600-
601-
TEST(locale_test, complex) {
602-
std::string s = fmt::format("{}", std::complex<double>(1, 2));
603-
EXPECT_EQ(s, "(1+2i)");
604-
EXPECT_EQ(fmt::format("{:.2f}", std::complex<double>(1, 2)), "(1.00+2.00i)");
605-
EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)");
606-
}
607-
608565
TEST(locale_test, chrono_weekday) {
609566
auto loc = get_locale("es_ES.UTF-8", "Spanish_Spain.1252");
610567
auto loc_old = std::locale::global(loc);
@@ -625,6 +582,13 @@ TEST(locale_test, sign) {
625582
EXPECT_EQ(fmt::format(std::locale(), L"{:L}", -50), L"-50");
626583
}
627584

585+
TEST(std_test_xchar, complex) {
586+
auto s = fmt::format(L"{}", std::complex<double>(1, 2));
587+
EXPECT_EQ(s, L"(1,2)");
588+
EXPECT_EQ(fmt::format(L"{:.2f}", std::complex<double>(1, 2)), L"(1.00,2.00)");
589+
EXPECT_EQ(fmt::format(L"{:8}", std::complex<double>(1, 2)), L"(1,2) ");
590+
}
591+
628592
TEST(std_test_xchar, optional) {
629593
# ifdef __cpp_lib_optional
630594
EXPECT_EQ(fmt::format(L"{}", std::optional{L'C'}), L"optional(\'C\')");

0 commit comments

Comments
 (0)