mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-24 03:17:53 +00:00
Optimize default formatting
This commit is contained in:
parent
c8a8464f7d
commit
7110b46076
@ -1338,12 +1338,10 @@ FMT_CONSTEXPR void handle_float_type_spec(Char spec, Handler &&handler) {
|
||||
|
||||
template <typename Char, typename Handler>
|
||||
FMT_CONSTEXPR void handle_char_specs(
|
||||
const basic_format_specs<Char> &specs, Handler &&handler) {
|
||||
if (specs.type() && specs.type() != 'c') {
|
||||
handler.on_int();
|
||||
return;
|
||||
}
|
||||
if (specs.align() == ALIGN_NUMERIC || specs.flag(~0u) != 0)
|
||||
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->flag(~0u) != 0)
|
||||
handler.on_error("invalid format specifier for char");
|
||||
handler.on_char();
|
||||
}
|
||||
@ -1470,7 +1468,7 @@ class arg_formatter_base {
|
||||
private:
|
||||
typedef basic_writer<Range> writer_type;
|
||||
writer_type writer_;
|
||||
format_specs &specs_;
|
||||
format_specs *specs_;
|
||||
|
||||
struct char_writer {
|
||||
char_type value;
|
||||
@ -1479,11 +1477,14 @@ class arg_formatter_base {
|
||||
};
|
||||
|
||||
void write_char(char_type value) {
|
||||
writer_.write_padded(1, specs_, char_writer{value});
|
||||
if (specs_)
|
||||
writer_.write_padded(1, *specs_, char_writer{value});
|
||||
else
|
||||
writer_.write(value);
|
||||
}
|
||||
|
||||
void write_pointer(const void *p) {
|
||||
format_specs specs = specs_;
|
||||
format_specs specs = specs_ ? *specs_ : format_specs();
|
||||
specs.flags_ = HASH_FLAG;
|
||||
specs.type_ = 'x';
|
||||
writer_.write_int(reinterpret_cast<uintptr_t>(p), specs);
|
||||
@ -1491,22 +1492,24 @@ class arg_formatter_base {
|
||||
|
||||
protected:
|
||||
writer_type &writer() { return writer_; }
|
||||
format_specs &spec() { return specs_; }
|
||||
format_specs *spec() { return specs_; }
|
||||
iterator out() { return writer_.out(); }
|
||||
|
||||
void write(bool value) {
|
||||
writer_.write_str(string_view(value ? "true" : "false"), specs_);
|
||||
string_view sv(value ? "true" : "false");
|
||||
specs_ ? writer_.write_str(sv, *specs_) : writer_.write(sv);
|
||||
}
|
||||
|
||||
void write(const char_type *value) {
|
||||
if (!value)
|
||||
FMT_THROW(format_error("string pointer is null"));
|
||||
auto length = std::char_traits<char_type>::length(value);
|
||||
writer_.write_str(basic_string_view<char_type>(value, length), specs_);
|
||||
basic_string_view<char_type> sv(value, length);
|
||||
specs_ ? writer_.write_str(sv, *specs_) : writer_.write(sv);
|
||||
}
|
||||
|
||||
public:
|
||||
arg_formatter_base(Range r, format_specs &s): writer_(r), specs_(s) {}
|
||||
arg_formatter_base(Range r, format_specs *s): writer_(r), specs_(s) {}
|
||||
|
||||
iterator operator()(monostate) {
|
||||
FMT_ASSERT(false, "invalid argument type");
|
||||
@ -1519,14 +1522,14 @@ class arg_formatter_base {
|
||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||
// use std::is_same instead.
|
||||
if (std::is_same<T, bool>::value) {
|
||||
if (specs_.type_)
|
||||
if (specs_ && specs_->type_)
|
||||
return (*this)(value ? 1 : 0);
|
||||
write(value != 0);
|
||||
} else if (std::is_same<T, char_type>::value) {
|
||||
internal::handle_char_specs(
|
||||
specs_, char_spec_handler(*this, static_cast<char_type>(value)));
|
||||
} else {
|
||||
writer_.write_int(value, specs_);
|
||||
specs_ ? writer_.write_int(value, *specs_) : writer_.write(value);
|
||||
}
|
||||
return out();
|
||||
}
|
||||
@ -1534,7 +1537,7 @@ class arg_formatter_base {
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
|
||||
operator()(T value) {
|
||||
writer_.write_double(value, specs_);
|
||||
writer_.write_double(value, specs_ ? *specs_ : format_specs());
|
||||
return out();
|
||||
}
|
||||
|
||||
@ -1545,7 +1548,12 @@ class arg_formatter_base {
|
||||
char_spec_handler(arg_formatter_base& f, char_type val)
|
||||
: formatter(f), value(val) {}
|
||||
|
||||
void on_int() { formatter.writer_.write_int(value, formatter.specs_); }
|
||||
void on_int() {
|
||||
if (formatter.specs_)
|
||||
formatter.writer_.write_int(value, *formatter.specs_);
|
||||
else
|
||||
formatter.writer_.write(value);
|
||||
}
|
||||
void on_char() { formatter.write_char(value); }
|
||||
};
|
||||
|
||||
@ -1561,19 +1569,26 @@ class arg_formatter_base {
|
||||
};
|
||||
|
||||
iterator operator()(const char_type *value) {
|
||||
if (!specs_) return write(value), out();
|
||||
internal::handle_cstring_type_spec(
|
||||
specs_.type_, cstring_spec_handler(*this, value));
|
||||
specs_->type_, cstring_spec_handler(*this, value));
|
||||
return out();
|
||||
}
|
||||
|
||||
iterator operator()(basic_string_view<char_type> value) {
|
||||
internal::check_string_type_spec(specs_.type_, internal::error_handler());
|
||||
writer_.write_str(value, specs_);
|
||||
if (specs_) {
|
||||
internal::check_string_type_spec(
|
||||
specs_->type_, internal::error_handler());
|
||||
writer_.write_str(value, *specs_);
|
||||
} else {
|
||||
writer_.write(value);
|
||||
}
|
||||
return out();
|
||||
}
|
||||
|
||||
iterator operator()(const void *value) {
|
||||
check_pointer_type_spec(specs_.type_, internal::error_handler());
|
||||
if (specs_)
|
||||
check_pointer_type_spec(specs_->type_, internal::error_handler());
|
||||
write_pointer(value);
|
||||
return out();
|
||||
}
|
||||
@ -2346,7 +2361,7 @@ class arg_formatter:
|
||||
*spec* contains format specifier information for standard argument types.
|
||||
\endrst
|
||||
*/
|
||||
arg_formatter(context_type &ctx, format_specs &spec)
|
||||
explicit arg_formatter(context_type &ctx, format_specs *spec = {})
|
||||
: base(Range(ctx.out()), spec), ctx_(ctx) {}
|
||||
|
||||
using base::operator();
|
||||
@ -2500,7 +2515,7 @@ class basic_writer {
|
||||
auto &&it = reserve((is_negative ? 1 : 0) + num_digits);
|
||||
if (is_negative)
|
||||
*it++ = '-';
|
||||
internal::format_decimal(it, abs_value, num_digits);
|
||||
it = internal::format_decimal(it, abs_value, num_digits);
|
||||
}
|
||||
|
||||
// The handle_int_type_spec handler that writes an integer.
|
||||
@ -2775,7 +2790,7 @@ class basic_writer {
|
||||
void write(wstring_view value) {
|
||||
internal::require_wchar<char_type>();
|
||||
auto &&it = reserve(value.size());
|
||||
it = std::uninitialized_copy(value.begin(), value.end(), it);
|
||||
it = std::copy(value.begin(), value.end(), it);
|
||||
}
|
||||
|
||||
template <typename... FormatSpecs>
|
||||
@ -3176,7 +3191,7 @@ struct formatter<
|
||||
break;
|
||||
case internal::char_type:
|
||||
handle_char_specs(
|
||||
specs_,
|
||||
&specs_,
|
||||
internal::char_specs_checker<decltype(eh), decltype(type_spec)>(
|
||||
type_spec, eh));
|
||||
break;
|
||||
@ -3211,7 +3226,7 @@ struct formatter<
|
||||
specs_.precision_, specs_.precision_ref, ctx);
|
||||
typedef output_range<typename FormatContext::iterator,
|
||||
typename FormatContext::char_type> range_type;
|
||||
return visit(arg_formatter<range_type>(ctx, specs_),
|
||||
return visit(arg_formatter<range_type>(ctx, &specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
}
|
||||
|
||||
@ -3272,7 +3287,7 @@ class dynamic_formatter {
|
||||
checker.end_precision();
|
||||
typedef output_range<typename FormatContext::iterator,
|
||||
typename FormatContext::char_type> range;
|
||||
visit(arg_formatter<range>(ctx, specs_),
|
||||
visit(arg_formatter<range>(ctx, &specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
return ctx.out();
|
||||
}
|
||||
@ -3328,10 +3343,8 @@ struct format_handler : internal::error_handler {
|
||||
|
||||
void on_replacement_field(const Char *p) {
|
||||
context.parse_context().advance_to(p);
|
||||
if (visit(internal::custom_formatter<Char, Context>(context), arg))
|
||||
return;
|
||||
basic_format_specs<Char> specs;
|
||||
context.advance_to(visit(ArgFormatter(context, specs), arg));
|
||||
if (!visit(internal::custom_formatter<Char, Context>(context), arg))
|
||||
context.advance_to(visit(ArgFormatter(context), arg));
|
||||
}
|
||||
|
||||
iterator on_format_specs(iterator it) {
|
||||
@ -3347,7 +3360,7 @@ struct format_handler : internal::error_handler {
|
||||
if (*it != '}')
|
||||
on_error("missing '}' in format string");
|
||||
parse_ctx.advance_to(pointer_from(it));
|
||||
context.advance_to(visit(ArgFormatter(context, specs), arg));
|
||||
context.advance_to(visit(ArgFormatter(context, &specs), arg));
|
||||
return it;
|
||||
}
|
||||
|
||||
|
@ -222,12 +222,12 @@ class printf_arg_formatter:
|
||||
context_type &context_;
|
||||
|
||||
void write_null_pointer(char) {
|
||||
this->spec().type_ = 0;
|
||||
this->spec()->type_ = 0;
|
||||
this->write("(nil)");
|
||||
}
|
||||
|
||||
void write_null_pointer(wchar_t) {
|
||||
this->spec().type_ = 0;
|
||||
this->spec()->type_ = 0;
|
||||
this->write(L"(nil)");
|
||||
}
|
||||
|
||||
@ -243,7 +243,7 @@ class printf_arg_formatter:
|
||||
*/
|
||||
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
|
||||
format_specs &spec, context_type &ctx)
|
||||
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), spec),
|
||||
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec),
|
||||
context_(ctx) {}
|
||||
|
||||
template <typename T>
|
||||
@ -252,13 +252,13 @@ class printf_arg_formatter:
|
||||
// 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_spec = this->spec();
|
||||
format_specs &fmt_spec = *this->spec();
|
||||
if (fmt_spec.type_ != 's')
|
||||
return base::operator()(value ? 1 : 0);
|
||||
fmt_spec.type_ = 0;
|
||||
this->write(value != 0);
|
||||
} else if (std::is_same<T, char_type>::value) {
|
||||
format_specs &fmt_spec = this->spec();
|
||||
format_specs &fmt_spec = *this->spec();
|
||||
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
|
||||
return (*this)(static_cast<int>(value));
|
||||
fmt_spec.flags_ = 0;
|
||||
@ -280,7 +280,7 @@ class printf_arg_formatter:
|
||||
iterator operator()(const char *value) {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else if (this->spec().type_ == 'p')
|
||||
else if (this->spec()->type_ == 'p')
|
||||
write_null_pointer(char_type());
|
||||
else
|
||||
this->write("(null)");
|
||||
@ -291,7 +291,7 @@ class printf_arg_formatter:
|
||||
iterator operator()(const wchar_t *value) {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else if (this->spec().type_ == 'p')
|
||||
else if (this->spec()->type_ == 'p')
|
||||
write_null_pointer(char_type());
|
||||
else
|
||||
this->write(L"(null)");
|
||||
@ -310,7 +310,7 @@ class printf_arg_formatter:
|
||||
iterator operator()(const void *value) {
|
||||
if (value)
|
||||
return base::operator()(value);
|
||||
this->spec().type_ = 0;
|
||||
this->spec()->type_ = 0;
|
||||
write_null_pointer(char_type());
|
||||
return this->out();
|
||||
}
|
||||
|
@ -19,14 +19,15 @@ class custom_arg_formatter :
|
||||
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||
typedef fmt::arg_formatter<range> base;
|
||||
|
||||
custom_arg_formatter(fmt::format_context &ctx, fmt::format_specs &s)
|
||||
custom_arg_formatter(
|
||||
fmt::format_context &ctx, fmt::format_specs *s = FMT_NULL)
|
||||
: base(ctx, s) {}
|
||||
|
||||
using base::operator();
|
||||
|
||||
iterator operator()(double value) {
|
||||
// Comparing a float to 0.0 is safe
|
||||
if (round(value * pow(10, spec().precision())) == 0.0)
|
||||
if (round(value * pow(10, spec()->precision())) == 0.0)
|
||||
value = 0;
|
||||
return base::operator()(value);
|
||||
}
|
||||
|
@ -1471,7 +1471,7 @@ class mock_arg_formatter:
|
||||
typedef fmt::internal::arg_formatter_base<buffer_range> base;
|
||||
typedef buffer_range range;
|
||||
|
||||
mock_arg_formatter(fmt::format_context &ctx, fmt::format_specs &s)
|
||||
mock_arg_formatter(fmt::format_context &ctx, fmt::format_specs *s = FMT_NULL)
|
||||
: base(fmt::internal::get_container(ctx.out()), s) {
|
||||
EXPECT_CALL(*this, call(42));
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||
|
||||
struct test_arg_formatter: fmt::arg_formatter<range> {
|
||||
test_arg_formatter(fmt::format_context &ctx, fmt::format_specs &s)
|
||||
: fmt::arg_formatter<range>(ctx, s) {}
|
||||
: fmt::arg_formatter<range>(ctx, &s) {}
|
||||
};
|
||||
|
||||
TEST(OStreamTest, CustomArg) {
|
||||
|
Loading…
Reference in New Issue
Block a user