mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Extending fmt::join to support C++20-only ranges. (#2549)
This commit is contained in:
@ -2748,7 +2748,12 @@ using arg_join FMT_DEPRECATED_ALIAS = join_view<It, Sentinel, Char>;
|
|||||||
template <typename It, typename Sentinel, typename Char>
|
template <typename It, typename Sentinel, typename Char>
|
||||||
struct formatter<join_view<It, Sentinel, Char>, Char> {
|
struct formatter<join_view<It, Sentinel, Char>, Char> {
|
||||||
private:
|
private:
|
||||||
using value_type = typename std::iterator_traits<It>::value_type;
|
using value_type =
|
||||||
|
#ifdef __cpp_lib_ranges
|
||||||
|
std::iter_value_t<It>;
|
||||||
|
#else
|
||||||
|
typename std::iterator_traits<It>::value_type;
|
||||||
|
#endif
|
||||||
using context = buffer_context<Char>;
|
using context = buffer_context<Char>;
|
||||||
using mapper = detail::arg_mapper<context>;
|
using mapper = detail::arg_mapper<context>;
|
||||||
|
|
||||||
@ -2782,11 +2787,13 @@ struct formatter<join_view<It, Sentinel, Char>, Char> {
|
|||||||
auto it = value.begin;
|
auto it = value.begin;
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
if (it != value.end) {
|
if (it != value.end) {
|
||||||
out = value_formatter_.format(map(*it++), ctx);
|
out = value_formatter_.format(map(*it), ctx);
|
||||||
|
++it;
|
||||||
while (it != value.end) {
|
while (it != value.end) {
|
||||||
out = detail::copy_str<Char>(value.sep.begin(), value.sep.end(), out);
|
out = detail::copy_str<Char>(value.sep.begin(), value.sep.end(), out);
|
||||||
ctx.advance_to(out);
|
ctx.advance_to(out);
|
||||||
out = value_formatter_.format(map(*it++), ctx);
|
out = value_formatter_.format(map(*it), ctx);
|
||||||
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
|
@ -258,6 +258,36 @@ struct zstring {
|
|||||||
zstring_sentinel end() const { return {}; }
|
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<cpp20_only_range::iterator>);
|
||||||
|
# endif
|
||||||
|
|
||||||
TEST(ranges_test, join_sentinel) {
|
TEST(ranges_test, join_sentinel) {
|
||||||
auto hello = zstring{"hello"};
|
auto hello = zstring{"hello"};
|
||||||
EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']");
|
EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']");
|
||||||
@ -282,6 +312,14 @@ TEST(ranges_test, join_range) {
|
|||||||
|
|
||||||
const auto z = std::vector<int>(3u, 0);
|
const auto z = std::vector<int>(3u, 0);
|
||||||
EXPECT_EQ(fmt::format("{}", fmt::join(z, ",")), "0,0,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
|
#endif // FMT_RANGES_TEST_ENABLE_JOIN
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user