mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-25 19:50:05 +00:00
Add a map formatter
This commit is contained in:
parent
be51ee1ceb
commit
121002d700
@ -71,7 +71,7 @@ OutputIterator copy(wchar_t ch, OutputIterator out) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true value if T has std::string interface, like std::string_view.
|
// Returns true if T has a std::string-like interface, like std::string_view.
|
||||||
template <typename T> class is_std_string_like {
|
template <typename T> class is_std_string_like {
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static auto check(U* p)
|
static auto check(U* p)
|
||||||
@ -86,6 +86,19 @@ template <typename T> class is_std_string_like {
|
|||||||
template <typename Char>
|
template <typename Char>
|
||||||
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename T> class is_map {
|
||||||
|
template <typename U> static auto check(U*) -> typename U::key_type;
|
||||||
|
template <typename> static void check(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
#ifdef FMT_FORMAT_MAP_AS_LIST
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value = false;
|
||||||
|
#else
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
template <typename... Ts> struct conditional_helper {};
|
template <typename... Ts> struct conditional_helper {};
|
||||||
|
|
||||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||||
@ -573,6 +586,7 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
|||||||
template <typename T, typename Char> struct is_range {
|
template <typename T, typename Char> struct is_range {
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||||
|
!detail::is_map<T>::value &&
|
||||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||||
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
||||||
};
|
};
|
||||||
@ -614,6 +628,44 @@ struct formatter<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<
|
||||||
|
T, Char,
|
||||||
|
enable_if_t<
|
||||||
|
detail::is_map<T>::value
|
||||||
|
// Workaround a bug in MSVC 2019 and earlier.
|
||||||
|
#if !FMT_MSC_VER
|
||||||
|
&& (is_formattable<detail::value_type<T>, Char>::value ||
|
||||||
|
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
|
||||||
|
#endif
|
||||||
|
>> {
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename FormatContext, typename U,
|
||||||
|
FMT_ENABLE_IF(
|
||||||
|
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
||||||
|
const T, T>>::value)>
|
||||||
|
auto format(U& map, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
|
auto out = ctx.out();
|
||||||
|
*out++ = '{';
|
||||||
|
int i = 0;
|
||||||
|
for (const auto& item : map) {
|
||||||
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
|
out = detail::write_range_entry<Char>(out, item.first);
|
||||||
|
*out++ = ':';
|
||||||
|
*out++ = ' ';
|
||||||
|
out = detail::write_range_entry<Char>(out, item.second);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
*out++ = '}';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
||||||
const std::tuple<T...>& tuple;
|
const std::tuple<T...>& tuple;
|
||||||
basic_string_view<Char> sep;
|
basic_string_view<Char> sep;
|
||||||
|
@ -55,7 +55,7 @@ TEST(ranges_test, format_vector2) {
|
|||||||
|
|
||||||
TEST(ranges_test, format_map) {
|
TEST(ranges_test, format_map) {
|
||||||
auto m = std::map<std::string, int>{{"one", 1}, {"two", 2}};
|
auto m = std::map<std::string, int>{{"one", 1}, {"two", 2}};
|
||||||
EXPECT_EQ(fmt::format("{}", m), "[(\"one\", 1), (\"two\", 2)]");
|
EXPECT_EQ(fmt::format("{}", m), "{\"one\": 1, \"two\": 2}");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ranges_test, format_pair) {
|
TEST(ranges_test, format_pair) {
|
||||||
|
Loading…
Reference in New Issue
Block a user