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