Cleanup the printf implementation

This commit is contained in:
Victor Zverovich
2021-06-01 20:20:41 -07:00
parent d338d66324
commit 87876d5474

View File

@@ -25,34 +25,25 @@ class basic_printf_parse_context : public basic_format_parse_context<Char> {
}; };
template <typename OutputIt, typename Char> class basic_printf_context { template <typename OutputIt, typename Char> class basic_printf_context {
private:
OutputIt out_;
basic_format_args<basic_printf_context> args_;
public: public:
/** The character type for the output. */
using char_type = Char; using char_type = Char;
using iterator = OutputIt;
using format_arg = basic_format_arg<basic_printf_context>; using format_arg = basic_format_arg<basic_printf_context>;
using parse_context_type = basic_printf_parse_context<Char>; using parse_context_type = basic_printf_parse_context<Char>;
template <typename T> using formatter_type = printf_formatter<T>; template <typename T> using formatter_type = printf_formatter<T>;
private:
using format_specs = basic_format_specs<char_type>;
OutputIt out_;
basic_format_args<basic_printf_context> args_;
parse_context_type parse_ctx_;
static void parse_flags(format_specs& specs, const Char*& it,
const Char* end);
public:
/** /**
\rst \rst
Constructs a ``printf_context`` object. References to the arguments are Constructs a ``printf_context`` object. References to the arguments are
stored in the context object so make sure they have appropriate lifetimes. stored in the context object so make sure they have appropriate lifetimes.
\endrst \endrst
*/ */
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str, basic_printf_context(OutputIt out,
basic_format_args<basic_printf_context> args) basic_format_args<basic_printf_context> args)
: out_(out), args_(args), parse_ctx_(format_str) {} : out_(out), args_(args) {}
OutputIt out() { return out_; } OutputIt out() { return out_; }
void advance_to(OutputIt it) { out_ = it; } void advance_to(OutputIt it) { out_ = it; }
@@ -61,14 +52,8 @@ template <typename OutputIt, typename Char> class basic_printf_context {
format_arg arg(int id) const { return args_.get(id); } format_arg arg(int id) const { return args_.get(id); }
// Returns the argument with specified index or, if arg_index is -1, the next
// argument.
format_arg get_arg(int arg_index = -1);
parse_context_type& parse_context() { return parse_ctx_; }
FMT_CONSTEXPR void on_error(const char* message) { FMT_CONSTEXPR void on_error(const char* message) {
parse_ctx_.on_error(message); detail::error_handler().on_error(message);
} }
}; };
@@ -306,7 +291,9 @@ class printf_arg_formatter : public arg_formatter<Char> {
/** Formats an argument of a custom (user-defined) type. */ /** Formats an argument of a custom (user-defined) type. */
OutputIt 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_); auto parse_ctx =
basic_printf_parse_context<Char>(basic_string_view<Char>());
handle.format(parse_ctx, context_);
return this->out; return this->out;
} }
}; };
@@ -371,7 +358,7 @@ int parse_header(const Char*& it, const Char* end,
} else if (*it == '*') { } else if (*it == '*') {
++it; ++it;
specs.width = static_cast<int>(visit_format_arg( specs.width = static_cast<int>(visit_format_arg(
detail::printf_width_handler<Char>(specs), get_arg())); detail::printf_width_handler<Char>(specs), get_arg(-1)));
} }
} }
return arg_index; return arg_index;
@@ -382,8 +369,19 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) { basic_format_args<Context> args) {
using OutputIt = buffer_appender<Char>; using OutputIt = buffer_appender<Char>;
auto out = OutputIt(buf); auto out = OutputIt(buf);
auto context = basic_printf_context<OutputIt, Char>(out, format, args); auto context = basic_printf_context<OutputIt, Char>(out, args);
auto& parse_ctx = context.parse_context(); auto parse_ctx = basic_printf_parse_context<Char>(format);
// Returns the argument with specified index or, if arg_index is -1, the next
// argument.
auto get_arg = [&](int arg_index) {
if (arg_index < 0)
arg_index = parse_ctx.next_arg_id();
else
parse_ctx.check_arg_id(--arg_index);
return detail::get_arg(context, arg_index);
};
const Char* start = parse_ctx.begin(); const Char* start = parse_ctx.begin();
const Char* end = parse_ctx.end(); const Char* end = parse_ctx.end();
auto it = start; auto it = start;
@@ -406,8 +404,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
specs.align = align::right; specs.align = align::right;
// Parse argument index, flags and width. // Parse argument index, flags and width.
int arg_index = int arg_index = parse_header(it, end, specs, get_arg);
parse_header(it, end, specs, [&]() { return context.get_arg(); });
if (arg_index == 0) parse_ctx.on_error("argument not found"); if (arg_index == 0) parse_ctx.on_error("argument not found");
// Parse precision. // Parse precision.
@@ -419,14 +416,14 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
specs.precision = parse_nonnegative_int(it, end, eh); specs.precision = parse_nonnegative_int(it, end, eh);
} else if (c == '*') { } else if (c == '*') {
++it; ++it;
specs.precision = static_cast<int>(visit_format_arg( specs.precision = static_cast<int>(
detail::printf_precision_handler(), context.get_arg())); visit_format_arg(detail::printf_precision_handler(), get_arg(-1)));
} else { } else {
specs.precision = 0; specs.precision = 0;
} }
} }
auto arg = context.get_arg(arg_index); auto arg = get_arg(arg_index);
// For d, i, o, u, x, and X conversion specifiers, if a precision is // For d, i, o, u, x, and X conversion specifiers, if a precision is
// specified, the '0' flag is ignored // specified, the '0' flag is ignored
if (specs.precision >= 0 && arg.is_integral()) if (specs.precision >= 0 && arg.is_integral())
@@ -520,16 +517,6 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
} }
FMT_END_DETAIL_NAMESPACE FMT_END_DETAIL_NAMESPACE
template <typename OutputIt, typename Char>
typename basic_printf_context<OutputIt, Char>::format_arg
basic_printf_context<OutputIt, Char>::get_arg(int arg_index) {
if (arg_index < 0)
arg_index = parse_ctx_.next_arg_id();
else
parse_ctx_.check_arg_id(--arg_index);
return detail::get_arg(*this, arg_index);
}
template <typename Char> template <typename Char>
using basic_printf_context_t = using basic_printf_context_t =
basic_printf_context<detail::buffer_appender<Char>, Char>; basic_printf_context<detail::buffer_appender<Char>, Char>;