1// Formatting library for C++ - the standard API implementation 2// 3// Copyright (c) 2012 - present, Victor Zverovich 4// All rights reserved. 5// 6// For the license information refer to format.h. 7 8#ifndef FMT_FORMAT_ 9#define FMT_FORMAT_ 10 11#include <cassert> 12#include <variant> 13#include "fmt/format.h" 14 15// This implementation verifies the correctness of the standard API proposed in 16// P0645 Text Formatting and is optimized for copy-pasting from the paper, not 17// for efficiency or readability. An efficient implementation should not use 18// std::variant and should store packed argument type tags separately from 19// values in basic_format_args for small number of arguments. 20 21namespace std { 22template<class T> 23constexpr bool Integral = is_integral_v<T>; 24 25template <class O> 26 using iter_difference_t = ptrdiff_t; 27} 28 29// https://fmt.dev/Text%20Formatting.html#format.syn 30namespace std { 31 // [format.error], class format_error 32 class format_error; 33 34 // [format.formatter], formatter 35 template<class charT> class basic_format_parse_context; 36 using format_parse_context = basic_format_parse_context<char>; 37 using wformat_parse_context = basic_format_parse_context<wchar_t>; 38 39 template<class Out, class charT> class basic_format_context; 40 using format_context = basic_format_context< 41 /* unspecified */ fmt::detail::buffer_appender<char>, char>; 42 using wformat_context = basic_format_context< 43 /* unspecified */ fmt::detail::buffer_appender<wchar_t>, wchar_t>; 44 45 template<class T, class charT = char> struct formatter { 46 formatter() = delete; 47 }; 48 49 // [format.arguments], arguments 50 template<class Context> class basic_format_arg; 51 52 template<class Visitor, class Context> 53 /* see below */ auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg); 54 55 template<class Context, class... Args> struct format_arg_store; // exposition only 56 57 template<class Context> class basic_format_args; 58 using format_args = basic_format_args<format_context>; 59 using wformat_args = basic_format_args<wformat_context>; 60 61 template<class Out, class charT> 62 using format_args_t = basic_format_args<basic_format_context<Out, charT>>; 63 64 template<class Context = format_context, class... Args> 65 format_arg_store<Context, Args...> 66 make_format_args(const Args&... args); 67 template<class... Args> 68 format_arg_store<wformat_context, Args...> 69 make_wformat_args(const Args&... args); 70 71 // [format.functions], formatting functions 72 template<class... Args> 73 string format(string_view fmt, const Args&... args); 74 template<class... Args> 75 wstring format(wstring_view fmt, const Args&... args); 76 77 string vformat(string_view fmt, format_args args); 78 wstring vformat(wstring_view fmt, wformat_args args); 79 80 template<class Out, class... Args> 81 Out format_to(Out out, string_view fmt, const Args&... args); 82 template<class Out, class... Args> 83 Out format_to(Out out, wstring_view fmt, const Args&... args); 84 85 template<class Out> 86 Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args); 87 template<class Out> 88 Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args); 89 90 template<class Out> 91 struct format_to_n_result { 92 Out out; 93 iter_difference_t<Out> size; 94 }; 95 96 template<class Out, class... Args> 97 format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, 98 string_view fmt, const Args&... args); 99 template<class Out, class... Args> 100 format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, 101 wstring_view fmt, const Args&... args); 102 103 template<class... Args> 104 size_t formatted_size(string_view fmt, const Args&... args); 105 template<class... Args> 106 size_t formatted_size(wstring_view fmt, const Args&... args); 107} 108 109// https://fmt.dev/Text%20Formatting.html#format.error 110namespace std { 111 class format_error : public runtime_error { 112 public: 113 explicit format_error(const string& what_arg) : runtime_error(what_arg) {} 114 explicit format_error(const char* what_arg) : runtime_error(what_arg) {} 115 }; 116} 117 118namespace std { 119namespace detail { 120struct error_handler { 121 // This function is intentionally not constexpr to give a compile-time error. 122 void on_error(const char* message) { 123 throw std::format_error(message); 124 } 125}; 126} 127} 128 129// https://fmt.dev/Text%20Formatting.html#format.parse_context 130namespace std { 131 template<class charT> 132 class basic_format_parse_context { 133 public: 134 using char_type = charT; 135 using const_iterator = typename basic_string_view<charT>::const_iterator; 136 using iterator = const_iterator; 137 138 private: 139 iterator begin_; // exposition only 140 iterator end_; // exposition only 141 enum indexing { unknown, manual, automatic }; // exposition only 142 indexing indexing_; // exposition only 143 size_t next_arg_id_; // exposition only 144 size_t num_args_; // exposition only 145 146 public: 147 explicit constexpr basic_format_parse_context(basic_string_view<charT> fmt, 148 size_t num_args = 0) noexcept; 149 basic_format_parse_context(const basic_format_parse_context&) = delete; 150 basic_format_parse_context& operator=(const basic_format_parse_context&) = delete; 151 152 constexpr const_iterator begin() const noexcept; 153 constexpr const_iterator end() const noexcept; 154 constexpr void advance_to(const_iterator it); 155 156 constexpr size_t next_arg_id(); 157 constexpr void check_arg_id(size_t id); 158 159 // Implementation detail: 160 constexpr void check_arg_id(fmt::string_view) {} 161 detail::error_handler error_handler() const { return {}; } 162 void on_error(const char* msg) { error_handler().on_error(msg); } 163 }; 164} 165 166namespace std { 167template<class charT> 168/* explicit */ constexpr basic_format_parse_context<charT>:: 169 basic_format_parse_context(basic_string_view<charT> fmt, 170 size_t num_args) noexcept 171: begin_(fmt.begin()), end_(fmt.end()), indexing_(unknown), next_arg_id_(0), num_args_(num_args) {} 172 173template<class charT> 174constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::begin() const noexcept { return begin_; } 175 176template<class charT> 177constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::end() const noexcept { return end_; } 178 179template<class charT> 180constexpr void basic_format_parse_context<charT>::advance_to(typename basic_format_parse_context<charT>::iterator it) { begin_ = it; } 181 182template<class charT> 183constexpr size_t basic_format_parse_context<charT>::next_arg_id() { 184 if (indexing_ == manual) 185 throw format_error("manual to automatic indexing"); 186 if (indexing_ == unknown) 187 indexing_ = automatic; 188 return next_arg_id_++; 189} 190 191template<class charT> 192constexpr void basic_format_parse_context<charT>::check_arg_id(size_t id) { 193 // clang doesn't support __builtin_is_constant_evaluated yet 194 //if (!(!__builtin_is_constant_evaluated() || id < num_args_)) 195 // throw format_error(invalid index is out of range"); 196 if (indexing_ == automatic) 197 throw format_error("automatic to manual indexing"); 198 if (indexing_ == unknown) 199 indexing_ = manual; 200} 201} 202 203// https://fmt.dev/Text%20Formatting.html#format.context 204namespace std { 205 template<class Out, class charT> 206 class basic_format_context { 207 basic_format_args<basic_format_context> args_; // exposition only 208 Out out_; // exposition only 209 210 public: 211 using iterator = Out; 212 using char_type = charT; 213 template<class T> using formatter_type = formatter<T, charT>; 214 215 basic_format_arg<basic_format_context> arg(size_t id) const; 216 217 iterator out(); 218 void advance_to(iterator it); 219 220 // Implementation details: 221 using format_arg = basic_format_arg<basic_format_context>; 222 basic_format_context(Out out, basic_format_args<basic_format_context> args, fmt::detail::locale_ref) 223 : args_(args), out_(out) {} 224 detail::error_handler error_handler() const { return {}; } 225 basic_format_arg<basic_format_context> arg(fmt::basic_string_view<charT>) const { 226 return {}; // unused: named arguments are not supported yet 227 } 228 void on_error(const char* msg) { error_handler().on_error(msg); } 229 }; 230} 231 232namespace std { 233template<class O, class charT> 234basic_format_arg<basic_format_context<O, charT>> basic_format_context<O, charT>::arg(size_t id) const { return args_.get(id); } 235 236template<class O, class charT> 237typename basic_format_context<O, charT>::iterator basic_format_context<O, charT>::out() { return out_; } 238 239template<class O, class charT> 240void basic_format_context<O, charT>::advance_to(typename basic_format_context<O, charT>::iterator it) { out_ = it; } 241} 242 243namespace std { 244namespace detail { 245template <typename T> 246constexpr bool is_standard_integer_v = 247 std::is_same_v<T, signed char> || 248 std::is_same_v<T, short int> || 249 std::is_same_v<T, int> || 250 std::is_same_v<T, long int> || 251 std::is_same_v<T, long long int>; 252 253template <typename T> 254constexpr bool is_standard_unsigned_integer_v = 255 std::is_same_v<T, unsigned char> || 256 std::is_same_v<T, unsigned short int> || 257 std::is_same_v<T, unsigned int> || 258 std::is_same_v<T, unsigned long int> || 259 std::is_same_v<T, unsigned long long int>; 260 261template <typename T, typename Char> struct formatter; 262} 263} 264 265// https://fmt.dev/Text%20Formatting.html#format.arg 266namespace std { 267 template<class Context> 268 class basic_format_arg { 269 public: 270 class handle; 271 272 private: 273 using char_type = typename Context::char_type; // exposition only 274 275 variant<monostate, bool, char_type, 276 int, unsigned int, long long int, unsigned long long int, 277 double, long double, 278 const char_type*, basic_string_view<char_type>, 279 const void*, handle> value; // exposition only 280 281 template<typename T, 282 typename = enable_if_t< 283 std::is_same_v<T, bool> || 284 std::is_same_v<T, char_type> || 285 (std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>) || 286 detail::is_standard_integer_v<T> || 287 detail::is_standard_unsigned_integer_v<T> || 288 sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0 289 >> explicit basic_format_arg(const T& v) noexcept; // exposition only 290 explicit basic_format_arg(float n) noexcept; // exposition only 291 explicit basic_format_arg(double n) noexcept; // exposition only 292 explicit basic_format_arg(long double n) noexcept; // exposition only 293 explicit basic_format_arg(const char_type* s); // exposition only 294 295 template<class traits> 296 explicit basic_format_arg( 297 basic_string_view<char_type, traits> s) noexcept; // exposition only 298 299 template<class traits, class Allocator> 300 explicit basic_format_arg( 301 const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only 302 303 explicit basic_format_arg(nullptr_t) noexcept; // exposition only 304 305 template<class T, typename = enable_if_t<is_void_v<T>>> 306 explicit basic_format_arg(const T* p) noexcept; // exposition only 307 308 // Fails due to a bug in clang 309 //template<class Visitor, class Ctx> 310 // friend auto visit_format_arg(Visitor&& vis, 311 // basic_format_arg<Ctx> arg); // exposition only 312 313 friend auto get_value(basic_format_arg arg) { 314 return arg.value; 315 } 316 317 template <typename T, typename Char> friend struct detail::formatter; 318 319 template<class Ctx, class... Args> 320 friend format_arg_store<Ctx, Args...> 321 make_format_args(const Args&... args); // exposition only 322 323 public: 324 basic_format_arg() noexcept; 325 326 explicit operator bool() const noexcept; 327 }; 328} 329 330namespace std { 331template<class Context> 332basic_format_arg<Context>::basic_format_arg() noexcept {} 333 334template<class Context> 335template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T& v) noexcept { 336 if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, char_type>) 337 value = v; 338 else if constexpr (std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>) 339 value = static_cast<wchar_t>(v); 340 else if constexpr (detail::is_standard_integer_v<T> && sizeof(T) <= sizeof(int)) 341 value = static_cast<int>(v); 342 else if constexpr (detail::is_standard_unsigned_integer_v<T> && sizeof(T) <= sizeof(unsigned)) 343 value = static_cast<unsigned>(v); 344 else if constexpr (detail::is_standard_integer_v<T>) 345 value = static_cast<long long int>(v); 346 else if constexpr (detail::is_standard_unsigned_integer_v<T>) 347 value = static_cast<unsigned long long int>(v); 348 else if constexpr (sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0) 349 value = handle(v); 350} 351 352template<class Context> 353/* explicit */ basic_format_arg<Context>::basic_format_arg(float n) noexcept 354 : value(static_cast<double>(n)) {} 355 356template<class Context> 357/* explicit */ basic_format_arg<Context>::basic_format_arg(double n) noexcept 358 : value(n) {} 359 360template<class Context> 361/* explicit */ basic_format_arg<Context>::basic_format_arg(long double n) noexcept 362 : value(n) {} 363 364template<class Context> 365/* explicit */ basic_format_arg<Context>::basic_format_arg(const typename basic_format_arg<Context>::char_type* s) 366 : value(s) { 367 assert(s != nullptr); 368} 369 370template<class Context> 371template<class traits> 372/* explicit */ basic_format_arg<Context>::basic_format_arg(basic_string_view<char_type, traits> s) noexcept 373 : value(s) {} 374 375template<class Context> 376template<class traits, class Allocator> 377/* explicit */ basic_format_arg<Context>::basic_format_arg( 378 const basic_string<char_type, traits, Allocator>& s) noexcept 379 : value(basic_string_view<char_type>(s.data(), s.size())) {} 380 381 382template<class Context> 383/* explicit */ basic_format_arg<Context>::basic_format_arg(nullptr_t) noexcept 384 : value(static_cast<const void*>(nullptr)) {} 385 386template<class Context> 387template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T* p) noexcept 388 : value(p) {} 389 390template<class Context> 391/* explicit */ basic_format_arg<Context>::operator bool() const noexcept { 392 return !holds_alternative<monostate>(value); 393} 394} 395 396namespace std { 397 template<class Context> 398 class basic_format_arg<Context>::handle { 399 const void* ptr_; // exposition only 400 void (*format_)(basic_format_parse_context<char_type>&, 401 Context&, const void*); // exposition only 402 403 template<class T> explicit handle(const T& val) noexcept; // exposition only 404 405 friend class basic_format_arg<Context>; // exposition only 406 407 public: 408 void format(basic_format_parse_context<char_type>&, Context& ctx) const; 409 }; 410} 411 412namespace std { 413template<class Context> 414template<class T> /* explicit */ basic_format_arg<Context>::handle::handle(const T& val) noexcept 415 : ptr_(&val), format_([](basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx, const void* ptr) { 416 typename Context::template formatter_type<T> f; 417 parse_ctx.advance_to(f.parse(parse_ctx)); 418 format_ctx.advance_to(f.format(*static_cast<const T*>(ptr), format_ctx)); 419 }) {} 420 421template<class Context> 422void basic_format_arg<Context>::handle::format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx) const { 423 format_(parse_ctx, format_ctx, ptr_); 424} 425 426// https://fmt.dev/Text%20Formatting.html#format.visit 427template<class Visitor, class Context> 428 auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg) { 429 return visit(vis, get_value(arg)); 430 } 431} 432 433// https://fmt.dev/Text%20Formatting.html#format.store 434namespace std { 435 template<class Context, class... Args> 436 struct format_arg_store { // exposition only 437 array<basic_format_arg<Context>, sizeof...(Args)> args; 438 }; 439} 440 441// https://fmt.dev/Text%20Formatting.html#format.basic_args 442namespace std { 443 template<class Context> 444 class basic_format_args { 445 size_t size_; // exposition only 446 const basic_format_arg<Context>* data_; // exposition only 447 448 public: 449 basic_format_args() noexcept; 450 451 template<class... Args> 452 basic_format_args(const format_arg_store<Context, Args...>& store) noexcept; 453 454 basic_format_arg<Context> get(size_t i) const noexcept; 455 }; 456} 457 458namespace std { 459 460template<class Context> 461basic_format_args<Context>::basic_format_args() noexcept : size_(0) {} 462 463template<class Context> 464template<class... Args> 465 basic_format_args<Context>::basic_format_args(const format_arg_store<Context, Args...>& store) noexcept 466 : size_(sizeof...(Args)), data_(store.args.data()) {} 467 468template<class Context> 469basic_format_arg<Context> basic_format_args<Context>::get(size_t i) const noexcept { 470 return i < size_ ? data_[i] : basic_format_arg<Context>(); 471} 472} 473 474namespace std { 475// https://fmt.dev/Text%20Formatting.html#format.make_args 476template<class Context /*= format_context*/, class... Args> 477 format_arg_store<Context, Args...> make_format_args(const Args&... args) { 478 return {basic_format_arg<Context>(args)...}; 479 } 480 481// https://fmt.dev/Text%20Formatting.html#format.make_wargs 482template<class... Args> 483 format_arg_store<wformat_context, Args...> make_wformat_args(const Args&... args) { 484 return make_format_args<wformat_context>(args...); 485 } 486} 487 488namespace std { 489namespace detail { 490 491template <typename OutputIt, typename Char> 492class arg_formatter 493 : public fmt::detail::arg_formatter_base<OutputIt, Char, error_handler> { 494 private: 495 using char_type = Char; 496 using base = fmt::detail::arg_formatter_base<OutputIt, Char, error_handler>; 497 using format_context = std::basic_format_context<OutputIt, Char>; 498 using parse_context = basic_format_parse_context<Char>; 499 500 parse_context* parse_ctx_; 501 format_context& ctx_; 502 503 public: 504 using iterator = OutputIt; 505 using format_specs = typename base::format_specs; 506 507 /** 508 \rst 509 Constructs an argument formatter object. 510 *ctx* is a reference to the formatting context, 511 *spec* contains format specifier information for standard argument types. 512 \endrst 513 */ 514 arg_formatter(format_context& ctx, parse_context* parse_ctx = nullptr, fmt::format_specs* spec = nullptr) 515 : base(ctx.out(), spec, {}), parse_ctx_(parse_ctx), ctx_(ctx) {} 516 517 using base::operator(); 518 519 /** Formats an argument of a user-defined type. */ 520 iterator operator()(typename std::basic_format_arg<format_context>::handle handle) { 521 handle.format(*parse_ctx_, ctx_); 522 return this->out(); 523 } 524 525 iterator operator()(monostate) { 526 throw format_error(""); 527 } 528}; 529 530template <typename Context> 531inline fmt::detail::type get_type(basic_format_arg<Context> arg) { 532 return visit_format_arg([&] (auto val) { 533 using char_type = typename Context::char_type; 534 using T = decltype(val); 535 if (std::is_same_v<T, monostate>) 536 return fmt::detail::type::none_type; 537 if (std::is_same_v<T, bool>) 538 return fmt::detail::type::bool_type; 539 if (std::is_same_v<T, char_type>) 540 return fmt::detail::type::char_type; 541 if (std::is_same_v<T, int>) 542 return fmt::detail::type::int_type; 543 if (std::is_same_v<T, unsigned int>) 544 return fmt::detail::type::uint_type; 545 if (std::is_same_v<T, long long int>) 546 return fmt::detail::type::long_long_type; 547 if (std::is_same_v<T, unsigned long long int>) 548 return fmt::detail::type::ulong_long_type; 549 if (std::is_same_v<T, double>) 550 return fmt::detail::type::double_type; 551 if (std::is_same_v<T, long double>) 552 return fmt::detail::type::long_double_type; 553 if (std::is_same_v<T, const char_type*>) 554 return fmt::detail::type::cstring_type; 555 if (std::is_same_v<T, basic_string_view<char_type>>) 556 return fmt::detail::type::string_type; 557 if (std::is_same_v<T, const void*>) 558 return fmt::detail::type::pointer_type; 559 assert(get_value(arg).index() == 12); 560 return fmt::detail::type::custom_type; 561 }, arg); 562} 563 564template <typename Context> 565class custom_formatter { 566 private: 567 using parse_context = basic_format_parse_context<typename Context::char_type>; 568 parse_context& parse_ctx_; 569 Context& format_ctx_; 570 571 public: 572 custom_formatter(parse_context& parse_ctx, Context& ctx) : parse_ctx_(parse_ctx), format_ctx_(ctx) {} 573 574 bool operator()(typename basic_format_arg<Context>::handle h) const { 575 h.format(parse_ctx_, format_ctx_); 576 return true; 577 } 578 579 template <typename T> bool operator()(T) const { return false; } 580}; 581 582template <typename ArgFormatter, typename Char, typename Context> 583struct format_handler : detail::error_handler { 584 using iterator = typename ArgFormatter::iterator; 585 586 format_handler(iterator out, basic_string_view<Char> str, 587 basic_format_args<Context> format_args, 588 fmt::detail::locale_ref loc) 589 : parse_ctx(str), context(out, format_args, loc) {} 590 591 void on_text(const Char* begin, const Char* end) { 592 auto size = fmt::detail::to_unsigned(end - begin); 593 auto out = context.out(); 594 auto&& it = fmt::detail::reserve(out, size); 595 it = std::copy_n(begin, size, it); 596 context.advance_to(out); 597 } 598 599 int on_arg_id() { return parse_ctx.next_arg_id(); } 600 int on_arg_id(unsigned id) { return parse_ctx.check_arg_id(id), id; } 601 int on_arg_id(fmt::basic_string_view<Char>) { return 0; } 602 603 void on_replacement_field(int id, const Char* p) { 604 auto arg = context.arg(id); 605 parse_ctx.advance_to(parse_ctx.begin() + (p - &*parse_ctx.begin())); 606 custom_formatter<Context> f(parse_ctx, context); 607 if (!visit_format_arg(f, arg)) 608 context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx), arg)); 609 } 610 611 const Char* on_format_specs(int id, const Char* begin, const Char* end) { 612 auto arg = context.arg(id); 613 parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin())); 614 custom_formatter<Context> f(parse_ctx, context); 615 if (visit_format_arg(f, arg)) return &*parse_ctx.begin(); 616 fmt::basic_format_specs<Char> specs; 617 using fmt::detail::specs_handler; 618 using parse_context = basic_format_parse_context<Char>; 619 fmt::detail::specs_checker<specs_handler<parse_context, Context>> handler( 620 specs_handler<parse_context, Context>(specs, parse_ctx, context), get_type(arg)); 621 begin = parse_format_specs(begin, end, handler); 622 if (begin == end || *begin != '}') on_error("missing '}' in format string"); 623 parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin())); 624 context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx, &specs), arg)); 625 return begin; 626 } 627 628 basic_format_parse_context<Char> parse_ctx; 629 Context context; 630}; 631 632template <typename T, typename Char> 633struct formatter { 634 // Parses format specifiers stopping either at the end of the range or at the 635 // terminating '}'. 636 template <typename ParseContext> 637 FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) { 638 namespace detail = fmt::detail; 639 typedef detail::dynamic_specs_handler<ParseContext> handler_type; 640 auto type = detail::mapped_type_constant<T, fmt::buffer_context<Char>>::value; 641 detail::specs_checker<handler_type> handler(handler_type(specs_, ctx), 642 type); 643 auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); 644 auto type_spec = specs_.type; 645 auto eh = ctx.error_handler(); 646 switch (type) { 647 case detail::type::none_type: 648 FMT_ASSERT(false, "invalid argument type"); 649 break; 650 case detail::type::int_type: 651 case detail::type::uint_type: 652 case detail::type::long_long_type: 653 case detail::type::ulong_long_type: 654 case detail::type::bool_type: 655 handle_int_type_spec(type_spec, 656 detail::int_type_checker<decltype(eh)>(eh)); 657 break; 658 case detail::type::char_type: 659 handle_char_specs( 660 &specs_, detail::char_specs_checker<decltype(eh)>(type_spec, eh)); 661 break; 662 case detail::type::double_type: 663 case detail::type::long_double_type: 664 detail::parse_float_type_spec(specs_, eh); 665 break; 666 case detail::type::cstring_type: 667 detail::handle_cstring_type_spec( 668 type_spec, detail::cstring_type_checker<decltype(eh)>(eh)); 669 break; 670 case detail::type::string_type: 671 detail::check_string_type_spec(type_spec, eh); 672 break; 673 case detail::type::pointer_type: 674 detail::check_pointer_type_spec(type_spec, eh); 675 break; 676 case detail::type::custom_type: 677 // Custom format specifiers should be checked in parse functions of 678 // formatter specializations. 679 break; 680 } 681 return it; 682 } 683 684 template <typename FormatContext> 685 auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { 686 fmt::detail::handle_dynamic_spec<fmt::detail::width_checker>( 687 specs_.width, specs_.width_ref, ctx); 688 fmt::detail::handle_dynamic_spec<fmt::detail::precision_checker>( 689 specs_.precision, specs_.precision_ref, ctx); 690 using af = arg_formatter<typename FormatContext::iterator, 691 typename FormatContext::char_type>; 692 return visit_format_arg(af(ctx, nullptr, &specs_), 693 basic_format_arg<FormatContext>(val)); 694 } 695 696 private: 697 fmt::detail::dynamic_format_specs<Char> specs_; 698}; 699} // namespace detail 700 701// https://fmt.dev/Text%20Formatting.html#format.functions 702template<class... Args> 703 string format(string_view fmt, const Args&... args) { 704 return vformat(fmt, make_format_args(args...)); 705 } 706 707template<class... Args> 708 wstring format(wstring_view fmt, const Args&... args) { 709 return vformat(fmt, make_wformat_args(args...)); 710 } 711 712string vformat(string_view fmt, format_args args) { 713 fmt::memory_buffer mbuf; 714 fmt::detail::buffer<char>& buf = mbuf; 715 using af = detail::arg_formatter<fmt::format_context::iterator, char>; 716 detail::format_handler<af, char, format_context> 717 h(fmt::detail::buffer_appender<char>(buf), fmt, args, {}); 718 fmt::detail::parse_format_string<false>(fmt::to_string_view(fmt), h); 719 return to_string(mbuf); 720} 721 722wstring vformat(wstring_view fmt, wformat_args args); 723 724template<class Out, class... Args> 725 Out format_to(Out out, string_view fmt, const Args&... args) { 726 using context = basic_format_context<Out, decltype(fmt)::value_type>; 727 return vformat_to(out, fmt, make_format_args<context>(args...)); 728 } 729 730template<class Out, class... Args> 731 Out format_to(Out out, wstring_view fmt, const Args&... args) { 732 using context = basic_format_context<Out, decltype(fmt)::value_type>; 733 return vformat_to(out, fmt, make_format_args<context>(args...)); 734 } 735 736template<class Out> 737 Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args) { 738 using af = detail::arg_formatter<Out, char>; 739 detail::format_handler<af, char, basic_format_context<Out, char>> 740 h(out, fmt, args, {}); 741 fmt::detail::parse_format_string<false>(fmt::to_string_view(fmt), h); 742 return h.context.out(); 743 } 744 745template<class Out> 746 Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args); 747 748template<class Out, class... Args> 749 format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, 750 string_view fmt, const Args&... args); 751template<class Out, class... Args> 752 format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n, 753 wstring_view fmt, const Args&... args); 754 755template<class... Args> 756 size_t formatted_size(string_view fmt, const Args&... args); 757template<class... Args> 758 size_t formatted_size(wstring_view fmt, const Args&... args); 759 760#define charT char 761 762template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {}; 763 764template<> struct formatter<char, wchar_t>; 765 766template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {}; 767 768template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {}; 769 770template<size_t N> struct formatter<const charT[N], charT> 771 : detail::formatter<std::basic_string_view<charT>, charT> {}; 772 773template<class traits, class Allocator> 774 struct formatter<basic_string<charT, traits, Allocator>, charT> 775 : detail::formatter<std::basic_string_view<charT>, charT> {}; 776 777template<class traits> 778 struct formatter<basic_string_view<charT, traits>, charT> 779 : detail::formatter<std::basic_string_view<charT>, charT> {}; 780 781template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {}; 782template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {}; 783template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {}; 784template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {}; 785 786template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {}; 787template <> struct formatter<short, charT> : detail::formatter<int, charT> {}; 788template <> struct formatter<int, charT> : detail::formatter<int, charT> {}; 789template <> struct formatter<long, charT> 790 : detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {}; 791template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {}; 792template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {}; 793template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {}; 794template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {}; 795template <> struct formatter<unsigned long, charT> 796 : detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {}; 797template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {}; 798 799template <> struct formatter<float, charT> : detail::formatter<double, charT> {}; 800template <> struct formatter<double, charT> : detail::formatter<double, charT> {}; 801template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {}; 802 803#undef charT 804 805#define charT wchar_t 806 807template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {}; 808 809template<> struct formatter<char, wchar_t> : detail::formatter<charT, charT> {}; 810 811template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {}; 812 813template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {}; 814 815template<size_t N> struct formatter<const charT[N], charT> 816 : detail::formatter<std::basic_string_view<charT>, charT> {}; 817 818template<class traits, class Allocator> 819 struct formatter<std::basic_string<charT, traits, Allocator>, charT> 820 : detail::formatter<std::basic_string_view<charT>, charT> {}; 821 822template<class traits> 823 struct formatter<std::basic_string_view<charT, traits>, charT> 824 : detail::formatter<std::basic_string_view<charT>, charT> {}; 825 826template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {}; 827template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {}; 828template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {}; 829template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {}; 830 831template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {}; 832template <> struct formatter<short, charT> : detail::formatter<int, charT> {}; 833template <> struct formatter<int, charT> : detail::formatter<int, charT> {}; 834template <> struct formatter<long, charT> 835 : detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {}; 836template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {}; 837template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {}; 838template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {}; 839template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {}; 840template <> struct formatter<unsigned long, charT> 841 : detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {}; 842template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {}; 843 844template <> struct formatter<float, charT> : detail::formatter<double, charT> {}; 845template <> struct formatter<double, charT> : detail::formatter<double, charT> {}; 846template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {}; 847 848#undef charT 849 850 template<> struct formatter<const wchar_t, char> { 851 formatter() = delete; 852 }; 853} 854 855#endif // FMT_FORMAT_ 856