diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h --- a/libcxx/include/__format/buffer.h +++ b/libcxx/include/__format/buffer.h @@ -183,6 +183,40 @@ size_t __size_{0}; }; +/// A buffer that counts and limits the number of insertions. +/// +/// This buffer holds another buffer to do the actual insertions until the +/// requested maximum has been reached. Once the maximum is reached it only +/// keeps track of the number of additional insertions. +template +requires(output_iterator<_OutIt, const _CharT&>) class _LIBCPP_TEMPLATE_VIS + __format_to_n_buffer { + using _Buffer = typename __buffer_selector<_OutIt, _CharT>::type; + using _Size = iter_difference_t<_OutIt>; + +public: + _LIBCPP_HIDE_FROM_ABI explicit __format_to_n_buffer(_OutIt __out_it, + _Size __n) + : __buffer_(_VSTD::move(__out_it)), __n_(__n) {} + + _LIBCPP_HIDE_FROM_ABI void put(_CharT __c) { + ++__size_; + if (__size_ <= __n_) + __buffer_.put(__c); + } + + _LIBCPP_HIDE_FROM_ABI _OutIt out() { return __buffer_.out(); } + + _LIBCPP_HIDE_FROM_ABI _Size formatted_size() const noexcept { + return __size_; + } + +private: + _Buffer __buffer_; + _Size __n_; + _Size __size_{0}; +}; + } // namespace __format #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) diff --git a/libcxx/include/format b/libcxx/include/format --- a/libcxx/include/format +++ b/libcxx/include/format @@ -597,13 +597,13 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt> format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, string_view __fmt, const _Args&... __args) { - // TODO FMT Improve PoC: using std::string is inefficient. - string __str = _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)); - iter_difference_t<_OutIt> __s = __str.size(); - iter_difference_t<_OutIt> __m = - _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); - __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it)); - return {_VSTD::move(__out_it), __s}; + + using _Buffer = __format::__format_to_n_buffer<_OutIt, char>; + _Buffer __buffer{_VSTD::move(__out_it), __n}; + _VSTD::__vformat_to( + __format::__output_iterator{_VSTD::addressof(__buffer)}, __fmt, + basic_format_args{_VSTD::make_format_args(__args...)}); + return {__buffer.out(), __buffer.formatted_size()}; } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS @@ -611,13 +611,13 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt> format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wstring_view __fmt, const _Args&... __args) { - // TODO FMT Improve PoC: using std::string is inefficient. - wstring __str = _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)); - iter_difference_t<_OutIt> __s = __str.size(); - iter_difference_t<_OutIt> __m = - _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); - __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it)); - return {_VSTD::move(__out_it), __s}; + + using _Buffer = __format::__format_to_n_buffer<_OutIt, wchar_t>; + _Buffer __buffer{_VSTD::move(__out_it), __n}; + _VSTD::__vformat_to( + __format::__output_iterator{_VSTD::addressof(__buffer)}, __fmt, + basic_format_args{_VSTD::make_wformat_args(__args...)}); + return {__buffer.out(), __buffer.formatted_size()}; } #endif @@ -750,14 +750,14 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt> format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, string_view __fmt, const _Args&... __args) { - // TODO FMT Improve PoC: using std::string is inefficient. - string __str = _VSTD::vformat(_VSTD::move(__loc), __fmt, - _VSTD::make_format_args(__args...)); - iter_difference_t<_OutIt> __s = __str.size(); - iter_difference_t<_OutIt> __m = - _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); - __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it)); - return {_VSTD::move(__out_it), __s}; + + using _Buffer = __format::__format_to_n_buffer<_OutIt, char>; + _Buffer __buffer{_VSTD::move(__out_it), __n}; + _VSTD::__vformat_to( + __format::__output_iterator{_VSTD::addressof(__buffer)}, + _VSTD::move(__loc), __fmt, + basic_format_args{_VSTD::make_format_args(__args...)}); + return {__buffer.out(), __buffer.formatted_size()}; } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS @@ -765,14 +765,14 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt> format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, wstring_view __fmt, const _Args&... __args) { - // TODO FMT Improve PoC: using std::string is inefficient. - wstring __str = _VSTD::vformat(_VSTD::move(__loc), __fmt, - _VSTD::make_wformat_args(__args...)); - iter_difference_t<_OutIt> __s = __str.size(); - iter_difference_t<_OutIt> __m = - _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); - __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it)); - return {_VSTD::move(__out_it), __s}; + + using _Buffer = __format::__format_to_n_buffer<_OutIt, wchar_t>; + _Buffer __buffer{_VSTD::move(__out_it), __n}; + _VSTD::__vformat_to( + __format::__output_iterator{_VSTD::addressof(__buffer)}, + _VSTD::move(__loc), __fmt, + basic_format_args{_VSTD::make_wformat_args(__args...)}); + return {__buffer.out(), __buffer.formatted_size()}; } #endif