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.
This commit is contained in:
Barry Revzin
2022-03-04 18:21:00 -06:00
committed by GitHub
parent 5c0d656401
commit 0cef1f819e
2 changed files with 40 additions and 21 deletions

View File

@ -323,7 +323,7 @@ template <typename T, typename Char> struct is_range {
}; };
namespace detail { namespace detail {
template <typename Context, typename Element> struct range_mapper { template <typename Context> struct range_mapper {
using mapper = arg_mapper<Context>; using mapper = arg_mapper<Context>;
template <typename T, template <typename T,
@ -340,29 +340,36 @@ template <typename Context, typename Element> struct range_mapper {
}; };
template <typename Char, typename Element> template <typename Char, typename Element>
using range_formatter_type = using range_formatter_type = conditional_t<
conditional_t<is_formattable<Element, Char>::value, is_formattable<Element, Char>::value,
formatter<remove_cvref_t<decltype( formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
range_mapper<buffer_context<Char>, Element>{} std::declval<Element>()))>,
.map(std::declval<Element>()))>, Char>,
Char>, fallback_formatter<Element, Char>>;
fallback_formatter<Element, Char>>;
template <typename R>
using maybe_const_range =
conditional_t<has_const_begin_end<R>::value, const R, R>;
} // namespace detail } // namespace detail
template <typename R, typename Char> template <typename R, typename Char>
struct formatter< struct formatter<
R, Char, R, Char,
enable_if_t<fmt::is_range<R, Char>::value enable_if_t<
fmt::is_range<R, Char>::value
// Workaround a bug in MSVC 2019 and earlier. // Workaround a bug in MSVC 2019 and earlier.
#if !FMT_MSC_VER #if !FMT_MSC_VER
&& (is_formattable<detail::uncvref_type<R>, Char>::value || &&
detail::has_fallback_formatter<detail::uncvref_type<R>, (is_formattable<detail::uncvref_type<detail::maybe_const_range<R>>,
Char>::value) Char>::value ||
detail::has_fallback_formatter<
detail::uncvref_type<detail::maybe_const_range<R>>, Char>::value)
#endif #endif
>> { >> {
using range_type = detail::maybe_const_range<R>;
using formatter_type = using formatter_type =
detail::range_formatter_type<Char, detail::uncvref_type<R>>; detail::range_formatter_type<Char, detail::uncvref_type<range_type>>;
formatter_type underlying_; formatter_type underlying_;
bool custom_specs_ = false; bool custom_specs_ = false;
@ -381,12 +388,9 @@ struct formatter<
return underlying_.parse(ctx); return underlying_.parse(ctx);
} }
template < template <typename FormatContext>
typename FormatContext, typename U, auto format(range_type& range, FormatContext& ctx) const
FMT_ENABLE_IF( -> decltype(ctx.out()) {
std::is_same<U, conditional_t<detail::has_const_begin_end<R>::value,
const R, R>>::value)>
auto format(U& range, FormatContext& ctx) const -> decltype(ctx.out()) {
#ifdef FMT_DEPRECATED_BRACED_RANGES #ifdef FMT_DEPRECATED_BRACED_RANGES
Char prefix = '{'; Char prefix = '{';
Char postfix = '}'; Char postfix = '}';
@ -394,7 +398,7 @@ struct formatter<
Char prefix = detail::is_set<R>::value ? '{' : '['; Char prefix = detail::is_set<R>::value ? '{' : '[';
Char postfix = detail::is_set<R>::value ? '}' : ']'; Char postfix = detail::is_set<R>::value ? '}' : ']';
#endif #endif
detail::range_mapper<buffer_context<Char>, detail::uncvref_type<R>> mapper; detail::range_mapper<buffer_context<Char>> mapper;
auto out = ctx.out(); auto out = ctx.out();
*out++ = prefix; *out++ = prefix;
int i = 0; int i = 0;

View File

@ -364,3 +364,18 @@ TEST(ranges_test, escape_convertible_to_string_view) {
"[\"foo\"]"); "[\"foo\"]");
} }
#endif // FMT_USE_STRING_VIEW #endif // FMT_USE_STRING_VIEW
template <typename R> 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<std::vector<int>> v = {{1, 2, 3}, {4, 5}};
EXPECT_EQ(fmt::format("{}", v), "[[1, 2, 3], [4, 5]]");
fmt_ref_view<decltype(v)> r{&v};
EXPECT_EQ(fmt::format("{}", r), "[[1, 2, 3], [4, 5]]");
}