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/ranges_copy.h>
14 #include <__algorithm/ranges_fill_n.h>
15 #include <__algorithm/ranges_transform.h>
16 #include <__chrono/statically_widen.h>
17 #include <__concepts/same_as.h>
18 #include <__config>
19 #include <__format/buffer.h>
20 #include <__format/concepts.h>
21 #include <__format/escaped_output_table.h>
22 #include <__format/formatter.h>
23 #include <__format/parser_std_format_spec.h>
24 #include <__format/unicode.h>
25 #include <__iterator/back_insert_iterator.h>
26 #include <__type_traits/make_unsigned.h>
27 #include <__utility/move.h>
28 #include <__utility/unreachable.h>
29 #include <charconv>
30 #include <cstddef>
31 #include <string>
32 #include <string_view>
33
34 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
35 # pragma GCC system_header
36 #endif
37
38 _LIBCPP_BEGIN_NAMESPACE_STD
39
40 #if _LIBCPP_STD_VER > 17
41
42 namespace __formatter {
43
__hex_to_upper(char __c)44 _LIBCPP_HIDE_FROM_ABI constexpr char __hex_to_upper(char __c) {
45 switch (__c) {
46 case 'a':
47 return 'A';
48 case 'b':
49 return 'B';
50 case 'c':
51 return 'C';
52 case 'd':
53 return 'D';
54 case 'e':
55 return 'E';
56 case 'f':
57 return 'F';
58 }
59 return __c;
60 }
61
62 struct _LIBCPP_TYPE_VIS __padding_size_result {
63 size_t __before_;
64 size_t __after_;
65 };
66
67 _LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result
__padding_size(size_t __size,size_t __width,__format_spec::__alignment __align)68 __padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) {
69 _LIBCPP_ASSERT(__width > __size, "don't call this function when no padding is required");
70 _LIBCPP_ASSERT(
71 __align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding");
72
73 size_t __fill = __width - __size;
74 switch (__align) {
75 case __format_spec::__alignment::__zero_padding:
76 __libcpp_unreachable();
77
78 case __format_spec::__alignment::__left:
79 return {0, __fill};
80
81 case __format_spec::__alignment::__center: {
82 // The extra padding is divided per [format.string.std]/3
83 // __before = floor(__fill, 2);
84 // __after = ceil(__fill, 2);
85 size_t __before = __fill / 2;
86 size_t __after = __fill - __before;
87 return {__before, __after};
88 }
89 case __format_spec::__alignment::__default:
90 case __format_spec::__alignment::__right:
91 return {__fill, 0};
92 }
93 __libcpp_unreachable();
94 }
95
96 /// Copy wrapper.
97 ///
98 /// This uses a "mass output function" of __format::__output_buffer when possible.
99 template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
100 _LIBCPP_HIDE_FROM_ABI auto __copy(basic_string_view<_CharT> __str, output_iterator<const _OutCharT&> auto __out_it)
101 -> decltype(__out_it) {
102 if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) {
103 __out_it.__get_container()->__copy(__str);
104 return __out_it;
105 } else if constexpr (_VSTD::same_as<decltype(__out_it),
106 typename __format::__retarget_buffer<_OutCharT>::__iterator>) {
107 __out_it.__buffer_->__copy(__str);
108 return __out_it;
109 } else {
110 return std::ranges::copy(__str, _VSTD::move(__out_it)).out;
111 }
112 }
113
114 template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
115 _LIBCPP_HIDE_FROM_ABI auto
116 __copy(const _CharT* __first, const _CharT* __last, output_iterator<const _OutCharT&> auto __out_it)
117 -> decltype(__out_it) {
118 return __formatter::__copy(basic_string_view{__first, __last}, _VSTD::move(__out_it));
119 }
120
121 template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT>
122 _LIBCPP_HIDE_FROM_ABI auto __copy(const _CharT* __first, size_t __n, output_iterator<const _OutCharT&> auto __out_it)
123 -> decltype(__out_it) {
124 return __formatter::__copy(basic_string_view{__first, __n}, _VSTD::move(__out_it));
125 }
126
127 /// Transform wrapper.
128 ///
129 /// This uses a "mass output function" of __format::__output_buffer when possible.
130 template <__fmt_char_type _CharT, __fmt_char_type _OutCharT = _CharT, class _UnaryOperation>
131 _LIBCPP_HIDE_FROM_ABI auto
132 __transform(const _CharT* __first,
133 const _CharT* __last,
134 output_iterator<const _OutCharT&> auto __out_it,
135 _UnaryOperation __operation) -> decltype(__out_it) {
136 if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_OutCharT>>>) {
137 __out_it.__get_container()->__transform(__first, __last, _VSTD::move(__operation));
138 return __out_it;
139 } else if constexpr (_VSTD::same_as<decltype(__out_it),
140 typename __format::__retarget_buffer<_OutCharT>::__iterator>) {
141 __out_it.__buffer_->__transform(__first, __last, _VSTD::move(__operation));
142 return __out_it;
143 } else {
144 return std::ranges::transform(__first, __last, _VSTD::move(__out_it), __operation).out;
145 }
146 }
147
148 /// Fill wrapper.
149 ///
150 /// This uses a "mass output function" of __format::__output_buffer when possible.
151 template <__fmt_char_type _CharT, output_iterator<const _CharT&> _OutIt>
__fill(_OutIt __out_it,size_t __n,_CharT __value)152 _LIBCPP_HIDE_FROM_ABI _OutIt __fill(_OutIt __out_it, size_t __n, _CharT __value) {
153 if constexpr (_VSTD::same_as<decltype(__out_it), _VSTD::back_insert_iterator<__format::__output_buffer<_CharT>>>) {
154 __out_it.__get_container()->__fill(__n, __value);
155 return __out_it;
156 } else if constexpr (_VSTD::same_as<decltype(__out_it), typename __format::__retarget_buffer<_CharT>::__iterator>) {
157 __out_it.__buffer_->__fill(__n, __value);
158 return __out_it;
159 } else {
160 return std::ranges::fill_n(_VSTD::move(__out_it), __n, __value);
161 }
162 }
163
164 template <class _OutIt, class _CharT>
__write_using_decimal_separators(_OutIt __out_it,const char * __begin,const char * __first,const char * __last,string && __grouping,_CharT __sep,__format_spec::__parsed_specifications<_CharT> __specs)165 _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, const char* __begin, const char* __first,
166 const char* __last, string&& __grouping, _CharT __sep,
167 __format_spec::__parsed_specifications<_CharT> __specs) {
168 int __size = (__first - __begin) + // [sign][prefix]
169 (__last - __first) + // data
170 (__grouping.size() - 1); // number of separator characters
171
172 __padding_size_result __padding = {0, 0};
173 if (__specs.__alignment_ == __format_spec::__alignment::__zero_padding) {
174 // Write [sign][prefix].
175 __out_it = __formatter::__copy(__begin, __first, _VSTD::move(__out_it));
176
177 if (__specs.__width_ > __size) {
178 // Write zero padding.
179 __padding.__before_ = __specs.__width_ - __size;
180 __out_it = __formatter::__fill(_VSTD::move(__out_it), __specs.__width_ - __size, _CharT('0'));
181 }
182 } else {
183 if (__specs.__width_ > __size) {
184 // Determine padding and write padding.
185 __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_);
186
187 __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
188 }
189 // Write [sign][prefix].
190 __out_it = __formatter::__copy(__begin, __first, _VSTD::move(__out_it));
191 }
192
193 auto __r = __grouping.rbegin();
194 auto __e = __grouping.rend() - 1;
195 _LIBCPP_ASSERT(__r != __e, "The slow grouping formatting is used while "
196 "there will be no separators written.");
197 // The output is divided in small groups of numbers to write:
198 // - A group before the first separator.
199 // - A separator and a group, repeated for the number of separators.
200 // - A group after the last separator.
201 // This loop achieves that process by testing the termination condition
202 // midway in the loop.
203 //
204 // TODO FMT This loop evaluates the loop invariant `__parser.__type !=
205 // _Flags::_Type::__hexadecimal_upper_case` for every iteration. (This test
206 // happens in the __write call.) Benchmark whether making two loops and
207 // hoisting the invariant is worth the effort.
208 while (true) {
209 if (__specs.__std_.__type_ == __format_spec::__type::__hexadecimal_upper_case) {
210 __last = __first + *__r;
211 __out_it = __formatter::__transform(__first, __last, _VSTD::move(__out_it), __hex_to_upper);
212 __first = __last;
213 } else {
214 __out_it = __formatter::__copy(__first, *__r, _VSTD::move(__out_it));
215 __first += *__r;
216 }
217
218 if (__r == __e)
219 break;
220
221 ++__r;
222 *__out_it++ = __sep;
223 }
224
225 return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
226 }
227
228 /// Writes the input to the output with the required padding.
229 ///
230 /// Since the output column width is specified the function can be used for
231 /// ASCII and Unicode output.
232 ///
233 /// \pre \a __size <= \a __width. Using this function when this pre-condition
234 /// doesn't hold incurs an unwanted overhead.
235 ///
236 /// \param __str The string to write.
237 /// \param __out_it The output iterator to write to.
238 /// \param __specs The parsed formatting specifications.
239 /// \param __size The (estimated) output column width. When the elements
240 /// to be written are ASCII the following condition holds
241 /// \a __size == \a __last - \a __first.
242 ///
243 /// \returns An iterator pointing beyond the last element written.
244 ///
245 /// \note The type of the elements in range [\a __first, \a __last) can differ
246 /// from the type of \a __specs. Integer output uses \c std::to_chars for its
247 /// conversion, which means the [\a __first, \a __last) always contains elements
248 /// of the type \c char.
249 template <class _CharT, class _ParserCharT>
250 _LIBCPP_HIDE_FROM_ABI auto
251 __write(basic_string_view<_CharT> __str,
252 output_iterator<const _CharT&> auto __out_it,
253 __format_spec::__parsed_specifications<_ParserCharT> __specs,
254 ptrdiff_t __size) -> decltype(__out_it) {
255 if (__size >= __specs.__width_)
256 return __formatter::__copy(__str, _VSTD::move(__out_it));
257
258 __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__std_.__alignment_);
259 __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
260 __out_it = __formatter::__copy(__str, _VSTD::move(__out_it));
261 return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
262 }
263
264 template <class _CharT, class _ParserCharT>
265 _LIBCPP_HIDE_FROM_ABI auto
266 __write(const _CharT* __first,
267 const _CharT* __last,
268 output_iterator<const _CharT&> auto __out_it,
269 __format_spec::__parsed_specifications<_ParserCharT> __specs,
270 ptrdiff_t __size) -> decltype(__out_it) {
271 _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
272 return __formatter::__write(basic_string_view{__first, __last}, _VSTD::move(__out_it), __specs, __size);
273 }
274
275 /// \overload
276 ///
277 /// Calls the function above where \a __size = \a __last - \a __first.
278 template <class _CharT, class _ParserCharT>
279 _LIBCPP_HIDE_FROM_ABI auto
280 __write(const _CharT* __first,
281 const _CharT* __last,
282 output_iterator<const _CharT&> auto __out_it,
283 __format_spec::__parsed_specifications<_ParserCharT> __specs) -> decltype(__out_it) {
284 _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
285 return __formatter::__write(__first, __last, _VSTD::move(__out_it), __specs, __last - __first);
286 }
287
288 template <class _CharT, class _ParserCharT, class _UnaryOperation>
289 _LIBCPP_HIDE_FROM_ABI auto __write_transformed(const _CharT* __first, const _CharT* __last,
290 output_iterator<const _CharT&> auto __out_it,
291 __format_spec::__parsed_specifications<_ParserCharT> __specs,
292 _UnaryOperation __op) -> decltype(__out_it) {
293 _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
294
295 ptrdiff_t __size = __last - __first;
296 if (__size >= __specs.__width_)
297 return __formatter::__transform(__first, __last, _VSTD::move(__out_it), __op);
298
299 __padding_size_result __padding = __formatter::__padding_size(__size, __specs.__width_, __specs.__alignment_);
300 __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
301 __out_it = __formatter::__transform(__first, __last, _VSTD::move(__out_it), __op);
302 return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
303 }
304
305 /// Writes additional zero's for the precision before the exponent.
306 /// This is used when the precision requested in the format string is larger
307 /// than the maximum precision of the floating-point type. These precision
308 /// digits are always 0.
309 ///
310 /// \param __exponent The location of the exponent character.
311 /// \param __num_trailing_zeros The number of 0's to write before the exponent
312 /// character.
313 template <class _CharT, class _ParserCharT>
314 _LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros(
315 const _CharT* __first,
316 const _CharT* __last,
317 output_iterator<const _CharT&> auto __out_it,
318 __format_spec::__parsed_specifications<_ParserCharT> __specs,
319 size_t __size,
320 const _CharT* __exponent,
321 size_t __num_trailing_zeros) -> decltype(__out_it) {
322 _LIBCPP_ASSERT(__first <= __last, "Not a valid range");
323 _LIBCPP_ASSERT(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used");
324
325 __padding_size_result __padding =
326 __formatter::__padding_size(__size + __num_trailing_zeros, __specs.__width_, __specs.__alignment_);
327 __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__fill_);
328 __out_it = __formatter::__copy(__first, __exponent, _VSTD::move(__out_it));
329 __out_it = __formatter::__fill(_VSTD::move(__out_it), __num_trailing_zeros, _CharT('0'));
330 __out_it = __formatter::__copy(__exponent, __last, _VSTD::move(__out_it));
331 return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
332 }
333
334 /// Writes a string using format's width estimation algorithm.
335 ///
336 /// \pre !__specs.__has_precision()
337 ///
338 /// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the
339 /// input is ASCII.
340 template <class _CharT>
341 _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision(
342 basic_string_view<_CharT> __str,
343 output_iterator<const _CharT&> auto __out_it,
344 __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
345 _LIBCPP_ASSERT(!__specs.__has_precision(), "use __write_string");
346
347 // No padding -> copy the string
348 if (!__specs.__has_width())
349 return __formatter::__copy(__str, _VSTD::move(__out_it));
350
351 // Note when the estimated width is larger than size there's no padding. So
352 // there's no reason to get the real size when the estimate is larger than or
353 // equal to the minimum field width.
354 size_t __size =
355 __format_spec::__estimate_column_width(__str, __specs.__width_, __format_spec::__column_width_rounding::__up)
356 .__width_;
357 return __formatter::__write(__str, _VSTD::move(__out_it), __specs, __size);
358 }
359
360 template <class _CharT>
__truncate(basic_string_view<_CharT> & __str,int __precision)361 _LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) {
362 __format_spec::__column_width_result<_CharT> __result =
363 __format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down);
364 __str = basic_string_view<_CharT>{__str.begin(), __result.__last_};
365 return __result.__width_;
366 }
367
368 /// Writes a string using format's width estimation algorithm.
369 ///
370 /// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the
371 /// input is ASCII.
372 template <class _CharT>
373 _LIBCPP_HIDE_FROM_ABI auto __write_string(
374 basic_string_view<_CharT> __str,
375 output_iterator<const _CharT&> auto __out_it,
376 __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
377 if (!__specs.__has_precision())
378 return __formatter::__write_string_no_precision(__str, _VSTD::move(__out_it), __specs);
379
380 int __size = __formatter::__truncate(__str, __specs.__precision_);
381
382 return __formatter::__write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __size);
383 }
384
385 # if _LIBCPP_STD_VER > 20
386
387 struct __nul_terminator {};
388
389 template <class _CharT>
390 _LIBCPP_HIDE_FROM_ABI bool operator==(const _CharT* __cstr, __nul_terminator) {
391 return *__cstr == _CharT('\0');
392 }
393
394 template <class _CharT>
395 _LIBCPP_HIDE_FROM_ABI void
__write_escaped_code_unit(basic_string<_CharT> & __str,char32_t __value,const _CharT * __prefix)396 __write_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value, const _CharT* __prefix) {
397 back_insert_iterator __out_it{__str};
398 std::ranges::copy(__prefix, __nul_terminator{}, __out_it);
399
400 char __buffer[8];
401 to_chars_result __r = std::to_chars(std::begin(__buffer), std::end(__buffer), __value, 16);
402 _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small");
403 std::ranges::copy(std::begin(__buffer), __r.ptr, __out_it);
404
405 __str += _CharT('}');
406 }
407
408 // [format.string.escaped]/2.2.1.2
409 // ...
410 // then the sequence \u{hex-digit-sequence} is appended to E, where
411 // hex-digit-sequence is the shortest hexadecimal representation of C using
412 // lower-case hexadecimal digits.
413 template <class _CharT>
__write_well_formed_escaped_code_unit(basic_string<_CharT> & __str,char32_t __value)414 _LIBCPP_HIDE_FROM_ABI void __write_well_formed_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value) {
415 __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\u{"));
416 }
417
418 // [format.string.escaped]/2.2.3
419 // Otherwise (X is a sequence of ill-formed code units), each code unit U is
420 // appended to E in order as the sequence \x{hex-digit-sequence}, where
421 // hex-digit-sequence is the shortest hexadecimal representation of U using
422 // lower-case hexadecimal digits.
423 template <class _CharT>
__write_escape_ill_formed_code_unit(basic_string<_CharT> & __str,char32_t __value)424 _LIBCPP_HIDE_FROM_ABI void __write_escape_ill_formed_code_unit(basic_string<_CharT>& __str, char32_t __value) {
425 __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\x{"));
426 }
427
428 template <class _CharT>
__is_escaped_sequence_written(basic_string<_CharT> & __str,char32_t __value)429 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_escaped_sequence_written(basic_string<_CharT>& __str, char32_t __value) {
430 # ifdef _LIBCPP_HAS_NO_UNICODE
431 // For ASCII assume everything above 127 is printable.
432 if (__value > 127)
433 return false;
434 # endif
435
436 if (!__escaped_output_table::__needs_escape(__value))
437 return false;
438
439 __formatter::__write_well_formed_escaped_code_unit(__str, __value);
440 return true;
441 }
442
443 template <class _CharT>
__to_char32(_CharT __value)444 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr char32_t __to_char32(_CharT __value) {
445 return static_cast<make_unsigned_t<_CharT>>(__value);
446 }
447
448 enum class _LIBCPP_ENUM_VIS __escape_quotation_mark { __apostrophe, __double_quote };
449
450 // [format.string.escaped]/2
451 template <class _CharT>
452 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool
__is_escaped_sequence_written(basic_string<_CharT> & __str,char32_t __value,__escape_quotation_mark __mark)453 __is_escaped_sequence_written(basic_string<_CharT>& __str, char32_t __value, __escape_quotation_mark __mark) {
454 // 2.2.1.1 - Mapped character in [tab:format.escape.sequences]
455 switch (__value) {
456 case _CharT('\t'):
457 __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\t");
458 return true;
459 case _CharT('\n'):
460 __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\n");
461 return true;
462 case _CharT('\r'):
463 __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\r");
464 return true;
465 case _CharT('\''):
466 if (__mark == __escape_quotation_mark::__apostrophe)
467 __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\')");
468 else
469 __str += __value;
470 return true;
471 case _CharT('"'):
472 if (__mark == __escape_quotation_mark::__double_quote)
473 __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\")");
474 else
475 __str += __value;
476 return true;
477 case _CharT('\\'):
478 __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\\)");
479 return true;
480
481 // 2.2.1.2 - Space
482 case _CharT(' '):
483 __str += __value;
484 return true;
485 }
486
487 // 2.2.2
488 // Otherwise, if X is a shift sequence, the effect on E and further
489 // decoding of S is unspecified.
490 // For now shift sequences are ignored and treated as Unicode. Other parts
491 // of the format library do the same. It's unknown how ostream treats them.
492 // TODO FMT determine what to do with shift sequences.
493
494 // 2.2.1.2.1 and 2.2.1.2.2 - Escape
495 return __formatter::__is_escaped_sequence_written(__str, __formatter::__to_char32(__value));
496 }
497
498 template <class _CharT>
499 _LIBCPP_HIDE_FROM_ABI void
__escape(basic_string<_CharT> & __str,basic_string_view<_CharT> __values,__escape_quotation_mark __mark)500 __escape(basic_string<_CharT>& __str, basic_string_view<_CharT> __values, __escape_quotation_mark __mark) {
501 __unicode::__code_point_view<_CharT> __view{__values.begin(), __values.end()};
502
503 while (!__view.__at_end()) {
504 const _CharT* __first = __view.__position();
505 typename __unicode::__consume_p2286_result __result = __view.__consume_p2286();
506 if (__result.__ill_formed_size == 0) {
507 if (!__formatter::__is_escaped_sequence_written(__str, __result.__value, __mark))
508 // 2.2.1.3 - Add the character
509 ranges::copy(__first, __view.__position(), std::back_insert_iterator(__str));
510
511 } else {
512 // 2.2.3 sequence of ill-formed code units
513 // The number of code-units in __result.__value depends on the character type being used.
514 if constexpr (sizeof(_CharT) == 1) {
515 _LIBCPP_ASSERT(__result.__ill_formed_size == 1 || __result.__ill_formed_size == 4,
516 "illegal number of invalid code units.");
517 if (__result.__ill_formed_size == 1) // ill-formed, one code unit
518 __formatter::__write_escape_ill_formed_code_unit(__str, __result.__value & 0xff);
519 else { // out of valid range, four code units
520 // The code point was properly encoded, decode the value.
521 __formatter::__write_escape_ill_formed_code_unit(__str, __result.__value >> 18 | 0xf0);
522 __formatter::__write_escape_ill_formed_code_unit(__str, (__result.__value >> 12 & 0x3f) | 0x80);
523 __formatter::__write_escape_ill_formed_code_unit(__str, (__result.__value >> 6 & 0x3f) | 0x80);
524 __formatter::__write_escape_ill_formed_code_unit(__str, (__result.__value & 0x3f) | 0x80);
525 }
526 } else if constexpr (sizeof(_CharT) == 2) {
527 _LIBCPP_ASSERT(__result.__ill_formed_size == 1, "for UTF-16 at most one invalid code unit");
528 __formatter::__write_escape_ill_formed_code_unit(__str, __result.__value & 0xffff);
529 } else {
530 static_assert(sizeof(_CharT) == 4, "unsupported character width");
531 _LIBCPP_ASSERT(__result.__ill_formed_size == 1, "for UTF-32 one code unit is one code point");
532 __formatter::__write_escape_ill_formed_code_unit(__str, __result.__value);
533 }
534 }
535 }
536 }
537
538 template <class _CharT>
539 _LIBCPP_HIDE_FROM_ABI auto
540 __format_escaped_char(_CharT __value,
541 output_iterator<const _CharT&> auto __out_it,
542 __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
543 basic_string<_CharT> __str;
544 __str += _CharT('\'');
545 __formatter::__escape(__str, basic_string_view{std::addressof(__value), 1}, __escape_quotation_mark::__apostrophe);
546 __str += _CharT('\'');
547 return __formatter::__write(__str.data(), __str.data() + __str.size(), _VSTD::move(__out_it), __specs, __str.size());
548 }
549
550 template <class _CharT>
551 _LIBCPP_HIDE_FROM_ABI auto
552 __format_escaped_string(basic_string_view<_CharT> __values,
553 output_iterator<const _CharT&> auto __out_it,
554 __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
555 basic_string<_CharT> __str;
556 __str += _CharT('"');
557 __formatter::__escape(__str, __values, __escape_quotation_mark::__double_quote);
558 __str += _CharT('"');
559 return __formatter::__write_string(basic_string_view{__str}, _VSTD::move(__out_it), __specs);
560 }
561
562 # endif // _LIBCPP_STD_VER > 20
563
564 } // namespace __formatter
565
566 #endif //_LIBCPP_STD_VER > 17
567
568 _LIBCPP_END_NAMESPACE_STD
569
570 #endif // _LIBCPP___FORMAT_FORMATTER_OUTPUT_H
571