mirror of
				https://github.com/fmtlib/fmt.git
				synced 2025-10-31 06:01:41 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			856 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			856 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| // Formatting library for C++ - the standard API implementation
 | |
| //
 | |
| // Copyright (c) 2012 - present, Victor Zverovich
 | |
| // All rights reserved.
 | |
| //
 | |
| // For the license information refer to format.h.
 | |
| 
 | |
| #ifndef FMT_FORMAT_
 | |
| #define FMT_FORMAT_
 | |
| 
 | |
| #include <cassert>
 | |
| #include <variant>
 | |
| #include "fmt/format.h"
 | |
| 
 | |
| // This implementation verifies the correctness of the standard API proposed in
 | |
| // P0645 Text Formatting and is optimized for copy-pasting from the paper, not
 | |
| // for efficiency or readability. An efficient implementation should not use
 | |
| // std::variant and should store packed argument type tags separately from
 | |
| // values in basic_format_args for small number of arguments.
 | |
| 
 | |
| namespace std {
 | |
| template<class T>
 | |
| constexpr bool Integral = is_integral_v<T>;
 | |
| 
 | |
| template <class O>
 | |
|   using iter_difference_t = ptrdiff_t;
 | |
| }
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.syn
 | |
| namespace std {
 | |
|   // [format.error], class format_error
 | |
|   class format_error;
 | |
| 
 | |
|   // [format.formatter], formatter
 | |
|   template<class charT> class basic_format_parse_context;
 | |
|   using format_parse_context = basic_format_parse_context<char>;
 | |
|   using wformat_parse_context = basic_format_parse_context<wchar_t>;
 | |
|   
 | |
|   template<class Out, class charT> class basic_format_context;
 | |
|   using format_context = basic_format_context<
 | |
|     /* unspecified */ fmt::detail::buffer_appender<char>, char>;
 | |
|   using wformat_context = basic_format_context<
 | |
|     /* unspecified */ fmt::detail::buffer_appender<wchar_t>, wchar_t>;
 | |
| 
 | |
|   template<class T, class charT = char> struct formatter {
 | |
|     formatter() = delete;
 | |
|   };
 | |
|   
 | |
|   // [format.arguments], arguments
 | |
|   template<class Context> class basic_format_arg;
 | |
| 
 | |
|   template<class Visitor, class Context>
 | |
|     /* see below */ auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
 | |
| 
 | |
|   template<class Context, class... Args> struct format_arg_store; // exposition only
 | |
| 
 | |
|   template<class Context> class basic_format_args;
 | |
|   using format_args = basic_format_args<format_context>;
 | |
|   using wformat_args = basic_format_args<wformat_context>;
 | |
| 
 | |
|   template<class Out, class charT>
 | |
|     using format_args_t = basic_format_args<basic_format_context<Out, charT>>;
 | |
| 
 | |
|   template<class Context = format_context, class... Args>
 | |
|     format_arg_store<Context, Args...>
 | |
|       make_format_args(const Args&... args);
 | |
|   template<class... Args>
 | |
|     format_arg_store<wformat_context, Args...>
 | |
|       make_wformat_args(const Args&... args);
 | |
| 
 | |
|   // [format.functions], formatting functions
 | |
|   template<class... Args>
 | |
|     string format(string_view fmt, const Args&... args);
 | |
|   template<class... Args>
 | |
|     wstring format(wstring_view fmt, const Args&... args);
 | |
| 
 | |
|   string vformat(string_view fmt, format_args args);
 | |
|   wstring vformat(wstring_view fmt, wformat_args args);
 | |
| 
 | |
|   template<class Out, class... Args>
 | |
|     Out format_to(Out out, string_view fmt, const Args&... args);
 | |
|   template<class Out, class... Args>
 | |
|     Out format_to(Out out, wstring_view fmt, const Args&... args);
 | |
| 
 | |
|   template<class Out>
 | |
|     Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args);
 | |
|   template<class Out>
 | |
|     Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args);
 | |
| 
 | |
|   template<class Out>
 | |
|     struct format_to_n_result {
 | |
|       Out out;
 | |
|       iter_difference_t<Out> size;
 | |
|     };
 | |
|   
 | |
|   template<class Out, class... Args>
 | |
|     format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
 | |
|                                         string_view fmt, const Args&... args);
 | |
|   template<class Out, class... Args>
 | |
|     format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
 | |
|                                         wstring_view fmt, const Args&... args);
 | |
| 
 | |
|   template<class... Args>
 | |
|     size_t formatted_size(string_view fmt, const Args&... args);
 | |
|   template<class... Args>
 | |
|     size_t formatted_size(wstring_view fmt, const Args&... args);
 | |
| }
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.error
 | |
