Type erase output iterators

This commit is contained in:
Victor Zverovich 2020-07-17 11:21:11 -07:00
parent 18024853b6
commit 9d3cd0afb2
2 changed files with 50 additions and 3 deletions

View File

@ -725,6 +725,41 @@ class container_buffer : public buffer<typename Container::value_type> {
: buffer<typename Container::value_type>(c.size()), container_(c) {}
};
// A buffer that writes to an output iterator when flushed.
template <typename OutputIt, typename T>
class iterator_buffer : public buffer<T> {
private:
enum { buffer_size = 256 };
OutputIt out_;
T data_[buffer_size];
protected:
void grow(size_t) final {
if (this->size() == buffer_size) flush();
}
public:
explicit iterator_buffer(OutputIt out)
: buffer<T>(data_, 0, buffer_size), out_(out) {}
~iterator_buffer() { flush(); }
OutputIt out() { return out_; }
void flush();
};
template <typename T>
class iterator_buffer<T*, T> : public buffer<T> {
protected:
void grow(size_t) final {}
public:
explicit iterator_buffer(T* out) : buffer<T>(out, 0, ~size_t()) {}
T* out() { return &*this->end(); }
void flush() {}
};
// An output iterator that appends to the buffer.
// It is used to reduce symbol sizes for the common case.
template <typename T>
@ -1229,6 +1264,9 @@ struct is_contiguous_back_insert_iterator : std::false_type {};
template <typename Container>
struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
: is_contiguous<Container> {};
template <typename Char>
struct is_contiguous_back_insert_iterator<buffer_appender<Char>>
: std::true_type {};
// A type-erased reference to an std::locale to avoid heavy <locale> include.
class locale_ref {

View File

@ -581,6 +581,12 @@ void buffer<T>::append(const U* begin, const U* end) {
begin += count;
} while (begin != end);
}
template <typename OutputIt, typename T>
void iterator_buffer<OutputIt, T>::flush() {
out_ = std::copy(data_, data_ + this->size(), out_);
this->clear();
}
} // namespace detail
// The number of characters to store in the basic_memory_buffer object itself
@ -3560,9 +3566,12 @@ template <typename OutputIt, typename S, typename... Args,
detail::is_string<S>::value)>
inline OutputIt format_to(OutputIt out, const S& format_str, Args&&... args) {
detail::check_format_string<Args...>(format_str);
using context = format_context_t<OutputIt, char_t<S>>;
return vformat_to(out, to_string_view(format_str),
make_format_args<context>(args...));
using Char = char_t<S>;
detail::iterator_buffer<OutputIt, Char> buf(out);
detail::vformat_to(buf, to_string_view(format_str),
make_format_args<buffer_context<Char>>(args...));
buf.flush();
return buf.out();
}
template <typename OutputIt> struct format_to_n_result {