Replace Range with ParseContext in parse()

This commit is contained in:
Victor Zverovich 2017-09-16 16:50:40 -07:00
parent 83dd2ab919
commit ec4f5175f1
4 changed files with 48 additions and 36 deletions

View File

@ -351,6 +351,8 @@ class basic_string_view {
std::size_t size_; std::size_t size_;
public: public:
using char_type = Char;
basic_string_view() : data_(0), size_(0) {} basic_string_view() : data_(0), size_(0) {}
/** Constructs a string reference object from a C string and a size. */ /** Constructs a string reference object from a C string and a size. */
@ -388,6 +390,9 @@ class basic_string_view {
/** Returns the string size. */ /** Returns the string size. */
std::size_t size() const { return 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) { void remove_prefix(size_t n) {
data_ += n; data_ += n;
size_ -= n; size_ -= n;
@ -425,9 +430,6 @@ class basic_string_view {
typedef basic_string_view<char> string_view; typedef basic_string_view<char> string_view;
typedef basic_string_view<wchar_t> wstring_view; typedef basic_string_view<wchar_t> wstring_view;
template <typename Char>
inline const Char *begin(basic_string_view<Char> s) { return s.data(); }
/** A formatting error such as invalid format string. */ /** A formatting error such as invalid format string. */
class format_error : public std::runtime_error { class format_error : public std::runtime_error {
public: public:
@ -776,7 +778,7 @@ class null_terminating_iterator {
: ptr_(ptr), end_(end) {} : ptr_(ptr), end_(end) {}
explicit null_terminating_iterator(basic_string_view<Char> s) explicit null_terminating_iterator(basic_string_view<Char> s)
: ptr_(s.data()), end_(s.data() + s.size()) {} : ptr_(s.begin()), end_(s.end()) {}
null_terminating_iterator &operator=(const Char *ptr) { null_terminating_iterator &operator=(const Char *ptr) {
assert(ptr <= end_); assert(ptr <= end_);
@ -1324,7 +1326,7 @@ class value {
// `printf_formatter<T>` for `printf`. // `printf_formatter<T>` for `printf`.
typename Context::template formatter_type<T> f; typename Context::template formatter_type<T> f;
auto it = f.parse(format); auto it = f.parse(format);
format.remove_prefix(it - begin(format)); format.remove_prefix(it - format.begin());
f.format(buffer, *static_cast<const T*>(arg), ctx); f.format(buffer, *static_cast<const T*>(arg), ctx);
} }
}; };
@ -3230,11 +3232,19 @@ struct dynamic_format_specs : basic_format_specs<Char> {
arg_ref<Char> precision_ref; arg_ref<Char> precision_ref;
}; };
template <typename Char> // Format spec handler that saves references to arguments representing dynamic
class dynamic_specs_handler: public specs_setter<Char> { // 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 <typename ParseContext>
class dynamic_specs_handler :
public specs_setter<typename ParseContext::char_type> {
public: public:
dynamic_specs_handler(dynamic_format_specs<Char> &specs) using char_type = typename ParseContext::char_type;
: specs_setter<Char>(specs), specs_(specs) {}
dynamic_specs_handler(
dynamic_format_specs<char_type> &specs, ParseContext &ctx)
: specs_setter<char_type>(specs), specs_(specs), context_(ctx) {}
template <typename Id> template <typename Id>
void on_dynamic_width(Id arg_id) { void on_dynamic_width(Id arg_id) {
@ -3247,7 +3257,7 @@ class dynamic_specs_handler: public specs_setter<Char> {
} }
private: private:
using arg_ref = arg_ref<Char>; using arg_ref = arg_ref<char_type>;
template <typename Id> template <typename Id>
arg_ref make_arg_ref(Id arg_id) { arg_ref make_arg_ref(Id arg_id) {
@ -3255,10 +3265,12 @@ class dynamic_specs_handler: public specs_setter<Char> {
} }
arg_ref make_arg_ref(auto_id) { arg_ref make_arg_ref(auto_id) {
// TODO: get next index from context
return arg_ref(arg_ref::NONE); return arg_ref(arg_ref::NONE);
} }
dynamic_format_specs<Char> &specs_; dynamic_format_specs<char_type> &specs_;
ParseContext &context_;
}; };
template <typename Iterator, typename Handler> template <typename Iterator, typename Handler>
@ -3417,7 +3429,7 @@ const Char *do_format_arg(basic_buffer<Char> &buffer,
if (*it == ':') { if (*it == ':') {
format.remove_prefix(1); format.remove_prefix(1);
if (visit(custom_formatter<Char, Context>(buffer, format, ctx), arg)) if (visit(custom_formatter<Char, Context>(buffer, format, ctx), arg))
return begin(format); return format.begin();
specs_checker<specs_handler<Context>> specs_checker<specs_handler<Context>>
handler(specs_handler<Context>(specs, ctx), arg.type()); handler(specs_handler<Context>(specs, ctx), arg.type());
it = parse_format_specs(it + 1, handler); 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 // Parses format specifiers stopping either at the end of the range or at the
// terminating '}'. // terminating '}'.
template <typename Range> template <typename ParseContext>
auto parse(Range format) -> decltype(begin(format)) { auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto it = internal::null_terminating_iterator<Char>(format); auto it = internal::null_terminating_iterator<Char>(ctx);
using handler_type = internal::dynamic_specs_handler<Char>; using handler_type = internal::dynamic_specs_handler<ParseContext>;
internal::specs_checker<handler_type> internal::specs_checker<handler_type>
handler(handler_type(specs_), internal::get_type<T>()); handler(handler_type(specs_, ctx), internal::get_type<T>());
it = parse_format_specs(it, handler); it = parse_format_specs(it, handler);
return pointer_from(it); return pointer_from(it);
} }
@ -3495,9 +3507,9 @@ template <typename T, typename Char>
struct formatter<T, Char, struct formatter<T, Char,
typename std::enable_if<internal::format_enum<T>::value>::type> typename std::enable_if<internal::format_enum<T>::value>::type>
: public formatter<int, Char> { : public formatter<int, Char> {
template <typename Range> template <typename ParseContext>
auto parse(Range format) -> decltype(begin(format)) { auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return begin(format); return ctx.begin();
} }
}; };
@ -3513,11 +3525,11 @@ struct formatter<T, Char,
// }; // };
template <typename Char = char> template <typename Char = char>
struct dynamic_formatter { struct dynamic_formatter {
template <typename Range> template <typename ParseContext>
auto parse(Range format) -> decltype(begin(format)) { auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto it = internal::null_terminating_iterator<Char>(format); auto it = internal::null_terminating_iterator<Char>(ctx);
// Checks are deferred to formatting time when the argument type is known. // Checks are deferred to formatting time when the argument type is known.
internal::dynamic_specs_handler<Char> handler(specs_); internal::dynamic_specs_handler<ParseContext> handler(specs_, ctx);
it = parse_format_specs(it, handler); it = parse_format_specs(it, handler);
return pointer_from(it); return pointer_from(it);
} }

View File

@ -17,9 +17,9 @@ namespace fmt {
template <> template <>
struct formatter<std::tm> { struct formatter<std::tm> {
template <typename Range> template <typename ParseContext>
auto parse(Range format) -> decltype(begin(format)) { auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto it = internal::null_terminating_iterator<char>(format); auto it = internal::null_terminating_iterator<char>(ctx);
if (*it == ':') if (*it == ':')
++it; ++it;
auto end = it; auto end = it;

View File

@ -1233,9 +1233,9 @@ TEST(FormatterTest, FormatStringView) {
namespace fmt { namespace fmt {
template <> template <>
struct formatter<Date> { struct formatter<Date> {
template <typename Range> template <typename ParseContext>
auto parse(Range format) -> decltype(begin(format)) { auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return begin(format); return ctx.begin();
} }
void format(buffer &buf, const Date &d, context &) { void format(buffer &buf, const Date &d, context &) {

View File

@ -75,9 +75,9 @@ basic_arg<Context> make_arg(const T &value) {
namespace fmt { namespace fmt {
template <typename Char> template <typename Char>
struct formatter<Test, Char> { struct formatter<Test, Char> {
template <typename Range> template <typename ParseContext>
auto parse(Range format) -> decltype(begin(format)) { auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return begin(format); return ctx.begin();
} }
void format(basic_buffer<Char> &b, Test, basic_context<Char> &) { void format(basic_buffer<Char> &b, Test, basic_context<Char> &) {
@ -436,9 +436,9 @@ struct CustomContext {
template <typename T> template <typename T>
struct formatter_type { struct formatter_type {
template <typename Range> template <typename ParseContext>
auto parse(Range range) -> decltype(begin(range)) { auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
return begin(range); return ctx.begin();
} }
void format(fmt::buffer &, const T &, CustomContext& ctx) { void format(fmt::buffer &, const T &, CustomContext& ctx) {