mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-26 09:28:21 +00:00
Optimize format string parsing
This commit is contained in:
parent
c99a259739
commit
e7e9578ed4
@ -2137,25 +2137,62 @@ struct id_adapter {
|
|||||||
Handler &handler;
|
Handler &handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char, typename Handler>
|
template <bool IS_CONSTEXPR, class InputIt, class T>
|
||||||
|
FMT_CONSTEXPR InputIt find(InputIt first, InputIt last, const T &value) {
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
if (*first == value)
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline const char *find<false, const char*, char>(
|
||||||
|
const char *first, const char *last, const char &value) {
|
||||||
|
auto result = static_cast<const char*>(
|
||||||
|
std::memchr(first, value, last - first));
|
||||||
|
return result ? result : last;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool IS_CONSTEXPR, typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR void parse_format_string(
|
FMT_CONSTEXPR void parse_format_string(
|
||||||
basic_string_view<Char> format_str, Handler &&handler) {
|
basic_string_view<Char> format_str, Handler &&handler) {
|
||||||
auto begin = format_str.data();
|
struct writer {
|
||||||
auto end = begin + format_str.size();
|
FMT_CONSTEXPR void operator()(const Char *begin, const Char *end) {
|
||||||
auto p = begin;
|
for (;;) {
|
||||||
while (p != end) {
|
auto p = find<IS_CONSTEXPR>(begin, end, '}');
|
||||||
Char ch = *p++;
|
if (p == end) {
|
||||||
if (ch != '{' && ch != '}') continue;
|
handler_.on_text(begin, end);
|
||||||
if (p != end && *p == ch) {
|
|
||||||
handler.on_text(begin, p);
|
|
||||||
begin = ++p;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ch == '}') {
|
|
||||||
handler.on_error("unmatched '}' in format string");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
handler.on_text(begin, p - 1);
|
++p;
|
||||||
|
if (p == end || *p != '}') {
|
||||||
|
handler_.on_error("unmatched '}' in format string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handler_.on_text(begin, p);
|
||||||
|
begin = p + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Handler &handler_;
|
||||||
|
} write{handler};
|
||||||
|
auto begin = format_str.data();
|
||||||
|
auto end = begin + format_str.size();
|
||||||
|
for (;;) {
|
||||||
|
// Doing two passes with memchr (one for '{' and another for '}') is up to
|
||||||
|
// 2.5x faster than the naive one-pass implementation on long format strings.
|
||||||
|
auto p = find<IS_CONSTEXPR>(begin, end, '{');
|
||||||
|
if (p == end) {
|
||||||
|
write(begin, end);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
write(begin, p);
|
||||||
|
++p;
|
||||||
|
if (p != end && *p == '{') {
|
||||||
|
handler.on_text(p, p + 1);
|
||||||
|
begin = p + 1;
|
||||||
|
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));
|
||||||
@ -2172,11 +2209,8 @@ FMT_CONSTEXPR void parse_format_string(
|
|||||||
handler.on_error("missing '}' in format string");
|
handler.on_error("missing '}' in format string");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
p = pointer_from(it);
|
begin = pointer_from(it) + 1;
|
||||||
|
|
||||||
begin = ++p;
|
|
||||||
}
|
}
|
||||||
handler.on_text(begin, p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename ParseContext>
|
template <typename T, typename ParseContext>
|
||||||
@ -2243,7 +2277,7 @@ template <typename Char, typename ErrorHandler, typename... Args>
|
|||||||
FMT_CONSTEXPR bool check_format_string(
|
FMT_CONSTEXPR bool check_format_string(
|
||||||
basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) {
|
basic_string_view<Char> s, ErrorHandler eh = ErrorHandler()) {
|
||||||
format_string_checker<Char, ErrorHandler, Args...> checker(s, eh);
|
format_string_checker<Char, ErrorHandler, Args...> checker(s, eh);
|
||||||
parse_format_string(s, checker);
|
parse_format_string<true>(s, checker);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3354,7 +3388,7 @@ typename Context::iterator vformat_to(typename ArgFormatter::range out,
|
|||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
basic_format_args<Context> args) {
|
basic_format_args<Context> args) {
|
||||||
format_handler<ArgFormatter, Char, Context> h(out, format_str, args);
|
format_handler<ArgFormatter, Char, Context> h(out, format_str, args);
|
||||||
parse_format_string(format_str, h);
|
internal::parse_format_string<false>(format_str, h);
|
||||||
return h.context.out();
|
return h.context.out();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1773,7 +1773,7 @@ struct test_format_string_handler {
|
|||||||
|
|
||||||
FMT_CONSTEXPR bool parse_string(fmt::string_view s) {
|
FMT_CONSTEXPR bool parse_string(fmt::string_view s) {
|
||||||
test_format_string_handler h;
|
test_format_string_handler h;
|
||||||
fmt::internal::parse_format_string(s, h);
|
fmt::internal::parse_format_string<true>(s, h);
|
||||||
return !h.error;
|
return !h.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user