mirror of
https://github.com/fmtlib/fmt.git
synced 2025-01-27 15:35:18 +00:00
Add parse_format_string
This commit is contained in:
parent
57e266ab1d
commit
e926ae78ac
@ -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) {
|
|||||||
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(const char *message) { handler.on_error(message); }
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
start = ++it;
|
||||||
}
|
}
|
||||||
|
handler.on_text(start, it);
|
||||||
if (*it != '}')
|
|
||||||
FMT_THROW(format_error("missing '}' in format string"));
|
|
||||||
|
|
||||||
// Format argument.
|
|
||||||
visit(ArgFormatter(buffer, ctx, specs), arg);
|
|
||||||
return pointer_from(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
|
|||||||
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);
|
|
||||||
|
|
||||||
|
void on_arg_id() { arg = context.next_arg(); }
|
||||||
|
void on_arg_id(unsigned id) {
|
||||||
|
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 on_replacement_field(iterator it) {
|
||||||
|
context.advance_to(pointer_from(it));
|
||||||
|
using internal::custom_formatter;
|
||||||
|
if (visit(custom_formatter<Char, Context>(buffer, context), arg))
|
||||||
|
return;
|
||||||
|
basic_format_specs<Char> specs;
|
||||||
|
visit(ArgFormatter(buffer, context, specs), arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator on_format_specs(iterator it) {
|
||||||
|
context.advance_to(pointer_from(it));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
basic_buffer<Char> &buffer;
|
||||||
|
basic_context<Char> context;
|
||||||
basic_arg<Context> arg;
|
basic_arg<Context> arg;
|
||||||
struct id_handler : internal::error_handler {
|
} handler(buffer, format_str, args);
|
||||||
id_handler(Context &c, basic_arg<Context> &a): context(c), arg(a) {}
|
parse_format_string(iterator(format_str.begin(), format_str.end()), handler);
|
||||||
|
|
||||||
void operator()() { arg = context.next_arg(); }
|
|
||||||
void operator()(unsigned id) {
|
|
||||||
context.check_arg_id(id);
|
|
||||||
arg = context.get_arg(id);
|
|
||||||
}
|
|
||||||
void operator()(basic_string_view<Char> id) {
|
|
||||||
arg = context.get_arg(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
Context &context;
|
|
||||||
basic_arg<Context> &arg;
|
|
||||||
} handler(ctx, arg);
|
|
||||||
|
|
||||||
it = parse_arg_id(it, handler);
|
|
||||||
ctx.advance_to(pointer_from(it));
|
|
||||||
it = internal::do_format_arg<ArgFormatter>(buffer, arg, ctx);
|
|
||||||
if (*it != '}')
|
|
||||||
FMT_THROW(format_error(fmt::format("unknown format specifier")));
|
|
||||||
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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user