| // -*- C++ -*- |
| //===----------------------------------------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef _LIBCPP_FORMAT |
| #define _LIBCPP_FORMAT |
| |
| /* |
| |
| namespace std { |
| // [format.context], class template basic_format_context |
| template<class Out, class charT> class basic_format_context; |
| using format_context = basic_format_context<unspecified, char>; |
| using wformat_context = basic_format_context<unspecified, wchar_t>; |
| |
| // [format.args], class template basic_format_args |
| template<class Context> class basic_format_args; |
| using format_args = basic_format_args<format_context>; |
| using wformat_args = basic_format_args<wformat_context>; |
| |
| // [format.functions], formatting functions |
| template<class... Args> |
| string format(string_view fmt, const Args&... args); |
| template<class... Args> |
| wstring format(wstring_view fmt, const Args&... args); |
| template<class... Args> |
| string format(const locale& loc, string_view fmt, const Args&... args); |
| template<class... Args> |
| wstring format(const locale& loc, wstring_view fmt, const Args&... args); |
| |
| string vformat(string_view fmt, format_args args); |
| wstring vformat(wstring_view fmt, wformat_args args); |
| string vformat(const locale& loc, string_view fmt, format_args args); |
| wstring vformat(const locale& loc, wstring_view fmt, wformat_args args); |
| |
| template<class Out, class... Args> |
| Out format_to(Out out, string_view fmt, const Args&... args); |
| template<class Out, class... Args> |
| Out format_to(Out out, wstring_view fmt, const Args&... args); |
| template<class Out, class... Args> |
| Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args); |
| template<class Out, class... Args> |
| Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args); |
| |
| template<class Out> |
| Out vformat_to(Out out, string_view fmt, format_args args); |
| template<class Out> |
| Out vformat_to(Out out, wstring_view fmt, wformat_args args); |
| template<class Out> |
| Out vformat_to(Out out, const locale& loc, string_view fmt, |
| format_args char> args); |
| template<class Out> |
| Out vformat_to(Out out, const locale& loc, wstring_view fmt, |
| wformat_args args); |
| |
| template<class Out> struct format_to_n_result { |
| Out out; |
| iter_difference_t<Out> size; |
| }; |
| template<class Out, class... Args> |
| format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, |
| string_view fmt, const Args&... args); |
| template<class Out, class... Args> |
| format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, |
| wstring_view fmt, const Args&... args); |
| template<class Out, class... Args> |
| format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, |
| const locale& loc, string_view fmt, |
| const Args&... args); |
| template<class Out, class... Args> |
| format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, |
| const locale& loc, wstring_view fmt, |
| const Args&... args); |
| |
| template<class... Args> |
| size_t formatted_size(string_view fmt, const Args&... args); |
| template<class... Args> |
| size_t formatted_size(wstring_view fmt, const Args&... args); |
| template<class... Args> |
| size_t formatted_size(const locale& loc, string_view fmt, const Args&... args); |
| template<class... Args> |
| size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args); |
| |
| // [format.formatter], formatter |
| template<class T, class charT = char> struct formatter; |
| |
| // [format.parse.ctx], class template basic_format_parse_context |
| template<class charT> class basic_format_parse_context; |
| using format_parse_context = basic_format_parse_context<char>; |
| using wformat_parse_context = basic_format_parse_context<wchar_t>; |
| |
| // [format.arguments], arguments |
| // [format.arg], class template basic_format_arg |
| template<class Context> class basic_format_arg; |
| |
| template<class Visitor, class Context> |
| see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg); |
| |
| // [format.arg.store], class template format-arg-store |
| template<class Context, class... Args> struct format-arg-store; // exposition only |
| |
| template<class Context = format_context, class... Args> |
| format-arg-store<Context, Args...> |
| make_format_args(const Args&... args); |
| template<class... Args> |
| format-arg-store<wformat_context, Args...> |
| make_wformat_args(const Args&... args); |
| |
| // [format.error], class format_error |
| class format_error; |
| } |
| |
| */ |
| |
| #include <__assert> // all public C++ headers provide the assertion handler |
| // Make sure all feature-test macros are available. |
| #include <version> |
| // Enable the contents of the header only when libc++ was built with LIBCXX_ENABLE_INCOMPLETE_FEATURES. |
| #if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) |
| |
| #include <__algorithm/clamp.h> |
| #include <__config> |
| #include <__debug> |
| #include <__format/buffer.h> |
| #include <__format/format_arg.h> |
| #include <__format/format_args.h> |
| #include <__format/format_context.h> |
| #include <__format/format_error.h> |
| #include <__format/format_fwd.h> |
| #include <__format/format_parse_context.h> |
| #include <__format/format_string.h> |
| #include <__format/format_to_n_result.h> |
| #include <__format/formatter.h> |
| #include <__format/formatter_bool.h> |
| #include <__format/formatter_char.h> |
| #include <__format/formatter_floating_point.h> |
| #include <__format/formatter_integer.h> |
| #include <__format/formatter_pointer.h> |
| #include <__format/formatter_string.h> |
| #include <__format/parser_std_format_spec.h> |
| #include <__variant/monostate.h> |
| #include <array> |
| #include <concepts> |
| #include <string> |
| #include <string_view> |
| #include <type_traits> |
| |
| #ifndef _LIBCPP_HAS_NO_LOCALIZATION |
| #include <locale> |
| #endif |
| |
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| # pragma GCC system_header |
| #endif |
| |
| _LIBCPP_BEGIN_NAMESPACE_STD |
| |
| #if _LIBCPP_STD_VER > 17 |
| |
| // TODO FMT Move the implementation in this file to its own granular headers. |
| |
| // TODO FMT Evaluate which templates should be external templates. This |
| // improves the efficiency of the header. However since the header is still |
| // under heavy development and not all classes are stable it makes no sense |
| // to do this optimization now. |
| |
| using format_args = basic_format_args<format_context>; |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| using wformat_args = basic_format_args<wformat_context>; |
| #endif |
| |
| template <class _Context, class... _Args> |
| struct _LIBCPP_TEMPLATE_VIS __format_arg_store { |
| // TODO FMT Use a built-in array. |
| array<basic_format_arg<_Context>, sizeof...(_Args)> __args; |
| }; |
| |
| template <class _Context = format_context, class... _Args> |
| _LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> |
| make_format_args(const _Args&... __args) { |
| return {basic_format_arg<_Context>(__args)...}; |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <class... _Args> |
| _LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...> |
| make_wformat_args(const _Args&... __args) { |
| return _VSTD::make_format_args<wformat_context>(__args...); |
| } |
| #endif |
| |
| namespace __format { |
| |
| template <class _CharT, class _ParseCtx, class _Ctx> |
| _LIBCPP_HIDE_FROM_ABI const _CharT* |
| __handle_replacement_field(const _CharT* __begin, const _CharT* __end, |
| _ParseCtx& __parse_ctx, _Ctx& __ctx) { |
| __format::__parse_number_result __r = |
| __format::__parse_arg_id(__begin, __end, __parse_ctx); |
| |
| switch (*__r.__ptr) { |
| case _CharT(':'): |
| // The arg-id has a format-specifier, advance the input to the format-spec. |
| __parse_ctx.advance_to(__r.__ptr + 1); |
| break; |
| case _CharT('}'): |
| // The arg-id has no format-specifier. |
| __parse_ctx.advance_to(__r.__ptr); |
| break; |
| default: |
| __throw_format_error( |
| "The replacement field arg-id should terminate at a ':' or '}'"); |
| } |
| |
| _VSTD::visit_format_arg( |
| [&](auto __arg) { |
| if constexpr (same_as<decltype(__arg), monostate>) |
| __throw_format_error("Argument index out of bounds"); |
| else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>) |
| __arg.format(__parse_ctx, __ctx); |
| else { |
| formatter<decltype(__arg), _CharT> __formatter; |
| __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); |
| __ctx.advance_to(__formatter.format(__arg, __ctx)); |
| } |
| }, |
| __ctx.arg(__r.__value)); |
| |
| __begin = __parse_ctx.begin(); |
| if (__begin == __end || *__begin != _CharT('}')) |
| __throw_format_error("The replacement field misses a terminating '}'"); |
| |
| return ++__begin; |
| } |
| |
| template <class _ParseCtx, class _Ctx> |
| _LIBCPP_HIDE_FROM_ABI typename _Ctx::iterator |
| __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) { |
| using _CharT = typename _ParseCtx::char_type; |
| static_assert(same_as<typename _Ctx::char_type, _CharT>); |
| |
| const _CharT* __begin = __parse_ctx.begin(); |
| const _CharT* __end = __parse_ctx.end(); |
| typename _Ctx::iterator __out_it = __ctx.out(); |
| while (__begin != __end) { |
| switch (*__begin) { |
| case _CharT('{'): |
| ++__begin; |
| if (__begin == __end) |
| __throw_format_error("The format string terminates at a '{'"); |
| |
| if (*__begin != _CharT('{')) [[likely]] { |
| __ctx.advance_to(_VSTD::move(__out_it)); |
| __begin = |
| __handle_replacement_field(__begin, __end, __parse_ctx, __ctx); |
| __out_it = __ctx.out(); |
| |
| // The output is written and __begin points to the next character. So |
| // start the next iteration. |
| continue; |
| } |
| // The string is an escape character. |
| break; |
| |
| case _CharT('}'): |
| ++__begin; |
| if (__begin == __end || *__begin != _CharT('}')) |
| __throw_format_error( |
| "The format string contains an invalid escape sequence"); |
| |
| break; |
| } |
| |
| // Copy the character to the output verbatim. |
| *__out_it++ = *__begin++; |
| } |
| return __out_it; |
| } |
| |
| } // namespace __format |
| |
| template <class _OutIt, class _CharT, class _FormatOutIt> |
| requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt |
| __vformat_to( |
| _OutIt __out_it, basic_string_view<_CharT> __fmt, |
| basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) { |
| if constexpr (same_as<_OutIt, _FormatOutIt>) |
| return _VSTD::__format::__vformat_to( |
| basic_format_parse_context{__fmt, __args.__size()}, |
| _VSTD::__format_context_create(_VSTD::move(__out_it), __args)); |
| else { |
| __format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)}; |
| _VSTD::__format::__vformat_to( |
| basic_format_parse_context{__fmt, __args.__size()}, |
| _VSTD::__format_context_create(__buffer.make_output_iterator(), |
| __args)); |
| return _VSTD::move(__buffer).out(); |
| } |
| } |
| |
| template <output_iterator<const char&> _OutIt> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt |
| vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) { |
| return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <output_iterator<const wchar_t&> _OutIt> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt |
| vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) { |
| return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args); |
| } |
| #endif |
| |
| template <output_iterator<const char&> _OutIt, class... _Args> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt |
| format_to(_OutIt __out_it, string_view __fmt, const _Args&... __args) { |
| return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt, |
| _VSTD::make_format_args(__args...)); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt |
| format_to(_OutIt __out_it, wstring_view __fmt, const _Args&... __args) { |
| return _VSTD::vformat_to(_VSTD::move(__out_it), __fmt, |
| _VSTD::make_wformat_args(__args...)); |
| } |
| #endif |
| |
| _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string |
| vformat(string_view __fmt, format_args __args) { |
| string __res; |
| _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args); |
| return __res; |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring |
| vformat(wstring_view __fmt, wformat_args __args) { |
| wstring __res; |
| _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args); |
| return __res; |
| } |
| #endif |
| |
| template <class... _Args> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string |
| format(string_view __fmt, const _Args&... __args) { |
| return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <class... _Args> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring |
| format(wstring_view __fmt, const _Args&... __args) { |
| return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)); |
| } |
| #endif |
| |
| template <output_iterator<const char&> _OutIt, class... _Args> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt> |
| format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, string_view __fmt, |
| const _Args&... __args) { |
| // TODO FMT Improve PoC: using std::string is inefficient. |
| string __str = _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)); |
| iter_difference_t<_OutIt> __s = __str.size(); |
| iter_difference_t<_OutIt> __m = |
| _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); |
| __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it)); |
| return {_VSTD::move(__out_it), __s}; |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt> |
| format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wstring_view __fmt, |
| const _Args&... __args) { |
| // TODO FMT Improve PoC: using std::string is inefficient. |
| wstring __str = _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)); |
| iter_difference_t<_OutIt> __s = __str.size(); |
| iter_difference_t<_OutIt> __m = |
| _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); |
| __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it)); |
| return {_VSTD::move(__out_it), __s}; |
| } |
| #endif |
| |
| template <class... _Args> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t |
| formatted_size(string_view __fmt, const _Args&... __args) { |
| // TODO FMT Improve PoC: using std::string is inefficient. |
| return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)).size(); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <class... _Args> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t |
| formatted_size(wstring_view __fmt, const _Args&... __args) { |
| // TODO FMT Improve PoC: using std::string is inefficient. |
| return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)).size(); |
| } |
| #endif |
| |
| #ifndef _LIBCPP_HAS_NO_LOCALIZATION |
| |
| template <class _OutIt, class _CharT, class _FormatOutIt> |
| requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt |
| __vformat_to( |
| _OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt, |
| basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) { |
| if constexpr (same_as<_OutIt, _FormatOutIt>) |
| return _VSTD::__format::__vformat_to( |
| basic_format_parse_context{__fmt, __args.__size()}, |
| _VSTD::__format_context_create(_VSTD::move(__out_it), __args, |
| _VSTD::move(__loc))); |
| else { |
| __format::__format_buffer<_OutIt, _CharT> __buffer{_VSTD::move(__out_it)}; |
| _VSTD::__format::__vformat_to( |
| basic_format_parse_context{__fmt, __args.__size()}, |
| _VSTD::__format_context_create(__buffer.make_output_iterator(), |
| __args, _VSTD::move(__loc))); |
| return _VSTD::move(__buffer).out(); |
| } |
| } |
| |
| template <output_iterator<const char&> _OutIt> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt vformat_to( |
| _OutIt __out_it, locale __loc, string_view __fmt, format_args __args) { |
| return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt, |
| __args); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <output_iterator<const wchar_t&> _OutIt> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt vformat_to( |
| _OutIt __out_it, locale __loc, wstring_view __fmt, wformat_args __args) { |
| return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt, |
| __args); |
| } |
| #endif |
| |
| template <output_iterator<const char&> _OutIt, class... _Args> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to( |
| _OutIt __out_it, locale __loc, string_view __fmt, const _Args&... __args) { |
| return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt, |
| _VSTD::make_format_args(__args...)); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to( |
| _OutIt __out_it, locale __loc, wstring_view __fmt, const _Args&... __args) { |
| return _VSTD::vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt, |
| _VSTD::make_wformat_args(__args...)); |
| } |
| #endif |
| |
| _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string |
| vformat(locale __loc, string_view __fmt, format_args __args) { |
| string __res; |
| _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt, |
| __args); |
| return __res; |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring |
| vformat(locale __loc, wstring_view __fmt, wformat_args __args) { |
| wstring __res; |
| _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt, |
| __args); |
| return __res; |
| } |
| #endif |
| |
| template <class... _Args> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string |
| format(locale __loc, string_view __fmt, const _Args&... __args) { |
| return _VSTD::vformat(_VSTD::move(__loc), __fmt, |
| _VSTD::make_format_args(__args...)); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <class... _Args> |
| _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring |
| format(locale __loc, wstring_view __fmt, const _Args&... __args) { |
| return _VSTD::vformat(_VSTD::move(__loc), __fmt, |
| _VSTD::make_wformat_args(__args...)); |
| } |
| #endif |
| |
| template <output_iterator<const char&> _OutIt, class... _Args> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt> |
| format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, |
| string_view __fmt, const _Args&... __args) { |
| // TODO FMT Improve PoC: using std::string is inefficient. |
| string __str = _VSTD::vformat(_VSTD::move(__loc), __fmt, |
| _VSTD::make_format_args(__args...)); |
| iter_difference_t<_OutIt> __s = __str.size(); |
| iter_difference_t<_OutIt> __m = |
| _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); |
| __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it)); |
| return {_VSTD::move(__out_it), __s}; |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt> |
| format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, |
| wstring_view __fmt, const _Args&... __args) { |
| // TODO FMT Improve PoC: using std::string is inefficient. |
| wstring __str = _VSTD::vformat(_VSTD::move(__loc), __fmt, |
| _VSTD::make_wformat_args(__args...)); |
| iter_difference_t<_OutIt> __s = __str.size(); |
| iter_difference_t<_OutIt> __m = |
| _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s); |
| __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it)); |
| return {_VSTD::move(__out_it), __s}; |
| } |
| #endif |
| |
| template <class... _Args> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t |
| formatted_size(locale __loc, string_view __fmt, const _Args&... __args) { |
| // TODO FMT Improve PoC: using std::string is inefficient. |
| return _VSTD::vformat(_VSTD::move(__loc), __fmt, |
| _VSTD::make_format_args(__args...)) |
| .size(); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <class... _Args> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t |
| formatted_size(locale __loc, wstring_view __fmt, const _Args&... __args) { |
| // TODO FMT Improve PoC: using std::string is inefficient. |
| return _VSTD::vformat(_VSTD::move(__loc), __fmt, |
| _VSTD::make_wformat_args(__args...)) |
| .size(); |
| } |
| #endif |
| |
| #endif // _LIBCPP_HAS_NO_LOCALIZATION |
| |
| #endif //_LIBCPP_STD_VER > 17 |
| |
| _LIBCPP_END_NAMESPACE_STD |
| |
| #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) |
| |
| #endif // _LIBCPP_FORMAT |