From 0cef1f819e9811209a6b110ae37fe65e70aa79b0 Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Fri, 4 Mar 2022 18:21:00 -0600 Subject: [PATCH] Fixing formatting of certain kinds of ranges of ranges. (#2787) * Fixing formatting of certain kinds of ranges of ranges. * Renaming const_range to range_type. --- include/fmt/ranges.h | 46 ++++++++++++++++++++++++-------------------- test/ranges-test.cc | 15 +++++++++++++++ 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index 2de95610..77089f36 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -323,7 +323,7 @@ template struct is_range { }; namespace detail { -template struct range_mapper { +template struct range_mapper { using mapper = arg_mapper; template struct range_mapper { }; template -using range_formatter_type = - conditional_t::value, - formatter, Element>{} - .map(std::declval()))>, - Char>, - fallback_formatter>; +using range_formatter_type = conditional_t< + is_formattable::value, + formatter>{}.map( + std::declval()))>, + Char>, + fallback_formatter>; + +template +using maybe_const_range = + conditional_t::value, const R, R>; } // namespace detail template struct formatter< R, Char, - enable_if_t::value + enable_if_t< + fmt::is_range::value // Workaround a bug in MSVC 2019 and earlier. #if !FMT_MSC_VER - && (is_formattable, Char>::value || - detail::has_fallback_formatter, - Char>::value) + && + (is_formattable>, + Char>::value || + detail::has_fallback_formatter< + detail::uncvref_type>, Char>::value) #endif - >> { + >> { + using range_type = detail::maybe_const_range; using formatter_type = - detail::range_formatter_type>; + detail::range_formatter_type>; formatter_type underlying_; bool custom_specs_ = false; @@ -381,12 +388,9 @@ struct formatter< return underlying_.parse(ctx); } - template < - typename FormatContext, typename U, - FMT_ENABLE_IF( - std::is_same::value, - const R, R>>::value)> - auto format(U& range, FormatContext& ctx) const -> decltype(ctx.out()) { + template + auto format(range_type& range, FormatContext& ctx) const + -> decltype(ctx.out()) { #ifdef FMT_DEPRECATED_BRACED_RANGES Char prefix = '{'; Char postfix = '}'; @@ -394,7 +398,7 @@ struct formatter< Char prefix = detail::is_set::value ? '{' : '['; Char postfix = detail::is_set::value ? '}' : ']'; #endif - detail::range_mapper, detail::uncvref_type> mapper; + detail::range_mapper> mapper; auto out = ctx.out(); *out++ = prefix; int i = 0; diff --git a/test/ranges-test.cc b/test/ranges-test.cc index a12bb9bb..8509ee79 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -364,3 +364,18 @@ TEST(ranges_test, escape_convertible_to_string_view) { "[\"foo\"]"); } #endif // FMT_USE_STRING_VIEW + +template struct fmt_ref_view { + R* r; + + auto begin() const -> decltype(r->begin()) { return r->begin(); } + auto end() const -> decltype(r->end()) { return r->end(); } +}; + +TEST(ranges_test, range_of_range_of_mixed_const) { + std::vector> v = {{1, 2, 3}, {4, 5}}; + EXPECT_EQ(fmt::format("{}", v), "[[1, 2, 3], [4, 5]]"); + + fmt_ref_view r{&v}; + EXPECT_EQ(fmt::format("{}", r), "[[1, 2, 3], [4, 5]]"); +}