blob: a869bbe1d6f9957fa9040294b2e2715cfc9d4893 [file] [log] [blame]
Mark de Weverdf5fd832020-11-26 19:12:18 +01001// -*- C++ -*-
2//===--------------------------- format -----------------------------------===//
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 {
Mark de Wevercba61372020-12-05 11:45:21 +010016 // [format.context], class template basic_format_context
17 template<class Out, class charT>
18 class basic_format_context {
19 basic_format_args<basic_format_context> args_; // exposition only
20 Out out_; // exposition only
21
22 public:
23 using iterator = Out;
24 using char_type = charT;
25 template<class T> using formatter_type = formatter<T, charT>;
26
27 basic_format_arg<basic_format_context> arg(size_t id) const;
28 std::locale locale();
29
30 iterator out();
31 void advance_to(iterator it);
32 };
33 using format_context = basic_format_context<unspecified, char>;
34 using wformat_context = basic_format_context<unspecified, wchar_t>;
35
36 // [format.args], class template basic_format_args
37 template<class Context>
38 class basic_format_args {
39 size_t size_; // exposition only
40 const basic_format_arg<Context>* data_; // exposition only
41
42 public:
43 basic_format_args() noexcept;
44
45 template<class... Args>
46 basic_format_args(const format-arg-store<Context, Args...>& store) noexcept;
47
48 basic_format_arg<Context> get(size_t i) const noexcept;
49 };
50 using format_args = basic_format_args<format_context>;
51 using wformat_args = basic_format_args<wformat_context>;
52
53
54 template<class Out, class charT>
55 using format_args_t = basic_format_args<basic_format_context<Out, charT>>;
56
Mark de Wevercb50a052020-12-19 13:52:07 +010057 // [format.functions], formatting functions
58 template<class... Args>
59 string format(string_view fmt, const Args&... args);
60 template<class... Args>
61 wstring format(wstring_view fmt, const Args&... args);
62 template<class... Args>
63 string format(const locale& loc, string_view fmt, const Args&... args);
64 template<class... Args>
65 wstring format(const locale& loc, wstring_view fmt, const Args&... args);
66
67 string vformat(string_view fmt, format_args args);
68 wstring vformat(wstring_view fmt, wformat_args args);
69 string vformat(const locale& loc, string_view fmt, format_args args);
70 wstring vformat(const locale& loc, wstring_view fmt, wformat_args args);
71
72 template<class Out, class... Args>
73 Out format_to(Out out, string_view fmt, const Args&... args);
74 template<class Out, class... Args>
75 Out format_to(Out out, wstring_view fmt, const Args&... args);
76 template<class Out, class... Args>
77 Out format_to(Out out, const locale& loc, string_view fmt, const Args&... args);
78 template<class Out, class... Args>
79 Out format_to(Out out, const locale& loc, wstring_view fmt, const Args&... args);
80
81 template<class Out>
82 Out vformat_to(Out out, string_view fmt,
83 format_args_t<type_identity_t<Out>, char> args);
84 template<class Out>
85 Out vformat_to(Out out, wstring_view fmt,
86 format_args_t<type_identity_t<Out>, wchar_t> args);
87 template<class Out>
88 Out vformat_to(Out out, const locale& loc, string_view fmt,
89 format_args_t<type_identity_t<Out>, char> args);
90 template<class Out>
91 Out vformat_to(Out out, const locale& loc, wstring_view fmt,
92 format_args_t<type_identity_t<Out>, wchar_t> args);
93
94 template<class Out> struct format_to_n_result {
95 Out out;
96 iter_difference_t<Out> size;
97 };
98
99 template<class Out, class... Args>
100 format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
101 string_view fmt, const Args&... args);
102 template<class Out, class... Args>
103 format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
104 wstring_view fmt, const Args&... args);
105 template<class Out, class... Args>
106 format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
107 const locale& loc, string_view fmt,
108 const Args&... args);
109 template<class Out, class... Args>
110 format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
111 const locale& loc, wstring_view fmt,
112 const Args&... args);
113
114 template<class... Args>
115 size_t formatted_size(string_view fmt, const Args&... args);
116 template<class... Args>
117 size_t formatted_size(wstring_view fmt, const Args&... args);
118 template<class... Args>
119 size_t formatted_size(const locale& loc, string_view fmt, const Args&... args);
120 template<class... Args>
121 size_t formatted_size(const locale& loc, wstring_view fmt, const Args&... args);
122
123 // [format.formatter], formatter
124 template<> struct formatter<char, char>;
125 template<> struct formatter<char, wchar_t>;
126 template<> struct formatter<wchar_t, wchar_t>;
127
128 template<> struct formatter<charT*, charT>;
129 template<> struct formatter<const charT*, charT>;
130 template<size_t N> struct formatter<const charT[N], charT>;
131 template<class traits, class Allocator>
132 struct formatter<basic_string<charT, traits, Allocator>, charT>;
133 template<class traits>
134 struct formatter<basic_string_view<charT, traits>, charT>;
135
Mark de Wevercba61372020-12-05 11:45:21 +0100136 // [format.parse.ctx], class template basic_format_parse_context
137 template<class charT>
138 class basic_format_parse_context {
139 public:
140 using char_type = charT;
141 using const_iterator = typename basic_string_view<charT>::const_iterator;
142 using iterator = const_iterator;
143
144 private:
145 iterator begin_; // exposition only
146 iterator end_; // exposition only
147 enum indexing { unknown, manual, automatic }; // exposition only
148 indexing indexing_; // exposition only
149 size_t next_arg_id_; // exposition only
150 size_t num_args_; // exposition only
151
152 public:
153 constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt,
154 size_t num_args = 0) noexcept;
155 basic_format_parse_context(const basic_format_parse_context&) = delete;
156 basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
157
158 constexpr const_iterator begin() const noexcept;
159 constexpr const_iterator end() const noexcept;
160 constexpr void advance_to(const_iterator it);
161
162 constexpr size_t next_arg_id();
163 constexpr void check_arg_id(size_t id);
164 };
165 using format_parse_context = basic_format_parse_context<char>;
166 using wformat_parse_context = basic_format_parse_context<wchar_t>;
167
168 // [format.arguments], arguments
169 // [format.arg], class template basic_format_arg
170 template<class Context>
171 class basic_format_arg {
172 public:
173 class handle;
174
175 private:
176 using char_type = typename Context::char_type; // exposition only
177
178 variant<monostate, bool, char_type,
179 int, unsigned int, long long int, unsigned long long int,
180 float, double, long double,
181 const char_type*, basic_string_view<char_type>,
182 const void*, handle> value; // exposition only
183
184 template<class T> explicit basic_format_arg(const T& v) noexcept; // exposition only
185 explicit basic_format_arg(float n) noexcept; // exposition only
186 explicit basic_format_arg(double n) noexcept; // exposition only
187 explicit basic_format_arg(long double n) noexcept; // exposition only
188 explicit basic_format_arg(const char_type* s); // exposition only
189
190 template<class traits>
191 explicit basic_format_arg(
192 basic_string_view<char_type, traits> s) noexcept; // exposition only
193
194 template<class traits, class Allocator>
195 explicit basic_format_arg(
196 const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only
197
198 explicit basic_format_arg(nullptr_t) noexcept; // exposition only
199
200 template<class T>
201 explicit basic_format_arg(const T* p) noexcept; // exposition only
202
203 public:
204 basic_format_arg() noexcept;
205
206 explicit operator bool() const noexcept;
207 };
208
209 template<class Visitor, class Context>
210 see below visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
211
212 // [format.arg.store], class template format-arg-store
213 template<class Context, class... Args>
214 struct format-arg-store { // exposition only
215 array<basic_format_arg<Context>, sizeof...(Args)> args;
216 };
217
218 template<class Context = format_context, class... Args>
219 format-arg-store<Context, Args...>
220 make_format_args(const Args&... args);
221 template<class... Args>
222 format-arg-store<wformat_context, Args...>
223 make_wformat_args(const Args&... args);
224
Mark de Weverdf5fd832020-11-26 19:12:18 +0100225 // [format.error], class format_error
226 class format_error : public runtime_error {
227 public:
228 explicit format_error(const string& what_arg);
229 explicit format_error(const char* what_arg);
230 };
Mark de Wever6a67a5f2021-02-02 18:10:33 +0100231
232 // [format.parse.ctx], class template basic_format_parse_context
233 template<class charT>
234 class basic_format_parse_context {
235 public:
236 using char_type = charT;
237 using const_iterator = typename basic_string_view<charT>::const_iterator;
238 using iterator = const_iterator;
239
240 private:
241 iterator begin_; // exposition only
242 iterator end_; // exposition only
243 enum indexing { unknown, manual, automatic }; // exposition only
244 indexing indexing_; // exposition only
245 size_t next_arg_id_; // exposition only
246 size_t num_args_; // exposition only
247
248 public:
249 constexpr explicit basic_format_parse_context(basic_string_view<charT> fmt,
250 size_t num_args = 0) noexcept;
251 basic_format_parse_context(const basic_format_parse_context&) = delete;
252 basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
253
254 constexpr const_iterator begin() const noexcept;
255 constexpr const_iterator end() const noexcept;
256 constexpr void advance_to(const_iterator it);
257
258 constexpr size_t next_arg_id();
259 constexpr void check_arg_id(size_t id);
260 };
261 using format_parse_context = basic_format_parse_context<char>;
262 using wformat_parse_context = basic_format_parse_context<wchar_t>;
Mark de Weverdf5fd832020-11-26 19:12:18 +0100263}
264
265*/
266
Mark de Weverbe38c382021-08-11 17:33:54 +0200267// Make sure all feature-test macros are available.
Mark de Wever14151d22021-07-30 14:35:37 -0400268#include <version>
Mark de Weverbe38c382021-08-11 17:33:54 +0200269// Enable the contents of the header only when libc++ was built with LIBCXX_ENABLE_INCOMPLETE_FEATURES.
Mark de Wever14151d22021-07-30 14:35:37 -0400270#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
271
Mark de Weverdf5fd832020-11-26 19:12:18 +0100272#include <__config>
Mark de Wevercb50a052020-12-19 13:52:07 +0100273#include <__debug>
Mark de Wevercba61372020-12-05 11:45:21 +0100274#include <__format/format_arg.h>
275#include <__format/format_args.h>
276#include <__format/format_context.h>
Mark de Wever1aef5d02021-04-25 17:58:03 +0200277#include <__format/format_error.h>
Mark de Wevere26bdbb2021-04-25 18:23:42 +0200278#include <__format/format_parse_context.h>
Mark de Wevercb50a052020-12-19 13:52:07 +0100279#include <__format/format_string.h>
280#include <__format/formatter.h>
Mark de Weverf82551e2020-12-14 17:39:15 +0100281#include <__format/formatter_string.h>
282#include <__format/parser_std_format_spec.h>
Mark de Wevercb50a052020-12-19 13:52:07 +0100283#include <__variant/monostate.h>
Mark de Wevercba61372020-12-05 11:45:21 +0100284#include <array>
Mark de Wevercb50a052020-12-19 13:52:07 +0100285#include <concepts>
286#include <string>
287#include <string_view>
288#include <type_traits>
289
290#ifndef _LIBCPP_HAS_NO_LOCALIZATION
291#include <locale>
292#endif
Mark de Wever8a0a1882021-07-25 09:18:53 +0200293
Mark de Weverdf5fd832020-11-26 19:12:18 +0100294#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Mark de Wevercba61372020-12-05 11:45:21 +0100295#pragma GCC system_header
Mark de Weverdf5fd832020-11-26 19:12:18 +0100296#endif
297
Mark de Wevercb50a052020-12-19 13:52:07 +0100298_LIBCPP_PUSH_MACROS
299#include <__undef_macros>
300
Mark de Wevercba61372020-12-05 11:45:21 +0100301_LIBCPP_BEGIN_NAMESPACE_STD
302
303#if _LIBCPP_STD_VER > 17
304
305// TODO FMT Remove this once we require compilers with proper C++20 support.
306// If the compiler has no concepts support, the format header will be disabled.
307// Without concepts support enable_if needs to be used and that too much effort
308// to support compilers with partial C++20 support.
309#if !defined(_LIBCPP_HAS_NO_CONCEPTS)
310
311// TODO FMT Evaluate which templates should be external templates. This
312// improves the efficiency of the header. However since the header is still
313// under heavy development and not all classes are stable it makes no sense
314// to do this optimization now.
315
316using format_args = basic_format_args<format_context>;
317using wformat_args = basic_format_args<wformat_context>;
318
319template <class _OutIt, class _CharT>
320using format_args_t = basic_format_args<basic_format_context<_OutIt, _CharT>>;
321
322template <class _Context, class... _Args>
323struct _LIBCPP_TEMPLATE_VIS __format_arg_store {
324 // TODO FMT Use a built-in array.
325 array<basic_format_arg<_Context>, sizeof...(_Args)> __args;
326};
327
328template <class _Context = format_context, class... _Args>
329_LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...>
330make_format_args(const _Args&... __args) {
331 return {basic_format_arg<_Context>(__args)...};
332}
333
334template <class... _Args>
335_LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...>
336make_wformat_args(const _Args&... __args) {
337 return _VSTD::make_format_args<wformat_context>(__args...);
338}
339
Mark de Wevercb50a052020-12-19 13:52:07 +0100340namespace __format {
341template <class _Tp, class _CharT>
342struct _LIBCPP_TEMPLATE_VIS __formatter_char {
343 _LIBCPP_HIDE_FROM_ABI
344 auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
345 // TODO FMT Implement this function.
346 return __parse_ctx.begin();
347 }
348
349 _LIBCPP_HIDE_FROM_ABI
350 auto format(_Tp __c, auto& __ctx) -> decltype(__ctx.out()) {
351 // TODO FMT Implement the parsed formatting arguments.
352 auto __out_it = __ctx.out();
353 *__out_it++ = _CharT(__c);
354 return __out_it;
355 }
356};
357
Mark de Wevercb50a052020-12-19 13:52:07 +0100358template <class _Tp, class _CharT>
359requires(is_arithmetic_v<_Tp> &&
360 !same_as<_Tp, bool>) struct _LIBCPP_HIDE_FROM_ABI
361 __formatter_arithmetic {
362 _LIBCPP_HIDE_FROM_ABI
363 auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
364 // TODO FMT Implement
365 return __parse_ctx.begin();
366 }
367
368 _LIBCPP_HIDE_FROM_ABI
369 auto format(_Tp __value, auto& __ctx) -> decltype(__ctx.out()) {
370 return __handle_format(__value, __ctx);
371 }
372
373private:
374 template <class _Uv>
375 _LIBCPP_HIDDEN static string
376 __convert(_Uv __value) requires(same_as<_CharT, char>) {
377 return _VSTD::to_string(__value);
378 }
379 template <class _Uv>
380 _LIBCPP_HIDDEN static wstring
381 __convert(_Uv __value) requires(same_as<_CharT, wchar_t>) {
382 return _VSTD::to_wstring(__value);
383 }
384
385 template <class _Uv>
386 _LIBCPP_HIDDEN auto __handle_format(_Uv __value, auto& __ctx)
387 -> decltype(__ctx.out())
388#ifndef _LIBCPP_HAS_NO_INT128
389 requires(!same_as<_Uv, __int128_t> && !same_as<_Uv, __uint128_t>)
390#endif
391 {
392 // TODO FMT Implement using formatting arguments
393 // TODO FMT Improve PoC since using std::to_string is inefficient.
394 // Note the code doesn't use std::string::iterator since the unit tests
395 // test with debug iterators and they fail with strings created from
396 // std::to_string.
397 auto __str = __convert(__value);
398 auto __out_it = __ctx.out();
399 for (size_t __i = 0, __e = __str.size(); __i != __e; ++__i)
400 *__out_it++ = __str[__i];
401 return __out_it;
402 }
403#ifndef _LIBCPP_HAS_NO_INT128
404 template <class _Uv>
405 _LIBCPP_HIDDEN auto __handle_format(_Uv __value, auto& __ctx)
406 -> decltype(__ctx.out()) requires(same_as<_Uv, __int128_t> ||
407 same_as<_Uv, __uint128_t>) {
408 using _To = conditional_t<is_signed_v<_Uv>, long long, unsigned long long>;
409 // TODO FMT Implement full 128-bit support.
410 if (__value < numeric_limits<_To>::min() ||
411 __value > numeric_limits<_To>::max())
412 __throw_format_error("128-bit value is outside of implemented range");
413
414 return __handle_format(static_cast<_To>(__value), __ctx);
415 }
416#endif
417};
418} // namespace __format
419
420// These specializations are helper stubs and not proper formatters.
421// TODO FMT Implement the proper formatter specializations.
422
423// [format.formatter.spec]/2.1 The specializations
424
425template <>
426struct _LIBCPP_TEMPLATE_VIS formatter<char, char>
427 : public __format::__formatter_char<char, char> {};
428
429template <>
430struct _LIBCPP_TEMPLATE_VIS formatter<char, wchar_t>
431 : public __format::__formatter_char<char, wchar_t> {};
432
433template <>
434struct _LIBCPP_TEMPLATE_VIS formatter<wchar_t, wchar_t>
435 : public __format::__formatter_char<wchar_t, wchar_t> {};
436
Mark de Wevercb50a052020-12-19 13:52:07 +0100437// [format.formatter.spec]/2.3
438// For each charT, for each cv-unqualified arithmetic type ArithmeticT other
439// than char, wchar_t, char8_t, char16_t, or char32_t, a specialization
440
441// Boolean.
442template <class _CharT>
443struct _LIBCPP_TEMPLATE_VIS formatter<bool, _CharT> {
444 _LIBCPP_HIDE_FROM_ABI
445 auto parse(auto& __parse_ctx) -> decltype(__parse_ctx.begin()) {
446 // TODO FMT Implement
447 return __parse_ctx.begin();
448 }
449
450 _LIBCPP_HIDE_FROM_ABI
451 auto format(bool __b, auto& __ctx) -> decltype(__ctx.out()) {
452 // TODO FMT Implement using formatting arguments
453 auto __out_it = __ctx.out();
454 *__out_it++ = _CharT('0') + __b;
455 return __out_it;
456 }
457};
458
459// Signed integral types.
460template <class _CharT>
461struct _LIBCPP_TEMPLATE_VIS formatter<signed char, _CharT>
462 : public __format::__formatter_arithmetic<signed char, _CharT> {};
463template <class _CharT>
464struct _LIBCPP_TEMPLATE_VIS formatter<short, _CharT>
465 : public __format::__formatter_arithmetic<short, _CharT> {};
466template <class _CharT>
467struct _LIBCPP_TEMPLATE_VIS formatter<int, _CharT>
468 : public __format::__formatter_arithmetic<int, _CharT> {};
469template <class _CharT>
470struct _LIBCPP_TEMPLATE_VIS formatter<long, _CharT>
471 : public __format::__formatter_arithmetic<long, _CharT> {};
472template <class _CharT>
473struct _LIBCPP_TEMPLATE_VIS formatter<long long, _CharT>
474 : public __format::__formatter_arithmetic<long long, _CharT> {};
475#ifndef _LIBCPP_HAS_NO_INT128
476template <class _CharT>
477struct _LIBCPP_TEMPLATE_VIS formatter<__int128_t, _CharT>
478 : public __format::__formatter_arithmetic<__int128_t, _CharT> {};
479#endif
480
481// Unsigned integral types.
482template <class _CharT>
483struct _LIBCPP_TEMPLATE_VIS formatter<unsigned char, _CharT>
484 : public __format::__formatter_arithmetic<unsigned char, _CharT> {};
485template <class _CharT>
486struct _LIBCPP_TEMPLATE_VIS formatter<unsigned short, _CharT>
487 : public __format::__formatter_arithmetic<unsigned short, _CharT> {};
488template <class _CharT>
489struct _LIBCPP_TEMPLATE_VIS formatter<unsigned, _CharT>
490 : public __format::__formatter_arithmetic<unsigned, _CharT> {};
491template <class _CharT>
492struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long, _CharT>
493 : public __format::__formatter_arithmetic<unsigned long, _CharT> {};
494template <class _CharT>
495struct _LIBCPP_TEMPLATE_VIS formatter<unsigned long long, _CharT>
496 : public __format::__formatter_arithmetic<unsigned long long, _CharT> {};
497#ifndef _LIBCPP_HAS_NO_INT128
498template <class _CharT>
499struct _LIBCPP_TEMPLATE_VIS formatter<__uint128_t, _CharT>
500 : public __format::__formatter_arithmetic<__uint128_t, _CharT> {};
501#endif
502
503// Floating point types.
504// TODO FMT There are no replacements for the floating point stubs due to not
505// having floating point support in std::to_chars yet. These stubs aren't
506// removed since they are useful for developing the real versions.
507// Ultimately the stubs should be implemented properly and this code can be
508// removed.
509#if 0
510template <class _CharT>
511struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<float, _CharT>
512 : public __format::__formatter_arithmetic<float, _CharT> {};
513template <class _CharT>
514struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT
515 formatter<double, _CharT>
516 : public __format::__formatter_arithmetic<double, _CharT> {};
517template <class _CharT>
518struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT
519 formatter<long double, _CharT>
520 : public __format::__formatter_arithmetic<long double, _CharT> {};
521#endif
522
523namespace __format {
524
525template <class _CharT, class _ParseCtx, class _Ctx>
526_LIBCPP_HIDE_FROM_ABI const _CharT*
527__handle_replacement_field(const _CharT* __begin, const _CharT* __end,
528 _ParseCtx& __parse_ctx, _Ctx& __ctx) {
529 __format::__parse_number_result __r =
530 __format::__parse_arg_id(__begin, __end, __parse_ctx);
531
532 switch (*__r.__ptr) {
533 case _CharT(':'):
534 // The arg-id has a format-specifier, advance the input to the format-spec.
535 __parse_ctx.advance_to(__r.__ptr + 1);
536 break;
537 case _CharT('}'):
538 // The arg-id has no format-specifier.
539 __parse_ctx.advance_to(__r.__ptr);
540 break;
541 default:
542 __throw_format_error(
543 "The replacement field arg-id should terminate at a ':' or '}'");
544 }
545
546 _VSTD::visit_format_arg(
547 [&](auto __arg) {
548 if constexpr (same_as<decltype(__arg), monostate>)
549 __throw_format_error("Argument index out of bounds");
550 else {
551 formatter<decltype(__arg), _CharT> __formatter;
552 __parse_ctx.advance_to(__formatter.parse(__parse_ctx));
553 __ctx.advance_to(__formatter.format(__arg, __ctx));
554 }
555 },
556 __ctx.arg(__r.__value));
557
558 __begin = __parse_ctx.begin();
559 if (__begin == __end || *__begin != _CharT('}'))
560 __throw_format_error("The replacement field misses a terminating '}'");
561
562 return ++__begin;
563}
564
565template <class _ParseCtx, class _Ctx>
566_LIBCPP_HIDE_FROM_ABI typename _Ctx::iterator
567__vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) {
568 using _CharT = typename _ParseCtx::char_type;
569 static_assert(same_as<typename _Ctx::char_type, _CharT>);
570
571 const _CharT* __begin = __parse_ctx.begin();
572 const _CharT* __end = __parse_ctx.end();
573 typename _Ctx::iterator __out_it = __ctx.out();
574 while (__begin != __end) {
575 switch (*__begin) {
576 case _CharT('{'):
577 ++__begin;
578 if (__begin == __end)
579 __throw_format_error("The format string terminates at a '{'");
580
581 if (*__begin != _CharT('{')) [[likely]] {
582 __ctx.advance_to(_VSTD::move(__out_it));
583 __begin =
584 __handle_replacement_field(__begin, __end, __parse_ctx, __ctx);
585 __out_it = __ctx.out();
586
587 // The output is written and __begin points to the next character. So
588 // start the next iteration.
589 continue;
590 }
591 // The string is an escape character.
592 break;
593
594 case _CharT('}'):
595 ++__begin;
596 if (__begin == __end || *__begin != _CharT('}'))
597 __throw_format_error(
598 "The format string contains an invalid escape sequence");
599
600 break;
601 }
602
603 // Copy the character to the output verbatim.
604 *__out_it++ = *__begin++;
605 }
606 return __out_it;
607}
608
609} // namespace __format
610
611template <class _OutIt, class _CharT>
612requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
613 __vformat_to(_OutIt __out_it, basic_string_view<_CharT> __fmt,
614 format_args_t<type_identity_t<_OutIt>, _CharT> __args) {
615 return __format::__vformat_to(
616 basic_format_parse_context{__fmt, __args.__size()},
617 _VSTD::__format_context_create(_VSTD::move(__out_it), __args));
618}
619
620template <output_iterator<const char&> _OutIt>
621_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
622vformat_to(_OutIt __out_it, string_view __fmt,
623 format_args_t<type_identity_t<_OutIt>, char> __args) {
624 return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
625}
626
627template <output_iterator<const wchar_t&> _OutIt>
628_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
629vformat_to(_OutIt __out_it, wstring_view __fmt,
630 format_args_t<type_identity_t<_OutIt>, wchar_t> __args) {
631 return _VSTD::__vformat_to(_VSTD::move(__out_it), __fmt, __args);
632}
633
634template <output_iterator<const char&> _OutIt, class... _Args>
635_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
636format_to(_OutIt __out_it, string_view __fmt, const _Args&... __args) {
637 return _VSTD::vformat_to(
638 _VSTD::move(__out_it), __fmt,
639 _VSTD::make_format_args<basic_format_context<_OutIt, char>>(__args...));
640}
641
642template <output_iterator<const wchar_t&> _OutIt, class... _Args>
643_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
644format_to(_OutIt __out_it, wstring_view __fmt, const _Args&... __args) {
645 return _VSTD::vformat_to(
646 _VSTD::move(__out_it), __fmt,
647 _VSTD::make_format_args<basic_format_context<_OutIt, wchar_t>>(
648 __args...));
649}
650
651inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
652vformat(string_view __fmt, format_args __args) {
653 string __res;
654 _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
655 return __res;
656}
657
658inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
659vformat(wstring_view __fmt, wformat_args __args) {
660 wstring __res;
661 _VSTD::vformat_to(_VSTD::back_inserter(__res), __fmt, __args);
662 return __res;
663}
664
665template <class... _Args>
666_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
667format(string_view __fmt, const _Args&... __args) {
668 return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...));
669}
670
671template <class... _Args>
672_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
673format(wstring_view __fmt, const _Args&... __args) {
674 return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...));
675}
676
677template <class _OutIt>
678struct _LIBCPP_TEMPLATE_VIS format_to_n_result {
679 _OutIt out;
680 iter_difference_t<_OutIt> size;
681};
682
683template <output_iterator<const char&> _OutIt, class... _Args>
684_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
685format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, string_view __fmt,
686 const _Args&... __args) {
687 // TODO FMT Improve PoC: using std::string is inefficient.
688 string __str = _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...));
689 iter_difference_t<_OutIt> __s = __str.size();
690 iter_difference_t<_OutIt> __m =
691 _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
692 __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
693 return {_VSTD::move(__out_it), __s};
694}
695
696template <output_iterator<const wchar_t&> _OutIt, class... _Args>
697_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
698format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wstring_view __fmt,
699 const _Args&... __args) {
700 // TODO FMT Improve PoC: using std::string is inefficient.
701 wstring __str = _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...));
702 iter_difference_t<_OutIt> __s = __str.size();
703 iter_difference_t<_OutIt> __m =
704 _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
705 __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
706 return {_VSTD::move(__out_it), __s};
707}
708
709template <class... _Args>
710_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
711formatted_size(string_view __fmt, const _Args&... __args) {
712 // TODO FMT Improve PoC: using std::string is inefficient.
713 return _VSTD::vformat(__fmt, _VSTD::make_format_args(__args...)).size();
714}
715
716template <class... _Args>
717_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
718formatted_size(wstring_view __fmt, const _Args&... __args) {
719 // TODO FMT Improve PoC: using std::string is inefficient.
720 return _VSTD::vformat(__fmt, _VSTD::make_wformat_args(__args...)).size();
721}
722
723#ifndef _LIBCPP_HAS_NO_LOCALIZATION
724
725template <class _OutIt, class _CharT>
726requires(output_iterator<_OutIt, const _CharT&>) _LIBCPP_HIDE_FROM_ABI _OutIt
727 __vformat_to(_OutIt __out_it, locale __loc, basic_string_view<_CharT> __fmt,
728 format_args_t<type_identity_t<_OutIt>, _CharT> __args) {
729 return __format::__vformat_to(
730 basic_format_parse_context{__fmt, __args.__size()},
731 _VSTD::__format_context_create(_VSTD::move(__out_it), __args,
732 _VSTD::move(__loc)));
733}
734
735template <output_iterator<const char&> _OutIt>
736_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
737vformat_to(_OutIt __out_it, locale __loc, string_view __fmt,
738 format_args_t<type_identity_t<_OutIt>, char> __args) {
739 return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
740 __args);
741}
742
743template <output_iterator<const wchar_t&> _OutIt>
744_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt
745vformat_to(_OutIt __out_it, locale __loc, wstring_view __fmt,
746 format_args_t<type_identity_t<_OutIt>, wchar_t> __args) {
747 return _VSTD::__vformat_to(_VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
748 __args);
749}
750
751template <output_iterator<const char&> _OutIt, class... _Args>
752_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to(
753 _OutIt __out_it, locale __loc, string_view __fmt, const _Args&... __args) {
754 return _VSTD::vformat_to(
755 _VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
756 _VSTD::make_format_args<basic_format_context<_OutIt, char>>(__args...));
757}
758
759template <output_iterator<const wchar_t&> _OutIt, class... _Args>
760_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT _OutIt format_to(
761 _OutIt __out_it, locale __loc, wstring_view __fmt, const _Args&... __args) {
762 return _VSTD::vformat_to(
763 _VSTD::move(__out_it), _VSTD::move(__loc), __fmt,
764 _VSTD::make_format_args<basic_format_context<_OutIt, wchar_t>>(
765 __args...));
766}
767
768inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
769vformat(locale __loc, string_view __fmt, format_args __args) {
770 string __res;
771 _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
772 __args);
773 return __res;
774}
775
776inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
777vformat(locale __loc, wstring_view __fmt, wformat_args __args) {
778 wstring __res;
779 _VSTD::vformat_to(_VSTD::back_inserter(__res), _VSTD::move(__loc), __fmt,
780 __args);
781 return __res;
782}
783
784template <class... _Args>
785_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT string
786format(locale __loc, string_view __fmt, const _Args&... __args) {
787 return _VSTD::vformat(_VSTD::move(__loc), __fmt,
788 _VSTD::make_format_args(__args...));
789}
790
791template <class... _Args>
792_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT wstring
793format(locale __loc, wstring_view __fmt, const _Args&... __args) {
794 return _VSTD::vformat(_VSTD::move(__loc), __fmt,
795 _VSTD::make_wformat_args(__args...));
796}
797
798template <output_iterator<const char&> _OutIt, class... _Args>
799_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
800format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc,
801 string_view __fmt, const _Args&... __args) {
802 // TODO FMT Improve PoC: using std::string is inefficient.
803 string __str = _VSTD::vformat(_VSTD::move(__loc), __fmt,
804 _VSTD::make_format_args(__args...));
805 iter_difference_t<_OutIt> __s = __str.size();
806 iter_difference_t<_OutIt> __m =
807 _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
808 __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
809 return {_VSTD::move(__out_it), __s};
810}
811
812template <output_iterator<const wchar_t&> _OutIt, class... _Args>
813_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT format_to_n_result<_OutIt>
814format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc,
815 wstring_view __fmt, const _Args&... __args) {
816 // TODO FMT Improve PoC: using std::string is inefficient.
817 wstring __str = _VSTD::vformat(_VSTD::move(__loc), __fmt,
818 _VSTD::make_wformat_args(__args...));
819 iter_difference_t<_OutIt> __s = __str.size();
820 iter_difference_t<_OutIt> __m =
821 _VSTD::clamp(__n, iter_difference_t<_OutIt>(0), __s);
822 __out_it = _VSTD::copy_n(__str.begin(), __m, _VSTD::move(__out_it));
823 return {_VSTD::move(__out_it), __s};
824}
825
826template <class... _Args>
827_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
828formatted_size(locale __loc, string_view __fmt, const _Args&... __args) {
829 // TODO FMT Improve PoC: using std::string is inefficient.
830 return _VSTD::vformat(_VSTD::move(__loc), __fmt,
831 _VSTD::make_format_args(__args...))
832 .size();
833}
834
835template <class... _Args>
836_LIBCPP_HIDE_FROM_ABI _LIBCPP_AVAILABILITY_FORMAT size_t
837formatted_size(locale __loc, wstring_view __fmt, const _Args&... __args) {
838 // TODO FMT Improve PoC: using std::string is inefficient.
839 return _VSTD::vformat(_VSTD::move(__loc), __fmt,
840 _VSTD::make_wformat_args(__args...))
841 .size();
842}
843
Louis Dionneaf2c8142021-09-09 14:43:02 -0400844#endif // _LIBCPP_HAS_NO_LOCALIZATION
Mark de Wevercb50a052020-12-19 13:52:07 +0100845
Mark de Wevercba61372020-12-05 11:45:21 +0100846#endif // !defined(_LIBCPP_HAS_NO_CONCEPTS)
847#endif //_LIBCPP_STD_VER > 17
848
849_LIBCPP_END_NAMESPACE_STD
850
Mark de Wevercb50a052020-12-19 13:52:07 +0100851_LIBCPP_POP_MACROS
852
Mark de Wever14151d22021-07-30 14:35:37 -0400853#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
854
Mark de Weverdf5fd832020-11-26 19:12:18 +0100855#endif // _LIBCPP_FORMAT