1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP___FORMAT_FORMATTER_OUTPUT_H 11 #define _LIBCPP___FORMAT_FORMATTER_OUTPUT_H 12 13 #include <__algorithm/ranges_copy.h> 14 #include <__algorithm/ranges_fill_n.h> 15 #include <__algorithm/ranges_transform.h> 16 #include <__bit/countl.h> 17 #include <__concepts/same_as.h> 18 #include <__config> 19 #include <__format/buffer.h> 20 #include <__format/concepts.h> 21 #include <__format/formatter.h> 22 #include <__format/parser_std_format_spec.h> 23 #include <__format/unicode.h> 24 #include <__iterator/back_insert_iterator.h> 25 #include <__iterator/concepts.h> 26 #include <__iterator/iterator_traits.h> // iter_value_t 27 #include <__memory/addressof.h> 28 #include <__utility/move.h> 29 #include <__utility/unreachable.h> 30 #include <cstddef> 31 #include <string_view> 32 33 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 34 # pragma GCC system_header 35 #endif 36 37 _LIBCPP_BEGIN_NAMESPACE_STD 38 39 #if _LIBCPP_STD_VER >= 20 40 41 namespace __formatter { 42 43 _LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char __c) { 44 switch (__c) { 45 case 'a': 46 return 'A'; 47 case 'b': 48 return 'B'; 49 case 'c': 50 return 'C'; 51 case 'd': 52 return 'D'; 53 case 'e': 54 return 'E'; 55 case 'f': 56 return 'F'; 57 } 58 return __c; 59 } 60 61 struct _LIBCPP_EXPORTED_FROM_ABI __padding_size_result { 62 size_t __before_; 63 size_t __after_; 64 }; 65 66 _LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result 67 __padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) { 68 _LIBCPP_ASSERT_UNCATEGORIZED(__width > __size, "don't call this function when no padding is required"); 69 _LIBCPP_ASSERT_UNCATEGORIZED( 70 __align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding"); 71 72 size_t __fill = __width - __size; 73 switch (__align) { 74 case __format_spec::__alignment::__zero_padding: 75 __libcpp_unreachable(); 76 77 case __format_spec::__alignment::__left: 78 return {0, __fill}; 79 80 case __format_spec::__alignment::__center: { 81 // The extra padding is divided per [format.string.std]/3 82 // __before = floor(__fill, 2); 83 // __after = ceil(__fill, 2); 84 size_t __before = __fill / 2; 85 size_t __after = __fill - __before; 86 return {__before, __after}; 87 } 88 case __format_spec::__alignment::__default: 89 case __format_spec::__alignment::__right: 90 return {__fill, 0}; 91 } 92 __libcpp_unreachable(); 93 } 94 95 /// Copy wrapper. 96 /// 97 /// This uses a "mass output function" of __format::__output_buffer when possible. 98 template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT> 99 _LIBCPP_HIDE_FROM_ABI auto __copy(basic_string_view<_CharT> __str, output_iterator<const _OutCharT&> auto __out_it) 100 -> decltype(__out_it) { 101 if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) { 102 __out_it.__get_container()->__copy(__str); 103 return __out_it; 104 } else if constexpr (_VSTD::same_as<decltype(__out_it), 105 typename __format::__retarget_buffer<_OutCharT>::__iterator>) { 106 __out_it.__buffer_->__copy(__str); 107 return __out_it; 108 } else { 109 return std::ranges::copy(__str, _VSTD::move(__out_it)).out; 110 } 111 } 112 113 template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT> 114 _LIBCPP_HIDE_FROM_ABI auto 115 __copy(const _CharT* __first, const _CharT* __last, output_iterator<const _OutCharT&> auto __out_it) 116 -> decltype(__out_it) { 117 return __formatter::__copy(basic_string_view{__first, __last}, _VSTD::move(__out_it)); 118 } 119 120 template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT> 121 _LIBCPP_HIDE_FROM_ABI auto __copy(const _CharT* __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it) 122 -> decltype(__out_it) { 123 return __formatter::__copy(basic_string_view{__first, __n}, _VSTD::move(__out_it)); 124 } 125 126 /// Transform wrapper. 127 /// 128 /// This uses a "mass output function" of __format::__output_buffer when possible. 129 template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT, class _UnaryOperation> 130 _LIBCPP_HIDE_FROM_ABI auto 131 __transform(const _CharT* __first, 132 const _CharT* __last, 133 output_iterator<const _OutCharT&> auto __out_it, 134 _UnaryOperation __operation) -> decltype(__out_it) { 135 if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) { 136 __out_it.__get_container()->__transform(__first, __last, _VSTD::move(__operation)); 137 return __out_it; 138 } else if constexpr (_VSTD::same_as<decltype(__out_it), 139 typename __format::__retarget_buffer<_OutCharT>::__iterator>) { 140 __out_it.__buffer_->__transform(__first, __last, _VSTD::move(__operation)); 141 return __out_it; 142 } else { 143 return std::ranges::transform(__first, __last, _VSTD::move(__out_it), __operation).out; 144 } 145 } 146 147 /// Fill wrapper. 148 /// 149 /// This uses a "mass output function" of __format::__output_buffer when possible. 150 template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 151 _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, _CharT __value) { 152 if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_CharT>>>) { 153 __out_it.__get_container()->__fill(__n, __value); 154 return __out_it; 155 } else if constexpr (_VSTD::same_as<decltype(__out_it), typename __format::__retarget_buffer<_CharT>::__iterator>) { 156 __out_it.__buffer_->__fill(__n, __value); 157 return __out_it; 158 } else { 159 return std::ranges::fill_n(_VSTD::move(__out_it), __n, __value); 160 } 161 } 162 163 # ifndef _LIBCPP_HAS_NO_UNICODE 164 template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 165 requires(same_as<_CharT, char>) 166 _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { 167 std::size_t __bytes = std::countl_one(static_cast<unsigned char>(__value.__data[0])); 168 if (__bytes == 0) 169 return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); 170 171 for (size_t __i = 0; __i < __n; ++__i) 172 __out_it = __formatter::__copy( 173 std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + __bytes, std::move(__out_it)); 174 return __out_it; 175 } 176 177 # ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS 178 template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 179 requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2) 180 _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { 181 if (!__unicode::__is_high_surrogate(__value.__data[0])) 182 return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); 183 184 for (size_t __i = 0; __i < __n; ++__i) 185 __out_it = __formatter::__copy( 186 std::addressof(__value.__data[0]), std::addressof(__value.__data[0]) + 2, std::move(__out_it)); 187 return __out_it; 188 } 189 190 template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 191 requires(same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4) 192 _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { 193 return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); 194 } 195 # endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS 196 # else // _LIBCPP_HAS_NO_UNICODE 197 template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt> 198 _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, __format_spec::__code_point<_CharT> __value) { 199 return __formatter::__fill(std::move(__out_it), __n, __value.__data[0]); 200 } 201 # endif // _LIBCPP_HAS_NO_UNICODE 202 203 /// Writes the input to the output with the required padding. 204 /// 205 /// Since the output column width is specified the function can be used for 206 /// ASCII and Unicode output. 207 /// 208 /// \pre \a __size <= \a __width. Using this function when this pre-condition 209 /// doesn't hold incurs an unwanted overhead. 210 /// 211 /// \param __str The string to write. 212 /// \param __out_it The output iterator to write to. 213 /// \param __specs The parsed formatting specifications. 214 /// \param __size The (estimated) output column width. When the elements 215 /// to be written are ASCII the following condition holds 216 /// \a __size == \a __last - \a __first. 217 /// 218 /// \returns An iterator pointing beyond the last element written. 219 /// 220 /// \note The type of the elements in range [\a __first, \a __last) can differ 221 /// from the type of \a __specs. Integer output uses \c std::to_chars for its 222 /// conversion, which means the [\a __first, \a __last) always contains elements 223 /// of the type \c char. 224 template <class _CharT, class _ParserCharT> 225 _LIBCPP_HIDE_FROM_ABI auto 226 __write(basic_string_view<_CharT> __str, 227 output_iterator<const _CharT&> auto __out_it, 228 __format_spec::__parsed_specifications<_ParserCharT> __specs, 229 ptrdiff_t __size) -> decltype(__out_it) { 230 if (__size >= __specs.__width_) 231 return __formatter::__copy(__str, _VSTD::move(__out_it)); 232 233 __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__std_.__alignment_); 234 __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); 235 __out_it = __formatter::__copy(__str, _VSTD::move(__out_it)); 236 return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); 237 } 238 239 template <contiguous_iterator _Iterator, class _ParserCharT> 240 _LIBCPP_HIDE_FROM_ABI auto 241 __write(_Iterator __first, 242 _Iterator __last, 243 output_iterator<const iter_value_t<_Iterator>&> auto __out_it, 244 __format_spec::__parsed_specifications<_ParserCharT> __specs, 245 ptrdiff_t __size) -> decltype(__out_it) { 246 _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "Not a valid range"); 247 return __formatter::__write(basic_string_view{__first, __last}, _VSTD::move(__out_it), __specs, __size); 248 } 249 250 /// \overload 251 /// 252 /// Calls the function above where \a __size = \a __last - \a __first. 253 template <contiguous_iterator _Iterator, class _ParserCharT> 254 _LIBCPP_HIDE_FROM_ABI auto 255 __write(_Iterator __first, 256 _Iterator __last, 257 output_iterator<const iter_value_t<_Iterator>&> auto __out_it, 258 __format_spec::__parsed_specifications<_ParserCharT> __specs) -> decltype(__out_it) { 259 _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "Not a valid range"); 260 return __formatter::__write(__first, __last, _VSTD::move(__out_it), __specs, __last - __first); 261 } 262 263 template <class _CharT, class _ParserCharT, class _UnaryOperation> 264 _LIBCPP_HIDE_FROM_ABI auto __write_transformed(const _CharT* __first, const _CharT* __last, 265 output_iterator<const _CharT&> auto __out_it, 266 __format_spec::__parsed_specifications<_ParserCharT> __specs, 267 _UnaryOperation __op) -> decltype(__out_it) { 268 _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "Not a valid range"); 269 270 ptrdiff_t __size = __last - __first; 271 if (__size >= __specs.__width_) 272 return __formatter::__transform(__first, __last, _VSTD::move(__out_it), __op); 273 274 __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_); 275 __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); 276 __out_it = __formatter::__transform(__first, __last, _VSTD::move(__out_it), __op); 277 return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); 278 } 279 280 /// Writes a string using format's width estimation algorithm. 281 /// 282 /// \pre !__specs.__has_precision() 283 /// 284 /// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the 285 /// input is ASCII. 286 template <class _CharT> 287 _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision( 288 basic_string_view<_CharT> __str, 289 output_iterator<const _CharT&> auto __out_it, 290 __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { 291 _LIBCPP_ASSERT_UNCATEGORIZED(!__specs.__has_precision(), "use __write_string"); 292 293 // No padding -> copy the string 294 if (!__specs.__has_width()) 295 return __formatter::__copy(__str, _VSTD::move(__out_it)); 296 297 // Note when the estimated width is larger than size there's no padding. So 298 // there's no reason to get the real size when the estimate is larger than or 299 // equal to the minimum field width. 300 size_t __size = 301 __format_spec::__estimate_column_width(__str, __specs.__width_, __format_spec::__column_width_rounding::__up) 302 .__width_; 303 return __formatter::__write(__str, _VSTD::move(__out_it), __specs, __size); 304 } 305 306 template <class _CharT> 307 _LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) { 308 __format_spec::__column_width_result __result = 309 __format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down); 310 __str = basic_string_view<_CharT>{__str.begin(), __result.__last_}; 311 return __result.__width_; 312 } 313 314 } // namespace __formatter 315 316 #endif //_LIBCPP_STD_VER >= 20 317 318 _LIBCPP_END_NAMESPACE_STD 319 320 #endif // _LIBCPP___FORMAT_FORMATTER_OUTPUT_H 321