Make format_to_n part of the core API

This commit is contained in:
Victor Zverovich 2020-07-24 08:28:23 -07:00
parent 98626093d2
commit 95d3abf95c
3 changed files with 73 additions and 47 deletions

View File

@ -48,6 +48,8 @@ participate in an overload resolution if the latter is not a string.
.. doxygenfunction:: format(const S&, Args&&...) .. doxygenfunction:: format(const S&, Args&&...)
.. doxygenfunction:: vformat(const S&, basic_format_args<buffer_context<type_identity_t<Char>>>) .. doxygenfunction:: vformat(const S&, basic_format_args<buffer_context<type_identity_t<Char>>>)
.. doxygenfunction:: fmt::format_to(OutputIt, string_view, Args&&...)
.. doxygenfunction:: fmt::format_to_n(OutputIt, size_t, string_view, Args&&...)
.. doxygenfunction:: fmt::formatted_size(string_view, Args&&...) .. doxygenfunction:: fmt::formatted_size(string_view, Args&&...)
.. _print: .. _print:

View File

@ -735,13 +735,33 @@ template <typename T> class buffer {
} }
}; };
// A buffer that writes to an output iterator when flushed. struct buffer_traits {
template <typename OutputIt, typename T> explicit buffer_traits(size_t) {}
class iterator_buffer : public buffer<T> { size_t count() const { return 0; }
private: size_t limit(size_t size) { return size; }
enum { buffer_size = 256 }; };
class fixed_buffer_traits {
private:
size_t count_ = 0;
size_t limit_;
public:
explicit fixed_buffer_traits(size_t limit) : limit_(limit) {}
size_t count() const { return count_; }
size_t limit(size_t size) {
size_t n = limit_ - count_;
count_ += size;
return size < n ? size : n;
}
};
// A buffer that writes to an output iterator when flushed.
template <typename OutputIt, typename T, typename Traits = buffer_traits>
class iterator_buffer : public Traits, public buffer<T> {
private:
OutputIt out_; OutputIt out_;
enum { buffer_size = 256 };
T data_[buffer_size]; T data_[buffer_size];
protected: protected:
@ -751,14 +771,17 @@ class iterator_buffer : public buffer<T> {
void flush(); void flush();
public: public:
explicit iterator_buffer(OutputIt out) explicit iterator_buffer(OutputIt out, size_t n = 0)
: buffer<T>(data_, 0, buffer_size), out_(out) {} : Traits(n),
buffer<T>(data_, 0, n < size_t(buffer_size) ? n : size_t(buffer_size)),
out_(out) {}
~iterator_buffer() { flush(); } ~iterator_buffer() { flush(); }
OutputIt out() { OutputIt out() {
flush(); flush();
return out_; return out_;
} }
size_t count() const { return Traits::count() + this->size(); }
}; };
template <typename T> class iterator_buffer<T*, T> : public buffer<T> { template <typename T> class iterator_buffer<T*, T> : public buffer<T> {
@ -766,7 +789,7 @@ template <typename T> class iterator_buffer<T*, T> : public buffer<T> {
void grow(size_t) final {} void grow(size_t) final {}
public: public:
explicit iterator_buffer(T* out) : buffer<T>(out, 0, ~size_t()) {} explicit iterator_buffer(T* out, size_t = 0) : buffer<T>(out, 0, ~size_t()) {}
T* out() { return &*this->end(); } T* out() { return &*this->end(); }
}; };
@ -781,7 +804,7 @@ class iterator_buffer<std::back_insert_iterator<Container>,
Container& container_; Container& container_;
protected: protected:
void grow(size_t capacity) FMT_OVERRIDE { void grow(size_t capacity) final {
container_.resize(capacity); container_.resize(capacity);
this->set(&container_[0], capacity); this->set(&container_[0], capacity);
} }
@ -789,7 +812,7 @@ class iterator_buffer<std::back_insert_iterator<Container>,
public: public:
explicit iterator_buffer(Container& c) explicit iterator_buffer(Container& c)
: buffer<typename Container::value_type>(c.size()), container_(c) {} : buffer<typename Container::value_type>(c.size()), container_(c) {}
explicit iterator_buffer(std::back_insert_iterator<Container> out) explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0)
: iterator_buffer(get_container(out)) {} : iterator_buffer(get_container(out)) {}
std::back_insert_iterator<Container> out() { std::back_insert_iterator<Container> out() {
return std::back_inserter(container_); return std::back_inserter(container_);
@ -1972,6 +1995,41 @@ inline OutputIt format_to(OutputIt out, const S& format_str, Args&&... args) {
return vformat_to(out, to_string_view(format_str), vargs); return vformat_to(out, to_string_view(format_str), vargs);
} }
template <typename OutputIt> struct format_to_n_result {
/** Iterator past the end of the output range. */
OutputIt out;
/** Total (not truncated) output size. */
size_t size;
};
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt>::value)>
inline format_to_n_result<OutputIt> vformat_to_n(
OutputIt out, size_t n, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
n);
detail::vformat_to(buf, format_str, args);
return {buf.out(), buf.count()};
}
/**
\rst
Formats arguments, writes up to ``n`` characters of the result to the output
iterator ``out`` and returns the total output size and the iterator past the
end of the output range.
\endrst
*/
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_string<S>::value&&
detail::is_output_iterator<OutputIt>::value)>
inline format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
const S& format_str,
const Args&... args) {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return vformat_to_n(out, n, to_string_view(format_str), vargs);
}
/** /**
Returns the number of characters in the output of Returns the number of characters in the output of
``format(format_str, args...)``. ``format(format_str, args...)``.

View File

@ -566,9 +566,9 @@ void buffer<T>::append(const U* begin, const U* end) {
} while (begin != end); } while (begin != end);
} }
template <typename OutputIt, typename T> template <typename OutputIt, typename T, typename Traits>
void iterator_buffer<OutputIt, T>::flush() { void iterator_buffer<OutputIt, T, Traits>::flush() {
out_ = std::copy(data_, data_ + this->size(), out_); out_ = std::copy_n(data_, this->limit(this->size()), out_);
this->clear(); this->clear();
} }
} // namespace detail } // namespace detail
@ -3530,13 +3530,6 @@ using format_context_t = basic_format_context<OutputIt, Char>;
template <typename OutputIt, typename Char = char> template <typename OutputIt, typename Char = char>
using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>; using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>;
template <typename OutputIt> struct format_to_n_result {
/** Iterator past the end of the output range. */
OutputIt out;
/** Total (not truncated) output size. */
size_t size;
};
template <typename OutputIt, typename Char = typename OutputIt::value_type> template <typename OutputIt, typename Char = typename OutputIt::value_type>
using format_to_n_context FMT_DEPRECATED_ALIAS = buffer_context<Char>; using format_to_n_context FMT_DEPRECATED_ALIAS = buffer_context<Char>;
@ -3550,33 +3543,6 @@ make_format_to_n_args(const Args&... args) {
return format_arg_store<buffer_context<Char>, Args...>(args...); return format_arg_store<buffer_context<Char>, Args...>(args...);
} }
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt>::value)>
inline format_to_n_result<OutputIt> vformat_to_n(
OutputIt out, size_t n, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
auto it = vformat_to(detail::truncating_iterator<OutputIt>(out, n),
format_str, args);
return {it.base(), it.count()};
}
/**
\rst
Formats arguments, writes up to ``n`` characters of the result to the output
iterator ``out`` and returns the total output size and the iterator past the
end of the output range.
\endrst
*/
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_string<S>::value&&
detail::is_output_iterator<OutputIt>::value)>
inline format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
const S& format_str,
const Args&... args) {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return vformat_to_n(out, n, to_string_view(format_str), vargs);
}
template <typename Char, enable_if_t<(!std::is_same<Char, char>::value), int>> template <typename Char, enable_if_t<(!std::is_same<Char, char>::value), int>>
std::basic_string<Char> detail::vformat( std::basic_string<Char> detail::vformat(
basic_string_view<Char> format_str, basic_string_view<Char> format_str,