mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-30 13:50:05 +00:00
Add code from p0645
This commit is contained in:
parent
fdd8e333c1
commit
83f052930a
@ -147,7 +147,8 @@ if (HAVE_OPEN)
|
|||||||
set(FMT_SOURCES ${FMT_SOURCES} src/posix.cc)
|
set(FMT_SOURCES ${FMT_SOURCES} src/posix.cc)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} include/format README.rst
|
||||||
|
ChangeLog.rst)
|
||||||
add_library(fmt::fmt ALIAS fmt)
|
add_library(fmt::fmt ALIAS fmt)
|
||||||
|
|
||||||
if (FMT_WERROR)
|
if (FMT_WERROR)
|
||||||
|
@ -1042,7 +1042,7 @@ class context_base {
|
|||||||
|
|
||||||
// Checks if manual indexing is used and returns the argument with
|
// Checks if manual indexing is used and returns the argument with
|
||||||
// specified index.
|
// specified index.
|
||||||
format_arg get_arg(unsigned arg_id) {
|
format_arg arg(unsigned arg_id) {
|
||||||
return this->parse_context().check_arg_id(arg_id) ? this->do_get_arg(arg_id)
|
return this->parse_context().check_arg_id(arg_id) ? this->do_get_arg(arg_id)
|
||||||
: format_arg();
|
: format_arg();
|
||||||
}
|
}
|
||||||
@ -1125,11 +1125,11 @@ class basic_format_context
|
|||||||
void operator=(const basic_format_context&) = delete;
|
void operator=(const basic_format_context&) = delete;
|
||||||
|
|
||||||
typedef internal::context_base<OutputIt, basic_format_context, Char> base;
|
typedef internal::context_base<OutputIt, basic_format_context, Char> base;
|
||||||
typedef typename base::format_arg format_arg;
|
using base::arg;
|
||||||
using base::get_arg;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using typename base::iterator;
|
using typename base::iterator;
|
||||||
|
typedef typename base::format_arg format_arg;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Constructs a ``basic_format_context`` object. References to the arguments are
|
Constructs a ``basic_format_context`` object. References to the arguments are
|
||||||
@ -1143,11 +1143,15 @@ class basic_format_context
|
|||||||
format_arg next_arg() {
|
format_arg next_arg() {
|
||||||
return this->do_get_arg(this->parse_context().next_arg_id());
|
return this->do_get_arg(this->parse_context().next_arg_id());
|
||||||
}
|
}
|
||||||
format_arg get_arg(unsigned arg_id) { return this->do_get_arg(arg_id); }
|
format_arg arg(unsigned arg_id) { return this->do_get_arg(arg_id); }
|
||||||
|
|
||||||
// Checks if manual indexing is used and returns the argument with the
|
// Checks if manual indexing is used and returns the argument with the
|
||||||
// specified name.
|
// specified name.
|
||||||
format_arg get_arg(basic_string_view<char_type> name);
|
format_arg arg(basic_string_view<char_type> name);
|
||||||
|
|
||||||
|
// DEPRECATED!
|
||||||
|
format_arg get_arg(unsigned arg_id) { return arg(arg_id); }
|
||||||
|
format_arg get_arg(basic_string_view<char_type> name) { return arg(name); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char> struct buffer_context {
|
template <typename Char> struct buffer_context {
|
||||||
|
@ -1662,10 +1662,9 @@ template <typename Handler> class specs_checker : public Handler {
|
|||||||
numeric_specs_checker<Handler> checker_;
|
numeric_specs_checker<Handler> checker_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <template <typename> class Handler, typename T, typename Context,
|
template <template <typename> class Handler, typename T, typename FormatArg,
|
||||||
typename ErrorHandler>
|
typename ErrorHandler>
|
||||||
FMT_CONSTEXPR void set_dynamic_spec(T& value, basic_format_arg<Context> arg,
|
FMT_CONSTEXPR void set_dynamic_spec(T& value, FormatArg arg, ErrorHandler eh) {
|
||||||
ErrorHandler eh) {
|
|
||||||
unsigned long long big_value =
|
unsigned long long big_value =
|
||||||
visit_format_arg(Handler<ErrorHandler>(eh), arg);
|
visit_format_arg(Handler<ErrorHandler>(eh), arg);
|
||||||
if (big_value > to_unsigned((std::numeric_limits<int>::max)()))
|
if (big_value > to_unsigned((std::numeric_limits<int>::max)()))
|
||||||
@ -1698,14 +1697,15 @@ class specs_handler : public specs_setter<typename Context::char_type> {
|
|||||||
void on_error(const char* message) { context_.on_error(message); }
|
void on_error(const char* message) { context_.on_error(message); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FMT_CONSTEXPR basic_format_arg<Context> get_arg(auto_id) {
|
// This is only needed for compatibility with gcc 4.4.
|
||||||
return context_.next_arg();
|
typedef typename Context::format_arg format_arg;
|
||||||
}
|
|
||||||
|
FMT_CONSTEXPR format_arg get_arg(auto_id) { return context_.next_arg(); }
|
||||||
|
|
||||||
template <typename Id>
|
template <typename Id>
|
||||||
FMT_CONSTEXPR basic_format_arg<Context> get_arg(Id arg_id) {
|
FMT_CONSTEXPR format_arg get_arg(Id arg_id) {
|
||||||
context_.parse_context().check_arg_id(arg_id);
|
context_.parse_context().check_arg_id(arg_id);
|
||||||
return context_.get_arg(arg_id);
|
return context_.arg(arg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context& context_;
|
Context& context_;
|
||||||
@ -2174,12 +2174,12 @@ void handle_dynamic_spec(Spec& value, arg_ref<typename Context::char_type> ref,
|
|||||||
case arg_ref<char_type>::NONE:
|
case arg_ref<char_type>::NONE:
|
||||||
break;
|
break;
|
||||||
case arg_ref<char_type>::INDEX:
|
case arg_ref<char_type>::INDEX:
|
||||||
internal::set_dynamic_spec<Handler>(value, ctx.get_arg(ref.val.index),
|
internal::set_dynamic_spec<Handler>(value, ctx.arg(ref.val.index),
|
||||||
ctx.error_handler());
|
ctx.error_handler());
|
||||||
break;
|
break;
|
||||||
case arg_ref<char_type>::NAME: {
|
case arg_ref<char_type>::NAME: {
|
||||||
const auto arg_id = ref.val.name.to_view(ctx.parse_context().begin());
|
const auto arg_id = ref.val.name.to_view(ctx.parse_context().begin());
|
||||||
internal::set_dynamic_spec<Handler>(value, ctx.get_arg(arg_id),
|
internal::set_dynamic_spec<Handler>(value, ctx.arg(arg_id),
|
||||||
ctx.error_handler());
|
ctx.error_handler());
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -3050,7 +3050,7 @@ template <typename Char = char> class dynamic_formatter {
|
|||||||
|
|
||||||
template <typename Range, typename Char>
|
template <typename Range, typename Char>
|
||||||
typename basic_format_context<Range, Char>::format_arg
|
typename basic_format_context<Range, Char>::format_arg
|
||||||
basic_format_context<Range, Char>::get_arg(basic_string_view<char_type> name) {
|
basic_format_context<Range, Char>::arg(basic_string_view<char_type> name) {
|
||||||
map_.init(this->args());
|
map_.init(this->args());
|
||||||
format_arg arg = map_.find(name);
|
format_arg arg = map_.find(name);
|
||||||
if (arg.type() == internal::none_type) this->on_error("argument not found");
|
if (arg.type() == internal::none_type) this->on_error("argument not found");
|
||||||
|
@ -418,7 +418,7 @@ typename basic_printf_context<OutputIt, Char, AF>::format_arg
|
|||||||
basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) {
|
basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) {
|
||||||
if (arg_index == std::numeric_limits<unsigned>::max())
|
if (arg_index == std::numeric_limits<unsigned>::max())
|
||||||
return this->do_get_arg(this->parse_context().next_arg_id());
|
return this->do_get_arg(this->parse_context().next_arg_id());
|
||||||
return base::get_arg(arg_index - 1);
|
return base::arg(arg_index - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename Char, typename AF>
|
template <typename OutputIt, typename Char, typename AF>
|
||||||
|
823
include/format
Normal file
823
include/format
Normal file
@ -0,0 +1,823 @@
|
|||||||
|
// 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 <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.
|
||||||
|
|
||||||
|
#define FMT_REQUIRES(...)
|
||||||
|
#define FMT_CONCEPT(C) typename
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template<class T>
|
||||||
|
constexpr bool Integral = is_integral_v<T>;
|
||||||
|
|
||||||
|
template <class O>
|
||||||
|
using iter_difference_t = ptrdiff_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://fmtlib.net/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 O, class charT> FMT_REQUIRES(OutputIterator<O, const charT&>)
|
||||||
|
class basic_format_context;
|
||||||
|
using format_context = basic_format_context<
|
||||||
|
/* unspecified */ std::back_insert_iterator<fmt::internal::basic_buffer<char>>,
|
||||||
|
char>;
|
||||||
|
using wformat_context = basic_format_context<
|
||||||
|
/* unspecified */ std::back_insert_iterator<fmt::internal::basic_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 O, class charT>
|
||||||
|
using format_args_t = basic_format_args<basic_format_context<O, 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<FMT_CONCEPT(OutputIterator<const char&>) O, class... Args>
|
||||||
|
O format_to(O out, string_view fmt, const Args&... args);
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const wchar_t&>) O, class... Args>
|
||||||
|
O format_to(O out, wstring_view fmt, const Args&... args);
|
||||||
|
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const char&>) O>
|
||||||
|
O vformat_to(O out, string_view fmt, format_args_t<O, char> args);
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const wchar_t&>) O>
|
||||||
|
O vformat_to(O out, wstring_view fmt, format_args_t<O, wchar_t> args);
|
||||||
|
|
||||||
|
template<class O>
|
||||||
|
struct format_to_n_result {
|
||||||
|
O out;
|
||||||
|
iter_difference_t<O> size;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const char&>) O, class... Args>
|
||||||
|
format_to_n_result<O> format_to_n(O out, iter_difference_t<O> n,
|
||||||
|
string_view fmt, const Args&... args);
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const wchar_t&>) O, class... Args>
|
||||||
|
format_to_n_result<O> format_to_n(O out, iter_difference_t<O> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://fmtlib.net/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) {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://fmtlib.net/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
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit constexpr basic_format_parse_context(basic_string_view<charT> fmt) 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(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) {}
|
||||||
|
fmt::internal::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) noexcept
|
||||||
|
: begin_(fmt.begin()), end_(fmt.end()), indexing_(unknown), next_arg_id_(0) {}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
if (indexing_ == automatic)
|
||||||
|
throw format_error("automatic to manual indexing");
|
||||||
|
if (indexing_ == unknown)
|
||||||
|
indexing_ = manual;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://fmtlib.net/Text%20Formatting.html#format.context
|
||||||
|
namespace std {
|
||||||
|
template<class O, class charT> FMT_REQUIRES(OutputIterator<O, const charT&>)
|
||||||
|
class basic_format_context {
|
||||||
|
basic_format_parse_context<charT> parse_context_; // exposition only
|
||||||
|
basic_format_args<basic_format_context> args_; // exposition only
|
||||||
|
O out_; // exposition only
|
||||||
|
|
||||||
|
public:
|
||||||
|
using iterator = O;
|
||||||
|
using char_type = charT;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
using formatter_type = formatter<T>;
|
||||||
|
|
||||||
|
basic_format_parse_context<charT>& parse_context() noexcept;
|
||||||
|
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(O out, fmt::string_view fmt, basic_format_args<basic_format_context> args, fmt::internal::locale_ref)
|
||||||
|
: out_(out), parse_context_({fmt.data(), fmt.size()}), args_(args) {}
|
||||||
|
basic_format_arg<basic_format_context> next_arg() {
|
||||||
|
return arg(parse_context_.next_arg_id());
|
||||||
|
}
|
||||||
|
fmt::internal::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_parse_context<charT>& basic_format_context<O, charT>::parse_context() noexcept { return parse_context_; }
|
||||||
|
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://fmtlib.net/Text%20Formatting.html#format.arg
|
||||||
|
namespace std {
|
||||||
|
template<class Context>
|
||||||
|
class basic_format_arg {
|
||||||
|
public:
|
||||||
|
class handle;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
basic_format_arg() noexcept;
|
||||||
|
|
||||||
|
template<FMT_CONCEPT(Integral) I, typename = std::enable_if_t<Integral<I>>> explicit basic_format_arg(I n) 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) noexcept; // exposition only
|
||||||
|
explicit basic_format_arg(nullptr_t) noexcept; // 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
|
||||||
|
|
||||||
|
template<class T, typename = std::enable_if_t<std::is_same_v<T, void>>>
|
||||||
|
explicit basic_format_arg(const T* p) noexcept; // exposition only
|
||||||
|
|
||||||
|
template<class T, typename = std::enable_if_t<
|
||||||
|
!Integral<T> && is_default_constructible_v<formatter<T, char_type>>>>
|
||||||
|
explicit basic_format_arg(const T& v) noexcept; // exposition only
|
||||||
|
|
||||||
|
explicit operator bool() const noexcept;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template<class Context>
|
||||||
|
basic_format_arg<Context>::basic_format_arg() noexcept {}
|
||||||
|
|
||||||
|
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<class Context>
|
||||||
|
template<FMT_CONCEPT(Integral) I, typename>
|
||||||
|
/* explicit */ basic_format_arg<Context>::basic_format_arg(I n) noexcept {
|
||||||
|
if (std::is_same_v<I, bool> || std::is_same_v<I, char_type>)
|
||||||
|
value = n;
|
||||||
|
else if (std::is_same_v<I, char> || std::is_same_v<char_type, wchar_t>)
|
||||||
|
value = static_cast<wchar_t>(n);
|
||||||
|
else if (std::is_standard_integer_v<I> && sizeof(I) <= sizeof(int))
|
||||||
|
value = static_cast<int>(n);
|
||||||
|
else if (std::is_standard_integer_v<I> && sizeof(I) <= sizeof(unsigned))
|
||||||
|
value = static_cast<unsigned>(n);
|
||||||
|
else if (std::is_standard_integer_v<I>)
|
||||||
|
value = static_cast<long long int>(n);
|
||||||
|
else if (std::is_standard_integer_v<I>)
|
||||||
|
value = static_cast<unsigned long long int>(n);
|
||||||
|
else assert(false); // should be a compile-time error instead
|
||||||
|
}
|
||||||
|
|
||||||
|
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) noexcept
|
||||||
|
: 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>
|
||||||
|
template<class T, typename>
|
||||||
|
/* explicit */ basic_format_arg<Context>::basic_format_arg(const T& v) noexcept
|
||||||
|
: value(handle(v)) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template<class Context>
|
||||||
|
class basic_format_arg<Context>::handle {
|
||||||
|
const void* ptr_; // exposition only
|
||||||
|
void (*format_)(Context&, const void*); // exposition only
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class T> explicit handle(const T& val) noexcept; // exposition only
|
||||||
|
|
||||||
|
void format(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_([](Context& ctx, const void* ptr) {
|
||||||
|
typename Context::template formatter_type<T> f;
|
||||||
|
ctx.parse_context().advance_to(f.parse(ctx.parse_context()));
|
||||||
|
ctx.advance_to(f.format(*static_cast<const T*>(ptr), ctx));
|
||||||
|
}) {}
|
||||||
|
|
||||||
|
template<class Context>
|
||||||
|
void basic_format_arg<Context>::handle::format(Context& ctx) const {
|
||||||
|
format_(ctx, ptr_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://fmtlib.net/Text%20Formatting.html#format.visit
|
||||||
|
template<class Visitor, class Context>
|
||||||
|
auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg) {
|
||||||
|
return visit(vis, arg.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://fmtlib.net/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;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://fmtlib.net/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 {
|
||||||
|
// http://fmtlib.net/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)...};
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://fmtlib.net/Text%20Formatting.html#format.make_wargs
|
||||||
|
template<class... Args>
|
||||||
|
format_arg_store<wformat_context, Args...> make_wformat_args(const Args&... args) {
|
||||||
|
return {basic_format_arg<wformat_context>(args)...};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
class arg_formatter
|
||||||
|
: public fmt::internal::function<
|
||||||
|
typename fmt::internal::arg_formatter_base<Range>::iterator>,
|
||||||
|
public fmt::internal::arg_formatter_base<Range> {
|
||||||
|
private:
|
||||||
|
typedef typename Range::value_type char_type;
|
||||||
|
typedef fmt::internal::arg_formatter_base<Range> base;
|
||||||
|
typedef std::basic_format_context<typename base::iterator, char_type> context_type;
|
||||||
|
|
||||||
|
context_type& 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
|
||||||
|
*/
|
||||||
|
explicit arg_formatter(context_type& ctx, fmt::format_specs* spec = FMT_NULL)
|
||||||
|
: base(Range(ctx.out()), spec, {}), ctx_(ctx) {}
|
||||||
|
|
||||||
|
using base::operator();
|
||||||
|
|
||||||
|
/** Formats an argument of a user-defined type. */
|
||||||
|
iterator operator()(typename std::basic_format_arg<context_type>::handle handle) {
|
||||||
|
handle.format(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::none_type;
|
||||||
|
if (std::is_same_v<T, bool>)
|
||||||
|
return fmt::internal::bool_type;
|
||||||
|
if (std::is_same_v<T, char_type>)
|
||||||
|
return fmt::internal::char_type;
|
||||||
|
if (std::is_same_v<T, int>)
|
||||||
|
return fmt::internal::int_type;
|
||||||
|
if (std::is_same_v<T, unsigned int>)
|
||||||
|
return fmt::internal::uint_type;
|
||||||
|
if (std::is_same_v<T, long long int>)
|
||||||
|
return fmt::internal::long_long_type;
|
||||||
|
if (std::is_same_v<T, unsigned long long int>)
|
||||||
|
return fmt::internal::ulong_long_type;
|
||||||
|
if (std::is_same_v<T, double>)
|
||||||
|
return fmt::internal::double_type;
|
||||||
|
if (std::is_same_v<T, long double>)
|
||||||
|
return fmt::internal::long_double_type;
|
||||||
|
if (std::is_same_v<T, const char_type*>)
|
||||||
|
return fmt::internal::cstring_type;
|
||||||
|
if (std::is_same_v<T, basic_string_view<char_type>>)
|
||||||
|
return fmt::internal::string_type;
|
||||||
|
if (std::is_same_v<T, const void*>)
|
||||||
|
return fmt::internal::pointer_type;
|
||||||
|
assert(arg.value.index() == 12);
|
||||||
|
return fmt::internal::custom_type;
|
||||||
|
}, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename Context>
|
||||||
|
class custom_formatter {
|
||||||
|
private:
|
||||||
|
Context& ctx_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit custom_formatter(Context& ctx) : ctx_(ctx) {}
|
||||||
|
|
||||||
|
bool operator()(typename basic_format_arg<Context>::handle h) const {
|
||||||
|
h.format(ctx_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> bool operator()(T) const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ArgFormatter, typename Char, typename Context>
|
||||||
|
struct format_handler : fmt::internal::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)
|
||||||
|
: context(r.begin(), str, 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.next_arg(); }
|
||||||
|
void on_arg_id(unsigned id) {
|
||||||
|
context.parse_context().check_arg_id(id);
|
||||||
|
arg = context.arg(id);
|
||||||
|
}
|
||||||
|
void on_arg_id(fmt::basic_string_view<Char> id) {}
|
||||||
|
|
||||||
|
void on_replacement_field(const Char* p) {
|
||||||
|
context.parse_context().advance_to(p);
|
||||||
|
custom_formatter<Char, Context> f(context);
|
||||||
|
if (!visit_format_arg(f, arg))
|
||||||
|
context.advance_to(visit_format_arg(ArgFormatter(context), arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
const Char* on_format_specs(const Char* begin, const Char* end) {
|
||||||
|
auto& parse_ctx = context.parse_context();
|
||||||
|
parse_ctx.advance_to(begin);
|
||||||
|
custom_formatter<Char, Context> f(context);
|
||||||
|
if (visit_format_arg(f, arg)) return parse_ctx.begin();
|
||||||
|
fmt::basic_format_specs<Char> specs;
|
||||||
|
using fmt::internal::specs_handler;
|
||||||
|
fmt::internal::specs_checker<specs_handler<Context>> handler(
|
||||||
|
specs_handler<Context>(specs, 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(begin);
|
||||||
|
context.advance_to(visit_format_arg(ArgFormatter(context, &specs), arg));
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
|
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::get_type<typename fmt::buffer_context<Char>::type, T>::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::none_type:
|
||||||
|
case internal::named_arg_type:
|
||||||
|
FMT_ASSERT(false, "invalid argument type");
|
||||||
|
break;
|
||||||
|
case internal::int_type:
|
||||||
|
case internal::uint_type:
|
||||||
|
case internal::long_long_type:
|
||||||
|
case internal::ulong_long_type:
|
||||||
|
case internal::bool_type:
|
||||||
|
handle_int_type_spec(type_spec,
|
||||||
|
internal::int_type_checker<decltype(eh)>(eh));
|
||||||
|
break;
|
||||||
|
case internal::char_type:
|
||||||
|
handle_char_specs(
|
||||||
|
&specs_, internal::char_specs_checker<decltype(eh)>(type_spec, eh));
|
||||||
|
break;
|
||||||
|
case internal::double_type:
|
||||||
|
case internal::long_double_type:
|
||||||
|
handle_float_type_spec(type_spec,
|
||||||
|
internal::float_type_checker<decltype(eh)>(eh));
|
||||||
|
break;
|
||||||
|
case internal::cstring_type:
|
||||||
|
internal::handle_cstring_type_spec(
|
||||||
|
type_spec, internal::cstring_type_checker<decltype(eh)>(eh));
|
||||||
|
break;
|
||||||
|
case internal::string_type:
|
||||||
|
internal::check_string_type_spec(type_spec, eh);
|
||||||
|
break;
|
||||||
|
case internal::pointer_type:
|
||||||
|
internal::check_pointer_type_spec(type_spec, eh);
|
||||||
|
break;
|
||||||
|
case internal::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);
|
||||||
|
typedef fmt::output_range<typename FormatContext::iterator,
|
||||||
|
typename FormatContext::char_type>
|
||||||
|
range_type;
|
||||||
|
return visit_format_arg(arg_formatter<range_type>(ctx, &specs_),
|
||||||
|
basic_format_arg<FormatContext>(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
fmt::internal::dynamic_format_specs<Char> specs_;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// http://fmtlib.net/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& buf = mbuf;
|
||||||
|
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||||
|
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<FMT_CONCEPT(OutputIterator<const char&>) O, class... Args>
|
||||||
|
O format_to(O out, string_view fmt, const Args&... args) {
|
||||||
|
return vformat_to(out, fmt, {make_format_args<basic_format_context<O, char>>(args...)});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const wchar_t&>) O, class... Args>
|
||||||
|
O format_to(O out, wstring_view fmt, const Args&... args) {
|
||||||
|
return vformat_to(out, fmt, {make_format_args<basic_format_context<O, wchar_t>>(args...)});
|
||||||
|
}
|
||||||
|
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const char&>) O>
|
||||||
|
O vformat_to(O out, string_view fmt, format_args_t<O, char> args) {
|
||||||
|
typedef fmt::output_range<O, char> range;
|
||||||
|
detail::format_handler<detail::arg_formatter<range>, char, format_context>
|
||||||
|
h(range(out), fmt, args, {});
|
||||||
|
fmt::internal::parse_format_string<false>(fmt::to_string_view(fmt), h);
|
||||||
|
return h.context.out();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const wchar_t&>) O>
|
||||||
|
O vformat_to(O out, wstring_view fmt, format_args_t<O, wchar_t> args);
|
||||||
|
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const char&>) O, class... Args>
|
||||||
|
format_to_n_result<O> format_to_n(O out, iter_difference_t<O> n,
|
||||||
|
string_view fmt, const Args&... args);
|
||||||
|
template<FMT_CONCEPT(OutputIterator<const wchar_t&>) O, class... Args>
|
||||||
|
format_to_n_result<O> format_to_n(O out, iter_difference_t<O> 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<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
|
||||||
|
|
||||||
|
#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_
|
@ -2142,13 +2142,14 @@ TEST(FormatTest, ConstexprParseFormatSpecs) {
|
|||||||
|
|
||||||
struct test_context {
|
struct test_context {
|
||||||
typedef char char_type;
|
typedef char char_type;
|
||||||
|
typedef fmt::basic_format_arg<test_context> format_arg;
|
||||||
|
|
||||||
FMT_CONSTEXPR fmt::basic_format_arg<test_context> next_arg() {
|
FMT_CONSTEXPR fmt::basic_format_arg<test_context> next_arg() {
|
||||||
return fmt::internal::make_arg<test_context>(11);
|
return fmt::internal::make_arg<test_context>(11);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Id>
|
template <typename Id>
|
||||||
FMT_CONSTEXPR fmt::basic_format_arg<test_context> get_arg(Id) {
|
FMT_CONSTEXPR fmt::basic_format_arg<test_context> arg(Id) {
|
||||||
return fmt::internal::make_arg<test_context>(22);
|
return fmt::internal::make_arg<test_context>(22);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user