Enable fmt::join for uncopyable iterators (#3946)

If iterator not copyable mutate the underlying iterator
Notably std::ranges::basic_istream_view::__iterator
Addresses issue (#3802)
This commit is contained in:
Justin Riddell
2024-05-05 23:44:23 +01:00
committed by GitHub
parent 16cec4f591
commit 10508a30ec
2 changed files with 73 additions and 4 deletions

View File

@@ -13,6 +13,7 @@
# include <iterator>
# include <tuple>
# include <type_traits>
# include <utility>
#endif
#include "format.h"
@@ -611,7 +612,7 @@ struct join_view : detail::view {
basic_string_view<Char> sep;
join_view(It b, Sentinel e, basic_string_view<Char> s)
: begin(b), end(e), sep(s) {}
: begin(std::move(b)), end(e), sep(s) {}
};
template <typename It, typename Sentinel, typename Char>
@@ -631,10 +632,25 @@ struct formatter<join_view<It, Sentinel, Char>, Char> {
return value_formatter_.parse(ctx);
}
template <typename FormatContext>
auto format(const join_view<It, Sentinel, Char>& value,
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 do_format(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 do_format(value, ctx, value.begin);
}
private:
template <typename FormatContext>
auto do_format(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);
@@ -656,7 +672,7 @@ struct formatter<join_view<It, Sentinel, Char>, Char> {
*/
template <typename It, typename Sentinel>
auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
return {begin, end, sep};
return {std::move(begin), end, sep};
}
/**