diff --git a/fmt/format.h b/fmt/format.h index 8f323c4c..c1f723ac 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -351,6 +351,8 @@ class basic_string_view { std::size_t size_; public: + using char_type = Char; + basic_string_view() : data_(0), size_(0) {} /** Constructs a string reference object from a C string and a size. */ @@ -388,6 +390,9 @@ class basic_string_view { /** Returns the string size. */ std::size_t size() const { return size_; } + const Char *begin() const { return data_; } + const Char *end() const { return data_ + size_; } + void remove_prefix(size_t n) { data_ += n; size_ -= n; @@ -425,9 +430,6 @@ class basic_string_view { typedef basic_string_view string_view; typedef basic_string_view wstring_view; -template -inline const Char *begin(basic_string_view s) { return s.data(); } - /** A formatting error such as invalid format string. */ class format_error : public std::runtime_error { public: @@ -776,7 +778,7 @@ class null_terminating_iterator { : ptr_(ptr), end_(end) {} explicit null_terminating_iterator(basic_string_view s) - : ptr_(s.data()), end_(s.data() + s.size()) {} + : ptr_(s.begin()), end_(s.end()) {} null_terminating_iterator &operator=(const Char *ptr) { assert(ptr <= end_); @@ -1324,7 +1326,7 @@ class value { // `printf_formatter` for `printf`. typename Context::template formatter_type f; auto it = f.parse(format); - format.remove_prefix(it - begin(format)); + format.remove_prefix(it - format.begin()); f.format(buffer, *static_cast(arg), ctx); } }; @@ -3230,11 +3232,19 @@ struct dynamic_format_specs : basic_format_specs { arg_ref precision_ref; }; -template -class dynamic_specs_handler: public specs_setter { +// Format spec handler that saves references to arguments representing dynamic +// width and precision to be resolved at formatting time. +// ParseContext: parsing context representing a sequence of format string +// characters and an argument counter for automatic indexing. +template +class dynamic_specs_handler : + public specs_setter { public: - dynamic_specs_handler(dynamic_format_specs &specs) - : specs_setter(specs), specs_(specs) {} + using char_type = typename ParseContext::char_type; + + dynamic_specs_handler( + dynamic_format_specs &specs, ParseContext &ctx) + : specs_setter(specs), specs_(specs), context_(ctx) {} template void on_dynamic_width(Id arg_id) { @@ -3247,7 +3257,7 @@ class dynamic_specs_handler: public specs_setter { } private: - using arg_ref = arg_ref; + using arg_ref = arg_ref; template arg_ref make_arg_ref(Id arg_id) { @@ -3255,10 +3265,12 @@ class dynamic_specs_handler: public specs_setter { } arg_ref make_arg_ref(auto_id) { + // TODO: get next index from context return arg_ref(arg_ref::NONE); } - dynamic_format_specs &specs_; + dynamic_format_specs &specs_; + ParseContext &context_; }; template @@ -3417,7 +3429,7 @@ const Char *do_format_arg(basic_buffer &buffer, if (*it == ':') { format.remove_prefix(1); if (visit(custom_formatter(buffer, format, ctx), arg)) - return begin(format); + return format.begin(); specs_checker> handler(specs_handler(specs, ctx), arg.type()); it = parse_format_specs(it + 1, handler); @@ -3466,12 +3478,12 @@ struct formatter< // Parses format specifiers stopping either at the end of the range or at the // terminating '}'. - template - auto parse(Range format) -> decltype(begin(format)) { - auto it = internal::null_terminating_iterator(format); - using handler_type = internal::dynamic_specs_handler; + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + auto it = internal::null_terminating_iterator(ctx); + using handler_type = internal::dynamic_specs_handler; internal::specs_checker - handler(handler_type(specs_), internal::get_type()); + handler(handler_type(specs_, ctx), internal::get_type()); it = parse_format_specs(it, handler); return pointer_from(it); } @@ -3495,9 +3507,9 @@ template struct formatter::value>::type> : public formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - return begin(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); } }; @@ -3513,11 +3525,11 @@ struct formatter struct dynamic_formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - auto it = internal::null_terminating_iterator(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + auto it = internal::null_terminating_iterator(ctx); // Checks are deferred to formatting time when the argument type is known. - internal::dynamic_specs_handler handler(specs_); + internal::dynamic_specs_handler handler(specs_, ctx); it = parse_format_specs(it, handler); return pointer_from(it); } diff --git a/fmt/time.h b/fmt/time.h index 648c60ef..c1687373 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -17,9 +17,9 @@ namespace fmt { template <> struct formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - auto it = internal::null_terminating_iterator(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + auto it = internal::null_terminating_iterator(ctx); if (*it == ':') ++it; auto end = it; diff --git a/test/format-test.cc b/test/format-test.cc index 85dac3dc..7ceb4d4b 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1233,9 +1233,9 @@ TEST(FormatterTest, FormatStringView) { namespace fmt { template <> struct formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - return begin(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); } void format(buffer &buf, const Date &d, context &) { diff --git a/test/util-test.cc b/test/util-test.cc index 17390c1c..c3387639 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -75,9 +75,9 @@ basic_arg make_arg(const T &value) { namespace fmt { template struct formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - return begin(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); } void format(basic_buffer &b, Test, basic_context &) { @@ -436,9 +436,9 @@ struct CustomContext { template struct formatter_type { - template - auto parse(Range range) -> decltype(begin(range)) { - return begin(range); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); } void format(fmt::buffer &, const T &, CustomContext& ctx) {