| namespace std {
 | |
|   class format_error : public runtime_error {
 | |
|   public:
 | |
|     explicit format_error(const string& what_arg) : runtime_error(what_arg) {}
 | |
|     explicit format_error(const char* what_arg) : runtime_error(what_arg) {}
 | |
|   };
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
| namespace detail {
 | |
| struct error_handler {
 | |
|   // This function is intentionally not constexpr to give a compile-time error.
 | |
|   void on_error(const char* message) {
 | |
|     throw std::format_error(message);
 | |
|   }
 | |
| };
 | |
| }
 | |
| }
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.parse_context
 | |
| namespace std {
 | |
|   template<class charT>
 | |
|   class basic_format_parse_context {
 | |
|   public:
 | |
|     using char_type = charT;
 | |
|     using const_iterator = typename basic_string_view<charT>::const_iterator;
 | |
|     using iterator = const_iterator;
 | |
| 
 | |
|   private:
 | |
|     iterator begin_;                              // exposition only
 | |
|     iterator end_;                                // exposition only
 | |
|     enum indexing { unknown, manual, automatic }; // exposition only
 | |
|     indexing indexing_;                           // exposition only
 | |
|     size_t next_arg_id_;                          // exposition only
 | |
|     size_t num_args_;                             // exposition only
 | |
| 
 | |
|   public:
 | |
|     explicit constexpr basic_format_parse_context(basic_string_view<charT> fmt,
 | |
|                                                   size_t num_args = 0) noexcept;
 | |
|     basic_format_parse_context(const basic_format_parse_context&) = delete;
 | |
|     basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
 | |
| 
 | |
|     constexpr const_iterator begin() const noexcept;
 | |
|     constexpr const_iterator end() const noexcept;
 | |
|     constexpr void advance_to(const_iterator it);
 | |
| 
 | |
|     constexpr size_t next_arg_id();
 | |
|     constexpr void check_arg_id(size_t id);
 | |
| 
 | |
|     // Implementation detail:
 | |
|     constexpr void check_arg_id(fmt::string_view) {}
 | |
|     detail::error_handler error_handler() const { return {}; }
 | |
|     void on_error(const char* msg) { error_handler().on_error(msg); }
 | |
|   };
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
| template<class charT>
 | |
| /* explicit */ constexpr basic_format_parse_context<charT>::
 | |
|                    basic_format_parse_context(basic_string_view<charT> fmt,
 | |
|                                               size_t num_args) noexcept
 | |
| : begin_(fmt.begin()), end_(fmt.end()), indexing_(unknown), next_arg_id_(0), num_args_(num_args) {}
 | |
| 
 | |
| template<class charT>
 | |
| constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::begin() const noexcept { return begin_; }
 | |
| 
 | |
| template<class charT>
 | |
| constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::end() const noexcept { return end_; }
 | |
| 
 | |
| template<class charT>
 | |
| constexpr void basic_format_parse_context<charT>::advance_to(typename basic_format_parse_context<charT>::iterator it) { begin_ = it; }
 | |
| 
 | |
| template<class charT>
 | |
| constexpr size_t basic_format_parse_context<charT>::next_arg_id() {
 | |
|   if (indexing_ == manual)
 | |
|     throw format_error("manual to automatic indexing");
 | |
|   if (indexing_ == unknown)
 | |
|     indexing_ = automatic;
 | |
|   return next_arg_id_++;
 | |
| }
 | |
| 
 | |
| template<class charT>
 | |
| constexpr void basic_format_parse_context<charT>::check_arg_id(size_t id) {
 | |
|   // clang doesn't support __builtin_is_constant_evaluated yet
 | |
|   //if (!(!__builtin_is_constant_evaluated() || id < num_args_))
 | |
|   //  throw format_error(invalid index is out of range");
 | |
|   if (indexing_ == automatic)
 | |
|     throw format_error("automatic to manual indexing");
 | |
|   if (indexing_ == unknown)
 | |
|     indexing_ = manual;
 | |
| }
 | |
| }
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.context
 | |
| namespace std {
 | |
|   template<class Out, class charT>
 | |
|   class basic_format_context {
 | |
|     basic_format_args<basic_format_context> args_; // exposition only
 | |
|     Out out_;                                      // exposition only
 | |
| 
 | |
|   public:
 | |
|     using iterator = Out;
 | |
|     using char_type = charT;
 | |
|     template<class T> using formatter_type = formatter<T, charT>;
 | |
| 
 | |
|     basic_format_arg<basic_format_context> arg(size_t id) const;
 | |
| 
 | |
|     iterator out();
 | |
|     void advance_to(iterator it);
 | |
| 
 | |
|     // Implementation details:
 | |
|     using format_arg = basic_format_arg<basic_format_context>;
 | |
|     basic_format_context(Out out, basic_format_args<basic_format_context> args, fmt::detail::locale_ref)
 | |
|     : args_(args), out_(out) {}
 | |
|     detail::error_handler error_handler() const { return {}; }
 | |
|     basic_format_arg<basic_format_context> arg(fmt::basic_string_view<charT>) const {
 | |
|       return {}; // unused: named arguments are not supported yet
 | |
|     }
 | |
|     void on_error(const char* msg) { error_handler().on_error(msg); }
 | |
|   };
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
| template<class O, class charT>
 | |
| basic_format_arg<basic_format_context<O, charT>> basic_format_context<O, charT>::arg(size_t id) const { return args_.get(id); }
 | |
| 
 | |
| template<class O, class charT>
 | |
| typename basic_format_context<O, charT>::iterator basic_format_context<O, charT>::out() { return out_; }
 | |
| 
 | |
| template<class O, class charT>
 | |
| void basic_format_context<O, charT>::advance_to(typename basic_format_context<O, charT>::iterator it) { out_ = it; }
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
| namespace detail {
 | |
| template <typename T>
 | |
| constexpr bool is_standard_integer_v =
 | |
|     std::is_same_v<T, signed char> ||
 | |
|     std::is_same_v<T, short int> ||
 | |
|     std::is_same_v<T, int> ||
 | |
|     std::is_same_v<T, long int> ||
 | |
|     std::is_same_v<T, long long int>;
 | |
| 
 | |
| template <typename T>
 | |
| constexpr bool is_standard_unsigned_integer_v =
 | |
|     std::is_same_v<T, unsigned char> ||
 | |
|     std::is_same_v<T, unsigned short int> ||
 | |
|     std::is_same_v<T, unsigned int> ||
 | |
|     std::is_same_v<T, unsigned long int> ||
 | |
|     std::is_same_v<T, unsigned long long int>;
 | |
| 
 | |
| template <typename T, typename Char> struct formatter;
 | |
| }
 | |
| }
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.arg
 | |
| namespace std {
 | |
|   template<class Context>
 | |
|   class basic_format_arg {
 | |
|   public:
 | |
|     class handle;
 | |
| 
 | |
|   private:
 | |
|     using char_type = typename Context::char_type;                       // exposition only
 | |
| 
 | |
|     variant<monostate, bool, char_type,
 | |
|             int, unsigned int, long long int, unsigned long long int,
 | |
|             double, long double,
 | |
|             const char_type*, basic_string_view<char_type>,
 | |
|             const void*, handle> value;                                  // exposition only
 | |
| 
 | |
|     template<typename T,
 | |
|       typename = enable_if_t<
 | |
|         std::is_same_v<T, bool> ||
 | |
|         std::is_same_v<T, char_type> ||
 | |
|         (std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>) ||
 | |
|         detail::is_standard_integer_v<T> ||
 | |
|         detail::is_standard_unsigned_integer_v<T> ||
 | |
|         sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0
 | |
|     >> explicit basic_format_arg(const T& v) noexcept; // exposition only
 | |
|     explicit basic_format_arg(float n) noexcept;                         // exposition only
 | |
|     explicit basic_format_arg(double n) noexcept;                        // exposition only
 | |
|     explicit basic_format_arg(long double n) noexcept;                   // exposition only
 | |
|     explicit basic_format_arg(const char_type* s);                       // exposition only
 | |
| 
 | |
|     template<class traits>
 | |
|       explicit basic_format_arg(
 | |
|         basic_string_view<char_type, traits> s) noexcept;                // exposition only
 | |
| 
 | |
|     template<class traits, class Allocator>
 | |
|       explicit basic_format_arg(
 | |
|         const basic_string<char_type, traits, Allocator>& s) noexcept;   // exposition only
 | |
| 
 | |
|     explicit basic_format_arg(nullptr_t) noexcept;                       // exposition only
 | |
| 
 | |
|     template<class T, typename = enable_if_t<is_void_v<T>>>
 | |
|       explicit basic_format_arg(const T* p) noexcept;                    // exposition only
 | |
| 
 | |
|     // Fails due to a bug in clang
 | |
|     //template<class Visitor, class Ctx>
 | |
|     //  friend auto visit_format_arg(Visitor&& vis,
 | |
|     //                                    basic_format_arg<Ctx> arg);           // exposition only
 | |
| 
 | |
|     friend auto get_value(basic_format_arg arg) {
 | |
|       return arg.value;
 | |
|     }
 | |
| 
 | |
|     template <typename T, typename Char> friend struct detail::formatter;
 | |
| 
 | |
|     template<class Ctx, class... Args>
 | |
|       friend format_arg_store<Ctx, Args...>
 | |
|         make_format_args(const Args&... args);                           // exposition only
 | |
| 
 | |
|   public:
 | |
|     basic_format_arg() noexcept;
 | |
| 
 | |
|     explicit operator bool() const noexcept;
 | |
|   };
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
| template<class Context>
 | |
| basic_format_arg<Context>::basic_format_arg() noexcept {}
 | |
| 
 | |
| template<class Context>
 | |
| template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T& v) noexcept {
 | |
|   if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, char_type>)
 | |
|     value = v;
 | |
|   else if constexpr (std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>)
 | |
|     value = static_cast<wchar_t>(v);
 | |
|   else if constexpr (detail::is_standard_integer_v<T> && sizeof(T) <= sizeof(int))
 | |
|     value = static_cast<int>(v);
 | |
|   else if constexpr (detail::is_standard_unsigned_integer_v<T> && sizeof(T) <= sizeof(unsigned))
 | |
|     value = static_cast<unsigned>(v);
 | |
|   else if constexpr (detail::is_standard_integer_v<T>)
 | |
|     value = static_cast<long long int>(v);
 | |
|   else if constexpr (detail::is_standard_unsigned_integer_v<T>)
 | |
|     value = static_cast<unsigned long long int>(v);
 | |
|   else if constexpr (sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0)
 | |
|     value = handle(v);
 | |
| }
 | |
| 
 | |
| template<class Context>
 | |
| /* explicit */ basic_format_arg<Context>::basic_format_arg(float n) noexcept
 | |
|   : value(static_cast<double>(n)) {}
 | |
| 
 | |
| template<class Context>
 | |
| /* explicit */ basic_format_arg<Context>::basic_format_arg(double n) noexcept
 | |
|   : value(n) {}
 | |
| 
 | |
| template<class Context>
 | |
| /* explicit */ basic_format_arg<Context>::basic_format_arg(long double n) noexcept
 | |
|   : value(n) {}
 | |
| 
 | |
| template<class Context>
 | |
| /* explicit */ basic_format_arg<Context>::basic_format_arg(const typename basic_format_arg<Context>::char_type* s)
 | |
|   : value(s) {
 | |
|   assert(s != nullptr);
 | |
| }
 | |
| 
 | |
| template<class Context>
 | |
| template<class traits>
 | |
| /* explicit */ basic_format_arg<Context>::basic_format_arg(basic_string_view<char_type, traits> s) noexcept
 | |
|   : value(s) {}
 | |
| 
 | |
| template<class Context>
 | |
| template<class traits, class Allocator>
 | |
| /* explicit */ basic_format_arg<Context>::basic_format_arg(
 | |
|     const basic_string<char_type, traits, Allocator>& s) noexcept
 | |
|   : value(basic_string_view<char_type>(s.data(), s.size())) {}
 | |
| 
 | |
| 
 | |
| template<class Context>
 | |
| /* explicit */ basic_format_arg<Context>::basic_format_arg(nullptr_t) noexcept
 | |
|   : value(static_cast<const void*>(nullptr)) {}
 | |
| 
 | |
| template<class Context>
 | |
| template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T* p) noexcept
 | |
|   : value(p) {}
 | |
| 
 | |
| template<class Context>
 | |
| /* explicit */ basic_format_arg<Context>::operator bool() const noexcept {
 | |
|     return !holds_alternative<monostate>(value);
 | |
| }
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
|   template<class Context>
 | |
|   class basic_format_arg<Context>::handle {
 | |
|     const void* ptr_;                                         // exposition only
 | |
|     void (*format_)(basic_format_parse_context<char_type>&,
 | |
|                     Context&, const void*);                   // exposition only
 | |
| 
 | |
|     template<class T> explicit handle(const T& val) noexcept; // exposition only
 | |
| 
 | |
|     friend class basic_format_arg<Context>;                   // exposition only
 | |
| 
 | |
|   public:
 | |
|     void format(basic_format_parse_context<char_type>&, Context& ctx) const;
 | |
|   };
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
| template<class Context>
 | |
| template<class T> /* explicit */ basic_format_arg<Context>::handle::handle(const T& val) noexcept
 | |
|   : ptr_(&val), format_([](basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx, const void* ptr) {
 | |
|     typename Context::template formatter_type<T> f;
 | |
|     parse_ctx.advance_to(f.parse(parse_ctx));
 | |
|     format_ctx.advance_to(f.format(*static_cast<const T*>(ptr), format_ctx));
 | |
|   }) {}
 | |
| 
 | |
| template<class Context>
 | |
| void basic_format_arg<Context>::handle::format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx) const {
 | |
|   format_(parse_ctx, format_ctx, ptr_);
 | |
| }
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.visit
 | |
| template<class Visitor, class Context>
 | |
|   auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg) {
 | |
|     return visit(vis, get_value(arg));
 | |
|   }
 | |
| }
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.store
 | |
| namespace std {
 | |
|   template<class Context, class... Args>
 | |
|   struct format_arg_store { // exposition only
 | |
|     array<basic_format_arg<Context>, sizeof...(Args)> args;
 | |
|   };
 | |
| }
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.basic_args
 | |
| namespace std {
 | |
|   template<class Context>
 | |
|   class basic_format_args {
 | |
|     size_t size_;                           // exposition only
 | |
|     const basic_format_arg<Context>* data_; // exposition only
 | |
| 
 | |
|   public:
 | |
|     basic_format_args() noexcept;
 | |
| 
 | |
|     template<class... Args>
 | |
|       basic_format_args(const format_arg_store<Context, Args...>& store) noexcept;
 | |
| 
 | |
|     basic_format_arg<Context> get(size_t i) const noexcept;
 | |
|   };
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
| 
 | |
| template<class Context>
 | |
| basic_format_args<Context>::basic_format_args() noexcept : size_(0) {}
 | |
| 
 | |
| template<class Context>
 | |
| template<class... Args>
 | |
|   basic_format_args<Context>::basic_format_args(const format_arg_store<Context, Args...>& store) noexcept
 | |
|   : size_(sizeof...(Args)), data_(store.args.data()) {}
 | |
| 
 | |
| template<class Context>
 | |
| basic_format_arg<Context> basic_format_args<Context>::get(size_t i) const noexcept {
 | |
|   return i < size_ ? data_[i] : basic_format_arg<Context>();
 | |
| }
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
| // https://fmt.dev/Text%20Formatting.html#format.make_args
 | |
| template<class Context /*= format_context*/, class... Args>
 | |
|   format_arg_store<Context, Args...> make_format_args(const Args&... args) {
 | |
|     return {basic_format_arg<Context>(args)...};
 | |
|   }
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.make_wargs
 | |
| template<class... Args>
 | |
|   format_arg_store<wformat_context, Args...> make_wformat_args(const Args&... args) {
 | |
|     return make_format_args<wformat_context>(args...);
 | |
|   }
 | |
| }
 | |
| 
 | |
| namespace std {
 | |
| namespace detail {
 | |
| 
 | |
| template <typename OutputIt, typename Char>
 | |
| class arg_formatter
 | |
|     : public fmt::detail::arg_formatter_base<OutputIt, Char, error_handler> {
 | |
|  private:
 | |
|   using char_type = Char;
 | |
|   using base = fmt::detail::arg_formatter_base<OutputIt, Char, error_handler>;
 | |
|   using format_context = std::basic_format_context<OutputIt, Char>;
 | |
|   using parse_context = basic_format_parse_context<Char>;
 | |
| 
 | |
|   parse_context* parse_ctx_;
 | |
|   format_context& ctx_;
 | |
| 
 | |
|  public:
 | |
|   using iterator = OutputIt;
 | |
|   using format_specs = typename base::format_specs;
 | |
| 
 | |
|   /**
 | |
|     \rst
 | |
|     Constructs an argument formatter object.
 | |
|     *ctx* is a reference to the formatting context,
 | |
|     *spec* contains format specifier information for standard argument types.
 | |
|     \endrst
 | |
|    */
 | |
|   arg_formatter(format_context& ctx, parse_context* parse_ctx = nullptr, fmt::format_specs* spec = nullptr)
 | |
|       : base(ctx.out(), spec, {}), parse_ctx_(parse_ctx), ctx_(ctx) {}
 | |
| 
 | |
|   using base::operator();
 | |
| 
 | |
|   /** Formats an argument of a user-defined type. */
 | |
|   iterator operator()(typename std::basic_format_arg<format_context>::handle handle) {
 | |
|     handle.format(*parse_ctx_, ctx_);
 | |
|     return this->out();
 | |
|   }
 | |
| 
 | |
|   iterator operator()(monostate) {
 | |
|     throw format_error("");
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <typename Context>
 | |
| inline fmt::detail::type get_type(basic_format_arg<Context> arg) {
 | |
|   return visit_format_arg([&] (auto val) {
 | |
|     using char_type = typename Context::char_type;
 | |
|     using T = decltype(val);
 | |
|     if (std::is_same_v<T, monostate>)
 | |
|       return fmt::detail::type::none_type;
 | |
|     if (std::is_same_v<T, bool>)
 | |
|       return fmt::detail::type::bool_type;
 | |
|     if (std::is_same_v<T, char_type>)
 | |
|       return fmt::detail::type::char_type;
 | |
|     if (std::is_same_v<T, int>)
 | |
|       return fmt::detail::type::int_type;
 | |
|     if (std::is_same_v<T, unsigned int>)
 | |
|       return fmt::detail::type::uint_type;
 | |
|     if (std::is_same_v<T, long long int>)
 | |
|       return fmt::detail::type::long_long_type;
 | |
|     if (std::is_same_v<T, unsigned long long int>)
 | |
|       return fmt::detail::type::ulong_long_type;
 | |
|     if (std::is_same_v<T, double>)
 | |
|       return fmt::detail::type::double_type;
 | |
|     if (std::is_same_v<T, long double>)
 | |
|       return fmt::detail::type::long_double_type;
 | |
|     if (std::is_same_v<T, const char_type*>)
 | |
|       return fmt::detail::type::cstring_type;
 | |
|     if (std::is_same_v<T, basic_string_view<char_type>>)
 | |
|       return fmt::detail::type::string_type;
 | |
|     if (std::is_same_v<T, const void*>)
 | |
|       return fmt::detail::type::pointer_type;
 | |
|     assert(get_value(arg).index() == 12);
 | |
|     return fmt::detail::type::custom_type;
 | |
|   }, arg);
 | |
| }
 | |
| 
 | |
| template <typename Context>
 | |
| class custom_formatter {
 | |
|  private:
 | |
|   using parse_context = basic_format_parse_context<typename Context::char_type>;
 | |
|   parse_context& parse_ctx_;
 | |
|   Context& format_ctx_;
 | |
| 
 | |
|  public:
 | |
|   custom_formatter(parse_context& parse_ctx, Context& ctx) : parse_ctx_(parse_ctx), format_ctx_(ctx) {}
 | |
| 
 | |
|   bool operator()(typename basic_format_arg<Context>::handle h) const {
 | |
|     h.format(parse_ctx_, format_ctx_);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   template <typename T> bool operator()(T) const { return false; }
 | |
| };
 | |
| 
 | |
| template <typename ArgFormatter, typename Char, typename Context>
 | |
| struct format_handler : detail::error_handler {
 | |
|   using iterator = typename ArgFormatter::iterator;
 | |
| 
 | |
|   format_handler(iterator out, basic_string_view<Char> str,
 | |
|                  basic_format_args<Context> format_args,
 | |
|                  fmt::detail::locale_ref loc)
 | |
|       : parse_ctx(str), context(out, format_args, loc) {}
 | |
| 
 | |
|   void on_text(const Char* begin, const Char* end) {
 | |
|     auto size = fmt::detail::to_unsigned(end - begin);
 | |
|     auto out = context.out();
 | |
|     auto&& it = fmt::detail::reserve(out, size);
 | |
|     it = std::copy_n(begin, size, it);
 | |
|     context.advance_to(out);
 | |
|   }
 | |
| 
 | |
|   int on_arg_id() { return parse_ctx.next_arg_id(); }
 | |
|   int on_arg_id(unsigned id) { return parse_ctx.check_arg_id(id), id; }
 | |
|   int on_arg_id(fmt::basic_string_view<Char>) { return 0; }
 | |
| 
 | |
|   void on_replacement_field(int id, const Char* p) {
 | |
|     auto arg = context.arg(id);
 | |
|     parse_ctx.advance_to(parse_ctx.begin() + (p  - &*parse_ctx.begin()));
 | |
|     custom_formatter<Context> f(parse_ctx, context);
 | |
|     if (!visit_format_arg(f, arg))
 | |
|       context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx), arg));
 | |
|   }
 | |
| 
 | |
|   const Char* on_format_specs(int id, const Char* begin, const Char* end) {
 | |
|     auto arg = context.arg(id);
 | |
|     parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin()));
 | |
|     custom_formatter<Context> f(parse_ctx, context);
 | |
|     if (visit_format_arg(f, arg)) return &*parse_ctx.begin();
 | |
|     fmt::basic_format_specs<Char> specs;
 | |
|     using fmt::detail::specs_handler;
 | |
|     using parse_context = basic_format_parse_context<Char>;
 | |
|     fmt::detail::specs_checker<specs_handler<parse_context, Context>> handler(
 | |
|         specs_handler<parse_context, Context>(specs, parse_ctx, context), get_type(arg));
 | |
|     begin = parse_format_specs(begin, end, handler);
 | |
|     if (begin == end || *begin != '}') on_error("missing '}' in format string");
 | |
|     parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin()));
 | |
|     context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx, &specs), arg));
 | |
|     return begin;
 | |
|   }
 | |
| 
 | |
|   basic_format_parse_context<Char> parse_ctx;
 | |
|   Context context;
 | |
| };
 | |
| 
 | |
| template <typename T, typename Char>
 | |
| struct formatter {
 | |
|   // Parses format specifiers stopping either at the end of the range or at the
 | |
|   // terminating '}'.
 | |
|   template <typename ParseContext>
 | |
|   FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) {
 | |
|     namespace detail = fmt::detail;
 | |
|     typedef detail::dynamic_specs_handler<ParseContext> handler_type;
 | |
|     auto type = detail::mapped_type_constant<T, fmt::buffer_context<Char>>::value;
 | |
|     detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
 | |
|                                                   type);
 | |
|     auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
 | |
|     auto type_spec = specs_.type;
 | |
|     auto eh = ctx.error_handler();
 | |
|     switch (type) {
 | |
|     case detail::type::none_type:
 | |
|       FMT_ASSERT(false, "invalid argument type");
 | |
|       break;
 | |
|     case detail::type::int_type:
 | |
|     case detail::type::uint_type:
 | |
|     case detail::type::long_long_type:
 | |
|     case detail::type::ulong_long_type:
 | |
|     case detail::type::bool_type:
 | |
|       handle_int_type_spec(type_spec,
 | |
|                            detail::int_type_checker<decltype(eh)>(eh));
 | |
|       break;
 | |
|     case detail::type::char_type:
 | |
|       handle_char_specs(
 | |
|           &specs_, detail::char_specs_checker<decltype(eh)>(type_spec, eh));
 | |
|       break;
 | |
|     case detail::type::double_type:
 | |
|     case detail::type::long_double_type:
 | |
|       detail::parse_float_type_spec(specs_, eh);
 | |
|       break;
 | |
|     case detail::type::cstring_type:
 | |
|       detail::handle_cstring_type_spec(
 | |
|           type_spec, detail::cstring_type_checker<decltype(eh)>(eh));
 | |
|       break;
 | |
|     case detail::type::string_type:
 | |
|       detail::check_string_type_spec(type_spec, eh);
 | |
|       break;
 | |
|     case detail::type::pointer_type:
 | |
|       detail::check_pointer_type_spec(type_spec, eh);
 | |
|       break;
 | |
|     case detail::type::custom_type:
 | |
|       // Custom format specifiers should be checked in parse functions of
 | |
|       // formatter specializations.
 | |
|       break;
 | |
|     }
 | |
|     return it;
 | |
|   }
 | |
| 
 | |
|   template <typename FormatContext>
 | |
|   auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
 | |
|     fmt::detail::handle_dynamic_spec<fmt::detail::width_checker>(
 | |
|         specs_.width, specs_.width_ref, ctx);
 | |
|     fmt::detail::handle_dynamic_spec<fmt::detail::precision_checker>(
 | |
|         specs_.precision, specs_.precision_ref, ctx);
 | |
|     using af = arg_formatter<typename FormatContext::iterator,
 | |
|                              typename FormatContext::char_type>;
 | |
|     return visit_format_arg(af(ctx, nullptr, &specs_),
 | |
|                             basic_format_arg<FormatContext>(val));
 | |
|   }
 | |
| 
 | |
|  private:
 | |
|   fmt::detail::dynamic_format_specs<Char> specs_;
 | |
| };
 | |
| }  // namespace detail
 | |
| 
 | |
| // https://fmt.dev/Text%20Formatting.html#format.functions
 | |
| template<class... Args>
 | |
|   string format(string_view fmt, const Args&... args) {
 | |
|     return vformat(fmt, make_format_args(args...));
 | |
|   }
 | |
| 
 | |
| template<class... Args>
 | |
|   wstring format(wstring_view fmt, const Args&... args) {
 | |
|     return vformat(fmt, make_wformat_args(args...));
 | |
|   }
 | |
| 
 | |
| string vformat(string_view fmt, format_args args) {
 | |
|   fmt::memory_buffer mbuf;
 | |
|   fmt::detail::buffer<char>& buf = mbuf;
 | |
|   using af = detail::arg_formatter<fmt::format_context::iterator, char>;
 | |
|   detail::format_handler<af, char, format_context>
 | |
|     h(fmt::detail::buffer_appender<char>(buf), fmt, args, {});
 | |
|   fmt::detail::parse_format_string<false>(fmt::to_string_view(fmt), h);
 | |
|   return to_string(mbuf);
 | |
| }
 | |
| 
 | |
| wstring vformat(wstring_view fmt, wformat_args args);
 | |
| 
 | |
| template<class Out, class... Args>
 | |
|   Out format_to(Out out, string_view fmt, const Args&... args) {
 | |
|     using context = basic_format_context<Out, decltype(fmt)::value_type>;
 | |
|     return vformat_to(out, fmt, make_format_args<context>(args...));
 | |
|   }
 | |
| 
 | |
| template<class Out, class... Args>
 | |
|   Out format_to(Out out, wstring_view fmt, const Args&... args) {
 | |
|     using context = basic_format_context<Out, decltype(fmt)::value_type>;
 | |
|     return vformat_to(out, fmt, make_format_args<context>(args...));
 | |
|   }
 | |
| 
 | |
| template<class Out>
 | |
