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