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