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