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