diff options
Diffstat (limited to 'src/fmt/test/format')
-rw-r--r-- | src/fmt/test/format | 860 |
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_ |