723 lines · c
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-exception7//8//===----------------------------------------------------------------------===//9 10#ifndef _LIBCPP___FORMAT_FORMAT_FUNCTIONS11#define _LIBCPP___FORMAT_FORMAT_FUNCTIONS12 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_t39#include <__variant/monostate.h>40#include <array>41#include <optional>42#include <string>43#include <string_view>44 45#if _LIBCPP_HAS_LOCALIZATION46# include <__locale>47#endif48 49#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)50# pragma GCC system_header51#endif52 53_LIBCPP_PUSH_MACROS54#include <__undef_macros>55 56_LIBCPP_BEGIN_NAMESPACE_STD57 58#if _LIBCPP_STD_VER >= 2059 60// TODO FMT Evaluate which templates should be external templates. This61// improves the efficiency of the header. However since the header is still62// under heavy development and not all classes are stable it makes no sense63// to do this optimization now.64 65using format_args = basic_format_args<format_context>;66# if _LIBCPP_HAS_WIDE_CHARACTERS67using wformat_args = basic_format_args<wformat_context>;68# endif69 70template <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_CHARACTERS76template <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# endif81 82namespace __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.88template <class _CharT>89class __compile_time_handle {90public: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 109private:110 void (*__parse_)(basic_format_parse_context<_CharT>&);111};112 113// Dummy format_context only providing the parts used during constant114// validation of the basic_format_string.115template <class _CharT>116struct __compile_time_basic_format_context {117public: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 147private:148 const __arg_t* __args_;149 const __compile_time_handle<_CharT>* __handles_;150 size_t __size_;151};152 153// [format.string.std]/8154// If { arg-idopt } is used in a width or precision, the value of the155// corresponding formatting argument is used in its place. If the156// corresponding formatting argument is not of standard signed or unsigned157// integer type, or its value is negative for precision or non-positive for158// width, an exception of type format_error is thrown.159//160// _HasPrecision does the formatter have a precision?161template <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", however166 // the final version explicitly changed it to "*standard* signed or unsigned167 // integer types". It's trivial to use 128-bit integrals in libc++'s168 // implementation, but other implementations may not implement it.169 // (Using a width or precision, that does not fit in 64-bits, sounds very170 // 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".194template <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_INT128212 return __format::__compile_time_validate_argument<_CharT, __int128_t>(__parse_ctx, __ctx);213# else214 std::__throw_format_error("Invalid argument");215# endif216 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_INT128223 return __format::__compile_time_validate_argument<_CharT, __uint128_t>(__parse_ctx, __ctx);224# else225 std::__throw_format_error("Invalid argument");226# endif227 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 246template <contiguous_iterator _Iterator, class _ParseCtx, class _Ctx>247_LIBCPP_HIDE_FROM_ABI constexpr _Iterator248__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 } else278 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 300template <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. So321 // 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 __format342 343# if _LIBCPP_STD_VER >= 26344template <class _CharT>345struct __runtime_format_string {346private:347 basic_string_view<_CharT> __str_;348 349 template <class _Cp, class... _Args>350 friend struct basic_format_string;351 352public: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_CHARACTERS361_LIBCPP_HIDE_FROM_ABI inline __runtime_format_string<wchar_t> runtime_format(wstring_view __fmt) noexcept {362 return __fmt;363}364# endif365# endif // _LIBCPP_STD_VER >= 26366 367template <class _CharT, class... _Args>368struct 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 >= 26378 _LIBCPP_HIDE_FROM_ABI basic_format_string(__runtime_format_string<_CharT> __s) noexcept : __str_(__s.__str_) {}379# endif380 381private: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 399template <class... _Args>400using format_string = basic_format_string<char, type_identity_t<_Args>...>;401 402# if _LIBCPP_HAS_WIDE_CHARACTERS403template <class... _Args>404using wformat_string = basic_format_string<wchar_t, type_identity_t<_Args>...>;405# endif406 407template <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 inlining424// https://reviews.llvm.org/D110499#inline-1180704425// TODO FMT Evaluate whether we want to file a Clang bug report regarding this.426template <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_CHARACTERS432template <output_iterator<const wchar_t&> _OutIt>433_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt434vformat_to(_OutIt __out_it, wstring_view __fmt, wformat_args __args) {435 return std::__vformat_to(std::move(__out_it), __fmt, __args);436}437# endif438 439template <output_iterator<const char&> _OutIt, class... _Args>440_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt441format_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_CHARACTERS446template <output_iterator<const wchar_t&> _OutIt, class... _Args>447_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt448format_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# endif452 453// Try constant folding the format string instead of going through the whole formatting machinery. If there is no454// constant folding no extra code should be emitted (with optimizations enabled) and the function returns nullopt. When455// constant folding is successful, the formatting is performed and the resulting string is returned.456namespace __format {457template <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 string462 if (bool __is_identity = [&] [[__gnu__::__pure__]] // Make sure the compiler knows this call can be eliminated463 { 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 function468 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 __format486 487// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup488// fires too eagerly, see http://llvm.org/PR61563.489template <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_CHARACTERS500// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup501// fires too eagerly, see http://llvm.org/PR61563.502template <class = void>503[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring504vformat(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# endif513 514template <class... _Args>515[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string516format(format_string<_Args...> __fmt, _Args&&... __args) {517 return std::vformat(__fmt.get(), std::make_format_args(__args...));518}519 520# if _LIBCPP_HAS_WIDE_CHARACTERS521template <class... _Args>522[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring523format(wformat_string<_Args...> __fmt, _Args&&... __args) {524 return std::vformat(__fmt.get(), std::make_wformat_args(__args...));525}526# endif527 528template <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 540template <output_iterator<const char&> _OutIt, class... _Args>541_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>542format_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_CHARACTERS547template <output_iterator<const wchar_t&> _OutIt, class... _Args>548_LIBCPP_HIDE_FROM_ABI format_to_n_result<_OutIt>549format_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# endif553 554template <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 562template <class... _Args>563[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t564formatted_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_CHARACTERS569template <class... _Args>570[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t571formatted_size(wformat_string<_Args...> __fmt, _Args&&... __args) {572 return std::__vformatted_size(__fmt.get(), basic_format_args{std::make_wformat_args(__args...)});573}574# endif575 576# if _LIBCPP_HAS_LOCALIZATION577 578template <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 597template <output_iterator<const char&> _OutIt>598_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt599vformat_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_CHARACTERS604template <output_iterator<const wchar_t&> _OutIt>605_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt606vformat_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# endif610 611template <output_iterator<const char&> _OutIt, class... _Args>612_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt613format_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_CHARACTERS618template <output_iterator<const wchar_t&> _OutIt, class... _Args>619_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _OutIt620format_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# endif624 625// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup626// fires too eagerly, see http://llvm.org/PR61563.627template <class = void>628[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI string629vformat(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_CHARACTERS636// TODO FMT This needs to be a template or std::to_chars(floating-point) availability markup637// fires too eagerly, see http://llvm.org/PR61563.638template <class = void>639[[nodiscard]] _LIBCPP_ALWAYS_INLINE inline _LIBCPP_HIDE_FROM_ABI wstring640vformat(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# endif646 647template <class... _Args>648[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI string649format(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_CHARACTERS654template <class... _Args>655[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI wstring656format(locale __loc, wformat_string<_Args...> __fmt, _Args&&... __args) {657 return std::vformat(std::move(__loc), __fmt.get(), std::make_wformat_args(__args...));658}659# endif660 661template <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 675template <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_CHARACTERS683template <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# endif690 691template <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 700template <class... _Args>701[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t702formatted_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_CHARACTERS707template <class... _Args>708[[nodiscard]] _LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI size_t709formatted_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# endif713 714# endif // _LIBCPP_HAS_LOCALIZATION715 716#endif // _LIBCPP_STD_VER >= 20717 718_LIBCPP_END_NAMESPACE_STD719 720_LIBCPP_POP_MACROS721 722#endif // _LIBCPP___FORMAT_FORMAT_FUNCTIONS723