Optimize and simplify format string parsing

This commit is contained in:
Victor Zverovich 2018-09-09 08:41:27 -07:00
parent 10c7f89351
commit 5614289dd8

View File

@ -2124,34 +2124,27 @@ FMT_CONSTEXPR void parse_format_string(
basic_string_view<Char> format_str, Handler &&handler) { basic_string_view<Char> format_str, Handler &&handler) {
struct writer { struct writer {
FMT_CONSTEXPR void operator()(const Char *begin, const Char *end) { FMT_CONSTEXPR void operator()(const Char *begin, const Char *end) {
if (begin == end) return;
for (;;) { for (;;) {
const Char *p = FMT_NULL; const Char *p = FMT_NULL;
if (!find<IS_CONSTEXPR>(begin, end, '}', p)) { if (!find<IS_CONSTEXPR>(begin, end, '}', p))
handler_.on_text(begin, end); return handler_.on_text(begin, end);
return;
}
++p; ++p;
if (p == end || *p != '}') { if (p == end || *p != '}')
handler_.on_error("unmatched '}' in format string"); return handler_.on_error("unmatched '}' in format string");
return;
}
handler_.on_text(begin, p); handler_.on_text(begin, p);
begin = p + 1; begin = p + 1;
} }
} }
Handler &handler_; Handler &handler_;
} write{handler}; } write{handler};
auto begin = format_str.data(); auto begin = format_str.data(), end = begin + format_str.size();
auto end = begin + format_str.size();
for (;;) { for (;;) {
// Doing two passes with memchr (one for '{' and another for '}') is up to // Doing two passes with memchr (one for '{' and another for '}') is up to
// 2.5x faster than the naive one-pass implementation on big format strings. // 2.5x faster than the naive one-pass implementation on big format strings.
const Char *p = FMT_NULL; const Char *p = FMT_NULL;
if (!find<IS_CONSTEXPR>(begin, end, '{', p)) { if (!find<IS_CONSTEXPR>(begin, end, '{', p))
if (begin != end) return write(begin, end);
write(begin, end);
return;
}
write(begin, p); write(begin, p);
++p; ++p;
if (p != end && *p == '{') { if (p != end && *p == '{') {
@ -2159,7 +2152,6 @@ FMT_CONSTEXPR void parse_format_string(
begin = p + 1; begin = p + 1;
continue; continue;
} }
internal::null_terminating_iterator<Char> it(p, end); internal::null_terminating_iterator<Char> it(p, end);
it = parse_arg_id(it, id_adapter<Handler, Char>(handler)); it = parse_arg_id(it, id_adapter<Handler, Char>(handler));
if (*it == '}') { if (*it == '}') {
@ -2167,17 +2159,13 @@ FMT_CONSTEXPR void parse_format_string(
} else if (*it == ':') { } else if (*it == ':') {
++it; ++it;
it = handler.on_format_specs(it); it = handler.on_format_specs(it);
if (*it != '}') { if (*it != '}')
handler.on_error("unknown format specifier"); return handler.on_error("unknown format specifier");
return;
}
} else { } else {
handler.on_error("missing '}' in format string"); return handler.on_error("missing '}' in format string");
return;
} }
begin = pointer_from(it) + 1; begin = pointer_from(it) + 1;
if (begin == end) if (begin == end) return;
return;
} }
} }