Make join() handle non-const-only begin/end ranges
See fmtlib/fmt#1784. Add tests that demonstrate the problem and check obvious variations.
This commit is contained in:
parent
d69e2da221
commit
a018b09aab
@ -3420,15 +3420,15 @@ arg_join<It, Sentinel, wchar_t> join(It begin, Sentinel end, wstring_view sep) {
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
arg_join<detail::iterator_t<const Range>, detail::sentinel_t<const Range>, char>
|
arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, char>
|
||||||
join(const Range& range, string_view sep) {
|
join(Range&& range, string_view sep) {
|
||||||
return join(std::begin(range), std::end(range), sep);
|
return join(std::begin(range), std::end(range), sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
arg_join<detail::iterator_t<const Range>, detail::sentinel_t<const Range>,
|
arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>,
|
||||||
wchar_t>
|
wchar_t>
|
||||||
join(const Range& range, wstring_view sep) {
|
join(Range&& range, wstring_view sep) {
|
||||||
return join(std::begin(range), std::end(range), sep);
|
return join(std::begin(range), std::end(range), sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -153,3 +153,39 @@ TEST(RangesTest, JoinSentinel) {
|
|||||||
EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello));
|
EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello));
|
||||||
EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(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 <typename T>
|
||||||
|
class non_const_only_range {
|
||||||
|
private:
|
||||||
|
std::vector<T> vec;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using const_iterator = typename ::std::vector<T>::const_iterator;
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
explicit non_const_only_range(Args &&...args) : vec( ::std::forward<Args>( args )... ) {}
|
||||||
|
|
||||||
|
const_iterator begin() {
|
||||||
|
return vec.begin();
|
||||||
|
}
|
||||||
|
const_iterator end() {
|
||||||
|
return vec.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(RangesTest, JoinRange) {
|
||||||
|
non_const_only_range<int> 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<int>( 3, 0 ), ",")));
|
||||||
|
|
||||||
|
std::vector<int> y( 3, 0 );
|
||||||
|
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ",")));
|
||||||
|
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(std::vector<int>( 3, 0 ), ",")));
|
||||||
|
|
||||||
|
const std::vector<int> z( 3, 0 );
|
||||||
|
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ",")));
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user