| // -*- C++ -*- |
| //===--------------------------- format -----------------------------------===// |
| // |
| // 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 { |
| basic_format_args<basic_format_context> args_; // exposition only |
| Out out_; // exposition only |
| |
| public: |
| using iterator = Out; |
| using char_type = charT; |
| template<class T> using formatter_type = formatter<T, charT>; |
| |
| basic_format_arg<basic_format_context> arg(size_t id) const; |
| std::locale locale(); |
| |
| iterator out(); |
| void advance_to(iterator it); |
| }; |
| 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 { |
| size_t size_; // exposition only |
| const basic_format_arg<Context>* data_; // exposition only |
| |
| public: |
| basic_format_args() noexcept; |
| |
| template<class... Args> |
| basic_format_args(const format-arg-store<Context, Args...>& store) noexcept; |
| |
| basic_format_arg<Context> get(size_t i) const noexcept; |
| }; |
| using format_args = basic_format_args<format_context>; |
| using wformat_args = basic_format_args<wformat_context>; |
| |
| |
| template<class Out, class charT> |
| using format_args_t = basic_format_args<basic_format_context<Out, charT>>; |
| |
| // [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_t<type_identity_t<Out>, char> args); |
| template<class Out> |
| Out vformat_to(Out out, wstring_view fmt, |
| format_args_t<type_identity_t<Out>, wchar_t> args); |
| template<class Out> |
| Out vformat_to(Out out, const locale& loc, string_view fmt, |
| format_args_t<type_identity_t<Out>, char> args); |
| template<class Out> |
| Out vformat_to(Out out, const locale& loc, wstring_view fmt, |
| format_args_t<type_identity_t<Out>, wchar_t> 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<> struct formatter<char, char>; |
| template<> struct formatter<char, wchar_t>; |
| template<> struct formatter<wchar_t, wchar_t>; |
| |
| template<> struct formatter<charT*, charT>; |
| template<> struct formatter<const charT*, charT>; |
| template<size_t N> struct formatter<const charT[N], charT>; |
| template<class traits, class Allocator> |
| struct formatter<basic_string<charT, traits, Allocator>, charT>; |
| template<class traits> |
| struct formatter<basic_string_view<charT, traits>, charT>; |
| |
| // [format.parse.ctx], class template basic_format_parse_context |
| template<class charT> |
| class basic_format_parse_context { |
| public: |
| using char_type = charT; |
| using const_iterator = typename basic_string_view<charT>::const_iterator; |
| using iterator = const_iterator; |
| |
| private: |
| iterator begin_; // exposition only |
| iterator end_; // exposition only |
| enum indexing { unknown, manual, automatic }; // exposition only |
| indexing indexing_; // exposition only |
| size_t next_arg_id_; // exposition only |
| size_t num_args_; // exposition only |
| |
| public: |
| constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt, |
| size_t num_args = 0) noexcept; |
| basic_format_parse_context(const basic_format_parse_context&) = delete; |
| basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; |
| |
| constexpr const_iterator begin() const noexcept; |
| constexpr const_iterator end() const noexcept; |
| constexpr void advance_to(const_iterator it); |
| |
| constexpr size_t next_arg_id(); |
| constexpr void check_arg_id(size_t id); |
| }; |
| 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 { |
| public: |
| class handle; |
| |
| private: |
| using char_type = typename Context::char_type; // exposition only |
| |
| variant<monostate, bool, char_type, |
| int, unsigned int, long long int, unsigned long long int, |
| float, double, long double, |
| const char_type*, basic_string_view<char_type>, |
| const void*, handle> value; // exposition only |
| |
| template<class T> explicit basic_format_arg(const T& v) noexcept; // exposition only |
| explicit basic_format_arg(float n) noexcept; // exposition only |
| explicit basic_format_arg(double n) noexcept; // exposition only |
| explicit basic_format_arg(long double n) noexcept; // exposition only |
| explicit basic_format_arg(const char_type* s); // exposition only |
| |
| template<class traits> |
| explicit basic_format_arg( |
| basic_string_view<char_type, traits> s) noexcept; // exposition only |
| |
| template<class traits, class Allocator> |
| explicit basic_format_arg( |
| const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only |
| |
| explicit basic_format_arg(nullptr_t) noexcept; // exposition only |
| |
| template<class T> |
| explicit basic_format_arg(const T* p) noexcept; // exposition only |
| |
| public: |
| basic_format_arg() noexcept; |
| |
| explicit operator bool() const noexcept; |
| }; |
| |
| 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 |
| array<basic_format_arg<Context>, sizeof...(Args)> args; |
| }; |
| |
| 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 : public runtime_error { |
| public: |
| explicit format_error(const string& what_arg); |
| explicit format_error(const char* what_arg); |
| }; |
| |
| // [format.parse.ctx], class template basic_format_parse_context |
| template<class charT> |
| class basic_format_parse_context { |
| public: |
| using char_type = charT; |
| using const_iterator = typename basic_string_view<charT>::const_iterator; |
| using iterator = const_iterator; |
| |
| private: |
| iterator begin_; // exposition only |
| iterator end_; // exposition only |
| enum indexing { unknown, manual, automatic }; // exposition only |
| indexing indexing_; // exposition only |
| size_t next_arg_id_; // exposition only |
| size_t num_args_; // exposition only |
| |
| public: |
| constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt, |
| size_t num_args = 0) noexcept; |
| basic_format_parse_context(const basic_format_parse_context&) = delete; |
| basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; |
| |
| constexpr const_iterator begin() const noexcept; |
| constexpr const_iterator end() const noexcept; |
| constexpr void advance_to(const_iterator it); |
| |
| constexpr size_t next_arg_id(); |
| constexpr void check_arg_id(size_t id); |
| }; |
| using format_parse_context = basic_format_parse_context<char>; |
| using wformat_parse_context = basic_format_parse_context<wchar_t>; |
| } |
| |
| */ |
| |
| // 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 <__config> |
| #include <__debug> |
| #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/formatter.h> |
| #include <__format/formatter_bool.h> |
| #include <__format/formatter_char.h> |
| #include <__format/formatter_integer.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_PUSH_MACROS |
| #include <__undef_macros> |
| |
| _LIBCPP_BEGIN_NAMESPACE_STD |
| |
| #if _LIBCPP_STD_VER > 17 |
| |
| // TODO FMT Remove this once we require compilers with proper C++20 support. |
| // If the compiler has no concepts support, the format header will be disabled. |
| // Without concepts support enable_if needs to be used and that too much effort |
| // to support compilers with partial C++20 support. |
| #if !defined(_LIBCPP_HAS_NO_CONCEPTS) |
| |
| // 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 _OutIt, class _CharT> |
| using format_args_t = basic_format_args<basic_format_context<_OutIt, _CharT>>; |
| |
| 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 _Tp, class _CharT> |
| requires(is_arithmetic_v<_Tp> && |
| !same_as<_Tp, bool>) struct _LIBCPP_HIDE_FROM_ABI |
| __formatter_arithmetic { |
| _LIBCPP_HIDE_FROM_ABI |
| auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) { |
| // TODO FMT Implement |
| return __parse_ctx.begin(); |
| } |
| |
| _LIBCPP_HIDE_FROM_ABI |
| auto format(_Tp __value, auto& __ctx) -> decltype(__ctx.out()) { |
| return __handle_format(__value, __ctx); |
| } |
| |
| private: |
| template <class _Uv> |
| _LIBCPP_HIDDEN static string |
| __convert(_Uv __value) requires(same_as<_CharT, char>) { |
| return _VSTD::to_string(__value); |
| } |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <class _Uv> |
| _LIBCPP_HIDDEN static wstring |
| __convert(_Uv __value) requires(same_as<_CharT, wchar_t>) { |
| return _VSTD::to_wstring(__value); |
| } |
| #endif |
| |
| template <class _Uv> |
| _LIBCPP_HIDDEN auto __handle_format(_Uv __value, auto& __ctx) |
| -> decltype(__ctx.out()) |
| { |
| // TODO FMT Implement using formatting arguments |
| // TODO FMT Improve PoC since using std::to_string is inefficient. |
| // Note the code doesn't use std::string::iterator since the unit tests |
| // test with debug iterators and they fail with strings created from |
| // std::to_string. |
| auto __str = __convert(__value); |
| auto __out_it = __ctx.out(); |
| for (size_t __i = 0, __e = __str.size(); __i != __e; ++__i) |
| *__out_it++ = __str[__i]; |
| return __out_it; |
| } |
| }; |
| } // namespace __format |
| |
| // These specializations are helper stubs and not proper formatters. |
| // TODO FMT Implement the proper formatter specializations. |
| |
| // Floating point types. |
| // TODO FMT There are no replacements for the floating point stubs due to not |
| // having floating point support in std::to_chars yet. These stubs aren't |
| // removed since they are useful for developing the real versions. |
| // Ultimately the stubs should be implemented properly and this code can be |
| // removed. |
| #if 0 |
| template <class _CharT> |
| struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<float, _CharT> |
| : public __format::__formatter_arithmetic<float, _CharT> {}; |
| template <class _CharT> |
| struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT |
| formatter<double, _CharT> |
| : public __format::__formatter_arithmetic<double, _CharT> {}; |
| template <class _CharT> |
| struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT |
| formatter<long double, _CharT> |
| : public __format::__formatter_arithmetic<long double, _CharT> {}; |
| #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 { |
| 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> |
| requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt |
| __vformat_to(_OutIt __out_it, basic_string_view<_CharT> __fmt, |
| format_args_t<type_identity_t<_OutIt>, _CharT> __args) { |
| return __format::__vformat_to( |
| basic_format_parse_context{__fmt, __args.__size()}, |
| _VSTD::__format_context_create(_VSTD::move(__out_it), __args)); |
| } |
| |
| template <output_iterator<const char&> _OutIt> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt |
| vformat_to(_OutIt __out_it, string_view __fmt, |
| format_args_t<type_identity_t<_OutIt>, char> __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_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt |
| vformat_to(_OutIt __out_it, wstring_view __fmt, |
| format_args_t<type_identity_t<_OutIt>, wchar_t> __args) { |
| return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args); |
| } |
| #endif |
| |
| template <output_iterator<const char&> _OutIt, class... _Args> |
| _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<basic_format_context<_OutIt, char>>(__args...)); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
| _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_format_args<basic_format_context<_OutIt, wchar_t>>( |
| __args...)); |
| } |
| #endif |
| |
| 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 |
| 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_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_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 <class _OutIt> |
| struct _LIBCPP_TEMPLATE_VIS format_to_n_result { |
| _OutIt out; |
| iter_difference_t<_OutIt> size; |
| }; |
| |
| 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> |
| requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt |
| __vformat_to(_OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt, |
| format_args_t<type_identity_t<_OutIt>, _CharT> __args) { |
| return __format::__vformat_to( |
| basic_format_parse_context{__fmt, __args.__size()}, |
| _VSTD::__format_context_create(_VSTD::move(__out_it), __args, |
| _VSTD::move(__loc))); |
| } |
| |
| template <output_iterator<const char&> _OutIt> |
| _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt |
| vformat_to(_OutIt __out_it, locale __loc, string_view __fmt, |
| format_args_t<type_identity_t<_OutIt>, char> __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_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt |
| vformat_to(_OutIt __out_it, locale __loc, wstring_view __fmt, |
| format_args_t<type_identity_t<_OutIt>, wchar_t> __args) { |
| return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt, |
| __args); |
| } |
| #endif |
| |
| template <output_iterator<const char&> _OutIt, class... _Args> |
| _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<basic_format_context<_OutIt, char>>(__args...)); |
| } |
| |
| #ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS |
| template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
| _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_format_args<basic_format_context<_OutIt, wchar_t>>( |
| __args...)); |
| } |
| #endif |
| |
| 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 |
| 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_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_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 // !defined(_LIBCPP_HAS_NO_CONCEPTS) |
| #endif //_LIBCPP_STD_VER > 17 |
| |
| _LIBCPP_END_NAMESPACE_STD |
| |
| _LIBCPP_POP_MACROS |
| |
| #endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT) |
| |
| #endif // _LIBCPP_FORMAT |