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