Warning: This file is not a C or C++ file. It does not have highlighting.
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_FORMAT_FUNCTIONS |
11 | #define _LIBCPP___FORMAT_FORMAT_FUNCTIONS |
12 | |
13 | #include <__algorithm/clamp.h> |
14 | #include <__algorithm/ranges_find_first_of.h> |
15 | #include <__chrono/statically_widen.h> |
16 | #include <__concepts/convertible_to.h> |
17 | #include <__concepts/same_as.h> |
18 | #include <__config> |
19 | #include <__format/buffer.h> |
20 | #include <__format/format_arg.h> |
21 | #include <__format/format_arg_store.h> |
22 | #include <__format/format_args.h> |
23 | #include <__format/format_context.h> |
24 | #include <__format/format_error.h> |
25 | #include <__format/format_parse_context.h> |
26 | #include <__format/format_string.h> |
27 | #include <__format/format_to_n_result.h> |
28 | #include <__format/formatter.h> |
29 | #include <__format/formatter_bool.h> |
30 | #include <__format/formatter_char.h> |
31 | #include <__format/formatter_floating_point.h> |
32 | #include <__format/formatter_integer.h> |
33 | #include <__format/formatter_pointer.h> |
34 | #include <__format/formatter_string.h> |
35 | #include <__format/parser_std_format_spec.h> |
36 | #include <__iterator/concepts.h> |
37 | #include <__iterator/incrementable_traits.h> |
38 | #include <__iterator/iterator_traits.h> // iter_value_t |
39 | #include <__variant/monostate.h> |
40 | #include <array> |
41 | #include <optional> |
42 | #include <string> |
43 | #include <string_view> |
44 | |
45 | #if _LIBCPP_HAS_LOCALIZATION |
46 | # include <__locale> |
47 | #endif |
48 | |
49 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
50 | # pragma GCC system_header |
51 | #endif |
52 | |
53 | _LIBCPP_PUSH_MACROS |
54 | #include <__undef_macros> |
55 | |
56 | _LIBCPP_BEGIN_NAMESPACE_STD |
57 | |
58 | #if _LIBCPP_STD_VER >= 20 |
59 | |
60 | // TODO FMT Evaluate which templates should be external templates. This |
61 | // improves the efficiency of the header. However since the header is still |
62 | // under heavy development and not all classes are stable it makes no sense |
63 | // to do this optimization now. |
64 | |
65 | using format_args = basic_format_args<format_context>; |
66 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
67 | using wformat_args = basic_format_args<wformat_context>; |
68 | # endif |
69 | |
70 | template <class _Context = format_context, class... _Args> |
71 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __format_arg_store<_Context, _Args...> make_format_args(_Args&... __args) { |
72 | return std::__format_arg_store<_Context, _Args...>(__args...); |
73 | } |
74 | |
75 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
76 | template <class... _Args> |
77 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI __format_arg_store<wformat_context, _Args...> make_wformat_args(_Args&... __args) { |
78 | return std::__format_arg_store<wformat_context, _Args...>(__args...); |
79 | } |
80 | # endif |
81 | |
82 | namespace __format { |
83 | |
84 | /// Helper class parse and handle argument. |
85 | /// |
86 | /// When parsing a handle which is not enabled the code is ill-formed. |
87 | /// This helper uses the parser of the appropriate formatter for the stored type. |
88 | template <class _CharT> |
89 | class __compile_time_handle { |
90 | public: |
91 | template <class _ParseContext> |
92 | _LIBCPP_HIDE_FROM_ABI constexpr void __parse(_ParseContext& __ctx) const { |
93 | __parse_(__ctx); |
94 | } |
95 | |
96 | template <class _Tp> |
97 | _LIBCPP_HIDE_FROM_ABI constexpr void __enable() { |
98 | __parse_ = [](basic_format_parse_context<_CharT>& __ctx) { |
99 | formatter<_Tp, _CharT> __f; |
100 | __ctx.advance_to(__f.parse(__ctx)); |
101 | }; |
102 | } |
103 | |
104 | // Before calling __parse the proper handler needs to be set with __enable. |
105 | // The default handler isn't a core constant expression. |
106 | _LIBCPP_HIDE_FROM_ABI constexpr __compile_time_handle() |
107 | : __parse_([](basic_format_parse_context<_CharT>&) { std::__throw_format_error("Not a handle"); }) {} |
108 | |
109 | private: |
110 | void (*__parse_)(basic_format_parse_context<_CharT>&); |
111 | }; |
112 | |
113 | // Dummy format_context only providing the parts used during constant |
114 | // validation of the basic_format_string. |
115 | template <class _CharT> |
116 | struct __compile_time_basic_format_context { |
117 | public: |
118 | using char_type = _CharT; |
119 | |
120 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __compile_time_basic_format_context( |
121 | const __arg_t* __args, const __compile_time_handle<_CharT>* __handles, size_t __size) |
122 | : __args_(__args), __handles_(__handles), __size_(__size) {} |
123 | |
124 | // During the compile-time validation nothing needs to be written. |
125 | // Therefore all operations of this iterator are a NOP. |
126 | struct iterator { |
127 | _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator=(_CharT) { return *this; } |
128 | _LIBCPP_HIDE_FROM_ABI constexpr iterator& operator*() { return *this; } |
129 | _LIBCPP_HIDE_FROM_ABI constexpr iterator operator++(int) { return *this; } |
130 | }; |
131 | |
132 | _LIBCPP_HIDE_FROM_ABI constexpr __arg_t arg(size_t __id) const { |
133 | if (__id >= __size_) |
134 | std::__throw_format_error("The argument index value is too large for the number of arguments supplied"); |
135 | return __args_[__id]; |
136 | } |
137 | |
138 | _LIBCPP_HIDE_FROM_ABI constexpr const __compile_time_handle<_CharT>& __handle(size_t __id) const { |
139 | if (__id >= __size_) |
140 | std::__throw_format_error("The argument index value is too large for the number of arguments supplied"); |
141 | return __handles_[__id]; |
142 | } |
143 | |
144 | _LIBCPP_HIDE_FROM_ABI constexpr iterator out() { return {}; } |
145 | _LIBCPP_HIDE_FROM_ABI constexpr void advance_to(iterator) {} |
146 | |
147 | private: |
148 | const __arg_t* __args_; |
149 | const __compile_time_handle<_CharT>* __handles_; |
150 | size_t __size_; |
151 | }; |
152 | |
153 | // [format.string.std]/8 |
154 | // If { arg-idopt } is used in a width or precision, the value of the |
155 | // corresponding formatting argument is used in its place. If the |
156 | // corresponding formatting argument is not of standard signed or unsigned |
157 | // integer type, or its value is negative for precision or non-positive for |
158 | // width, an exception of type format_error is thrown. |
159 | // |
160 | // _HasPrecision does the formatter have a precision? |
161 | template <class _CharT, class _Tp, bool _HasPrecision = false> |
162 | _LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_validate_argument( |
163 | basic_format_parse_context<_CharT>& __parse_ctx, __compile_time_basic_format_context<_CharT>& __ctx) { |
164 | auto __validate_type = [](__arg_t __type) { |
165 | // LWG3720 originally allowed "signed or unsigned integer types", however |
166 | // the final version explicitly changed it to "*standard* signed or unsigned |
167 | // integer types". It's trivial to use 128-bit integrals in libc++'s |
168 | // implementation, but other implementations may not implement it. |
169 | // (Using a width or precision, that does not fit in 64-bits, sounds very |
170 | // unlikely in real world code.) |
171 | switch (__type) { |
172 | case __arg_t::__int: |
173 | case __arg_t::__long_long: |
174 | case __arg_t::__unsigned: |
175 | case __arg_t::__unsigned_long_long: |
176 | return; |
177 | |
178 | default: |
179 | std::__throw_format_error("Replacement argument isn't a standard signed or unsigned integer type"); |
180 | } |
181 | }; |
182 | |
183 | formatter<_Tp, _CharT> __formatter; |
184 | __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); |
185 | if (__formatter.__parser_.__width_as_arg_) |
186 | __validate_type(__ctx.arg(__formatter.__parser_.__width_)); |
187 | |
188 | if constexpr (_HasPrecision) |
189 | if (__formatter.__parser_.__precision_as_arg_) |
190 | __validate_type(__ctx.arg(__formatter.__parser_.__precision_)); |
191 | } |
192 | |
193 | // This function is not user facing, so it can directly use the non-standard types of the "variant". |
194 | template <class _CharT> |
195 | _LIBCPP_HIDE_FROM_ABI constexpr void __compile_time_visit_format_arg( |
196 | basic_format_parse_context<_CharT>& __parse_ctx, |
197 | __compile_time_basic_format_context<_CharT>& __ctx, |
198 | __arg_t __type) { |
199 | switch (__type) { |
200 | case __arg_t::__none: |
201 | std::__throw_format_error("Invalid argument"); |
202 | case __arg_t::__boolean: |
203 | return __format::__compile_time_validate_argument<_CharT, bool>(__parse_ctx, __ctx); |
204 | case __arg_t::__char_type: |
205 | return __format::__compile_time_validate_argument<_CharT, _CharT>(__parse_ctx, __ctx); |
206 | case __arg_t::__int: |
207 | return __format::__compile_time_validate_argument<_CharT, int>(__parse_ctx, __ctx); |
208 | case __arg_t::__long_long: |
209 | return __format::__compile_time_validate_argument<_CharT, long long>(__parse_ctx, __ctx); |
210 | case __arg_t::__i128: |
211 | # if _LIBCPP_HAS_INT128 |
212 | return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx); |
213 | # else |
214 | std::__throw_format_error("Invalid argument"); |
215 | # endif |
216 | return; |
217 | case __arg_t::__unsigned: |
218 | return __format::__compile_time_validate_argument<_CharT, unsigned>(__parse_ctx, __ctx); |
219 | case __arg_t::__unsigned_long_long: |
220 | return __format::__compile_time_validate_argument<_CharT, unsigned long long>(__parse_ctx, __ctx); |
221 | case __arg_t::__u128: |
222 | # if _LIBCPP_HAS_INT128 |
223 | return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx); |
224 | # else |
225 | std::__throw_format_error("Invalid argument"); |
226 | # endif |
227 | return; |
228 | case __arg_t::__float: |
229 | return __format::__compile_time_validate_argument<_CharT, float, true>(__parse_ctx, __ctx); |
230 | case __arg_t::__double: |
231 | return __format::__compile_time_validate_argument<_CharT, double, true>(__parse_ctx, __ctx); |
232 | case __arg_t::__long_double: |
233 | return __format::__compile_time_validate_argument<_CharT, long double, true>(__parse_ctx, __ctx); |
234 | case __arg_t::__const_char_type_ptr: |
235 | return __format::__compile_time_validate_argument<_CharT, const _CharT*, true>(__parse_ctx, __ctx); |
236 | case __arg_t::__string_view: |
237 | return __format::__compile_time_validate_argument<_CharT, basic_string_view<_CharT>, true>(__parse_ctx, __ctx); |
238 | case __arg_t::__ptr: |
239 | return __format::__compile_time_validate_argument<_CharT, const void*>(__parse_ctx, __ctx); |
240 | case __arg_t::__handle: |
241 | std::__throw_format_error("Handle should use __compile_time_validate_handle_argument"); |
242 | } |
243 | std::__throw_format_error("Invalid argument"); |
244 | } |
245 | |
246 | template <contiguous_iterator _Iterator, class _ParseCtx, class _Ctx> |
247 | _LIBCPP_HIDE_FROM_ABI constexpr _Iterator |
248 | __handle_replacement_field(_Iterator __begin, _Iterator __end, _ParseCtx& __parse_ctx, _Ctx& __ctx) { |
249 | using _CharT = iter_value_t<_Iterator>; |
250 | __format::__parse_number_result __r = __format::__parse_arg_id(__begin, __end, __parse_ctx); |
251 | |
252 | if (__r.__last == __end) |
253 | std::__throw_format_error("The argument index should end with a ':' or a '}'"); |
254 | |
255 | bool __parse = *__r.__last == _CharT(':'); |
256 | switch (*__r.__last) { |
257 | case _CharT(':'): |
258 | // The arg-id has a format-specifier, advance the input to the format-spec. |
259 | __parse_ctx.advance_to(__r.__last + 1); |
260 | break; |
261 | case _CharT('}'): |
262 | // The arg-id has no format-specifier. |
263 | __parse_ctx.advance_to(__r.__last); |
264 | break; |
265 | default: |
266 | std::__throw_format_error("The argument index should end with a ':' or a '}'"); |
267 | } |
268 | |
269 | if constexpr (same_as<_Ctx, __compile_time_basic_format_context<_CharT>>) { |
270 | __arg_t __type = __ctx.arg(__r.__value); |
271 | if (__type == __arg_t::__none) |
272 | std::__throw_format_error("The argument index value is too large for the number of arguments supplied"); |
273 | else if (__type == __arg_t::__handle) |
274 | __ctx.__handle(__r.__value).__parse(__parse_ctx); |
275 | else if (__parse) |
276 | __format::__compile_time_visit_format_arg(__parse_ctx, __ctx, __type); |
277 | } else |
278 | std::__visit_format_arg( |
279 | [&](auto __arg) { |
280 | if constexpr (same_as<decltype(__arg), monostate>) |
281 | std::__throw_format_error("The argument index value is too large for the number of arguments supplied"); |
282 | else if constexpr (same_as<decltype(__arg), typename basic_format_arg<_Ctx>::handle>) |
283 | __arg.format(__parse_ctx, __ctx); |
284 | else { |
285 | formatter<decltype(__arg), _CharT> __formatter; |
286 | if (__parse) |
287 | __parse_ctx.advance_to(__formatter.parse(__parse_ctx)); |
288 | __ctx.advance_to(__formatter.format(__arg, __ctx)); |
289 | } |
290 | }, |
291 | __ctx.arg(__r.__value)); |
292 | |
293 | __begin = __parse_ctx.begin(); |
294 | if (__begin == __end || *__begin != _CharT('}')) |
295 | std::__throw_format_error("The replacement field misses a terminating '}'"); |
296 | |
297 | return ++__begin; |
298 | } |
299 | |
300 | template <class _ParseCtx, class _Ctx> |
301 | _LIBCPP_HIDE_FROM_ABI constexpr typename _Ctx::iterator __vformat_to(_ParseCtx&& __parse_ctx, _Ctx&& __ctx) { |
302 | using _CharT = typename _ParseCtx::char_type; |
303 | static_assert(same_as<typename _Ctx::char_type, _CharT>); |
304 | |
305 | auto __begin = __parse_ctx.begin(); |
306 | auto __end = __parse_ctx.end(); |
307 | typename _Ctx::iterator __out_it = __ctx.out(); |
308 | while (__begin != __end) { |
309 | switch (*__begin) { |
310 | case _CharT('{'): |
311 | ++__begin; |
312 | if (__begin == __end) |
313 | std::__throw_format_error("The format string terminates at a '{'"); |
314 | |
315 | if (*__begin != _CharT('{')) [[likely]] { |
316 | __ctx.advance_to(std::move(__out_it)); |
317 | __begin = __format::__handle_replacement_field(__begin, __end, __parse_ctx, __ctx); |
318 | __out_it = __ctx.out(); |
319 | |
320 | // The output is written and __begin points to the next character. So |
321 | // start the next iteration. |
322 | continue; |
323 | } |
324 | // The string is an escape character. |
325 | break; |
326 | |
327 | case _CharT('}'): |
328 | ++__begin; |
329 | if (__begin == __end || *__begin != _CharT('}')) |
330 | std::__throw_format_error("The format string contains an invalid escape sequence"); |
331 | |
332 | break; |
333 | } |
334 | |
335 | // Copy the character to the output verbatim. |
336 | *__out_it++ = *__begin++; |
337 | } |
338 | return __out_it; |
339 | } |
340 | |
341 | } // namespace __format |
342 | |
343 | # if _LIBCPP_STD_VER >= 26 |
344 | template <class _CharT> |
345 | struct __runtime_format_string { |
346 | private: |
347 | basic_string_view<_CharT> __str_; |
348 | |
349 | template <class _Cp, class... _Args> |
350 | friend struct basic_format_string; |
351 | |
352 | public: |
353 | _LIBCPP_HIDE_FROM_ABI __runtime_format_string(basic_string_view<_CharT> __s) noexcept : __str_(__s) {} |
354 | |
355 | __runtime_format_string(const __runtime_format_string&) = delete; |
356 | __runtime_format_string& operator=(const __runtime_format_string&) = delete; |
357 | }; |
358 | |
359 | _LIBCPP_HIDE_FROM_ABI inline __runtime_format_string<char> runtime_format(string_view __fmt) noexcept { return __fmt; } |
360 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
361 | _LIBCPP_HIDE_FROM_ABI inline __runtime_format_string<wchar_t> runtime_format(wstring_view __fmt) noexcept { |
362 | return __fmt; |
363 | } |
364 | # endif |
365 | # endif // _LIBCPP_STD_VER >= 26 |
366 | |
367 | template <class _CharT, class... _Args> |
368 | struct basic_format_string { |
369 | template <class _Tp> |
370 | requires convertible_to<const _Tp&, basic_string_view<_CharT>> |
371 | consteval basic_format_string(const _Tp& __str) : __str_{__str} { |
372 | __format::__vformat_to(basic_format_parse_context<_CharT>{__str_, sizeof...(_Args)}, |
373 | _Context{__types_.data(), __handles_.data(), sizeof...(_Args)}); |
374 | } |
375 | |
376 | _LIBCPP_HIDE_FROM_ABI constexpr basic_string_view<_CharT> get() const noexcept { return __str_; } |
377 | # if _LIBCPP_STD_VER >= 26 |
378 | _LIBCPP_HIDE_FROM_ABI basic_format_string(__runtime_format_string<_CharT> __s) noexcept : __str_(__s.__str_) {} |
379 | # endif |
380 | |
381 | private: |
382 | basic_string_view<_CharT> __str_; |
383 | |
384 | using _Context _LIBCPP_NODEBUG = __format::__compile_time_basic_format_context<_CharT>; |
385 | |
386 | static constexpr array<__format::__arg_t, sizeof...(_Args)> __types_{ |
387 | __format::__determine_arg_t<_Context, remove_cvref_t<_Args>>()...}; |
388 | |
389 | static constexpr array<__format::__compile_time_handle<_CharT>, sizeof...(_Args)> __handles_{[] { |
390 | using _Tp = remove_cvref_t<_Args>; |
391 | __format::__compile_time_handle<_CharT> __handle; |
392 | if (__format::__determine_arg_t<_Context, _Tp>() == __format::__arg_t::__handle) |
393 | __handle.template __enable<_Tp>(); |
394 | |
395 | return __handle; |
396 | }()...}; |
397 | }; |
398 | |
399 | template <class... _Args> |
400 | using format_string = basic_format_string<char, type_identity_t<_Args>...>; |
401 | |
402 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
403 | template <class... _Args> |
404 | using wformat_string = basic_format_string<wchar_t, type_identity_t<_Args>...>; |
405 | # endif |
406 | |
407 | template <class _OutIt, class _CharT, class _FormatOutIt> |
408 | requires(output_iterator<_OutIt, const _CharT&>) |
409 | _LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to(_OutIt __out_it, |
410 | basic_string_view<_CharT> __fmt, |
411 | basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) { |
412 | if constexpr (same_as<_OutIt, _FormatOutIt>) |
413 | return std::__format::__vformat_to( |
414 | basic_format_parse_context{__fmt, __args.__size()}, std::__format_context_create(std::move(__out_it), __args)); |
415 | else { |
416 | typename __format::__buffer_selector<_OutIt, _CharT>::type __buffer{std::move(__out_it)}; |
417 | std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, |
418 | std::__format_context_create(__buffer.__make_output_iterator(), __args)); |
419 | return std::move(__buffer).__out_it(); |
420 | } |
421 | } |
422 | |
423 | // The function is _LIBCPP_ALWAYS_INLINE since the compiler is bad at inlining |
424 | // https://reviews.llvm.org/D110499#inline-1180704 |
425 | // TODO FMT Evaluate whether we want to file a Clang bug report regarding this. |
426 | template <output_iterator<const char&> _OutIt> |
427 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt vformat_to(_OutIt __out_it, string_view __fmt, format_args __args) { |
428 | return std::__vformat_to(std::move(__out_it), __fmt, __args); |
429 | } |
430 | |
431 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
432 | template <output_iterator<const wchar_t&> _OutIt> |
433 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt |
434 | vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) { |
435 | return std::__vformat_to(std::move(__out_it), __fmt, __args); |
436 | } |
437 | # endif |
438 | |
439 | template <output_iterator<const char&> _OutIt, class... _Args> |
440 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt |
441 | format_to(_OutIt __out_it, format_string<_Args...> __fmt, _Args&&... __args) { |
442 | return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_format_args(__args...)); |
443 | } |
444 | |
445 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
446 | template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
447 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt |
448 | format_to(_OutIt __out_it, wformat_string<_Args...> __fmt, _Args&&... __args) { |
449 | return std::vformat_to(std::move(__out_it), __fmt.get(), std::make_wformat_args(__args...)); |
450 | } |
451 | # endif |
452 | |
453 | // Try constant folding the format string instead of going through the whole formatting machinery. If there is no |
454 | // constant folding no extra code should be emitted (with optimizations enabled) and the function returns nullopt. When |
455 | // constant folding is successful, the formatting is performed and the resulting string is returned. |
456 | namespace __format { |
457 | template <class _CharT> |
458 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI optional<basic_string<_CharT>> __try_constant_folding( |
459 | basic_string_view<_CharT> __fmt, |
460 | basic_format_args<basic_format_context<back_insert_iterator<__format::__output_buffer<_CharT>>, _CharT>> __args) { |
461 | // Fold strings not containing '{' or '}' to just return the string |
462 | if (bool __is_identity = [&] [[__gnu__::__pure__]] // Make sure the compiler knows this call can be eliminated |
463 | { return std::ranges::find_first_of(__fmt, array{'{', '}'}) == __fmt.end(); }(); |
464 | __builtin_constant_p(__is_identity) && __is_identity) |
465 | return basic_string<_CharT>{__fmt}; |
466 | |
467 | // Fold '{}' to the appropriate conversion function |
468 | if (auto __only_first_arg = __fmt == _LIBCPP_STATICALLY_WIDEN(_CharT, "{}"); |
469 | __builtin_constant_p(__only_first_arg) && __only_first_arg) { |
470 | if (auto __arg = __args.get(0); __builtin_constant_p(__arg.__type_)) { |
471 | return std::__visit_format_arg( |
472 | []<class _Tp>(_Tp&& __argument) -> optional<basic_string<_CharT>> { |
473 | if constexpr (is_same_v<remove_cvref_t<_Tp>, basic_string_view<_CharT>>) { |
474 | return basic_string<_CharT>{__argument}; |
475 | } else { |
476 | return nullopt; |
477 | } |
478 | }, |
479 | __arg); |
480 | } |
481 | } |
482 | |
483 | return nullopt; |
484 | } |
485 | } // namespace __format |
486 | |
487 | // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup |
488 | // fires too eagerly, see http://llvm.org/PR61563. |
489 | template <class = void> |
490 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string vformat(string_view __fmt, format_args __args) { |
491 | auto __result = __format::__try_constant_folding(__fmt, __args); |
492 | if (__result.has_value()) |
493 | return *std::move(__result); |
494 | __format::__allocating_buffer<char> __buffer; |
495 | std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args); |
496 | return string{__buffer.__view()}; |
497 | } |
498 | |
499 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
500 | // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup |
501 | // fires too eagerly, see http://llvm.org/PR61563. |
502 | template <class = void> |
503 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring |
504 | vformat(wstring_view __fmt, wformat_args __args) { |
505 | auto __result = __format::__try_constant_folding(__fmt, __args); |
506 | if (__result.has_value()) |
507 | return *std::move(__result); |
508 | __format::__allocating_buffer<wchar_t> __buffer; |
509 | std::vformat_to(__buffer.__make_output_iterator(), __fmt, __args); |
510 | return wstring{__buffer.__view()}; |
511 | } |
512 | # endif |
513 | |
514 | template <class... _Args> |
515 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string |
516 | format(format_string<_Args...> __fmt, _Args&&... __args) { |
517 | return std::vformat(__fmt.get(), std::make_format_args(__args...)); |
518 | } |
519 | |
520 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
521 | template <class... _Args> |
522 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring |
523 | format(wformat_string<_Args...> __fmt, _Args&&... __args) { |
524 | return std::vformat(__fmt.get(), std::make_wformat_args(__args...)); |
525 | } |
526 | # endif |
527 | |
528 | template <class _Context, class _OutIt, class _CharT> |
529 | _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> |
530 | __vformat_to_n(_OutIt __out_it, |
531 | iter_difference_t<_OutIt> __n, |
532 | basic_string_view<_CharT> __fmt, |
533 | basic_format_args<_Context> __args) { |
534 | __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{std::move(__out_it), __n}; |
535 | std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, |
536 | std::__format_context_create(__buffer.__make_output_iterator(), __args)); |
537 | return std::move(__buffer).__result(); |
538 | } |
539 | |
540 | template <output_iterator<const char&> _OutIt, class... _Args> |
541 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> |
542 | format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, format_string<_Args...> __fmt, _Args&&... __args) { |
543 | return std::__vformat_to_n<format_context>(std::move(__out_it), __n, __fmt.get(), std::make_format_args(__args...)); |
544 | } |
545 | |
546 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
547 | template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
548 | _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> |
549 | format_to_n(_OutIt __out_it, iter_difference_t<_OutIt> __n, wformat_string<_Args...> __fmt, _Args&&... __args) { |
550 | return std::__vformat_to_n<wformat_context>(std::move(__out_it), __n, __fmt.get(), std::make_wformat_args(__args...)); |
551 | } |
552 | # endif |
553 | |
554 | template <class _CharT> |
555 | _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(basic_string_view<_CharT> __fmt, auto __args) { |
556 | __format::__formatted_size_buffer<_CharT> __buffer; |
557 | std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, |
558 | std::__format_context_create(__buffer.__make_output_iterator(), __args)); |
559 | return std::move(__buffer).__result(); |
560 | } |
561 | |
562 | template <class... _Args> |
563 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t |
564 | formatted_size(format_string<_Args...> __fmt, _Args&&... __args) { |
565 | return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_format_args(__args...)}); |
566 | } |
567 | |
568 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
569 | template <class... _Args> |
570 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t |
571 | formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) { |
572 | return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_wformat_args(__args...)}); |
573 | } |
574 | # endif |
575 | |
576 | # if _LIBCPP_HAS_LOCALIZATION |
577 | |
578 | template <class _OutIt, class _CharT, class _FormatOutIt> |
579 | requires(output_iterator<_OutIt, const _CharT&>) |
580 | _LIBCPP_HIDE_FROM_ABI _OutIt __vformat_to( |
581 | _OutIt __out_it, |
582 | locale __loc, |
583 | basic_string_view<_CharT> __fmt, |
584 | basic_format_args<basic_format_context<_FormatOutIt, _CharT>> __args) { |
585 | if constexpr (same_as<_OutIt, _FormatOutIt>) |
586 | return std::__format::__vformat_to(basic_format_parse_context{__fmt, __args.__size()}, |
587 | std::__format_context_create(std::move(__out_it), __args, std::move(__loc))); |
588 | else { |
589 | typename __format::__buffer_selector<_OutIt, _CharT>::type __buffer{std::move(__out_it)}; |
590 | std::__format::__vformat_to( |
591 | basic_format_parse_context{__fmt, __args.__size()}, |
592 | std::__format_context_create(__buffer.__make_output_iterator(), __args, std::move(__loc))); |
593 | return std::move(__buffer).__out_it(); |
594 | } |
595 | } |
596 | |
597 | template <output_iterator<const char&> _OutIt> |
598 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt |
599 | vformat_to(_OutIt __out_it, locale __loc, string_view __fmt, format_args __args) { |
600 | return std::__vformat_to(std::move(__out_it), std::move(__loc), __fmt, __args); |
601 | } |
602 | |
603 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
604 | template <output_iterator<const wchar_t&> _OutIt> |
605 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt |
606 | vformat_to(_OutIt __out_it, locale __loc, wstring_view __fmt, wformat_args __args) { |
607 | return std::__vformat_to(std::move(__out_it), std::move(__loc), __fmt, __args); |
608 | } |
609 | # endif |
610 | |
611 | template <output_iterator<const char&> _OutIt, class... _Args> |
612 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt |
613 | format_to(_OutIt __out_it, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { |
614 | return std::vformat_to(std::move(__out_it), std::move(__loc), __fmt.get(), std::make_format_args(__args...)); |
615 | } |
616 | |
617 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
618 | template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
619 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt |
620 | format_to(_OutIt __out_it, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { |
621 | return std::vformat_to(std::move(__out_it), std::move(__loc), __fmt.get(), std::make_wformat_args(__args...)); |
622 | } |
623 | # endif |
624 | |
625 | // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup |
626 | // fires too eagerly, see http://llvm.org/PR61563. |
627 | template <class = void> |
628 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string |
629 | vformat(locale __loc, string_view __fmt, format_args __args) { |
630 | __format::__allocating_buffer<char> __buffer; |
631 | std::vformat_to(__buffer.__make_output_iterator(), std::move(__loc), __fmt, __args); |
632 | return string{__buffer.__view()}; |
633 | } |
634 | |
635 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
636 | // TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup |
637 | // fires too eagerly, see http://llvm.org/PR61563. |
638 | template <class = void> |
639 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring |
640 | vformat(locale __loc, wstring_view __fmt, wformat_args __args) { |
641 | __format::__allocating_buffer<wchar_t> __buffer; |
642 | std::vformat_to(__buffer.__make_output_iterator(), std::move(__loc), __fmt, __args); |
643 | return wstring{__buffer.__view()}; |
644 | } |
645 | # endif |
646 | |
647 | template <class... _Args> |
648 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string |
649 | format(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { |
650 | return std::vformat(std::move(__loc), __fmt.get(), std::make_format_args(__args...)); |
651 | } |
652 | |
653 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
654 | template <class... _Args> |
655 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring |
656 | format(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { |
657 | return std::vformat(std::move(__loc), __fmt.get(), std::make_wformat_args(__args...)); |
658 | } |
659 | # endif |
660 | |
661 | template <class _Context, class _OutIt, class _CharT> |
662 | _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> __vformat_to_n( |
663 | _OutIt __out_it, |
664 | iter_difference_t<_OutIt> __n, |
665 | locale __loc, |
666 | basic_string_view<_CharT> __fmt, |
667 | basic_format_args<_Context> __args) { |
668 | __format::__format_to_n_buffer<_OutIt, _CharT> __buffer{std::move(__out_it), __n}; |
669 | std::__format::__vformat_to( |
670 | basic_format_parse_context{__fmt, __args.__size()}, |
671 | std::__format_context_create(__buffer.__make_output_iterator(), __args, std::move(__loc))); |
672 | return std::move(__buffer).__result(); |
673 | } |
674 | |
675 | template <output_iterator<const char&> _OutIt, class... _Args> |
676 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> format_to_n( |
677 | _OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { |
678 | return std::__vformat_to_n<format_context>( |
679 | std::move(__out_it), __n, std::move(__loc), __fmt.get(), std::make_format_args(__args...)); |
680 | } |
681 | |
682 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
683 | template <output_iterator<const wchar_t&> _OutIt, class... _Args> |
684 | _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt> format_to_n( |
685 | _OutIt __out_it, iter_difference_t<_OutIt> __n, locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { |
686 | return std::__vformat_to_n<wformat_context>( |
687 | std::move(__out_it), __n, std::move(__loc), __fmt.get(), std::make_wformat_args(__args...)); |
688 | } |
689 | # endif |
690 | |
691 | template <class _CharT> |
692 | _LIBCPP_HIDE_FROM_ABI size_t __vformatted_size(locale __loc, basic_string_view<_CharT> __fmt, auto __args) { |
693 | __format::__formatted_size_buffer<_CharT> __buffer; |
694 | std::__format::__vformat_to( |
695 | basic_format_parse_context{__fmt, __args.__size()}, |
696 | std::__format_context_create(__buffer.__make_output_iterator(), __args, std::move(__loc))); |
697 | return std::move(__buffer).__result(); |
698 | } |
699 | |
700 | template <class... _Args> |
701 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t |
702 | formatted_size(locale __loc, format_string<_Args...> __fmt, _Args&&... __args) { |
703 | return std::__vformatted_size(std::move(__loc), __fmt.get(), basic_format_args{std::make_format_args(__args...)}); |
704 | } |
705 | |
706 | # if _LIBCPP_HAS_WIDE_CHARACTERS |
707 | template <class... _Args> |
708 | [[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t |
709 | formatted_size(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) { |
710 | return std::__vformatted_size(std::move(__loc), __fmt.get(), basic_format_args{std::make_wformat_args(__args...)}); |
711 | } |
712 | # endif |
713 | |
714 | # endif // _LIBCPP_HAS_LOCALIZATION |
715 | |
716 | #endif // _LIBCPP_STD_VER >= 20 |
717 | |
718 | _LIBCPP_END_NAMESPACE_STD |
719 | |
720 | _LIBCPP_POP_MACROS |
721 | |
722 | #endif // _LIBCPP___FORMAT_FORMAT_FUNCTIONS |
723 |
Warning: This file is not a C or C++ file. It does not have highlighting.