From f76603f21ea75bcd8d0007d7599cac75862b13b9 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Tue, 3 Oct 2023 18:53:47 +0200 Subject: [PATCH] fix: make std::bitset formattable again (#3660) * fix: make std::bitset formattable again It used to be formattable via operator<<(ostream&) implicitly. Make it formattable again, but this time via formatter specialization. * fix: make nested_formatter constexpr default constructible --- include/fmt/format.h | 2 ++ include/fmt/std.h | 26 ++++++++++++++++++++++++++ test/std-test.cc | 8 ++++++++ 3 files changed, 36 insertions(+) diff --git a/include/fmt/format.h b/include/fmt/format.h index 2e24e131a98d..6646f0409f30 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -4215,6 +4215,8 @@ template struct nested_formatter { formatter formatter_; public: + constexpr nested_formatter() : width_(0), align_(align_t::none) {} + FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> const char* { auto specs = detail::dynamic_format_specs(); auto it = parse_format_specs(ctx.begin(), ctx.end(), specs, ctx, diff --git a/include/fmt/std.h b/include/fmt/std.h index b4e055c28d41..262ad4d209c0 100644 --- a/include/fmt/std.h +++ b/include/fmt/std.h @@ -145,6 +145,32 @@ FMT_END_NAMESPACE #endif FMT_BEGIN_NAMESPACE +FMT_EXPORT +template +struct formatter, Char> : nested_formatter { + private: + // Functor because C++11 doesn't support generic lambdas. + struct writer { + const std::bitset& bs; + + template + FMT_CONSTEXPR OutputIt operator()(OutputIt out) { + for (auto pos = N; pos > 0; --pos) { + out = detail::write(out, bs[pos - 1] ? Char('1') : Char('0')); + } + + return out; + } + }; + + public: + template + auto format(const std::bitset& bs, FormatContext& ctx) const + -> decltype(ctx.out()) { + return write_padded(ctx, writer{bs}); + } +}; + FMT_EXPORT template struct formatter : basic_ostream_formatter {}; diff --git a/test/std-test.cc b/test/std-test.cc index 56904cc9889d..4279fec10b0f 100644 --- a/test/std-test.cc +++ b/test/std-test.cc @@ -237,6 +237,14 @@ TEST(std_test, format_const_bit_reference) { EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); } +TEST(std_test, format_bitset) { + const std::bitset<6> bs(42); + EXPECT_EQ(fmt::format("{}", bs), "101010"); + EXPECT_EQ(fmt::format("{:.4}", bs), "101010"); + EXPECT_EQ(fmt::format("{:0>8}", bs), "00101010"); + EXPECT_EQ(fmt::format("{:-^12}", bs), "---101010---"); +} + TEST(std_test, format_atomic) { std::atomic b(false); EXPECT_EQ(fmt::format("{}", b), "false");