181ad6265SDimitry Andric // -*- C++ -*- 281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 381ad6265SDimitry Andric // 481ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 581ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 681ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 781ad6265SDimitry Andric // 881ad6265SDimitry Andric //===----------------------------------------------------------------------===// 981ad6265SDimitry Andric 1081ad6265SDimitry Andric #ifndef _LIBCPP___FORMAT_FORMATTER_OUTPUT_H 1181ad6265SDimitry Andric #define _LIBCPP___FORMAT_FORMATTER_OUTPUT_H 1281ad6265SDimitry Andric 13bdd1243dSDimitry Andric #include <__algorithm/ranges_copy.h> 14bdd1243dSDimitry Andric #include <__algorithm/ranges_fill_n.h> 15bdd1243dSDimitry Andric #include <__algorithm/ranges_transform.h> 1606c3fb27SDimitry Andric #include <__bit/countl.h> 17bdd1243dSDimitry Andric #include <__concepts/same_as.h> 1881ad6265SDimitry Andric #include <__config> 19bdd1243dSDimitry Andric #include <__format/buffer.h> 20bdd1243dSDimitry Andric #include <__format/concepts.h> 2181ad6265SDimitry Andric #include <__format/formatter.h> 2281ad6265SDimitry Andric #include <__format/parser_std_format_spec.h> 23fcaf7f86SDimitry Andric #include <__format/unicode.h> 24bdd1243dSDimitry Andric #include <__iterator/back_insert_iterator.h> 2506c3fb27SDimitry Andric #include <__iterator/concepts.h> 26cb14a3feSDimitry Andric #include <__iterator/iterator_traits.h> 2706c3fb27SDimitry Andric #include <__memory/addressof.h> 28cb14a3feSDimitry Andric #include <__memory/pointer_traits.h> 2981ad6265SDimitry Andric #include <__utility/move.h> 3081ad6265SDimitry Andric #include <__utility/unreachable.h> 3181ad6265SDimitry Andric #include <cstddef> 3281ad6265SDimitry Andric #include <string_view> 3381ad6265SDimitry Andric 3481ad6265SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 3581ad6265SDimitry Andric # pragma GCC system_header 3681ad6265SDimitry Andric #endif 3781ad6265SDimitry Andric 38b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS 39b3edf446SDimitry Andric #include <__undef_macros> 40b3edf446SDimitry Andric 4181ad6265SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 4281ad6265SDimitry Andric 4306c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 20 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric namespace __formatter { 4681ad6265SDimitry Andric 47753f127fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char __c) { 48753f127fSDimitry Andric switch (__c) { 4981ad6265SDimitry Andric case 'a': 5081ad6265SDimitry Andric return 'A'; 5181ad6265SDimitry Andric case 'b': 5281ad6265SDimitry Andric return 'B'; 5381ad6265SDimitry Andric case 'c': 5481ad6265SDimitry Andric return 'C'; 5581ad6265SDimitry Andric case 'd': 5681ad6265SDimitry Andric return 'D'; 5781ad6265SDimitry Andric case 'e': 5881ad6265SDimitry Andric return 'E'; 5981ad6265SDimitry Andric case 'f': 6081ad6265SDimitry Andric return 'F'; 6181ad6265SDimitry Andric } 62753f127fSDimitry Andric return __c; 6381ad6265SDimitry Andric } 6481ad6265SDimitry Andric 6506c3fb27SDimitry Andric struct _LIBCPP_EXPORTED_FROM_ABI __padding_size_result { 6681ad6265SDimitry Andric size_t __before_; 6781ad6265SDimitry Andric size_t __after_; 6881ad6265SDimitry Andric }; 6981ad6265SDimitry Andric 70753f127fSDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result 71753f127fSDimitry Andric __padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) { 721db9f3b2SDimitry Andric _LIBCPP_ASSERT_INTERNAL(__width > __size, "don't call this function when no padding is required"); 731db9f3b2SDimitry Andric _LIBCPP_ASSERT_INTERNAL( 74fcaf7f86SDimitry Andric __align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding"); 7581ad6265SDimitry Andric 7681ad6265SDimitry Andric size_t __fill = __width - __size; 7781ad6265SDimitry Andric switch (__align) { 7881ad6265SDimitry Andric case __format_spec::__alignment::__zero_padding: 7981ad6265SDimitry Andric __libcpp_unreachable(); 8081ad6265SDimitry Andric 8181ad6265SDimitry Andric case __format_spec::__alignment::__left: 8281ad6265SDimitry Andric return {0, __fill}; 8381ad6265SDimitry Andric 8481ad6265SDimitry Andric case __format_spec::__alignment::__center: { 8581ad6265SDimitry Andric // The extra padding is divided per [format.string.std]/3 8681ad6265SDimitry Andric // __before = floor(__fill, 2); 8781ad6265SDimitry Andric // __after = ceil(__fill, 2); 8881ad6265SDimitry Andric size_t __before = __fill / 2; 8981ad6265SDimitry Andric size_t __after = __fill - __before; 9081ad6265SDimitry Andric return {__before, __after}; 9181ad6265SDimitry Andric } 92753f127fSDimitry Andric case __format_spec::__alignment::__default: 9381ad6265SDimitry Andric case __format_spec::__alignment::__right: 9481ad6265SDimitry Andric return {__fill, 0}; 9581ad6265SDimitry Andric } 9681ad6265SDimitry Andric __libcpp_unreachable(); 9781ad6265SDimitry Andric } 9881ad6265SDimitry Andric 99bdd1243dSDimitry Andric /// Copy wrapper. 100bdd1243dSDimitry Andric /// 101bdd1243dSDimitry Andric /// This uses a "mass output function" of __format::__output_buffer when possible. 102bdd1243dSDimitry Andric template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT> 103*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI auto 104*0fca6ea1SDimitry Andric __copy(basic_string_view<_CharT> __str, output_iterator<const _OutCharT&> auto __out_it) -> decltype(__out_it) { 1055f757f3fSDimitry Andric if constexpr (std::same_as<decltype(__out_it), std::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) { 106bdd1243dSDimitry Andric __out_it.__get_container()->__copy(__str); 107bdd1243dSDimitry Andric return __out_it; 108cb14a3feSDimitry Andric } else if constexpr (std::same_as<decltype(__out_it), typename __format::__retarget_buffer<_OutCharT>::__iterator>) { 109bdd1243dSDimitry Andric __out_it.__buffer_->__copy(__str); 110bdd1243dSDimitry Andric return __out_it; 111bdd1243dSDimitry Andric } else { 1125f757f3fSDimitry Andric return std::ranges::copy(__str, std::move(__out_it)).out; 113bdd1243dSDimitry Andric } 114bdd1243dSDimitry Andric } 115bdd1243dSDimitry Andric 116cb14a3feSDimitry Andric template <contiguous_iterator _Iterator, 117cb14a3feSDimitry Andric __fmt_char_type _CharT = typename iterator_traits<_Iterator>::value_type, 118cb14a3feSDimitry Andric __fmt_char_type _OutCharT = _CharT> 119*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI auto 120*0fca6ea1SDimitry Andric __copy(_Iterator __first, _Iterator __last, output_iterator<const _OutCharT&> auto __out_it) -> decltype(__out_it) { 1215f757f3fSDimitry Andric return __formatter::__copy(basic_string_view{__first, __last}, std::move(__out_it)); 122bdd1243dSDimitry Andric } 123bdd1243dSDimitry Andric 124cb14a3feSDimitry Andric template <contiguous_iterator _Iterator, 125cb14a3feSDimitry Andric __fmt_char_type _CharT = typename iterator_traits<_Iterator>::value_type, 126cb14a3feSDimitry Andric __fmt_char_type _OutCharT = _CharT> 127*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI auto 128*0fca6ea1SDimitry Andric __copy(_Iterator __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it) -> decltype(__out_it) { 129cb14a3feSDimitry Andric return __formatter::__copy(basic_string_view{std::to_address(__first), __n}, std::move(__out_it)); 130bdd1243dSDimitry Andric } 131bdd1243dSDimitry Andric 132bdd1243dSDimitry Andric /// Transform wrapper. 133bdd1243dSDimitry Andric /// 134bdd1243dSDimitry Andric /// This uses a "mass output function" of __format::__output_buffer when possible. 135cb14a3feSDimitry Andric template <contiguous_iterator _Iterator, 136cb14a3feSDimitry Andric __fmt_char_type _CharT = typename iterator_traits<_Iterator>::value_type, 137cb14a3feSDimitry Andric __fmt_char_type _OutCharT = _CharT, 138cb14a3feSDimitry Andric class _UnaryOperation> 139*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI auto 140*0fca6ea1SDimitry Andric __transform(_Iterator __first, 141*0fca6ea1SDimitry Andric _Iterator __last, 142*0fca6ea1SDimitry Andric output_iterator<const _OutCharT&> auto __out_it, 143*0fca6ea1SDimitry Andric _UnaryOperation __operation) -> decltype(__out_it) { 1445f757f3fSDimitry Andric if constexpr (std::same_as<decltype(__out_it), std::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) { 1455f757f3fSDimitry Andric __out_it.__get_container()->__transform(__first, __last, std::move(__operation)); 146bdd1243dSDimitry Andric return __out_it; 147cb14a3feSDimitry Andric } else if constexpr (std::same_as<decltype(__out_it), typename __format::__retarget_buffer<_OutCharT>::__iterator>) { 1485f757f3fSDimitry Andric __out_it.__buffer_->__transform(__first, __last, std::move(__operation)); 149bdd1243dSDimitry Andric return __out_it; 150bdd1243dSDimitry Andric } else { 1515f757f3fSDimitry Andric return std::ranges::transform(__first, __last, std::move(__out_it), __operation).out; 152bdd1243dSDimitry Andric } 153bdd1243dSDimitry Andric } 154bdd1243dSDimitry Andric 155bdd1243dSDimitry Andric /// Fill wrapper. 156bdd1243dSDimitry Andric /// 157bdd1243dSDimitry Andric /// This uses a "mass output function" of __format::__output_buffer when possible. 158bdd1243dSDimitry Andric template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 159bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, _CharT __value) { 1605f757f3fSDimitry Andric if constexpr (std::same_as<decltype(__out_it), std::back_insert_iterator<__format::__output_buffer<_CharT>>>) { 161bdd1243dSDimitry Andric __out_it.__get_container()->__fill(__n, __value); 162bdd1243dSDimitry Andric return __out_it; 1635f757f3fSDimitry Andric } else if constexpr (std::same_as<decltype(__out_it), typename __format::__retarget_buffer<_CharT>::__iterator>) { 164bdd1243dSDimitry Andric __out_it.__buffer_->__fill(__n, __value); 165bdd1243dSDimitry Andric return __out_it; 166bdd1243dSDimitry Andric } else { 1675f757f3fSDimitry Andric return std::ranges::fill_n(std::move(__out_it), __n, __value); 168bdd1243dSDimitry Andric } 169bdd1243dSDimitry Andric } 170bdd1243dSDimitry Andric 17106c3fb27SDimitry Andric # ifndef _LIBCPP_HAS_NO_UNICODE 17206c3fb27SDimitry Andric template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 17306c3fb27SDimitry Andric requires(same_as<_CharT, char>) 17406c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { 17506c3fb27SDimitry Andric std::size_t __bytes = std::countl_one(static_cast<unsigned char>(__value.__data[0])); 17606c3fb27SDimitry Andric if (__bytes == 0) 17706c3fb27SDimitry Andric return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); 17881ad6265SDimitry Andric 17906c3fb27SDimitry Andric for (size_t __i = 0; __i < __n; ++__i) 18006c3fb27SDimitry Andric __out_it = __formatter::__copy( 18106c3fb27SDimitry Andric std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + __bytes, std::move(__out_it)); 18206c3fb27SDimitry Andric return __out_it; 18381ad6265SDimitry Andric } 18481ad6265SDimitry Andric 18506c3fb27SDimitry Andric # ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 18606c3fb27SDimitry Andric template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 18706c3fb27SDimitry Andric requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2) 18806c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { 18906c3fb27SDimitry Andric if (!__unicode::__is_high_surrogate(__value.__data[0])) 19006c3fb27SDimitry Andric return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); 19106c3fb27SDimitry Andric 19206c3fb27SDimitry Andric for (size_t __i = 0; __i < __n; ++__i) 19306c3fb27SDimitry Andric __out_it = __formatter::__copy( 19406c3fb27SDimitry Andric std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + 2, std::move(__out_it)); 19506c3fb27SDimitry Andric return __out_it; 19681ad6265SDimitry Andric } 19781ad6265SDimitry Andric 19806c3fb27SDimitry Andric template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 19906c3fb27SDimitry Andric requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4) 20006c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { 20106c3fb27SDimitry Andric return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); 20281ad6265SDimitry Andric } 20306c3fb27SDimitry Andric # endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS 20406c3fb27SDimitry Andric # else // _LIBCPP_HAS_NO_UNICODE 20506c3fb27SDimitry Andric template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 20606c3fb27SDimitry Andric _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { 20706c3fb27SDimitry Andric return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); 20881ad6265SDimitry Andric } 20906c3fb27SDimitry Andric # endif // _LIBCPP_HAS_NO_UNICODE 21081ad6265SDimitry Andric 21181ad6265SDimitry Andric /// Writes the input to the output with the required padding. 21281ad6265SDimitry Andric /// 21381ad6265SDimitry Andric /// Since the output column width is specified the function can be used for 21481ad6265SDimitry Andric /// ASCII and Unicode output. 21581ad6265SDimitry Andric /// 21681ad6265SDimitry Andric /// \pre \a __size <= \a __width. Using this function when this pre-condition 21781ad6265SDimitry Andric /// doesn't hold incurs an unwanted overhead. 21881ad6265SDimitry Andric /// 219bdd1243dSDimitry Andric /// \param __str The string to write. 22081ad6265SDimitry Andric /// \param __out_it The output iterator to write to. 22181ad6265SDimitry Andric /// \param __specs The parsed formatting specifications. 22281ad6265SDimitry Andric /// \param __size The (estimated) output column width. When the elements 22381ad6265SDimitry Andric /// to be written are ASCII the following condition holds 22481ad6265SDimitry Andric /// \a __size == \a __last - \a __first. 22581ad6265SDimitry Andric /// 22681ad6265SDimitry Andric /// \returns An iterator pointing beyond the last element written. 22781ad6265SDimitry Andric /// 22881ad6265SDimitry Andric /// \note The type of the elements in range [\a __first, \a __last) can differ 22981ad6265SDimitry Andric /// from the type of \a __specs. Integer output uses \c std::to_chars for its 23081ad6265SDimitry Andric /// conversion, which means the [\a __first, \a __last) always contains elements 23181ad6265SDimitry Andric /// of the type \c char. 23281ad6265SDimitry Andric template <class _CharT, class _ParserCharT> 233bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto 234bdd1243dSDimitry Andric __write(basic_string_view<_CharT> __str, 235bdd1243dSDimitry Andric output_iterator<const _CharT&> auto __out_it, 236bdd1243dSDimitry Andric __format_spec::__parsed_specifications<_ParserCharT> __specs, 237bdd1243dSDimitry Andric ptrdiff_t __size) -> decltype(__out_it) { 238bdd1243dSDimitry Andric if (__size >= __specs.__width_) 2395f757f3fSDimitry Andric return __formatter::__copy(__str, std::move(__out_it)); 240bdd1243dSDimitry Andric 241bdd1243dSDimitry Andric __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__std_.__alignment_); 2425f757f3fSDimitry Andric __out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_); 2435f757f3fSDimitry Andric __out_it = __formatter::__copy(__str, std::move(__out_it)); 2445f757f3fSDimitry Andric return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_); 245bdd1243dSDimitry Andric } 246bdd1243dSDimitry Andric 24706c3fb27SDimitry Andric template <contiguous_iterator _Iterator, class _ParserCharT> 248bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto 24906c3fb27SDimitry Andric __write(_Iterator __first, 25006c3fb27SDimitry Andric _Iterator __last, 25106c3fb27SDimitry Andric output_iterator<const iter_value_t<_Iterator>&> auto __out_it, 252fcaf7f86SDimitry Andric __format_spec::__parsed_specifications<_ParserCharT> __specs, 253fcaf7f86SDimitry Andric ptrdiff_t __size) -> decltype(__out_it) { 254cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "Not a valid range"); 2555f757f3fSDimitry Andric return __formatter::__write(basic_string_view{__first, __last}, std::move(__out_it), __specs, __size); 25681ad6265SDimitry Andric } 25781ad6265SDimitry Andric 25881ad6265SDimitry Andric /// \overload 259fcaf7f86SDimitry Andric /// 26081ad6265SDimitry Andric /// Calls the function above where \a __size = \a __last - \a __first. 26106c3fb27SDimitry Andric template <contiguous_iterator _Iterator, class _ParserCharT> 262bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto 26306c3fb27SDimitry Andric __write(_Iterator __first, 26406c3fb27SDimitry Andric _Iterator __last, 26506c3fb27SDimitry Andric output_iterator<const iter_value_t<_Iterator>&> auto __out_it, 26681ad6265SDimitry Andric __format_spec::__parsed_specifications<_ParserCharT> __specs) -> decltype(__out_it) { 267cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "Not a valid range"); 2685f757f3fSDimitry Andric return __formatter::__write(__first, __last, std::move(__out_it), __specs, __last - __first); 26981ad6265SDimitry Andric } 27081ad6265SDimitry Andric 271cb14a3feSDimitry Andric template <contiguous_iterator _Iterator, 272cb14a3feSDimitry Andric class _CharT = typename iterator_traits<_Iterator>::value_type, 273cb14a3feSDimitry Andric class _ParserCharT, 274cb14a3feSDimitry Andric class _UnaryOperation> 275cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI auto __write_transformed( 276cb14a3feSDimitry Andric _Iterator __first, 277cb14a3feSDimitry Andric _Iterator __last, 27881ad6265SDimitry Andric output_iterator<const _CharT&> auto __out_it, 27981ad6265SDimitry Andric __format_spec::__parsed_specifications<_ParserCharT> __specs, 28081ad6265SDimitry Andric _UnaryOperation __op) -> decltype(__out_it) { 281cb14a3feSDimitry Andric _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "Not a valid range"); 28281ad6265SDimitry Andric 28381ad6265SDimitry Andric ptrdiff_t __size = __last - __first; 28481ad6265SDimitry Andric if (__size >= __specs.__width_) 2855f757f3fSDimitry Andric return __formatter::__transform(__first, __last, std::move(__out_it), __op); 28681ad6265SDimitry Andric 287bdd1243dSDimitry Andric __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_); 2885f757f3fSDimitry Andric __out_it = __formatter::__fill(std::move(__out_it), __padding.__before_, __specs.__fill_); 2895f757f3fSDimitry Andric __out_it = __formatter::__transform(__first, __last, std::move(__out_it), __op); 2905f757f3fSDimitry Andric return __formatter::__fill(std::move(__out_it), __padding.__after_, __specs.__fill_); 29181ad6265SDimitry Andric } 29281ad6265SDimitry Andric 293fcaf7f86SDimitry Andric /// Writes a string using format's width estimation algorithm. 294fcaf7f86SDimitry Andric /// 295fcaf7f86SDimitry Andric /// \pre !__specs.__has_precision() 296fcaf7f86SDimitry Andric /// 297fcaf7f86SDimitry Andric /// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the 298fcaf7f86SDimitry Andric /// input is ASCII. 29981ad6265SDimitry Andric template <class _CharT> 300fcaf7f86SDimitry Andric _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision( 301fcaf7f86SDimitry Andric basic_string_view<_CharT> __str, 30281ad6265SDimitry Andric output_iterator<const _CharT&> auto __out_it, 303fcaf7f86SDimitry Andric __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { 3041db9f3b2SDimitry Andric _LIBCPP_ASSERT_INTERNAL(!__specs.__has_precision(), "use __write_string"); 30581ad6265SDimitry Andric 30681ad6265SDimitry Andric // No padding -> copy the string 30781ad6265SDimitry Andric if (!__specs.__has_width()) 3085f757f3fSDimitry Andric return __formatter::__copy(__str, std::move(__out_it)); 30981ad6265SDimitry Andric 310fcaf7f86SDimitry Andric // Note when the estimated width is larger than size there's no padding. So 311fcaf7f86SDimitry Andric // there's no reason to get the real size when the estimate is larger than or 312fcaf7f86SDimitry Andric // equal to the minimum field width. 313fcaf7f86SDimitry Andric size_t __size = 314fcaf7f86SDimitry Andric __format_spec::__estimate_column_width(__str, __specs.__width_, __format_spec::__column_width_rounding::__up) 315fcaf7f86SDimitry Andric .__width_; 3165f757f3fSDimitry Andric return __formatter::__write(__str, std::move(__out_it), __specs, __size); 31781ad6265SDimitry Andric } 31881ad6265SDimitry Andric 31981ad6265SDimitry Andric template <class _CharT> 320fcaf7f86SDimitry Andric _LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) { 32106c3fb27SDimitry Andric __format_spec::__column_width_result __result = 322fcaf7f86SDimitry Andric __format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down); 323fcaf7f86SDimitry Andric __str = basic_string_view<_CharT>{__str.begin(), __result.__last_}; 324fcaf7f86SDimitry Andric return __result.__width_; 32581ad6265SDimitry Andric } 32681ad6265SDimitry Andric 32781ad6265SDimitry Andric } // namespace __formatter 32881ad6265SDimitry Andric 32906c3fb27SDimitry Andric #endif //_LIBCPP_STD_VER >= 20 33081ad6265SDimitry Andric 33181ad6265SDimitry Andric _LIBCPP_END_NAMESPACE_STD 33281ad6265SDimitry Andric 333b3edf446SDimitry Andric _LIBCPP_POP_MACROS 334b3edf446SDimitry Andric 33581ad6265SDimitry Andric #endif // _LIBCPP___FORMAT_FORMATTER_OUTPUT_H 336