summaryrefslogtreecommitdiffstats
path: root/src/fmt/test/format
diff options
context:
space:
mode:
Diffstat (limited to 'src/fmt/test/format')
-rw-r--r--src/fmt/test/format860
1 files changed, 860 insertions, 0 deletions
diff --git a/src/fmt/test/format b/src/fmt/test/format
new file mode 100644
index 000000000..589ac2412
--- /dev/null
+++ b/src/fmt/test/format
@@ -0,0 +1,860 @@
+// 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 */ std::back_insert_iterator<fmt::internal::buffer<char>>, char>;
+ using wformat_context = basic_format_context<
+ /* unspecified */ std::back_insert_iterator<fmt::internal::buffer<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::internal::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 Range>
+class arg_formatter
+ : public fmt::internal::arg_formatter_base<Range, error_handler> {
+ private:
+ using char_type = typename Range::value_type;
+ using base = fmt::internal::arg_formatter_base<Range, error_handler>;
+ using format_context = std::basic_format_context<typename base::iterator, char_type>;
+ using parse_context = basic_format_parse_context<char_type>;
+
+ parse_context* parse_ctx_;
+ format_context& ctx_;
+
+ public:
+ typedef Range range;
+ typedef typename base::iterator iterator;
+ typedef typename base::format_specs 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(Range(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::internal::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::internal::type::none_type;
+ if (std::is_same_v<T, bool>)
+ return fmt::internal::type::bool_type;
+ if (std::is_same_v<T, char_type>)
+ return fmt::internal::type::char_type;
+ if (std::is_same_v<T, int>)
+ return fmt::internal::type::int_type;
+ if (std::is_same_v<T, unsigned int>)
+ return fmt::internal::type::uint_type;
+ if (std::is_same_v<T, long long int>)
+ return fmt::internal::type::long_long_type;
+ if (std::is_same_v<T, unsigned long long int>)
+ return fmt::internal::type::ulong_long_type;
+ if (std::is_same_v<T, double>)
+ return fmt::internal::type::double_type;
+ if (std::is_same_v<T, long double>)
+ return fmt::internal::type::long_double_type;
+ if (std::is_same_v<T, const char_type*>)
+ return fmt::internal::type::cstring_type;
+ if (std::is_same_v<T, basic_string_view<char_type>>)
+ return fmt::internal::type::string_type;
+ if (std::is_same_v<T, const void*>)
+ return fmt::internal::type::pointer_type;
+ assert(get_value(arg).index() == 12);
+ return fmt::internal::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 {
+ typedef typename ArgFormatter::range range;
+
+ format_handler(range r, basic_string_view<Char> str,
+ basic_format_args<Context> format_args,
+ fmt::internal::locale_ref loc)
+ : parse_ctx(str), context(r.begin(), format_args, loc) {}
+
+ void on_text(const Char* begin, const Char* end) {
+ auto size = fmt::internal::to_unsigned(end - begin);
+ auto out = context.out();
+ auto&& it = fmt::internal::reserve(out, size);
+ it = std::copy_n(begin, size, it);
+ context.advance_to(out);
+ }
+
+ void on_arg_id() {
+ arg = context.arg(parse_ctx.next_arg_id());
+ }
+ void on_arg_id(unsigned id) {
+ parse_ctx.check_arg_id(id);
+ arg = context.arg(id);
+ }
+ void on_arg_id(fmt::basic_string_view<Char>) {}
+
+ void on_replacement_field(const Char* p) {
+ 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(const Char* begin, const Char* end) {
+ 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::internal::specs_handler;
+ using parse_context = basic_format_parse_context<Char>;
+ fmt::internal::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;
+ basic_format_arg<Context> arg;
+};
+
+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 internal = fmt::internal;
+ typedef internal::dynamic_specs_handler<ParseContext> handler_type;
+ auto type = internal::mapped_type_constant<T, fmt::buffer_context<Char>>::value;
+ internal::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 internal::type::none_type:
+ FMT_ASSERT(false, "invalid argument type");
+ break;
+ case internal::type::int_type:
+ case internal::type::uint_type:
+ case internal::type::long_long_type:
+ case internal::type::ulong_long_type:
+ case internal::type::bool_type:
+ handle_int_type_spec(type_spec,
+ internal::int_type_checker<decltype(eh)>(eh));
+ break;
+ case internal::type::char_type:
+ handle_char_specs(
+ &specs_, internal::char_specs_checker<decltype(eh)>(type_spec, eh));
+ break;
+ case internal::type::double_type:
+ case internal::type::long_double_type:
+ internal::parse_float_type_spec(specs_, eh);
+ break;
+ case internal::type::cstring_type:
+ internal::handle_cstring_type_spec(
+ type_spec, internal::cstring_type_checker<decltype(eh)>(eh));
+ break;
+ case internal::type::string_type:
+ internal::check_string_type_spec(type_spec, eh);
+ break;
+ case internal::type::pointer_type:
+ internal::check_pointer_type_spec(type_spec, eh);
+ break;
+ case internal::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::internal::handle_dynamic_spec<fmt::internal::width_checker>(
+ specs_.width, specs_.width_ref, ctx);
+ fmt::internal::handle_dynamic_spec<fmt::internal::precision_checker>(
+ specs_.precision, specs_.precision_ref, ctx);
+ using range_type = fmt::internal::output_range<typename FormatContext::iterator,
+ typename FormatContext::char_type>;
+ return visit_format_arg(arg_formatter<range_type>(ctx, nullptr, &specs_),
+ basic_format_arg<FormatContext>(val));
+ }
+
+ private:
+ fmt::internal::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::internal::buffer<char>& buf = mbuf;
+ using range = fmt::buffer_range<char>;
+ detail::format_handler<detail::arg_formatter<range>, char, format_context>
+ h(range(std::back_inserter(buf)), fmt, args, {});
+ fmt::internal::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 range = fmt::internal::output_range<Out, char>;
+ detail::format_handler<detail::arg_formatter<range>, char, basic_format_context<Out, char>>
+ h(range(out), fmt, args, {});
+ fmt::internal::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_