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 @@ -190,6 +190,23 @@ __container_buffer<_Iterator>>; }; +/// 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 void put(_CharT) { ++__size_; } + + _LIBCPP_HIDE_FROM_ABI size_t formatted_size() const noexcept { + return __size_; + } + +private: + size_t __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 @@ -608,15 +608,25 @@ 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(); + using _Buffer = __format::__formatted_size_buffer; + _Buffer __buffer; + _VSTD::__vformat_to( + __format::__output_iterator{&__format::__put<_Buffer, char>, + &__buffer}, + __fmt, basic_format_args{_VSTD::make_format_args(__args...)}); + return __buffer.formatted_size(); } 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(); + using _Buffer = __format::__formatted_size_buffer; + _Buffer __buffer; + _VSTD::__vformat_to( + __format::__output_iterator{&__format::__put<_Buffer, wchar_t>, + &__buffer}, + __fmt, basic_format_args{_VSTD::make_wformat_args(__args...)}); + return __buffer.formatted_size(); } #ifndef _LIBCPP_HAS_NO_LOCALIZATION @@ -743,19 +753,27 @@ 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(); + using _Buffer = __format::__formatted_size_buffer; + _Buffer __buffer; + _VSTD::__vformat_to( + __format::__output_iterator{&__format::__put<_Buffer, char>, + &__buffer}, + _VSTD::move(__loc), __fmt, + basic_format_args{_VSTD::make_format_args(__args...)}); + return __buffer.formatted_size(); } 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(); + using _Buffer = __format::__formatted_size_buffer; + _Buffer __buffer; + _VSTD::__vformat_to( + __format::__output_iterator{&__format::__put<_Buffer, wchar_t>, + &__buffer}, + _VSTD::move(__loc), __fmt, + basic_format_args{_VSTD::make_wformat_args(__args...)}); + return __buffer.formatted_size(); } #endif