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 @@ -244,6 +244,29 @@ __output_buffer<_CharT> __output_; typename __writer_selector<_OutIt, _CharT>::type __writer_; }; + +/// A buffer that counts the number of insertions. +/// +/// Since \ref formatted_size only needs to know the size, the output itself is +/// discarded. +template <__formatter::__char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __formatted_size_buffer { +public: + _LIBCPP_HIDE_FROM_ABI auto make_output_iterator() { return __output_.make_output_iterator(); } + + _LIBCPP_HIDE_FROM_ABI void flush(const _CharT*, size_t __size) { __size_ += __size; } + + _LIBCPP_HIDE_FROM_ABI size_t result() && { + __output_.flush(); + return __size_; + } + +private: + __internal_storage<_CharT> __storage_; + __output_buffer<_CharT> __output_{__storage_.begin(), __storage_.capacity(), this}; + size_t __size_{0}; +}; + } // namespace __format #endif //_LIBCPP_STD_VER > 17 diff --git a/libcxx/include/format b/libcxx/include/format --- a/libcxx/include/format +++ b/libcxx/include/format @@ -392,19 +392,25 @@ } #endif +template +_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt, auto __args) { + __format::__formatted_size_buffer<_CharT> __buffer; + _VSTD::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, + _VSTD::__format_context_create(__buffer.make_output_iterator(), __args)); + return _VSTD::move(__buffer).result(); +} + template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t -formatted_size(string_view __fmt, const _Args&... __args) { - // TODO FMT Improve PoC: using std::string is inefficient. - return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)).size(); +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(string_view __fmt, + const _Args&... __args) { + return _VSTD::__vformatted_size(__fmt, basic_format_args{_VSTD::make_format_args(__args...)}); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t -formatted_size(wstring_view __fmt, const _Args&... __args) { - // TODO FMT Improve PoC: using std::string is inefficient. - return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)).size(); +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(wstring_view __fmt, + const _Args&... __args) { + return _VSTD::__vformatted_size(__fmt, basic_format_args{_VSTD::make_wformat_args(__args...)}); } #endif @@ -526,23 +532,28 @@ } #endif +template +_LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_CharT> __fmt, auto __args) { + __format::__formatted_size_buffer<_CharT> __buffer; + _VSTD::__format::__vformat_to( + basic_format_parse_context{__fmt, __args.__size()}, + _VSTD::__format_context_create(__buffer.make_output_iterator(), __args, _VSTD::move(__loc))); + return _VSTD::move(__buffer).result(); +} + template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t -formatted_size(locale __loc, string_view __fmt, const _Args&... __args) { - // TODO FMT Improve PoC: using std::string is inefficient. - return _VSTD::vformat(_VSTD::move(__loc), __fmt, - _VSTD::make_format_args(__args...)) - .size(); +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(locale __loc, + string_view __fmt, + const _Args&... __args) { + return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt, basic_format_args{_VSTD::make_format_args(__args...)}); } #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t -formatted_size(locale __loc, wstring_view __fmt, const _Args&... __args) { - // TODO FMT Improve PoC: using std::string is inefficient. - return _VSTD::vformat(_VSTD::move(__loc), __fmt, - _VSTD::make_wformat_args(__args...)) - .size(); +_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t formatted_size(locale __loc, + wstring_view __fmt, + const _Args&... __args) { + return _VSTD::__vformatted_size(_VSTD::move(__loc), __fmt, basic_format_args{_VSTD::make_wformat_args(__args...)}); } #endif