From 7aca36bca4a6baf12297139b9d6dead1a4394655 Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Sat, 16 Oct 2021 12:02:03 -0500 Subject: [PATCH] Extending fmt::join to support C++20-only ranges. (#2549) --- include/fmt/format.h | 13 ++++++++++--- test/ranges-test.cc | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index c24d5ba0..558f23f5 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2748,7 +2748,12 @@ using arg_join FMT_DEPRECATED_ALIAS = join_view; template struct formatter, Char> { private: - using value_type = typename std::iterator_traits::value_type; + using value_type = +#ifdef __cpp_lib_ranges + std::iter_value_t; +#else + typename std::iterator_traits::value_type; +#endif using context = buffer_context; using mapper = detail::arg_mapper; @@ -2782,11 +2787,13 @@ struct formatter, Char> { auto it = value.begin; auto out = ctx.out(); if (it != value.end) { - out = value_formatter_.format(map(*it++), ctx); + out = value_formatter_.format(map(*it), ctx); + ++it; while (it != value.end) { out = detail::copy_str(value.sep.begin(), value.sep.end(), out); ctx.advance_to(out); - out = value_formatter_.format(map(*it++), ctx); + out = value_formatter_.format(map(*it), ctx); + ++it; } } return out; diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 1c572e62..f8e67390 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -258,6 +258,36 @@ struct zstring { zstring_sentinel end() const { return {}; } }; +# ifdef __cpp_lib_ranges +struct cpp20_only_range { + struct iterator { + int val = 0; + + using value_type = int; + using difference_type = std::ptrdiff_t; + using iterator_concept = std::input_iterator_tag; + + iterator() = default; + iterator(int i) : val(i) {} + int operator*() const { return val; } + iterator& operator++() { + ++val; + return *this; + } + void operator++(int) { ++*this; } + bool operator==(const iterator& rhs) const { return val == rhs.val; } + }; + + int lo; + int hi; + + iterator begin() const { return iterator(lo); } + iterator end() const { return iterator(hi); } +}; + +static_assert(std::input_iterator); +# endif + TEST(ranges_test, join_sentinel) { auto hello = zstring{"hello"}; EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']"); @@ -282,6 +312,14 @@ TEST(ranges_test, join_range) { const auto z = std::vector(3u, 0); EXPECT_EQ(fmt::format("{}", fmt::join(z, ",")), "0,0,0"); + +# ifdef __cpp_lib_ranges + EXPECT_EQ(fmt::format("{}", cpp20_only_range{.lo = 0, .hi = 5}), + "[0, 1, 2, 3, 4]"); + EXPECT_EQ( + fmt::format("{}", fmt::join(cpp20_only_range{.lo = 0, .hi = 5}, ",")), + "0,1,2,3,4"); +# endif } #endif // FMT_RANGES_TEST_ENABLE_JOIN