mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 02:37:36 +02:00
Add support for arbitrary output iterators
This commit is contained in:
@ -832,25 +832,32 @@ inline Container &get_container(std::back_insert_iterator<Container> it) {
|
|||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
// A range where begin() returns back_insert_iterator.
|
template <typename OutputIt, typename T = typename OutputIt::value_type>
|
||||||
template <typename Container>
|
class output_range {
|
||||||
class back_insert_range {
|
|
||||||
private:
|
private:
|
||||||
Container &container_;
|
OutputIt it_;
|
||||||
|
|
||||||
|
// Unused yet.
|
||||||
|
using sentinel = void;
|
||||||
|
sentinel end() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using iterator = std::back_insert_iterator<Container>;
|
using value_type = T;
|
||||||
|
|
||||||
|
explicit output_range(OutputIt it): it_(it) {}
|
||||||
|
OutputIt begin() const { return it_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// A range where begin() returns back_insert_iterator.
|
||||||
|
template <typename Container>
|
||||||
|
class back_insert_range:
|
||||||
|
public output_range<std::back_insert_iterator<Container>> {
|
||||||
|
using base = output_range<std::back_insert_iterator<Container>>;
|
||||||
|
public:
|
||||||
using value_type = typename Container::value_type;
|
using value_type = typename Container::value_type;
|
||||||
|
|
||||||
struct sentinel {
|
using base::base;
|
||||||
friend bool operator!=(sentinel, iterator) { return false; }
|
back_insert_range(Container &c): base(std::back_inserter(c)) {}
|
||||||
friend bool operator!=(iterator, sentinel) { return false; }
|
|
||||||
};
|
|
||||||
|
|
||||||
back_insert_range(Container &c) : container_(c) {}
|
|
||||||
|
|
||||||
iterator begin() const { return std::back_inserter(container_); }
|
|
||||||
sentinel end() const { return sentinel(); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Formatting context.
|
// Formatting context.
|
||||||
|
@ -2023,7 +2023,7 @@ class arg_formatter: public internal::arg_formatter_base<Range> {
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
arg_formatter(basic_context<Range> &ctx, format_specs &spec)
|
arg_formatter(basic_context<Range> &ctx, format_specs &spec)
|
||||||
: base(Range(internal::get_container(ctx.begin())), spec), ctx_(ctx) {}
|
: base(Range(ctx.begin()), spec), ctx_(ctx) {}
|
||||||
|
|
||||||
using base::operator();
|
using base::operator();
|
||||||
|
|
||||||
@ -3036,6 +3036,13 @@ inline void format_to(wmemory_buffer &buf, wstring_view format_str,
|
|||||||
vformat_to(buf, format_str, make_args<wcontext>(args...));
|
vformat_to(buf, format_str, make_args<wcontext>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Container, typename Context>
|
||||||
|
typename std::enable_if<!is_contiguous<Container>::value>::type
|
||||||
|
vformat_to(std::back_insert_iterator<Container> out,
|
||||||
|
string_view format_str,
|
||||||
|
basic_format_args<Context> args) {
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Container, typename... Args>
|
template <typename Container, typename... Args>
|
||||||
inline typename std::enable_if<is_contiguous<Container>::value>::type
|
inline typename std::enable_if<is_contiguous<Container>::value>::type
|
||||||
format_to(std::back_insert_iterator<Container> out,
|
format_to(std::back_insert_iterator<Container> out,
|
||||||
@ -3043,15 +3050,13 @@ inline typename std::enable_if<is_contiguous<Container>::value>::type
|
|||||||
vformat_to(out, format_str, make_args(args...));
|
vformat_to(out, format_str, make_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Container, typename... Args>
|
template <typename OutputIt, typename... Args>
|
||||||
inline typename std::enable_if<!is_contiguous<Container>::value>::type
|
inline void format_to(OutputIt out, string_view format_str,
|
||||||
format_to(std::back_insert_iterator<Container> out,
|
const Args & ... args) {
|
||||||
string_view format_str, const Args & ... args) {
|
using range = output_range<OutputIt, char>;
|
||||||
using range = back_insert_range<Container>;
|
|
||||||
auto store = make_args<basic_context<range>>(args...);
|
auto store = make_args<basic_context<range>>(args...);
|
||||||
do_vformat_to<arg_formatter<range>>(
|
do_vformat_to<arg_formatter<range>>(
|
||||||
range(internal::get_container(out)), format_str,
|
range(out), format_str, basic_format_args<basic_context<range>>(store));
|
||||||
basic_format_args<basic_context<range>>(store));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string vformat(string_view format_str, format_args args) {
|
inline std::string vformat(string_view format_str, format_args args) {
|
||||||
|
@ -1910,8 +1910,11 @@ TEST(FormatTest, ToString) {
|
|||||||
EXPECT_EQ("42", fmt::to_string(42));
|
EXPECT_EQ("42", fmt::to_string(42));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(WriterTest, NoncontiguousIterator) {
|
TEST(WriterTest, OutputIterators) {
|
||||||
std::list<char> out;
|
std::list<char> out;
|
||||||
fmt::format_to(std::back_inserter(out), "{}", 42);
|
fmt::format_to(std::back_inserter(out), "{}", 42);
|
||||||
EXPECT_EQ("42", std::string(out.begin(), out.end()));
|
EXPECT_EQ("42", std::string(out.begin(), out.end()));
|
||||||
|
std::stringstream s;
|
||||||
|
fmt::format_to(std::ostream_iterator<char>(s), "{}", 42);
|
||||||
|
EXPECT_EQ("42", s.str());
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user