From 77bfd8499af75c5cff6b42d131b02bfdfbd7d5e0 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 4 May 2024 09:18:35 -0700 Subject: [PATCH] Split range and map formatters --- include/fmt/ranges.h | 91 +++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index cf03c03b..96b93ea8 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -511,37 +511,25 @@ struct range_format_kind template struct formatter< R, Char, - enable_if_t::value != - range_format::disabled> + enable_if_t::value != + range_format::disabled && + range_format_kind::value != range_format::map> // Workaround a bug in MSVC 2015 and earlier. #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910 - , - detail::is_formattable_delayed + , + detail::is_formattable_delayed #endif - >::value>> { + >::value>> { private: using range_type = detail::maybe_const_range; range_formatter, Char> range_formatter_; - FMT_CONSTEXPR void init(detail::range_format_constant) { - range_formatter_.set_brackets(detail::string_literal{}, - detail::string_literal{}); - } - - FMT_CONSTEXPR void init(detail::range_format_constant) { - range_formatter_.set_brackets(detail::string_literal{}, - detail::string_literal{}); - range_formatter_.underlying().set_brackets({}, {}); - range_formatter_.underlying().set_separator( - detail::string_literal{}); - } - - FMT_CONSTEXPR void init( - detail::range_format_constant) {} - public: FMT_CONSTEXPR formatter() { - init(detail::range_format_constant::value>()); + if (range_format_kind::value != range_format::set) return; + range_formatter_.set_brackets(detail::string_literal{}, + detail::string_literal{}); } template @@ -556,6 +544,65 @@ struct formatter< } }; +template +struct formatter< + R, Char, + enable_if_t::value == range_format::map>> { + private: + using map_type = detail::maybe_const_range; + detail::range_formatter_type> + underlying_; + bool no_delimiters_ = false; + + public: + FMT_CONSTEXPR formatter() { + underlying_.set_brackets({}, {}); + underlying_.set_separator(detail::string_literal{}); + } + + template + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + auto it = ctx.begin(); + auto end = ctx.end(); + detail::maybe_set_debug_format(underlying_, true); + if (it == end) return underlying_.parse(ctx); + + if (detail::to_ascii(*it) == 'n') { + no_delimiters_ = true; + ++it; + } + if (it != end && *it != '}') { + if (*it != ':') report_error("invalid format specifier"); + detail::maybe_set_debug_format(underlying_, false); + ++it; + } + ctx.advance_to(it); + return underlying_.parse(ctx); + } + + template + auto format(map_type& map, FormatContext& ctx) const -> decltype(ctx.out()) { + auto mapper = detail::range_mapper>(); + auto out = ctx.out(); + auto it = detail::range_begin(map); + auto end = detail::range_end(map); + + basic_string_view open = detail::string_literal{}; + if (!no_delimiters_) out = detail::copy(open, out); + int i = 0; + basic_string_view sep = detail::string_literal{}; + for (; it != end; ++it) { + if (i > 0) out = detail::copy(sep, out); + ctx.advance_to(out); + out = underlying_.format(mapper.map(*it), ctx); + ++i; + } + basic_string_view close = detail::string_literal{}; + if (!no_delimiters_) out = detail::copy(close, out); + return out; + } +}; + template struct join_view : detail::view { It begin;