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