Commit e926ae78 authored by Victor Zverovich's avatar Victor Zverovich

Add parse_format_string

parent 57e266ab
...@@ -815,6 +815,10 @@ class null_terminating_iterator { ...@@ -815,6 +815,10 @@ class null_terminating_iterator {
return null_terminating_iterator(ptr_ + n, end_); return null_terminating_iterator(ptr_ + n, end_);
} }
null_terminating_iterator operator-(difference_type n) {
return null_terminating_iterator(ptr_ - n, end_);
}
null_terminating_iterator operator+=(difference_type n) { null_terminating_iterator operator+=(difference_type n) {
ptr_ += n; ptr_ += n;
return *this; return *this;
...@@ -3514,28 +3518,51 @@ constexpr Iterator parse_format_specs(Iterator it, SpecHandler &handler) { ...@@ -3514,28 +3518,51 @@ constexpr Iterator parse_format_specs(Iterator it, SpecHandler &handler) {
return it; return it;
} }
// Formats a single argument. template <typename Iterator, typename Handler>
template <typename ArgFormatter, typename Char, typename Context> void parse_format_string(Iterator it, Handler &handler) {
const Char *do_format_arg(basic_buffer<Char> &buffer, using char_type = typename std::iterator_traits<Iterator>::value_type;
const basic_arg<Context> &arg, auto start = it;
Context &ctx) { while (*it) {
auto it = null_terminating_iterator<Char>(ctx); char_type ch = *it++;
basic_format_specs<Char> specs; if (ch != '{' && ch != '}') continue;
if (*it == ':') { if (*it == ch) {
ctx.advance_to(pointer_from(++it)); handler.on_text(start, it);
if (visit(custom_formatter<Char, Context>(buffer, ctx), arg)) start = ++it;
return ctx.begin(); continue;
specs_checker<specs_handler<Context>> }
handler(specs_handler<Context>(specs, ctx), arg.type()); if (ch == '}')
it = parse_format_specs(it, handler); handler.on_error("unmatched '}' in format string");
} handler.on_text(start, it - 1);
struct id_adapter {
explicit id_adapter(Handler &h): handler(h) {}
void operator()() { handler.on_arg_id(); }
void operator()(unsigned id) { handler.on_arg_id(id); }
void operator()(basic_string_view<char_type> id) {
handler.on_arg_id(id);
}
if (*it != '}') void on_error(const char *message) { handler.on_error(message); }
FMT_THROW(format_error("missing '}' in format string"));
Handler &handler;
} adapter(handler);
it = parse_arg_id(it, adapter);
if (*it == '}') {
handler.on_replacement_field(it);
} else if (*it == ':') {
++it;
it = handler.on_format_specs(it);
if (*it != '}')
handler.on_error("unknown format specifier");
} else {
handler.on_error("missing '}' in format string");
}
// Format argument. start = ++it;
visit(ArgFormatter(buffer, ctx, specs), arg); }
return pointer_from(it); handler.on_text(start, it);
} }
// Specifies whether to format T using the standard formatter. // Specifies whether to format T using the standard formatter.
...@@ -3688,47 +3715,57 @@ inline typename basic_context<Char>::format_arg ...@@ -3688,47 +3715,57 @@ inline typename basic_context<Char>::format_arg
template <typename ArgFormatter, typename Char, typename Context> template <typename ArgFormatter, typename Char, typename Context>
void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str, void vformat_to(basic_buffer<Char> &buffer, basic_string_view<Char> format_str,
basic_args<Context> args) { basic_args<Context> args) {
basic_context<Char> ctx(format_str, args); using iterator = internal::null_terminating_iterator<Char>;
auto start = internal::null_terminating_iterator<Char>(ctx);
auto it = start; struct handler : internal::error_handler {
using internal::pointer_from; handler(basic_buffer<Char> &b, basic_string_view<Char> format_str,
while (*it) { basic_args<Context> args)
Char ch = *it++; : buffer(b), context(format_str, args) {}
if (ch != '{' && ch != '}') continue;
if (*it == ch) { void on_text(iterator begin, iterator end) {
buffer.append(pointer_from(start), pointer_from(it)); buffer.append(pointer_from(begin), pointer_from(end));
start = ++it;
continue;
} }
if (ch == '}')
FMT_THROW(format_error("unmatched '}' in format string"));
buffer.append(pointer_from(start), pointer_from(it) - 1);
basic_arg<Context> arg; void on_arg_id() { arg = context.next_arg(); }
struct id_handler : internal::error_handler { void on_arg_id(unsigned id) {
id_handler(Context &c, basic_arg<Context> &a): context(c), arg(a) {} context.check_arg_id(id);
arg = context.get_arg(id);
}
void on_arg_id(basic_string_view<Char> id) {
arg = context.get_arg(id);
}
void operator()() { arg = context.next_arg(); } void on_replacement_field(iterator it) {
void operator()(unsigned id) { context.advance_to(pointer_from(it));
context.check_arg_id(id); using internal::custom_formatter;
arg = context.get_arg(id); if (visit(custom_formatter<Char, Context>(buffer, context), arg))
} return;
void operator()(basic_string_view<Char> id) { basic_format_specs<Char> specs;
arg = context.get_arg(id); visit(ArgFormatter(buffer, context, specs), arg);
} }
Context &context; iterator on_format_specs(iterator it) {
basic_arg<Context> &arg; context.advance_to(pointer_from(it));
} handler(ctx, arg); using internal::custom_formatter;
if (visit(custom_formatter<Char, Context>(buffer, context), arg))
return iterator(context);
basic_format_specs<Char> specs;
using internal::specs_handler;
internal::specs_checker<specs_handler<Context>>
handler(specs_handler<Context>(specs, context), arg.type());
it = parse_format_specs(it, handler);
if (*it != '}')
on_error("missing '}' in format string");
context.advance_to(pointer_from(it));
visit(ArgFormatter(buffer, context, specs), arg);
return it;
}
it = parse_arg_id(it, handler); basic_buffer<Char> &buffer;
ctx.advance_to(pointer_from(it)); basic_context<Char> context;
it = internal::do_format_arg<ArgFormatter>(buffer, arg, ctx); basic_arg<Context> arg;
if (*it != '}') } handler(buffer, format_str, args);
FMT_THROW(format_error(fmt::format("unknown format specifier"))); parse_format_string(iterator(format_str.begin(), format_str.end()), handler);
start = ++it;
}
buffer.append(pointer_from(start), pointer_from(it));
} }
// Casts ``p`` to ``const void*`` for pointer formatting. // Casts ``p`` to ``const void*`` for pointer formatting.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment