xref: /freebsd-src/contrib/llvm-project/libcxx/include/__format/formatter.h (revision 5e801ac66d24704442eba426ed13c3effb8a34e7)
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 // Currently not implemented specializations throw an exception when used. This
42 // does not conform to the Standard. However not all Standard defined formatters
43 // have been implemented yet. Until that time the current behavior is intended.
44 // TODO FMT Disable the default template.
45 template <class _Tp, class _CharT>
46 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter {
47   _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto parse(auto& __parse_ctx)
48       -> decltype(__parse_ctx.begin()) {
49     __throw();
50   }
51 
52   _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI auto format(_Tp, auto& __ctx)
53       -> decltype(__ctx.out()) {
54     __throw();
55   }
56 
57 private:
58   _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI void __throw() {
59     __throw_format_error("Argument type not implemented yet");
60   }
61 };
62 
63 namespace __format_spec {
64 
65 _LIBCPP_HIDE_FROM_ABI inline char* __insert_sign(char* __buf, bool __negative,
66                                                  _Flags::_Sign __sign) {
67   if (__negative)
68     *__buf++ = '-';
69   else
70     switch (__sign) {
71     case _Flags::_Sign::__default:
72     case _Flags::_Sign::__minus:
73       // No sign added.
74       break;
75     case _Flags::_Sign::__plus:
76       *__buf++ = '+';
77       break;
78     case _Flags::_Sign::__space:
79       *__buf++ = ' ';
80       break;
81     }
82 
83   return __buf;
84 }
85 
86 _LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char c) {
87   switch (c) {
88   case 'a':
89     return 'A';
90   case 'b':
91     return 'B';
92   case 'c':
93     return 'C';
94   case 'd':
95     return 'D';
96   case 'e':
97     return 'E';
98   case 'f':
99     return 'F';
100   }
101   return c;
102 }
103 
104 } // namespace __format_spec
105 
106 namespace __formatter {
107 
108 /** The character types that formatters are specialized for. */
109 template <class _CharT>
110 concept __char_type = same_as<_CharT, char> || same_as<_CharT, wchar_t>;
111 
112 struct _LIBCPP_TEMPLATE_VIS __padding_size_result {
113   size_t __before;
114   size_t __after;
115 };
116 
117 _LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result
118 __padding_size(size_t __size, size_t __width,
119                __format_spec::_Flags::_Alignment __align) {
120   _LIBCPP_ASSERT(__width > __size,
121                  "Don't call this function when no padding is required");
122   _LIBCPP_ASSERT(
123       __align != __format_spec::_Flags::_Alignment::__default,
124       "Caller should adjust the default to the value required by the type");
125 
126   size_t __fill = __width - __size;
127   switch (__align) {
128   case __format_spec::_Flags::_Alignment::__default:
129     _LIBCPP_UNREACHABLE();
130 
131   case __format_spec::_Flags::_Alignment::__left:
132     return {0, __fill};
133 
134   case __format_spec::_Flags::_Alignment::__center: {
135     // The extra padding is divided per [format.string.std]/3
136     // __before = floor(__fill, 2);
137     // __after = ceil(__fill, 2);
138     size_t __before = __fill / 2;
139     size_t __after = __fill - __before;
140     return {__before, __after};
141   }
142   case __format_spec::_Flags::_Alignment::__right:
143     return {__fill, 0};
144   }
145   _LIBCPP_UNREACHABLE();
146 }
147 
148 /**
149  * Writes the input to the output with the required padding.
150  *
151  * Since the output column width is specified the function can be used for
152  * ASCII and Unicode input.
153  *
154  * @pre [@a __first, @a __last) is a valid range.
155  * @pre @a __size <= @a __width. Using this function when this pre-condition
156  *      doesn't hold incurs an unwanted overhead.
157  *
158  * @param __out_it    The output iterator to write to.
159  * @param __first     Pointer to the first element to write.
160  * @param __last      Pointer beyond the last element to write.
161  * @param __size      The (estimated) output column width. When the elements
162  *                    to be written are ASCII the following condition holds
163  *                    @a __size == @a __last - @a __first.
164  * @param __width     The number of output columns to write.
165  * @param __fill      The character used for the alignment of the output.
166  *                    TODO FMT Will probably change to support Unicode grapheme
167  *                    cluster.
168  * @param __alignment The requested alignment.
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 __fill. 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  */
177 template <class _CharT, class _Fill>
178 _LIBCPP_HIDE_FROM_ABI auto
179 __write(output_iterator<const _CharT&> auto __out_it, const _CharT* __first,
180         const _CharT* __last, size_t __size, size_t __width, _Fill __fill,
181         __format_spec::_Flags::_Alignment __alignment) -> decltype(__out_it) {
182 
183   _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
184   _LIBCPP_ASSERT(__size < __width, "Precondition failure");
185 
186   __padding_size_result __padding =
187       __padding_size(__size, __width, __alignment);
188   __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill);
189   __out_it = _VSTD::copy(__first, __last, _VSTD::move(__out_it));
190   return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill);
191 }
192 
193 /**
194  * @overload
195  *
196  * Uses a transformation operation before writing an element.
197  *
198  * TODO FMT Fill will probably change to support Unicode grapheme cluster.
199  */
200 template <class _CharT, class _UnaryOperation, class _Fill>
201 _LIBCPP_HIDE_FROM_ABI auto
202 __write(output_iterator<const _CharT&> auto __out_it, const _CharT* __first,
203         const _CharT* __last, size_t __size, _UnaryOperation __op,
204         size_t __width, _Fill __fill,
205         __format_spec::_Flags::_Alignment __alignment) -> decltype(__out_it) {
206 
207   _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
208   _LIBCPP_ASSERT(__size < __width, "Precondition failure");
209 
210   __padding_size_result __padding =
211       __padding_size(__size, __width, __alignment);
212   __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill);
213   __out_it = _VSTD::transform(__first, __last, _VSTD::move(__out_it), __op);
214   return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill);
215 }
216 
217 /**
218  * Writes Unicode input to the output with the required padding.
219  *
220  * This function does almost the same as the @ref __write function, but handles
221  * the width estimation of the Unicode input.
222  *
223  * @param __str       The range [@a __first, @a __last).
224  * @param __precision The width to truncate the input string to, use @c -1 for
225  *                     no limit.
226  */
227 template <class _CharT, class _Fill>
228 _LIBCPP_HIDE_FROM_ABI auto
229 __write_unicode(output_iterator<const _CharT&> auto __out_it,
230                 basic_string_view<_CharT> __str, ptrdiff_t __width,
231                 ptrdiff_t __precision, _Fill __fill,
232                 __format_spec::_Flags::_Alignment __alignment)
233     -> decltype(__out_it) {
234 
235   // This value changes when there Unicode column width limits the output
236   // size.
237   auto __last = __str.end();
238   if (__width != 0 || __precision != -1) {
239     __format_spec::__string_alignment<_CharT> __format_traits =
240         __format_spec::__get_string_alignment(__str.begin(), __str.end(),
241                                               __width, __precision);
242 
243     if (__format_traits.__align)
244       return __write(_VSTD::move(__out_it), __str.begin(),
245                      __format_traits.__last, __format_traits.__size, __width,
246                      __fill, __alignment);
247 
248     // No alignment required update the output based on the precision.
249     // This might be the same as __str.end().
250     __last = __format_traits.__last;
251   }
252 
253   // Copy the input to the output. The output size might be limited by the
254   // precision.
255   return _VSTD::copy(__str.begin(), __last, _VSTD::move(__out_it));
256 }
257 
258 } // namespace __formatter
259 
260 #endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
261 
262 #endif //_LIBCPP_STD_VER > 17
263 
264 _LIBCPP_END_NAMESPACE_STD
265 
266 _LIBCPP_POP_MACROS
267 
268 #endif // _LIBCPP___FORMAT_FORMATTER_H
269