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

@@ -652,3 +652,56 @@ struct lvalue_qualified_begin_end {
TEST(ranges_test, lvalue_qualified_begin_end) {
EXPECT_EQ(fmt::format("{}", lvalue_qualified_begin_end{}), "[1, 2, 3, 4, 5]");
}
#if !defined(__cpp_lib_ranges) || __cpp_lib_ranges <= 202106L
# define ENABLE_INPUT_RANGE_JOIN_TEST 0
#elif FMT_CLANG_VERSION
# if FMT_CLANG_VERSION > 1500
# define ENABLE_INPUT_RANGE_JOIN_TEST 1
# else
# define ENABLE_INPUT_RANGE_JOIN_TEST 0
# endif
#else
# define ENABLE_INPUT_RANGE_JOIN_TEST 1
#endif
#if ENABLE_INPUT_RANGE_JOIN_TEST
TEST(ranges_test, input_range_join) {
std::istringstream iss("1 2 3 4 5");
auto view = std::views::istream<std::string>(iss);
auto joined_view = fmt::join(view.begin(), view.end(), ", ");
EXPECT_EQ("1, 2, 3, 4, 5", fmt::format("{}", std::move(joined_view)));
}
TEST(ranges_test, input_range_join_overload) {
std::istringstream iss("1 2 3 4 5");
EXPECT_EQ(
"1.2.3.4.5",
fmt::format("{}", fmt::join(std::views::istream<std::string>(iss), ".")));
}
#endif
TEST(ranges_test, std_istream_iterator_join) {
std::istringstream iss("1 2 3 4 5");
std::istream_iterator<int> first{iss};
std::istream_iterator<int> last{};
auto joined_view = fmt::join(first, last, ", ");
EXPECT_EQ("1, 2, 3, 4, 5", fmt::format("{}", std::move(joined_view)));
}
TEST(ranges_test, movable_only_istream_iter_join) {
// Mirrors c++20 std::ranges::basic_istream_view::iterator
struct UncopyableIstreamIter : std::istream_iterator<int> {
explicit UncopyableIstreamIter(std::istringstream& iss)
: std::istream_iterator<int>{iss} {}
UncopyableIstreamIter(const UncopyableIstreamIter&) = delete;
UncopyableIstreamIter(UncopyableIstreamIter&&) = default;
};
static_assert(!std::is_copy_constructible<UncopyableIstreamIter>::value, "");
std::istringstream iss("1 2 3 4 5");
UncopyableIstreamIter first{iss};
std::istream_iterator<int> last{};
auto joined_view = fmt::join(std::move(first), last, ", ");
EXPECT_EQ("1, 2, 3, 4, 5", fmt::format("{}", std::move(joined_view)));
}