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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 {
template <typename Context, typename Element> struct range_mapper {
template <typename Context> struct range_mapper {
using mapper = arg_mapper<Context>;
template <typename T,
@ -340,29 +340,36 @@ template <typename Context, typename Element> struct range_mapper {
};
template <typename Char, typename Element>
using range_formatter_type =
conditional_t<is_formattable<Element, Char>::value,
formatter<remove_cvref_t<decltype(
range_mapper<buffer_context<Char>, Element>{}
.map(std::declval<Element>()))>,
using range_formatter_type = conditional_t<
is_formattable<Element, Char>::value,
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
std::declval<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
template <typename R, typename Char>
struct formatter<
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.
#if !FMT_MSC_VER
&& (is_formattable<detail::uncvref_type<R>, Char>::value ||
detail::has_fallback_formatter<detail::uncvref_type<R>,
Char>::value)
&&
(is_formattable<detail::uncvref_type<detail::maybe_const_range<R>>,
Char>::value ||
detail::has_fallback_formatter<
detail::uncvref_type<detail::maybe_const_range<R>>, Char>::value)
#endif
>> {
using range_type = detail::maybe_const_range<R>;
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_;
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<U, conditional_t<detail::has_const_begin_end<R>::value,
const R, R>>::value)>
auto format(U& range, FormatContext& ctx) const -> decltype(ctx.out()) {
template <typename FormatContext>
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<R>::value ? '{' : '[';
Char postfix = detail::is_set<R>::value ? '}' : ']';
#endif
detail::range_mapper<buffer_context<Char>, detail::uncvref_type<R>> mapper;
detail::range_mapper<buffer_context<Char>> mapper;
auto out = ctx.out();
*out++ = prefix;
int i = 0;

View File

@ -364,3 +364,18 @@ TEST(ranges_test, escape_convertible_to_string_view) {
"[\"foo\"]");
}
#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]]");
}