xref: /llvm-project-15.0.7/libcxx/include/format (revision dd33f9cd)
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
11#define _LIBCPP_FORMAT
12
13/*
14
15namespace std {
16  // [format.context], class template basic_format_context
17  template<class Out, class charT> class basic_format_context;
18  using format_context = basic_format_context<unspecified, char>;
19  using wformat_context = basic_format_context<unspecified, wchar_t>;
20
21  // [format.args], class template basic_format_args
22  template<class Context> class basic_format_args;
23  using format_args = basic_format_args<format_context>;
24  using wformat_args = basic_format_args<wformat_context>;
25
26  // [format.functions], formatting functions
27  template<class... Args>
28    string format(string_view fmt, const Args&... args);
29  template<class... Args>
30    wstring format(wstring_view fmt, const Args&... args);
31  template<class... Args>
32    string format(const locale& loc, string_view fmt, const Args&... args);
33  template<class... Args>
34    wstring format(const locale& loc, wstring_view fmt, const Args&... args);
35
36  string vformat(string_view fmt, format_args args);
37  wstring vformat(wstring_view fmt, wformat_args args);
38  string vformat(const locale& loc, string_view fmt, format_args args);
39  wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
40
41  template<class Out, class... Args>
42    Out format_to(Out out, string_view fmt, const Args&... args);
43  template<class Out, class... Args>
44    Out format_to(Out out, wstring_view fmt, const Args&... args);
45  template<class Out, class... Args>
46    Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args);
47  template<class Out, class... Args>
48    Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args);
49
50  template<class Out>
51    Out vformat_to(Out out, string_view fmt, format_args args);
52  template<class Out>
53    Out vformat_to(Out out, wstring_view fmt, wformat_args args);
54  template<class Out>
55    Out vformat_to(Out out, const locale& loc, string_view fmt,
56                   format_args char> args);
57  template<class Out>
58    Out vformat_to(Out out, const locale& loc, wstring_view fmt,
59                   wformat_args args);
60
61  template<class Out> struct format_to_n_result {
62    Out out;
63    iter_difference_t<Out> size;
64  };
65  template<class Out, class... Args>
66    format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
67                                        string_view fmt, const Args&... args);
68  template<class Out, class... Args>
69    format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
70                                        wstring_view fmt, const Args&... args);
71  template<class Out, class... Args>
72    format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
73                                        const locale& loc, string_view fmt,
74                                        const Args&... args);
75  template<class Out, class... Args>
76    format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
77                                        const locale& loc, wstring_view fmt,
78                                        const Args&... args);
79
80  template<class... Args>
81    size_t formatted_size(string_view fmt, const Args&... args);
82  template<class... Args>
83    size_t formatted_size(wstring_view fmt, const Args&... args);
84  template<class... Args>
85    size_t formatted_size(const locale& loc, string_view fmt, const Args&... args);
86  template<class... Args>
87    size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);
88
89  // [format.formatter], formatter
90  template<class T, class charT = char> struct formatter;
91
92  // [format.parse.ctx], class template basic_format_parse_context
93  template<class charT> class basic_format_parse_context;
94  using format_parse_context = basic_format_parse_context<char>;
95  using wformat_parse_context = basic_format_parse_context<wchar_t>;
96
97  // [format.arguments], arguments
98  // [format.arg], class template basic_format_arg
99  template<class Context> class basic_format_arg;
100
101  template<class Visitor, class Context>
102    see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
103
104  // [format.arg.store], class template format-arg-store
105  template<class Context, class... Args> struct format-arg-store;      // exposition only
106
107  template<class Context = format_context, class... Args>
108    format-arg-store<Context, Args...>
109      make_format_args(const Args&... args);
110  template<class... Args>
111    format-arg-store<wformat_context, Args...>
112      make_wformat_args(const Args&... args);
113
114  // [format.error], class format_error
115  class format_error;
116}
117
118*/
119
120// Make sure all feature-test macros are available.
121#include <version>
122// Enable the contents of the header only when libc++ was built with LIBCXX_ENABLE_INCOMPLETE_FEATURES.
123#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
124
125#include <__algorithm/clamp.h>
126#include <__config>
127#include <__debug>
128#include <__format/format_arg.h>
129#include <__format/format_args.h>
130#include <__format/format_context.h>
131#include <__format/format_error.h>
132#include <__format/format_fwd.h>
133#include <__format/format_parse_context.h>
134#include <__format/format_string.h>
135#include <__format/format_to_n_result.h>
136#include <__format/formatter.h>
137#include <__format/formatter_bool.h>
138#include <__format/formatter_char.h>
139#include <__format/formatter_floating_point.h>
140#include <__format/formatter_integer.h>
141#include <__format/formatter_pointer.h>
142#include <__format/formatter_string.h>
143#include <__format/parser_std_format_spec.h>
144#include <__variant/monostate.h>
145#include <array>
146#include <concepts>
147#include <string>
148#include <string_view>
149#include <type_traits>
150
151#ifndef _LIBCPP_HAS_NO_LOCALIZATION
152#include <locale>
153#endif
154
155#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
156#  pragma GCC system_header
157#endif
158
159_LIBCPP_BEGIN_NAMESPACE_STD
160
161#if _LIBCPP_STD_VER > 17
162
163// TODO FMT Remove this once we require compilers with proper C++20 support.
164// If the compiler has no concepts support, the format header will be disabled.
165// Without concepts support enable_if needs to be used and that too much effort
166// to support compilers with partial C++20 support.
167#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
168
169// TODO FMT Move the implementation in this file to its own granular headers.
170
171// TODO FMT Evaluate which templates should be external templates. This
172// improves the efficiency of the header. However since the header is still
173// under heavy development and not all classes are stable it makes no sense
174// to do this optimization now.
175
176using format_args = basic_format_args<format_context>;
177#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
178using wformat_args = basic_format_args<wformat_context>;
179#endif
180
181template <class _Context, class... _Args>
182struct _LIBCPP_TEMPLATE_VIS __format_arg_store {
183  // TODO FMT Use a built-in array.
184  array<basic_format_arg<_Context>, sizeof...(_Args)> __args;
185};
186
187template <class _Context = format_context, class... _Args>
188_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...>
189make_format_args(const _Args&... __args) {
190  return {basic_format_arg<_Context>(__args)...};
191}
192
193#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
194template <class... _Args>
195_LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...>
196make_wformat_args(const _Args&... __args) {
197  return _VSTD::make_format_args<wformat_context>(__args...);
198}
199#endif
200
201namespace __format {
202
203template <class _CharT, class _ParseCtx, class _Ctx>
204_LIBCPP_HIDE_FROM_ABI const _CharT*
205__handle_replacement_field(const _CharT* __begin, const _CharT* __end,
206                           _ParseCtx& __parse_ctx, _Ctx& __ctx) {
207  __format::__parse_number_result __r =
208      __format::__parse_arg_id(__begin, __end, __parse_ctx);
209
210  switch (*__r.__ptr) {
211  case _CharT(':'):
212    // The arg-id has a format-specifier, advance the input to the format-spec.
213    __parse_ctx.advance_to(__r.__ptr + 1);
214    break;
215  case _CharT('}'):
216    // The arg-id has no format-specifier.
217    __parse_ctx.advance_to(__r.__ptr);
218    break;
219  default:
220    __throw_format_error(
221        "The replacement field arg-id should terminate at a ':' or '}'");
222  }
223
224  _VSTD::visit_format_arg(
225      [&](auto __arg) {
226        if constexpr (same_as<decltype(__arg), monostate>)
227          __throw_format_error("Argument index out of bounds");
228        else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>)
229          __arg.format(__parse_ctx, __ctx);
230        else {
231          formatter<decltype(__arg), _CharT> __formatter;
232          __parse_ctx.advance_to(__formatter.parse(__parse_ctx));
233          __ctx.advance_to(__formatter.format(__arg, __ctx));
234        }
235      },
236      __ctx.arg(__r.__value));
237
238  __begin = __parse_ctx.begin();
239  if (__begin == __end || *__begin != _CharT('}'))
240    __throw_format_error("The replacement field misses a terminating '}'");
241
242  return ++__begin;
243}
244
245template <class _ParseCtx, class _Ctx>
246_LIBCPP_HIDE_FROM_ABI typename _Ctx::iterator
247__vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
248  using _CharT = typename _ParseCtx::char_type;
249  static_assert(same_as<typename _Ctx::char_type, _CharT>);
250
251  const _CharT* __begin = __parse_ctx.begin();
252  const _CharT* __end = __parse_ctx.end();
253  typename _Ctx::iterator __out_it = __ctx.out();
254  while (__begin != __end) {
255    switch (*__begin) {
256    case _CharT('{'):
257      ++__begin;
258      if (__begin == __end)
259        __throw_format_error("The format string terminates at a '{'");
260
261      if (*__begin != _CharT('{')) [[likely]] {
262        __ctx.advance_to(_VSTD::move(__out_it));
263        __begin =
264            __handle_replacement_field(__begin, __end, __parse_ctx, __ctx);
265        __out_it = __ctx.out();
266
267        // The output is written and __begin points to the next character. So
268        // start the next iteration.
269        continue;
270      }
271      // The string is an escape character.
272      break;
273
274    case _CharT('}'):
275      ++__begin;
276      if (__begin == __end || *__begin != _CharT('}'))
277        __throw_format_error(
278            "The format string contains an invalid escape sequence");
279
280      break;
281    }
282
283    // Copy the character to the output verbatim.
284    *__out_it++ = *__begin++;
285  }
286  return __out_it;
287}
288
289} // namespace __format
290
291template <class _OutIt, class _CharT, class _FormatOutIt>
292requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
293    __vformat_to(
294        _OutIt __out_it, basic_string_view<_CharT> __fmt,
295        basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
296  if constexpr (same_as<_OutIt, _FormatOutIt>)
297    return _VSTD::__format::__vformat_to(
298        basic_format_parse_context{__fmt, __args.__size()},
299        _VSTD::__format_context_create(_VSTD::move(__out_it), __args));
300  else {
301    basic_string<_CharT> __str;
302    _VSTD::__format::__vformat_to(
303        basic_format_parse_context{__fmt, __args.__size()},
304        _VSTD::__format_context_create(_VSTD::back_inserter(__str), __args));
305    return _VSTD::copy_n(__str.begin(), __str.size(), _VSTD::move(__out_it));
306  }
307}
308
309template <output_iterator<const char&> _OutIt>
310_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
311vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) {
312  return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
313}
314
315#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
316template <output_iterator<const wchar_t&> _OutIt>
317_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
318vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {
319  return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
320}
321#endif
322
323template <output_iterator<const char&> _OutIt, class... _Args>
324_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
325format_to(_OutIt __out_it, string_view __fmt, const _Args&... __args) {
326  return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt,
327                           _VSTD::make_format_args(__args...));
328}
329
330#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
331template <output_iterator<const wchar_t&> _OutIt, class... _Args>
332_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
333format_to(_OutIt __out_it, wstring_view __fmt, const _Args&... __args) {
334  return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt,
335                           _VSTD::make_wformat_args(__args...));
336}
337#endif
338
339_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
340vformat(string_view __fmt, format_args __args) {
341  string __res;
342  _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
343  return __res;
344}
345
346#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
347_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
348vformat(wstring_view __fmt, wformat_args __args) {
349  wstring __res;
350  _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
351  return __res;
352}
353#endif
354
355template <class... _Args>
356_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
357format(string_view __fmt, const _Args&... __args) {
358  return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...));
359}
360
361#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
362template <class... _Args>
363_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
364format(wstring_view __fmt, const _Args&... __args) {
365  return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...));
366}
367#endif
368
369template <output_iterator<const char&> _OutIt, class... _Args>
370_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
371format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, string_view __fmt,
372            const _Args&... __args) {
373  // TODO FMT Improve PoC: using std::string is inefficient.
374  string __str = _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...));
375  iter_difference_t<_OutIt> __s = __str.size();
376  iter_difference_t<_OutIt> __m =
377      _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
378  __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
379  return {_VSTD::move(__out_it), __s};
380}
381
382#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
383template <output_iterator<const wchar_t&> _OutIt, class... _Args>
384_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
385format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wstring_view __fmt,
386            const _Args&... __args) {
387  // TODO FMT Improve PoC: using std::string is inefficient.
388  wstring __str = _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...));
389  iter_difference_t<_OutIt> __s = __str.size();
390  iter_difference_t<_OutIt> __m =
391      _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
392  __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
393  return {_VSTD::move(__out_it), __s};
394}
395#endif
396
397template <class... _Args>
398_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
399formatted_size(string_view __fmt, const _Args&... __args) {
400  // TODO FMT Improve PoC: using std::string is inefficient.
401  return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)).size();
402}
403
404#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
405template <class... _Args>
406_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
407formatted_size(wstring_view __fmt, const _Args&... __args) {
408  // TODO FMT Improve PoC: using std::string is inefficient.
409  return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)).size();
410}
411#endif
412
413#ifndef _LIBCPP_HAS_NO_LOCALIZATION
414
415template <class _OutIt, class _CharT, class _FormatOutIt>
416requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
417    __vformat_to(
418        _OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt,
419        basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) {
420  if constexpr (same_as<_OutIt, _FormatOutIt>)
421    return _VSTD::__format::__vformat_to(
422        basic_format_parse_context{__fmt, __args.__size()},
423        _VSTD::__format_context_create(_VSTD::move(__out_it), __args,
424                                       _VSTD::move(__loc)));
425  else {
426    basic_string<_CharT> __str;
427    _VSTD::__format::__vformat_to(
428        basic_format_parse_context{__fmt, __args.__size()},
429        _VSTD::__format_context_create(_VSTD::back_inserter(__str), __args,
430                                       _VSTD::move(__loc)));
431    return _VSTD::copy_n(__str.begin(), __str.size(), _VSTD::move(__out_it));
432  }
433}
434
435template <output_iterator<const char&> _OutIt>
436_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt vformat_to(
437    _OutIt __out_it, locale __loc, string_view __fmt, format_args __args) {
438  return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
439                             __args);
440}
441
442#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
443template <output_iterator<const wchar_t&> _OutIt>
444_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt vformat_to(
445    _OutIt __out_it, locale __loc, wstring_view __fmt, wformat_args __args) {
446  return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
447                             __args);
448}
449#endif
450
451template <output_iterator<const char&> _OutIt, class... _Args>
452_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to(
453    _OutIt __out_it, locale __loc, string_view __fmt, const _Args&... __args) {
454  return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
455                           _VSTD::make_format_args(__args...));
456}
457
458#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
459template <output_iterator<const wchar_t&> _OutIt, class... _Args>
460_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to(
461    _OutIt __out_it, locale __loc, wstring_view __fmt, const _Args&... __args) {
462  return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
463                           _VSTD::make_wformat_args(__args...));
464}
465#endif
466
467_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
468vformat(locale __loc, string_view __fmt, format_args __args) {
469  string __res;
470  _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
471                    __args);
472  return __res;
473}
474
475#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
476_LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
477vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
478  wstring __res;
479  _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
480                    __args);
481  return __res;
482}
483#endif
484
485template <class... _Args>
486_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
487format(locale __loc, string_view __fmt, const _Args&... __args) {
488  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
489                        _VSTD::make_format_args(__args...));
490}
491
492#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
493template <class... _Args>
494_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
495format(locale __loc, wstring_view __fmt, const _Args&... __args) {
496  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
497                        _VSTD::make_wformat_args(__args...));
498}
499#endif
500
501template <output_iterator<const char&> _OutIt, class... _Args>
502_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
503format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc,
504            string_view __fmt, const _Args&... __args) {
505  // TODO FMT Improve PoC: using std::string is inefficient.
506  string __str = _VSTD::vformat(_VSTD::move(__loc), __fmt,
507                                _VSTD::make_format_args(__args...));
508  iter_difference_t<_OutIt> __s = __str.size();
509  iter_difference_t<_OutIt> __m =
510      _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
511  __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
512  return {_VSTD::move(__out_it), __s};
513}
514
515#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
516template <output_iterator<const wchar_t&> _OutIt, class... _Args>
517_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
518format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc,
519            wstring_view __fmt, const _Args&... __args) {
520  // TODO FMT Improve PoC: using std::string is inefficient.
521  wstring __str = _VSTD::vformat(_VSTD::move(__loc), __fmt,
522                                 _VSTD::make_wformat_args(__args...));
523  iter_difference_t<_OutIt> __s = __str.size();
524  iter_difference_t<_OutIt> __m =
525      _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
526  __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
527  return {_VSTD::move(__out_it), __s};
528}
529#endif
530
531template <class... _Args>
532_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
533formatted_size(locale __loc, string_view __fmt, const _Args&... __args) {
534  // TODO FMT Improve PoC: using std::string is inefficient.
535  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
536                        _VSTD::make_format_args(__args...))
537      .size();
538}
539
540#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
541template <class... _Args>
542_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
543formatted_size(locale __loc, wstring_view __fmt, const _Args&... __args) {
544  // TODO FMT Improve PoC: using std::string is inefficient.
545  return _VSTD::vformat(_VSTD::move(__loc), __fmt,
546                        _VSTD::make_wformat_args(__args...))
547      .size();
548}
549#endif
550
551#endif // _LIBCPP_HAS_NO_LOCALIZATION
552
553#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
554#endif //_LIBCPP_STD_VER > 17
555
556_LIBCPP_END_NAMESPACE_STD
557
558#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
559
560#endif // _LIBCPP_FORMAT
561