mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Make the map formatter correctly handle elements with custom formatters
This commit is contained in:
@ -483,7 +483,7 @@ struct range_formatter<
|
|||||||
|
|
||||||
template <typename R, typename FormatContext>
|
template <typename R, typename FormatContext>
|
||||||
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
|
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
detail::range_mapper<buffered_context<Char>> mapper;
|
auto mapper = detail::range_mapper<buffered_context<Char>>();
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
auto it = detail::range_begin(range);
|
auto it = detail::range_begin(range);
|
||||||
auto end = detail::range_end(range);
|
auto end = detail::range_end(range);
|
||||||
@ -544,40 +544,39 @@ struct formatter<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A map formatter.
|
||||||
template <typename R, typename Char>
|
template <typename R, typename Char>
|
||||||
struct formatter<
|
struct formatter<
|
||||||
R, Char,
|
R, Char,
|
||||||
enable_if_t<range_format_kind<R, Char>::value == range_format::map>> {
|
enable_if_t<range_format_kind<R, Char>::value == range_format::map>> {
|
||||||
private:
|
private:
|
||||||
using map_type = detail::maybe_const_range<R>;
|
using map_type = detail::maybe_const_range<R>;
|
||||||
detail::range_formatter_type<Char, detail::uncvref_type<map_type>>
|
using element_type = detail::uncvref_type<map_type>;
|
||||||
underlying_;
|
|
||||||
|
decltype(detail::tuple::get_formatters<element_type, Char>(
|
||||||
|
detail::tuple_index_sequence<element_type>())) formatters_;
|
||||||
bool no_delimiters_ = false;
|
bool no_delimiters_ = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR formatter() {
|
FMT_CONSTEXPR formatter() {}
|
||||||
underlying_.set_brackets({}, {});
|
|
||||||
underlying_.set_separator(detail::string_literal<Char, ':', ' '>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
auto it = ctx.begin();
|
auto it = ctx.begin();
|
||||||
auto end = ctx.end();
|
auto end = ctx.end();
|
||||||
detail::maybe_set_debug_format(underlying_, true);
|
if (it != end) {
|
||||||
if (it == end) return underlying_.parse(ctx);
|
if (detail::to_ascii(*it) == 'n') {
|
||||||
|
no_delimiters_ = true;
|
||||||
if (detail::to_ascii(*it) == 'n') {
|
++it;
|
||||||
no_delimiters_ = true;
|
}
|
||||||
++it;
|
if (it != end && *it != '}') {
|
||||||
|
if (*it != ':') report_error("invalid format specifier");
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
ctx.advance_to(it);
|
||||||
}
|
}
|
||||||
if (it != end && *it != '}') {
|
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
|
||||||
if (*it != ':') report_error("invalid format specifier");
|
return it;
|
||||||
detail::maybe_set_debug_format(underlying_, false);
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
ctx.advance_to(it);
|
|
||||||
return underlying_.parse(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
@ -594,7 +593,9 @@ struct formatter<
|
|||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
if (i > 0) out = detail::copy<Char>(sep, out);
|
if (i > 0) out = detail::copy<Char>(sep, out);
|
||||||
ctx.advance_to(out);
|
ctx.advance_to(out);
|
||||||
out = underlying_.format(mapper.map(*it), ctx);
|
detail::for_each2(formatters_, mapper.map(*it),
|
||||||
|
detail::format_tuple_element<FormatContext>{
|
||||||
|
0, ctx, detail::string_literal<Char, ':', ' '>{}});
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
basic_string_view<Char> close = detail::string_literal<Char, '}'>{};
|
basic_string_view<Char> close = detail::string_literal<Char, '}'>{};
|
||||||
|
@ -89,6 +89,35 @@ TEST(ranges_test, format_map) {
|
|||||||
EXPECT_EQ(fmt::format("{:n}", m), "\"one\": 1, \"two\": 2");
|
EXPECT_EQ(fmt::format("{:n}", m), "\"one\": 1, \"two\": 2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct test_map_value {};
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
template <> struct formatter<test_map_value> : formatter<string_view> {
|
||||||
|
auto format(test_map_value, format_context& ctx) const
|
||||||
|
-> format_context::iterator {
|
||||||
|
return formatter<string_view>::format("foo", ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
struct formatter<std::pair<K, test_map_value>> : formatter<string_view> {
|
||||||
|
auto format(std::pair<K, test_map_value>, format_context& ctx) const
|
||||||
|
-> format_context::iterator {
|
||||||
|
return ctx.out();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
struct is_tuple_formattable<std::pair<K, test_map_value>, char>
|
||||||
|
: std::false_type {};
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
TEST(ranges_test, format_map_custom_pair) {
|
||||||
|
EXPECT_EQ(fmt::format("{}", std::map<int, test_map_value>{{42, {}}}),
|
||||||
|
"{42: \"foo\"}");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ranges_test, format_set) {
|
TEST(ranges_test, format_set) {
|
||||||
EXPECT_EQ(fmt::format("{}", std::set<std::string>{"one", "two"}),
|
EXPECT_EQ(fmt::format("{}", std::set<std::string>{"one", "two"}),
|
||||||
"{\"one\", \"two\"}");
|
"{\"one\", \"two\"}");
|
||||||
@ -468,7 +497,7 @@ struct vec {
|
|||||||
|
|
||||||
auto begin(const vec& v) -> const int* { return v.n; }
|
auto begin(const vec& v) -> const int* { return v.n; }
|
||||||
auto end(const vec& v) -> const int* { return v.n + 2; }
|
auto end(const vec& v) -> const int* { return v.n + 2; }
|
||||||
}
|
} // namespace adl
|
||||||
|
|
||||||
TEST(ranges_test, format_join_adl_begin_end) {
|
TEST(ranges_test, format_join_adl_begin_end) {
|
||||||
EXPECT_EQ(fmt::format("{}", fmt::join(adl::vec(), "/")), "42/43");
|
EXPECT_EQ(fmt::format("{}", fmt::join(adl::vec(), "/")), "42/43");
|
||||||
|
Reference in New Issue
Block a user