diff --git a/include/fmt/format.h b/include/fmt/format.h index 45bcef12..f73e8053 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2514,63 +2514,12 @@ template struct id_adapter { Handler& handler; }; -template -FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_replacement_field( - const Char* begin, const Char* end, Handler&& handler) { - ++begin; - if (begin == end) return handler.on_error("invalid format string"), end; - if (static_cast(*begin) == '}') { - handler.on_arg_id(); - handler.on_replacement_field(begin); - } else if (*begin == '{') { - handler.on_text(begin, begin + 1); - } else { - begin = parse_arg_id(begin, end, id_adapter{handler}); - Char c = begin != end ? *begin : Char(); - if (c == '}') { - handler.on_replacement_field(begin); - } else if (c == ':') { - begin = handler.on_format_specs(begin + 1, end); - if (begin == end || *begin != '}') - return handler.on_error("unknown format specifier"), end; - } else { - return handler.on_error("missing '}' in format string"), end; - } - } - return begin + 1; -} - template FMT_CONSTEXPR void parse_format_string(basic_string_view format_str, Handler&& handler) { - auto begin = format_str.data(); - auto end = begin + format_str.size(); - if (end - begin < 32) { - // Use a simple loop instead of memchr for small strings. - const Char* p = begin; - while (p != end) { - auto c = *p++; - if (c == '{') { - handler.on_text(begin, p - 1); - begin = p = parse_replacement_field(p - 1, end, handler); - } else if (c == '}') { - if (p == end || *p != '}') - return handler.on_error("unmatched '}' in format string"); - handler.on_text(begin, p); - begin = ++p; - } - } - handler.on_text(begin, end); - return; - } struct writer { FMT_CONSTEXPR void operator()(const Char* begin, const Char* end) { - if (begin + 1 >= end) { - if (begin == end) return; - if (*begin == '}') - return handler_.on_error("unmatched '}' in format string"); - return handler_.on_text(begin, begin + 1); - } + if (begin == end) return; for (;;) { const Char* p = nullptr; if (!find(begin, end, '}', p)) @@ -2584,6 +2533,8 @@ FMT_CONSTEXPR void parse_format_string(basic_string_view format_str, } Handler& handler_; } write{handler}; + auto begin = format_str.data(); + auto end = begin + format_str.size(); while (begin != end) { // 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. @@ -2591,7 +2542,27 @@ FMT_CONSTEXPR void parse_format_string(basic_string_view format_str, if (*begin != '{' && !find(begin + 1, end, '{', p)) return write(begin, end); write(begin, p); - begin = parse_replacement_field(p, end, handler); + ++p; + if (p == end) return handler.on_error("invalid format string"); + if (static_cast(*p) == '}') { + handler.on_arg_id(); + handler.on_replacement_field(p); + } else if (*p == '{') { + handler.on_text(p, p + 1); + } else { + p = parse_arg_id(p, end, id_adapter{handler}); + Char c = p != end ? *p : Char(); + if (c == '}') { + handler.on_replacement_field(p); + } else if (c == ':') { + p = handler.on_format_specs(p + 1, end); + if (p == end || *p != '}') + return handler.on_error("unknown format specifier"); + } else { + return handler.on_error("missing '}' in format string"); + } + } + begin = p + 1; } }