From febffa4e64b60099055d057c7818951ccb33ad69 Mon Sep 17 00:00:00 2001 From: Tony E Lewis Date: Tue, 21 Jul 2020 20:13:00 +0100 Subject: [PATCH] Make join() handle non-const-only begin/end ranges (#1786) See fmtlib/fmt#1784. Add tests that demonstrate the problem and check obvious variations. --- include/fmt/format.h | 9 ++++----- test/ranges-test.cc | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 65d27161..712c6ebe 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3420,15 +3420,14 @@ arg_join join(It begin, Sentinel end, wstring_view sep) { \endrst */ template -arg_join, detail::sentinel_t, char> -join(const Range& range, string_view sep) { +arg_join, detail::sentinel_t, char> join( + Range&& range, string_view sep) { return join(std::begin(range), std::end(range), sep); } template -arg_join, detail::sentinel_t, - wchar_t> -join(const Range& range, wstring_view sep) { +arg_join, detail::sentinel_t, wchar_t> join( + Range&& range, wstring_view sep) { return join(std::begin(range), std::end(range), sep); } diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 46208e8d..518e7ba2 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -153,3 +153,37 @@ TEST(RangesTest, JoinSentinel) { EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello)); EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(hello, "_"))); } + +// A range that provides non-const only begin()/end() to test fmt::join handles +// that +// +// Some ranges (eg those produced by range-v3's views::filter()) can cache +// information during iteration so they only provide non-const begin()/end(). +template class non_const_only_range { + private: + std::vector vec; + + public: + using const_iterator = typename ::std::vector::const_iterator; + + template + explicit non_const_only_range(Args&&... args) + : vec(::std::forward(args)...) {} + + const_iterator begin() { return vec.begin(); } + const_iterator end() { return vec.end(); } +}; + +TEST(RangesTest, JoinRange) { + non_const_only_range x(3, 0); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(x, ","))); + EXPECT_EQ("0,0,0", + fmt::format("{}", fmt::join(non_const_only_range(3, 0), ","))); + + std::vector y(3, 0); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ","))); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(std::vector(3, 0), ","))); + + const std::vector z(3, 0); + EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ","))); +}