|   Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args) {
 | |
|     using af = detail::arg_formatter<Out, char>;
 | |
|     detail::format_handler<af, char, basic_format_context<Out, char>>
 | |
|       h(out, fmt, args, {});
 | |
|     fmt::detail::parse_format_string<false>(fmt::to_string_view(fmt), h);
 | |
|     return h.context.out();
 | |
|   }
 | |
| 
 | |
| template<class Out>
 | |
|   Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args);
 | |
| 
 | |
| template<class Out, class... Args>
 | |
|   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
 | |
|                                       string_view fmt, const Args&... args);
 | |
| template<class Out, class... Args>
 | |
|   format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
 | |
|                                       wstring_view fmt, const Args&... args);
 | |
| 
 | |
| template<class... Args>
 | |
|   size_t formatted_size(string_view fmt, const Args&... args);
 | |
| template<class... Args>
 | |
|   size_t formatted_size(wstring_view fmt, const Args&... args);
 | |
| 
 | |
| #define charT char
 | |
| 
 | |
| template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {};
 | |
| 
 | |
| template<> struct formatter<char, wchar_t>;
 | |
| 
 | |
| template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {};
 | |
| 
 | |
| template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {};
 | |
| 
 | |
| template<size_t N> struct formatter<const charT[N], charT>
 | |
|       : detail::formatter<std::basic_string_view<charT>, charT> {};
 | |
| 
 | |
| template<class traits, class Allocator>
 | |
|   struct formatter<basic_string<charT, traits, Allocator>, charT>
 | |
|       : detail::formatter<std::basic_string_view<charT>, charT> {};
 | |
| 
 | |
| template<class traits>
 | |
|   struct formatter<basic_string_view<charT, traits>, charT>
 | |
|       : detail::formatter<std::basic_string_view<charT>, charT> {};
 | |
| 
 | |
| template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {};
 | |
| template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {};
 | |
| template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {};
 | |
| template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {};
 | |
| 
 | |
| template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {};
 | |
| template <> struct formatter<short, charT> : detail::formatter<int, charT> {};
 | |
| template <> struct formatter<int, charT> : detail::formatter<int, charT> {};
 | |
| template <> struct formatter<long, charT>
 | |
|       : detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {};
 | |
| template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {};
 | |
| template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {};
 | |
| template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {};
 | |
| template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {};
 | |
| template <> struct formatter<unsigned long, charT>
 | |
|       : detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {};
 | |
| template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {};
 | |
| 
 | |
| template <> struct formatter<float, charT> : detail::formatter<double, charT> {};
 | |
| template <> struct formatter<double, charT> : detail::formatter<double, charT> {};
 | |
| template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {};
 | |
| 
 | |
| #undef charT
 | |
| 
 | |
| #define charT wchar_t
 | |
| 
 | |
| template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {};
 | |
| 
 | |
| template<> struct formatter<char, wchar_t> : detail::formatter<charT, charT> {};
 | |
| 
 | |
| template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {};
 | |
| 
 | |
| template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {};
 | |
| 
 | |
| template<size_t N> struct formatter<const charT[N], charT>
 | |
|       : detail::formatter<std::basic_string_view<charT>, charT> {};
 | |
| 
 | |
| template<class traits, class Allocator>
 | |
|   struct formatter<std::basic_string<charT, traits, Allocator>, charT>
 | |
|       : detail::formatter<std::basic_string_view<charT>, charT> {};
 | |
| 
 | |
| template<class traits>
 | |
|   struct formatter<std::basic_string_view<charT, traits>, charT>
 | |
|       : detail::formatter<std::basic_string_view<charT>, charT> {};
 | |
| 
 | |
| template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {};
 | |
| template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {};
 | |
| template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {};
 | |
| template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {};
 | |
| 
 | |
| template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {};
 | |
| template <> struct formatter<short, charT> : detail::formatter<int, charT> {};
 | |
| template <> struct formatter<int, charT> : detail::formatter<int, charT> {};
 | |
| template <> struct formatter<long, charT>
 | |
|       : detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {};
 | |
| template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {};
 | |
| template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {};
 | |
| template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {};
 | |
| template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {};
 | |
| template <> struct formatter<unsigned long, charT>
 | |
|       : detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {};
 | |
| template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {};
 | |
| 
 | |
| template <> struct formatter<float, charT> : detail::formatter<double, charT> {};
 | |
| template <> struct formatter<double, charT> : detail::formatter<double, charT> {};
 | |
| template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {};
 | |
| 
 | |
| #undef charT
 | |
| 
 | |
|   template<> struct formatter<const wchar_t, char> {
 | |
|     formatter() = delete;
 | |
|   };
 | |
| }
 | |
| 
 | |
| #endif  // FMT_FORMAT_
 |