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