Commit f9e9bf02 authored by Victor Zverovich's avatar Victor Zverovich

Optimize format string parsing

parent c2ce7e4f
...@@ -212,7 +212,14 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) { ...@@ -212,7 +212,14 @@ FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
return static_cast<typename std::make_unsigned<Int>::type>(value); return static_cast<typename std::make_unsigned<Int>::type>(value);
} }
// A constexpr std::char_traits::length replacement for pre-C++17.
template <typename Char>
FMT_CONSTEXPR size_t length(const Char *s) {
const Char *start = s;
while (*s) ++s;
return s - start;
} }
} // namespace internal
/** /**
An implementation of ``std::basic_string_view`` for pre-C++17. It provides a An implementation of ``std::basic_string_view`` for pre-C++17. It provides a
...@@ -255,8 +262,8 @@ class basic_string_view { ...@@ -255,8 +262,8 @@ class basic_string_view {
the size with ``std::char_traits<Char>::length``. the size with ``std::char_traits<Char>::length``.
\endrst \endrst
*/ */
basic_string_view(const Char *s) FMT_CONSTEXPR basic_string_view(const Char *s)
: data_(s), size_(std::char_traits<Char>::length(s)) {} : data_(s), size_(internal::length(s)) {}
/** Constructs a string reference from a ``std::basic_string`` object. */ /** Constructs a string reference from a ``std::basic_string`` object. */
template <typename Alloc> template <typename Alloc>
...@@ -268,7 +275,7 @@ class basic_string_view { ...@@ -268,7 +275,7 @@ class basic_string_view {
: data_(s.data()), size_(s.size()) {} : data_(s.data()), size_(s.size()) {}
/** Returns a pointer to the string data. */ /** Returns a pointer to the string data. */
const Char *data() const { return data_; } FMT_CONSTEXPR const Char *data() const { return data_; }
/** Returns the string size. */ /** Returns the string size. */
FMT_CONSTEXPR size_t size() const { return size_; } FMT_CONSTEXPR size_t size() const { return size_; }
...@@ -1088,7 +1095,8 @@ class basic_format_args { ...@@ -1088,7 +1095,8 @@ class basic_format_args {
format_arg do_get(size_type index) const { format_arg do_get(size_type index) const {
long long signed_types = static_cast<long long>(types_); long long signed_types = static_cast<long long>(types_);
if (signed_types < 0) { if (signed_types < 0) {
unsigned long long num_args = static_cast<unsigned long long>(-signed_types); unsigned long long num_args =
static_cast<unsigned long long>(-signed_types);
return index < num_args ? args_[index] : format_arg(); return index < num_args ? args_[index] : format_arg();
} }
format_arg arg; format_arg arg;
......
...@@ -737,7 +737,7 @@ class null_terminating_iterator { ...@@ -737,7 +737,7 @@ class null_terminating_iterator {
FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r) FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r)
: ptr_(r.begin()), end_(r.end()) {} : ptr_(r.begin()), end_(r.end()) {}
null_terminating_iterator &operator=(const Char *ptr) { FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) {
assert(ptr <= end_); assert(ptr <= end_);
ptr_ = ptr; ptr_ = ptr;
return *this; return *this;
...@@ -2138,25 +2138,28 @@ struct id_adapter { ...@@ -2138,25 +2138,28 @@ struct id_adapter {
Handler &handler; Handler &handler;
}; };
template <typename Iterator, typename Handler> template <typename Char, typename Handler>
FMT_CONSTEXPR void parse_format_string(Iterator it, Handler &&handler) { FMT_CONSTEXPR void parse_format_string(
typedef typename std::iterator_traits<Iterator>::value_type char_type; basic_string_view<Char> format_str, Handler &&handler) {
auto start = it; auto begin = format_str.data();
while (*it) { auto end = begin + format_str.size();
char_type ch = *it++; auto p = begin;
while (p != end) {
Char ch = *p++;
if (ch != '{' && ch != '}') continue; if (ch != '{' && ch != '}') continue;
if (*it == ch) { if (p != end && *p == ch) {
handler.on_text(start, it); handler.on_text(begin, p);
start = ++it; begin = ++p;
continue; continue;
} }
if (ch == '}') { if (ch == '}') {
handler.on_error("unmatched '}' in format string"); handler.on_error("unmatched '}' in format string");
return; return;
} }
handler.on_text(start, it - 1); handler.on_text(begin, p - 1);
it = parse_arg_id(it, id_adapter<Handler, char_type>(handler)); internal::null_terminating_iterator<Char> it(p, end);
it = parse_arg_id(it, id_adapter<Handler, Char>(handler));
if (*it == '}') { if (*it == '}') {
handler.on_replacement_field(it); handler.on_replacement_field(it);
} else if (*it == ':') { } else if (*it == ':') {
...@@ -2170,10 +2173,11 @@ FMT_CONSTEXPR void parse_format_string(Iterator it, Handler &&handler) { ...@@ -2170,10 +2173,11 @@ FMT_CONSTEXPR void parse_format_string(Iterator it, Handler &&handler) {
handler.on_error("missing '}' in format string"); handler.on_error("missing '}' in format string");
return; return;
} }
p = pointer_from(it);
start = ++it; begin = ++p;
} }
handler.on_text(start, it); handler.on_text(begin, p);
} }
template <typename T, typename ParseContext> template <typename T, typename ParseContext>
...@@ -2192,6 +2196,8 @@ class format_string_checker { ...@@ -2192,6 +2196,8 @@ class format_string_checker {
: arg_id_(-1), context_(format_str, eh), : arg_id_(-1), context_(format_str, eh),
parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {} parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
typedef internal::null_terminating_iterator<Char> iterator;
FMT_CONSTEXPR void on_text(const Char *, const Char *) {} FMT_CONSTEXPR void on_text(const Char *, const Char *) {}
FMT_CONSTEXPR void on_arg_id() { FMT_CONSTEXPR void on_arg_id() {
...@@ -2205,12 +2211,12 @@ class format_string_checker { ...@@ -2205,12 +2211,12 @@ class format_string_checker {
} }
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) {} FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) {}
FMT_CONSTEXPR void on_replacement_field(const Char *) {} FMT_CONSTEXPR void on_replacement_field(iterator) {}
FMT_CONSTEXPR const Char *on_format_specs(const Char *s) { FMT_CONSTEXPR const Char *on_format_specs(iterator it) {
context_.advance_to(s); auto p = pointer_from(it);
return to_unsigned(arg_id_) < NUM_ARGS ? context_.advance_to(p);
parse_funcs_[arg_id_](context_) : s; return to_unsigned(arg_id_) < NUM_ARGS ? parse_funcs_[arg_id_](context_) : p;
} }
FMT_CONSTEXPR void on_error(const char *message) { FMT_CONSTEXPR void on_error(const char *message) {
...@@ -2238,7 +2244,7 @@ template <typename Char, typename ErrorHandler, typename... Args> ...@@ -2238,7 +2244,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.begin(), checker); parse_format_string(s, checker);
return true; return true;
} }
...@@ -3297,7 +3303,7 @@ struct format_handler : internal::error_handler { ...@@ -3297,7 +3303,7 @@ struct format_handler : internal::error_handler {
basic_format_args<Context> format_args) basic_format_args<Context> format_args)
: context(r.begin(), str, format_args) {} : context(r.begin(), str, format_args) {}
void on_text(iterator begin, iterator end) { void on_text(const Char *begin, const Char *end) {
auto size = internal::to_unsigned(end - begin); auto size = internal::to_unsigned(end - begin);
auto out = context.out(); auto out = context.out();
auto &&it = internal::reserve(out, size); auto &&it = internal::reserve(out, size);
...@@ -3348,9 +3354,8 @@ template <typename ArgFormatter, typename Char, typename Context> ...@@ -3348,9 +3354,8 @@ template <typename ArgFormatter, typename Char, typename Context>
typename Context::iterator vformat_to(typename ArgFormatter::range out, 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) {
typedef internal::null_terminating_iterator<Char> iterator;
format_handler<ArgFormatter, Char, Context> h(out, format_str, args); format_handler<ArgFormatter, Char, Context> h(out, format_str, args);
parse_format_string(iterator(format_str.begin(), format_str.end()), h); parse_format_string(format_str, h);
return h.context.out(); return h.context.out();
} }
......
...@@ -1760,16 +1760,18 @@ struct test_format_string_handler { ...@@ -1760,16 +1760,18 @@ struct test_format_string_handler {
template <typename T> template <typename T>
FMT_CONSTEXPR void on_arg_id(T) {} FMT_CONSTEXPR void on_arg_id(T) {}
FMT_CONSTEXPR void on_replacement_field(const char *) {} template <typename Iterator>
FMT_CONSTEXPR void on_replacement_field(Iterator) {}
FMT_CONSTEXPR const char *on_format_specs(const char *s) { return s; } template <typename Iterator>
FMT_CONSTEXPR Iterator on_format_specs(Iterator it) { return it; }
FMT_CONSTEXPR void on_error(const char *) { error = true; } FMT_CONSTEXPR void on_error(const char *) { error = true; }
bool error = false; bool error = false;
}; };
FMT_CONSTEXPR bool parse_string(const char *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(s, h);
return !h.error; return !h.error;
......
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