Simplify argument formatters
This commit is contained in:
parent
0f85a4683a
commit
9cb347b4b2
@ -307,7 +307,9 @@ void format_arg(
|
||||
visit_format_arg(custom_formatter<Context>(parse_ctx, ctx), arg);
|
||||
} else {
|
||||
ctx.advance_to(visit_format_arg(
|
||||
arg_formatter<OutputIt, typename Context::char_type>(ctx), arg));
|
||||
default_arg_formatter<OutputIt, typename Context::char_type>{
|
||||
ctx.out(), ctx.args(), ctx.locale()},
|
||||
arg));
|
||||
}
|
||||
}
|
||||
|
||||
@ -368,10 +370,9 @@ auto vformat_to(OutputIt out, CompiledFormat& cf,
|
||||
if (specs.precision >= 0) checker.check_precision();
|
||||
|
||||
advance_to(parse_ctx, part.arg_id_end);
|
||||
ctx.advance_to(
|
||||
visit_format_arg(arg_formatter<OutputIt, typename Context::char_type>(
|
||||
ctx, &specs),
|
||||
arg));
|
||||
ctx.advance_to(visit_format_arg(
|
||||
arg_formatter<OutputIt, typename Context::char_type>(ctx, specs),
|
||||
arg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1485,11 +1485,10 @@ FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) {
|
||||
}
|
||||
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR void handle_char_specs(const basic_format_specs<Char>* specs,
|
||||
FMT_CONSTEXPR void handle_char_specs(const basic_format_specs<Char>& specs,
|
||||
Handler&& handler) {
|
||||
if (!specs) return handler.on_char();
|
||||
if (specs->type && specs->type != 'c') return handler.on_int();
|
||||
if (specs->align == align::numeric || specs->sign != sign::none || specs->alt)
|
||||
if (specs.type && specs.type != 'c') return handler.on_int();
|
||||
if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
|
||||
handler.on_error("invalid format specifier for char");
|
||||
handler.on_char();
|
||||
}
|
||||
@ -2203,8 +2202,8 @@ class arg_formatter_base {
|
||||
|
||||
private:
|
||||
iterator out_;
|
||||
const format_specs& specs_;
|
||||
locale_ref locale_;
|
||||
format_specs* specs_;
|
||||
|
||||
// Attempts to reserve space for n extra characters in the output range.
|
||||
// Returns a pointer to the reserved range or a reference to out_.
|
||||
@ -2249,7 +2248,7 @@ class arg_formatter_base {
|
||||
}
|
||||
|
||||
void write_pointer(const void* p) {
|
||||
out_ = write_ptr<char_type>(out_, to_uintptr(p), specs_);
|
||||
out_ = write_ptr<char_type>(out_, to_uintptr(p), &specs_);
|
||||
}
|
||||
|
||||
struct char_spec_handler : ErrorHandler {
|
||||
@ -2263,13 +2262,10 @@ class arg_formatter_base {
|
||||
// char is only formatted as int if there are specs.
|
||||
formatter.out_ =
|
||||
detail::write_int(formatter.out_, static_cast<int>(value),
|
||||
*formatter.specs_, formatter.locale_);
|
||||
formatter.specs_, formatter.locale_);
|
||||
}
|
||||
FMT_CONSTEXPR void on_char() {
|
||||
if (formatter.specs_)
|
||||
formatter.out_ = write_char(formatter.out_, value, *formatter.specs_);
|
||||
else
|
||||
formatter.write(value);
|
||||
formatter.out_ = write_char(formatter.out_, value, formatter.specs_);
|
||||
}
|
||||
};
|
||||
|
||||
@ -2286,28 +2282,22 @@ class arg_formatter_base {
|
||||
|
||||
protected:
|
||||
iterator out() { return out_; }
|
||||
format_specs* specs() { return specs_; }
|
||||
const format_specs& specs() { return specs_; }
|
||||
|
||||
FMT_CONSTEXPR void write(bool value) {
|
||||
if (specs_)
|
||||
write(string_view(value ? "true" : "false"), *specs_);
|
||||
else
|
||||
out_ = detail::write<Char>(out_, value);
|
||||
write(string_view(value ? "true" : "false"), specs_);
|
||||
}
|
||||
|
||||
void write(const Char* value) {
|
||||
if (!value) {
|
||||
if (value)
|
||||
write(basic_string_view<char_type>(value), specs_);
|
||||
else
|
||||
FMT_THROW(format_error("string pointer is null"));
|
||||
} else {
|
||||
auto length = std::char_traits<char_type>::length(value);
|
||||
basic_string_view<char_type> sv(value, length);
|
||||
specs_ ? write(sv, *specs_) : write(sv);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr arg_formatter_base(OutputIt out, format_specs* s, locale_ref loc)
|
||||
: out_(out), locale_(loc), specs_(s) {}
|
||||
constexpr arg_formatter_base(OutputIt out, const format_specs& s, locale_ref loc)
|
||||
: out_(out), specs_(s), locale_(loc) {}
|
||||
|
||||
iterator operator()(monostate) {
|
||||
FMT_ASSERT(false, "invalid argument type");
|
||||
@ -2316,8 +2306,7 @@ class arg_formatter_base {
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(is_integral<T>::value)>
|
||||
FMT_CONSTEXPR FMT_INLINE iterator operator()(T value) {
|
||||
return out_ = specs_ ? detail::write_int(out_, value, *specs_, locale_)
|
||||
: detail::write<Char>(out_, value);
|
||||
return out_ = detail::write_int(out_, value, specs_, locale_);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR iterator operator()(Char value) {
|
||||
@ -2327,40 +2316,33 @@ class arg_formatter_base {
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR iterator operator()(bool value) {
|
||||
if (specs_ && specs_->type && specs_->type != 's')
|
||||
return (*this)(value ? 1 : 0);
|
||||
if (specs_.type && specs_.type != 's') return (*this)(value ? 1 : 0);
|
||||
write(value != 0);
|
||||
return out_;
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
||||
iterator operator()(T value) {
|
||||
auto specs = specs_ ? *specs_ : format_specs();
|
||||
if (const_check(is_supported_floating_point(value)))
|
||||
out_ = detail::write(out_, value, specs, locale_);
|
||||
out_ = detail::write(out_, value, specs_, locale_);
|
||||
else
|
||||
FMT_ASSERT(false, "unsupported float argument type");
|
||||
return out_;
|
||||
}
|
||||
|
||||
iterator operator()(const Char* value) {
|
||||
if (!specs_) return write(value), out_;
|
||||
handle_cstring_type_spec(specs_->type, cstring_spec_handler(*this, value));
|
||||
handle_cstring_type_spec(specs_.type, cstring_spec_handler(*this, value));
|
||||
return out_;
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR iterator operator()(basic_string_view<Char> value) {
|
||||
if (specs_) {
|
||||
check_string_type_spec(specs_->type, error_handler());
|
||||
write(value, *specs_);
|
||||
} else {
|
||||
write(value);
|
||||
}
|
||||
check_string_type_spec(specs_.type, error_handler());
|
||||
write(value, specs_);
|
||||
return out_;
|
||||
}
|
||||
|
||||
iterator operator()(const void* value) {
|
||||
if (specs_) check_pointer_type_spec(specs_->type, error_handler());
|
||||
check_pointer_type_spec(specs_.type, error_handler());
|
||||
write_pointer(value);
|
||||
return out_;
|
||||
}
|
||||
@ -2387,8 +2369,7 @@ class arg_formatter : public arg_formatter_base<OutputIt, Char> {
|
||||
*specs* contains format specifier information for standard argument types.
|
||||
\endrst
|
||||
*/
|
||||
constexpr explicit arg_formatter(context_type& ctx,
|
||||
format_specs* specs = nullptr)
|
||||
constexpr explicit arg_formatter(context_type& ctx, const format_specs& specs)
|
||||
: base(ctx.out(), specs, ctx.locale()), ctx_(ctx) {}
|
||||
|
||||
using base::operator();
|
||||
@ -3167,7 +3148,7 @@ struct format_handler : detail::error_handler {
|
||||
begin = parse_format_specs(begin, end, handler);
|
||||
if (begin == end || *begin != '}') on_error("missing '}' in format string");
|
||||
context.advance_to(
|
||||
visit_format_arg(arg_formatter<OutputIt, Char>(context, &specs), arg));
|
||||
visit_format_arg(arg_formatter<OutputIt, Char>(context, specs), arg));
|
||||
return begin;
|
||||
}
|
||||
};
|
||||
@ -3496,7 +3477,7 @@ struct formatter<T, Char,
|
||||
break;
|
||||
case detail::type::char_type:
|
||||
handle_char_specs(
|
||||
&specs_, detail::char_specs_checker<decltype(eh)>(specs_.type, eh));
|
||||
specs_, detail::char_specs_checker<decltype(eh)>(specs_.type, eh));
|
||||
break;
|
||||
case detail::type::float_type:
|
||||
if (detail::const_check(FMT_USE_FLOAT))
|
||||
@ -3544,7 +3525,7 @@ struct formatter<T, Char,
|
||||
specs.precision, specs.precision_ref, ctx);
|
||||
using af = detail::arg_formatter<typename FormatContext::iterator,
|
||||
typename FormatContext::char_type>;
|
||||
return visit_format_arg(af(ctx, &specs),
|
||||
return visit_format_arg(af(ctx, specs),
|
||||
detail::make_arg<FormatContext>(val));
|
||||
}
|
||||
|
||||
@ -3647,7 +3628,7 @@ template <typename Char = char> class dynamic_formatter {
|
||||
if (specs_.precision >= 0) checker.end_precision();
|
||||
using af = detail::arg_formatter<typename FormatContext::iterator,
|
||||
typename FormatContext::char_type>;
|
||||
visit_format_arg(af(ctx, &specs_), detail::make_arg<FormatContext>(val));
|
||||
visit_format_arg(af(ctx, specs_), detail::make_arg<FormatContext>(val));
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
|
@ -52,8 +52,8 @@ inline OutputIt vformat_to(
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
|
||||
inline auto format_to(OutputIt out, const std::locale& loc,
|
||||
const S& format_str, Args&&... args) ->
|
||||
inline auto format_to(OutputIt out, const std::locale& loc, const S& format_str,
|
||||
Args&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
||||
|
@ -207,50 +207,32 @@ template <typename OutputIt, typename Char> class basic_printf_context;
|
||||
*/
|
||||
template <typename OutputIt, typename Char>
|
||||
class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
|
||||
public:
|
||||
using iterator = OutputIt;
|
||||
|
||||
private:
|
||||
using char_type = Char;
|
||||
using base = detail::arg_formatter_base<OutputIt, Char>;
|
||||
using context_type = basic_printf_context<OutputIt, Char>;
|
||||
using format_specs = typename base::format_specs;
|
||||
|
||||
context_type& context_;
|
||||
|
||||
void write_null_pointer(char) {
|
||||
this->specs()->type = 0;
|
||||
this->write("(nil)");
|
||||
}
|
||||
|
||||
void write_null_pointer(wchar_t) {
|
||||
this->specs()->type = 0;
|
||||
this->write(L"(nil)");
|
||||
OutputIt write_null_pointer(bool is_string = false) {
|
||||
auto s = this->specs();
|
||||
s.type = 0;
|
||||
return detail::write(this->out(),
|
||||
string_view(is_string ? "(null)" : "(nil)"), s);
|
||||
}
|
||||
|
||||
public:
|
||||
using format_specs = typename base::format_specs;
|
||||
printf_arg_formatter(OutputIt iter, format_specs& specs, context_type& ctx)
|
||||
: base(iter, specs, detail::locale_ref()), context_(ctx) {}
|
||||
|
||||
/**
|
||||
\rst
|
||||
Constructs an argument formatter object.
|
||||
*buffer* is a reference to the output buffer and *specs* contains format
|
||||
specifier information for standard argument types.
|
||||
\endrst
|
||||
*/
|
||||
printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx)
|
||||
: base(iter, &specs, detail::locale_ref()), context_(ctx) {}
|
||||
OutputIt operator()(monostate value) { return base::operator()(value); }
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(fmt::detail::is_integral<T>::value)>
|
||||
iterator operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||
// use std::is_same instead.
|
||||
if (std::is_same<T, bool>::value) {
|
||||
format_specs& fmt_specs = *this->specs();
|
||||
if (fmt_specs.type != 's') return base::operator()(value ? 1 : 0);
|
||||
fmt_specs.type = 0;
|
||||
this->write(value != 0);
|
||||
} else if (std::is_same<T, char_type>::value) {
|
||||
format_specs& fmt_specs = *this->specs();
|
||||
OutputIt operator()(T value) {
|
||||
// MSVC2013 fails to compile separate overloads for bool and Char so use
|
||||
// std::is_same instead.
|
||||
if (std::is_same<T, Char>::value) {
|
||||
format_specs fmt_specs = this->specs();
|
||||
if (fmt_specs.type && fmt_specs.type != 'c')
|
||||
return (*this)(static_cast<int>(value));
|
||||
fmt_specs.sign = sign::none;
|
||||
@ -260,56 +242,39 @@ class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
|
||||
// ignored for non-numeric types
|
||||
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
|
||||
fmt_specs.align = align::right;
|
||||
return base::operator()(value);
|
||||
} else {
|
||||
return base::operator()(value);
|
||||
return write_char(this->out(), static_cast<Char>(value), fmt_specs);
|
||||
}
|
||||
return this->out();
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
||||
iterator operator()(T value) {
|
||||
OutputIt operator()(T value) {
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
/** Formats a null-terminated C string. */
|
||||
iterator operator()(const char* value) {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else if (this->specs()->type == 'p')
|
||||
write_null_pointer(char_type());
|
||||
else
|
||||
this->write("(null)");
|
||||
return this->out();
|
||||
OutputIt operator()(const char* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs().type != 'p');
|
||||
}
|
||||
|
||||
/** Formats a null-terminated wide C string. */
|
||||
iterator operator()(const wchar_t* value) {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else if (this->specs()->type == 'p')
|
||||
write_null_pointer(char_type());
|
||||
else
|
||||
this->write(L"(null)");
|
||||
return this->out();
|
||||
OutputIt operator()(const wchar_t* value) {
|
||||
if (value) return base::operator()(value);
|
||||
return write_null_pointer(this->specs().type != 'p');
|
||||
}
|
||||
|
||||
iterator operator()(basic_string_view<char_type> value) {
|
||||
OutputIt operator()(basic_string_view<Char> value) {
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
||||
iterator operator()(monostate value) { return base::operator()(value); }
|
||||
|
||||
/** Formats a pointer. */
|
||||
iterator operator()(const void* value) {
|
||||
if (value) return base::operator()(value);
|
||||
this->specs()->type = 0;
|
||||
write_null_pointer(char_type());
|
||||
return this->out();
|
||||
OutputIt operator()(const void* value) {
|
||||
return value ? base::operator()(value) : write_null_pointer();
|
||||
}
|
||||
|
||||
/** Formats an argument of a custom (user-defined) type. */
|
||||
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||
OutputIt operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||
handle.format(context_.parse_context(), context_);
|
||||
return this->out();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user