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/copy.h> 14 #include <__algorithm/copy_n.h> 15 #include <__algorithm/fill_n.h> 16 #include <__algorithm/transform.h> 17 #include <__config> 18 #include <__format/formatter.h> 19 #include <__format/parser_std_format_spec.h> 20 #include <__format/unicode.h> 21 #include <__utility/move.h> 22 #include <__utility/unreachable.h> 23 #include <cstddef> 24 #include <string> 25 #include <string_view> 26 27 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 28 # pragma GCC system_header 29 #endif 30 31 _LIBCPP_BEGIN_NAMESPACE_STD 32 33 #if _LIBCPP_STD_VER > 17 34 35 namespace __formatter { 36 37 _LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char __c) { 38 switch (__c) { 39 case 'a': 40 return 'A'; 41 case 'b': 42 return 'B'; 43 case 'c': 44 return 'C'; 45 case 'd': 46 return 'D'; 47 case 'e': 48 return 'E'; 49 case 'f': 50 return 'F'; 51 } 52 return __c; 53 } 54 55 struct _LIBCPP_TYPE_VIS __padding_size_result { 56 size_t __before_; 57 size_t __after_; 58 }; 59 60 _LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result 61 __padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) { 62 _LIBCPP_ASSERT(__width > __size, "don't call this function when no padding is required"); 63 _LIBCPP_ASSERT( 64 __align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding"); 65 66 size_t __fill = __width - __size; 67 switch (__align) { 68 case __format_spec::__alignment::__zero_padding: 69 __libcpp_unreachable(); 70 71 case __format_spec::__alignment::__left: 72 return {0, __fill}; 73 74 case __format_spec::__alignment::__center: { 75 // The extra padding is divided per [format.string.std]/3 76 // __before = floor(__fill, 2); 77 // __after = ceil(__fill, 2); 78 size_t __before = __fill / 2; 79 size_t __after = __fill - __before; 80 return {__before, __after}; 81 } 82 case __format_spec::__alignment::__default: 83 case __format_spec::__alignment::__right: 84 return {__fill, 0}; 85 } 86 __libcpp_unreachable(); 87 } 88 89 template <class _OutIt, class _CharT> 90 _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, const char* __begin, const char* __first, 91 const char* __last, string&& __grouping, _CharT __sep, 92 __format_spec::__parsed_specifications<_CharT> __specs) { 93 int __size = (__first - __begin) + // [sign][prefix] 94 (__last - __first) + // data 95 (__grouping.size() - 1); // number of separator characters 96 97 __padding_size_result __padding = {0, 0}; 98 if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) { 99 // Write [sign][prefix]. 100 __out_it = _VSTD::copy(__begin, __first, _VSTD::move(__out_it)); 101 102 if (__specs.__width_ > __size) { 103 // Write zero padding. 104 __padding.__before_ = __specs.__width_ - __size; 105 __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __specs.__width_ - __size, _CharT('0')); 106 } 107 } else { 108 if (__specs.__width_ > __size) { 109 // Determine padding and write padding. 110 __padding = __padding_size(__size, __specs.__width_, __specs.__alignment_); 111 112 __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); 113 } 114 // Write [sign][prefix]. 115 __out_it = _VSTD::copy(__begin, __first, _VSTD::move(__out_it)); 116 } 117 118 auto __r = __grouping.rbegin(); 119 auto __e = __grouping.rend() - 1; 120 _LIBCPP_ASSERT(__r != __e, "The slow grouping formatting is used while " 121 "there will be no separators written."); 122 // The output is divided in small groups of numbers to write: 123 // - A group before the first separator. 124 // - A separator and a group, repeated for the number of separators. 125 // - A group after the last separator. 126 // This loop achieves that process by testing the termination condition 127 // midway in the loop. 128 // 129 // TODO FMT This loop evaluates the loop invariant `__parser.__type != 130 // _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test 131 // happens in the __write call.) Benchmark whether making two loops and 132 // hoisting the invariant is worth the effort. 133 while (true) { 134 if (__specs.__std_.__type_ == __format_spec::__type::__hexadecimal_upper_case) { 135 __last = __first + *__r; 136 __out_it = _VSTD::transform(__first, __last, _VSTD::move(__out_it), __hex_to_upper); 137 __first = __last; 138 } else { 139 __out_it = _VSTD::copy_n(__first, *__r, _VSTD::move(__out_it)); 140 __first += *__r; 141 } 142 143 if (__r == __e) 144 break; 145 146 ++__r; 147 *__out_it++ = __sep; 148 } 149 150 return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); 151 } 152 153 /// Writes the input to the output with the required padding. 154 /// 155 /// Since the output column width is specified the function can be used for 156 /// ASCII and Unicode output. 157 /// 158 /// \pre [\a __first, \a __last) is a valid range. 159 /// \pre \a __size <= \a __width. Using this function when this pre-condition 160 /// doesn't hold incurs an unwanted overhead. 161 /// 162 /// \param __first Pointer to the first element to write. 163 /// \param __last Pointer beyond the last element to write. 164 /// \param __out_it The output iterator to write to. 165 /// \param __specs The parsed formatting specifications. 166 /// \param __size The (estimated) output column width. When the elements 167 /// to be written are ASCII the following condition holds 168 /// \a __size == \a __last - \a __first. 169 /// 170 /// \returns An iterator pointing beyond the last element written. 171 /// 172 /// \note The type of the elements in range [\a __first, \a __last) can differ 173 /// from the type of \a __specs. Integer output uses \c std::to_chars for its 174 /// conversion, which means the [\a __first, \a __last) always contains elements 175 /// of the type \c char. 176 template <class _CharT, class _ParserCharT> 177 _LIBCPP_HIDE_FROM_ABI auto __write( 178 const _CharT* __first, 179 const _CharT* __last, 180 output_iterator<const _CharT&> auto __out_it, 181 __format_spec::__parsed_specifications<_ParserCharT> __specs, 182 ptrdiff_t __size) -> decltype(__out_it) { 183 _LIBCPP_ASSERT(__first <= __last, "Not a valid range"); 184 185 if (__size >= __specs.__width_) 186 return _VSTD::copy(__first, __last, _VSTD::move(__out_it)); 187 188 __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__std_.__alignment_); 189 __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); 190 __out_it = _VSTD::copy(__first, __last, _VSTD::move(__out_it)); 191 return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); 192 } 193 194 /// \overload 195 /// 196 /// Calls the function above where \a __size = \a __last - \a __first. 197 template <class _CharT, class _ParserCharT> 198 _LIBCPP_HIDE_FROM_ABI auto __write(const _CharT* __first, const _CharT* __last, 199 output_iterator<const _CharT&> auto __out_it, 200 __format_spec::__parsed_specifications<_ParserCharT> __specs) -> decltype(__out_it) { 201 return __write(__first, __last, _VSTD::move(__out_it), __specs, __last - __first); 202 } 203 204 template <class _CharT, class _ParserCharT, class _UnaryOperation> 205 _LIBCPP_HIDE_FROM_ABI auto __write_transformed(const _CharT* __first, const _CharT* __last, 206 output_iterator<const _CharT&> auto __out_it, 207 __format_spec::__parsed_specifications<_ParserCharT> __specs, 208 _UnaryOperation __op) -> decltype(__out_it) { 209 _LIBCPP_ASSERT(__first <= __last, "Not a valid range"); 210 211 ptrdiff_t __size = __last - __first; 212 if (__size >= __specs.__width_) 213 return _VSTD::transform(__first, __last, _VSTD::move(__out_it), __op); 214 215 __padding_size_result __padding = __padding_size(__size, __specs.__width_, __specs.__alignment_); 216 __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); 217 __out_it = _VSTD::transform(__first, __last, _VSTD::move(__out_it), __op); 218 return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); 219 } 220 221 /// Writes additional zero's for the precision before the exponent. 222 /// This is used when the precision requested in the format string is larger 223 /// than the maximum precision of the floating-point type. These precision 224 /// digits are always 0. 225 /// 226 /// \param __exponent The location of the exponent character. 227 /// \param __num_trailing_zeros The number of 0's to write before the exponent 228 /// character. 229 template <class _CharT, class _ParserCharT> 230 _LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros( 231 const _CharT* __first, 232 const _CharT* __last, 233 output_iterator<const _CharT&> auto __out_it, 234 __format_spec::__parsed_specifications<_ParserCharT> __specs, 235 size_t __size, 236 const _CharT* __exponent, 237 size_t __num_trailing_zeros) -> decltype(__out_it) { 238 _LIBCPP_ASSERT(__first <= __last, "Not a valid range"); 239 _LIBCPP_ASSERT(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used"); 240 241 __padding_size_result __padding = 242 __padding_size(__size + __num_trailing_zeros, __specs.__width_, __specs.__alignment_); 243 __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_); 244 __out_it = _VSTD::copy(__first, __exponent, _VSTD::move(__out_it)); 245 __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __num_trailing_zeros, _CharT('0')); 246 __out_it = _VSTD::copy(__exponent, __last, _VSTD::move(__out_it)); 247 return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_); 248 } 249 250 /// Writes a string using format's width estimation algorithm. 251 /// 252 /// \pre !__specs.__has_precision() 253 /// 254 /// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the 255 /// input is ASCII. 256 template <class _CharT> 257 _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision( 258 basic_string_view<_CharT> __str, 259 output_iterator<const _CharT&> auto __out_it, 260 __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { 261 _LIBCPP_ASSERT(!__specs.__has_precision(), "use __write_string"); 262 263 // No padding -> copy the string 264 if (!__specs.__has_width()) 265 return _VSTD::copy(__str.begin(), __str.end(), _VSTD::move(__out_it)); 266 267 // Note when the estimated width is larger than size there's no padding. So 268 // there's no reason to get the real size when the estimate is larger than or 269 // equal to the minimum field width. 270 size_t __size = 271 __format_spec::__estimate_column_width(__str, __specs.__width_, __format_spec::__column_width_rounding::__up) 272 .__width_; 273 274 return __formatter::__write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __size); 275 } 276 277 template <class _CharT> 278 _LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) { 279 __format_spec::__column_width_result<_CharT> __result = 280 __format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down); 281 __str = basic_string_view<_CharT>{__str.begin(), __result.__last_}; 282 return __result.__width_; 283 } 284 285 /// Writes a string using format's width estimation algorithm. 286 /// 287 /// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the 288 /// input is ASCII. 289 template <class _CharT> 290 _LIBCPP_HIDE_FROM_ABI auto __write_string( 291 basic_string_view<_CharT> __str, 292 output_iterator<const _CharT&> auto __out_it, 293 __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { 294 if (!__specs.__has_precision()) 295 return __formatter::__write_string_no_precision(__str, _VSTD::move(__out_it), __specs); 296 297 int __size = __formatter::__truncate(__str, __specs.__precision_); 298 299 return __write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __size); 300 } 301 302 } // namespace __formatter 303 304 #endif //_LIBCPP_STD_VER > 17 305 306 _LIBCPP_END_NAMESPACE_STD 307 308 #endif // _LIBCPP___FORMAT_FORMATTER_OUTPUT_H 309