• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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