xref: /llvm-project/libcxx/include/__format/formatter.h (revision 11e4001ba2b40ffa7988e54e965b51b584bb827b)
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_H
11 #define _LIBCPP___FORMAT_FORMATTER_H
12 
13 #include <__algorithm/copy.h>
14 #include <__algorithm/fill_n.h>
15 #include <__availability>
16 #include <__config>
17 #include <__format/format_error.h>
18 #include <__format/format_fwd.h>
19 #include <__format/format_string.h>
20 #include <__format/parser_std_format_spec.h>
21 #include <string_view>
22 
23 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
24 #  pragma GCC system_header
25 #endif
26 
27 _LIBCPP_BEGIN_NAMESPACE_STD
28 
29 #if _LIBCPP_STD_VER > 17
30 
31 // TODO FMT Remove this once we require compilers with proper C++20 support.
32 // If the compiler has no concepts support, the format header will be disabled.
33 // Without concepts support enable_if needs to be used and that too much effort
34 // to support compilers with partial C++20 support.
35 #if !defined(_LIBCPP_HAS_NO_CONCEPTS)
36 
37 /// The default formatter template.
38 ///
39 /// [format.formatter.spec]/5
40 /// If F is a disabled specialization of formatter, these values are false:
41 /// - is_default_constructible_v<F>,
42 /// - is_copy_constructible_v<F>,
43 /// - is_move_constructible_v<F>,
44 /// - is_copy_assignable<F>, and
45 /// - is_move_assignable<F>.
46 template <class _Tp, class _CharT>
47 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter {
48   formatter() = delete;
49   formatter(const formatter&) = delete;
50   formatter& operator=(const formatter&) = delete;
51 };
52 
53 namespace __format_spec {
54 
55 _LIBCPP_HIDE_FROM_ABI inline char* __insert_sign(char* __buf, bool __negative,
56                                                  _Flags::_Sign __sign) {
57   if (__negative)
58     *__buf++ = '-';
59   else
60     switch (__sign) {
61     case _Flags::_Sign::__default:
62     case _Flags::_Sign::__minus:
63       // No sign added.
64       break;
65     case _Flags::_Sign::__plus:
66       *__buf++ = '+';
67       break;
68     case _Flags::_Sign::__space:
69       *__buf++ = ' ';
70       break;
71     }
72 
73   return __buf;
74 }
75 
76 _LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char c) {
77   switch (c) {
78   case 'a':
79     return 'A';
80   case 'b':
81     return 'B';
82   case 'c':
83     return 'C';
84   case 'd':
85     return 'D';
86   case 'e':
87     return 'E';
88   case 'f':
89     return 'F';
90   }
91   return c;
92 }
93 
94 } // namespace __format_spec
95 
96 namespace __formatter {
97 
98 /** The character types that formatters are specialized for. */
99 template <class _CharT>
100 concept __char_type = same_as<_CharT, char> || same_as<_CharT, wchar_t>;
101 
102 struct _LIBCPP_TEMPLATE_VIS __padding_size_result {
103   size_t __before;
104   size_t __after;
105 };
106 
107 _LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result
108 __padding_size(size_t __size, size_t __width,
109                __format_spec::_Flags::_Alignment __align) {
110   _LIBCPP_ASSERT(__width > __size,
111                  "Don't call this function when no padding is required");
112   _LIBCPP_ASSERT(
113       __align != __format_spec::_Flags::_Alignment::__default,
114       "Caller should adjust the default to the value required by the type");
115 
116   size_t __fill = __width - __size;
117   switch (__align) {
118   case __format_spec::_Flags::_Alignment::__default:
119     _LIBCPP_UNREACHABLE();
120 
121   case __format_spec::_Flags::_Alignment::__left:
122     return {0, __fill};
123 
124   case __format_spec::_Flags::_Alignment::__center: {
125     // The extra padding is divided per [format.string.std]/3
126     // __before = floor(__fill, 2);
127     // __after = ceil(__fill, 2);
128     size_t __before = __fill / 2;
129     size_t __after = __fill - __before;
130     return {__before, __after};
131   }
132   case __format_spec::_Flags::_Alignment::__right:
133     return {__fill, 0};
134   }
135   _LIBCPP_UNREACHABLE();
136 }
137 
138 /**
139  * Writes the input to the output with the required padding.
140  *
141  * Since the output column width is specified the function can be used for
142  * ASCII and Unicode input.
143  *
144  * @pre [@a __first, @a __last) is a valid range.
145  * @pre @a __size <= @a __width. Using this function when this pre-condition
146  *      doesn't hold incurs an unwanted overhead.
147  *
148  * @param __out_it    The output iterator to write to.
149  * @param __first     Pointer to the first element to write.
150  * @param __last      Pointer beyond the last element to write.
151  * @param __size      The (estimated) output column width. When the elements
152  *                    to be written are ASCII the following condition holds
153  *                    @a __size == @a __last - @a __first.
154  * @param __width     The number of output columns to write.
155  * @param __fill      The character used for the alignment of the output.
156  *                    TODO FMT Will probably change to support Unicode grapheme
157  *                    cluster.
158  * @param __alignment The requested alignment.
159  *
160  * @returns           An iterator pointing beyond the last element written.
161  *
162  * @note The type of the elements in range [@a __first, @a __last) can differ
163  * from the type of @a __fill. Integer output uses @c std::to_chars for its
164  * conversion, which means the [@a __first, @a __last) always contains elements
165  * of the type @c char.
166  */
167 template <class _CharT, class _Fill>
168 _LIBCPP_HIDE_FROM_ABI auto
169 __write(output_iterator<const _CharT&> auto __out_it, const _CharT* __first,
170         const _CharT* __last, size_t __size, size_t __width, _Fill __fill,
171         __format_spec::_Flags::_Alignment __alignment) -> decltype(__out_it) {
172 
173   _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
174   _LIBCPP_ASSERT(__size < __width, "Precondition failure");
175 
176   __padding_size_result __padding =
177       __padding_size(__size, __width, __alignment);
178   __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill);
179   __out_it = _VSTD::copy(__first, __last, _VSTD::move(__out_it));
180   return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill);
181 }
182 
183 /**
184  * @overload
185  *
186  * Writes additional zero's for the precision before the exponent.
187  * This is used when the precision requested in the format string is larger
188  * than the maximum precision of the floating-point type. These precision
189  * digits are always 0.
190  *
191  * @param __exponent           The location of the exponent character.
192  * @param __num_trailing_zeros The number of 0's to write before the exponent
193  *                             character.
194  */
195 template <class _CharT, class _Fill>
196 _LIBCPP_HIDE_FROM_ABI auto __write(output_iterator<const _CharT&> auto __out_it, const _CharT* __first,
197                                    const _CharT* __last, size_t __size, size_t __width, _Fill __fill,
198                                    __format_spec::_Flags::_Alignment __alignment, const _CharT* __exponent,
199                                    size_t __num_trailing_zeros) -> decltype(__out_it) {
200   _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
201   _LIBCPP_ASSERT(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used");
202 
203   __padding_size_result __padding = __padding_size(__size + __num_trailing_zeros, __width, __alignment);
204   __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill);
205   __out_it = _VSTD::copy(__first, __exponent, _VSTD::move(__out_it));
206   __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __num_trailing_zeros, _CharT('0'));
207   __out_it = _VSTD::copy(__exponent, __last, _VSTD::move(__out_it));
208   return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill);
209 }
210 
211 /**
212  * @overload
213  *
214  * Uses a transformation operation before writing an element.
215  *
216  * TODO FMT Fill will probably change to support Unicode grapheme cluster.
217  */
218 template <class _CharT, class _UnaryOperation, class _Fill>
219 _LIBCPP_HIDE_FROM_ABI auto
220 __write(output_iterator<const _CharT&> auto __out_it, const _CharT* __first,
221         const _CharT* __last, size_t __size, _UnaryOperation __op,
222         size_t __width, _Fill __fill,
223         __format_spec::_Flags::_Alignment __alignment) -> decltype(__out_it) {
224 
225   _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
226   _LIBCPP_ASSERT(__size < __width, "Precondition failure");
227 
228   __padding_size_result __padding =
229       __padding_size(__size, __width, __alignment);
230   __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill);
231   __out_it = _VSTD::transform(__first, __last, _VSTD::move(__out_it), __op);
232   return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill);
233 }
234 
235 /**
236  * Writes Unicode input to the output with the required padding.
237  *
238  * This function does almost the same as the @ref __write function, but handles
239  * the width estimation of the Unicode input.
240  *
241  * @param __str       The range [@a __first, @a __last).
242  * @param __precision The width to truncate the input string to, use @c -1 for
243  *                     no limit.
244  */
245 template <class _CharT, class _Fill>
246 _LIBCPP_HIDE_FROM_ABI auto
247 __write_unicode(output_iterator<const _CharT&> auto __out_it,
248                 basic_string_view<_CharT> __str, ptrdiff_t __width,
249                 ptrdiff_t __precision, _Fill __fill,
250                 __format_spec::_Flags::_Alignment __alignment)
251     -> decltype(__out_it) {
252 
253   // This value changes when there Unicode column width limits the output
254   // size.
255   auto __last = __str.end();
256   if (__width != 0 || __precision != -1) {
257     __format_spec::__string_alignment<_CharT> __format_traits =
258         __format_spec::__get_string_alignment(__str.begin(), __str.end(),
259                                               __width, __precision);
260 
261     if (__format_traits.__align)
262       return __write(_VSTD::move(__out_it), __str.begin(),
263                      __format_traits.__last, __format_traits.__size, __width,
264                      __fill, __alignment);
265 
266     // No alignment required update the output based on the precision.
267     // This might be the same as __str.end().
268     __last = __format_traits.__last;
269   }
270 
271   // Copy the input to the output. The output size might be limited by the
272   // precision.
273   return _VSTD::copy(__str.begin(), __last, _VSTD::move(__out_it));
274 }
275 
276 } // namespace __formatter
277 
278 #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
279 
280 #endif //_LIBCPP_STD_VER > 17
281 
282 _LIBCPP_END_NAMESPACE_STD
283 
284 #endif // _LIBCPP___FORMAT_FORMATTER_H
285