Repository: fmtlib/fmt
File: include/fmt/ranges.h (C/C++)

Code before:
#endif
  formatter<remove_cvref_t<value_type>, Char> value_formatter_;

 public:
  template <typename ParseContext>
  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* {
    return value_formatter_.parse(ctx);
  }

  template <typename FormatContext, typename Iter,
            FMT_ENABLE_IF(std::is_copy_constructible<Iter>::value)>
  auto format(const join_view<Iter, Sentinel, Char>& value,
              FormatContext& ctx) const -> decltype(ctx.out()) {
    auto it = value.begin;
    return format_impl(value, ctx, it);
  }

  template <typename FormatContext, typename Iter,
            FMT_ENABLE_IF(!std::is_copy_constructible<Iter>::value)>
  auto format(join_view<Iter, Sentinel, Char>& value, FormatContext& ctx) const
      -> decltype(ctx.out()) {
    return format_impl(value, ctx, value.begin);
  }

  template <typename FormatContext>
  auto format_impl(const join_view<It, Sentinel, Char>& value,
                   FormatContext& ctx, It& it) const -> decltype(ctx.out()) {
    auto out = ctx.out();
    if (it != value.end) {
      out = value_formatter_.format(*it, ctx);
      ++it;
      while (it != value.end) {
        out = detail::copy<Char>(value.sep.begin(), value.sep.end(), out);
        ctx.advance_to(out);
        out = value_formatter_.format(*it, ctx);
        ++it;
      }
    }
    return out;
  }
};

/**
  Returns a view that formats the iterator range `[begin, end)` with elements
  separated by `sep`.
 */
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
  return {std::move(begin), end, sep};
}


Review comment (suggestion):
This should be private. Also let's rename to `do_format` to follow the convention for such methods in {fmt}.

Code after:
    auto out = ctx.out();
    auto it = detail::range_begin(map);
    auto end = detail::range_end(map);

    basic_string_view<Char> open = detail::string_literal<Char, '{'>{};
    if (!no_delimiters_) out = detail::copy<Char>(open, out);
    int i = 0;
    basic_string_view<Char> sep = detail::string_literal<Char, ',', ' '>{};
    for (; it != end; ++it) {
      if (i > 0) out = detail::copy<Char>(sep, out);
      ctx.advance_to(out);
      detail::for_each2(formatters_, mapper.map(*it),
                        detail::format_tuple_element<FormatContext>{
                            0, ctx, detail::string_literal<Char, ':', ' '>{}});
      ++i;
    }
    basic_string_view<Char> close = detail::string_literal<Char, '}'>{};
    if (!no_delimiters_) out = detail::copy<Char>(close, out);
    return out;
  }
};

template <typename It, typename Sentinel, typename Char = char>
struct join_view : detail::view {
  It begin;
  Sentinel end;
  basic_string_view<Char> sep;

  join_view(It b, Sentinel e, basic_string_view<Char> s)
      : begin(std::move(b)), end(e), sep(s) {}
};

template <typename It, typename Sentinel, typename Char>
struct formatter<join_view<It, Sentinel, Char>, Char> {
 private:
  using value_type =
#ifdef __cpp_lib_ranges
      std::iter_value_t<It>;
#else
      typename std::iterator_traits<It>::value_type;
#endif
  formatter<remove_cvref_t<value_type>, Char> value_formatter_;

 public:
  template <typename ParseContext>
  FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* {
    return value_formatter_.parse(ctx);
  }

  template <typename FormatContext, typename Iter,
            FMT_ENABLE_IF(std::is_copy_constructible<Iter>::value)>