Decouple format and parse contexts
This commit is contained in:
parent
744e66bb08
commit
442fa1bd46
@ -481,10 +481,10 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||
auto out = std::back_inserter(buf);
|
||||
typedef output_range<decltype(ctx.out()), Char> range;
|
||||
basic_writer<range> w(range(ctx.out()));
|
||||
internal::handle_dynamic_spec<internal::width_checker>(spec.width_,
|
||||
width_ref, ctx);
|
||||
internal::handle_dynamic_spec<internal::width_checker>(
|
||||
spec.width_, width_ref, ctx, format_str.begin());
|
||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
||||
precision, precision_ref, ctx);
|
||||
precision, precision_ref, ctx, format_str.begin());
|
||||
if (begin == end || *begin == '}') {
|
||||
out = internal::format_chrono_duration_value(out, d.count(), precision);
|
||||
internal::format_chrono_duration_unit<Period>(out);
|
||||
|
@ -687,7 +687,7 @@ template <typename Context> class value {
|
||||
};
|
||||
|
||||
FMT_CONSTEXPR value(int val = 0) : int_value(val) {}
|
||||
value(unsigned val) { uint_value = val; }
|
||||
FMT_CONSTEXPR value(unsigned val) : uint_value(val) {}
|
||||
value(long long val) { long_long_value = val; }
|
||||
value(unsigned long long val) { ulong_long_value = val; }
|
||||
value(double val) { double_value = val; }
|
||||
@ -936,7 +936,7 @@ template <typename Context> class basic_format_arg {
|
||||
|
||||
FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {}
|
||||
|
||||
FMT_EXPLICIT operator bool() const FMT_NOEXCEPT {
|
||||
FMT_CONSTEXPR FMT_EXPLICIT operator bool() const FMT_NOEXCEPT {
|
||||
return type_ != internal::none_type;
|
||||
}
|
||||
|
||||
@ -1045,76 +1045,13 @@ class locale_ref {
|
||||
|
||||
public:
|
||||
locale_ref() : locale_(FMT_NULL) {}
|
||||
|
||||
template <typename Locale> explicit locale_ref(const Locale& loc);
|
||||
|
||||
template <typename Locale> Locale get() const;
|
||||
};
|
||||
|
||||
template <typename OutputIt, typename Context, typename Char>
|
||||
class context_base {
|
||||
public:
|
||||
typedef OutputIt iterator;
|
||||
|
||||
private:
|
||||
basic_parse_context<Char> parse_context_;
|
||||
iterator out_;
|
||||
basic_format_args<Context> args_;
|
||||
locale_ref loc_;
|
||||
|
||||
protected:
|
||||
typedef Char char_type;
|
||||
typedef basic_format_arg<Context> format_arg;
|
||||
|
||||
context_base(OutputIt out, basic_string_view<char_type> format_str,
|
||||
basic_format_args<Context> ctx_args,
|
||||
locale_ref loc = locale_ref())
|
||||
: parse_context_(format_str), out_(out), args_(ctx_args), loc_(loc) {}
|
||||
|
||||
// Returns the argument with specified index.
|
||||
format_arg do_get_arg(unsigned arg_id) {
|
||||
format_arg arg = args_.get(arg_id);
|
||||
if (!arg) parse_context_.on_error("argument index out of range");
|
||||
return arg;
|
||||
}
|
||||
|
||||
friend basic_parse_context<Char>& get_parse_context(context_base& ctx) {
|
||||
return ctx.parse_context_;
|
||||
}
|
||||
|
||||
// Checks if manual indexing is used and returns the argument with
|
||||
// specified index.
|
||||
format_arg arg(unsigned arg_id) {
|
||||
return parse_context_.check_arg_id(arg_id) ? this->do_get_arg(arg_id)
|
||||
: format_arg();
|
||||
}
|
||||
|
||||
public:
|
||||
FMT_DEPRECATED basic_parse_context<Char>& parse_context() {
|
||||
return parse_context_;
|
||||
}
|
||||
|
||||
// basic_format_context::arg() depends on this
|
||||
// Cannot be marked as deprecated without causing warnings
|
||||
/*FMT_DEPRECATED*/ basic_format_args<Context> args() const { return args_; }
|
||||
|
||||
basic_format_arg<Context> arg(unsigned id) const { return args_.get(id); }
|
||||
|
||||
internal::error_handler error_handler() {
|
||||
return parse_context_.error_handler();
|
||||
}
|
||||
|
||||
void on_error(const char* message) { parse_context_.on_error(message); }
|
||||
|
||||
// Returns an iterator to the beginning of the output range.
|
||||
iterator out() { return out_; }
|
||||
FMT_DEPRECATED iterator begin() { return out_; }
|
||||
|
||||
// Advances the begin iterator to ``it``.
|
||||
void advance_to(iterator it) { out_ = it; }
|
||||
|
||||
locale_ref locale() { return loc_; }
|
||||
};
|
||||
class context_base {};
|
||||
|
||||
template <typename Context, typename T> struct get_type {
|
||||
typedef decltype(
|
||||
@ -1153,54 +1090,54 @@ make_arg(const T& value) {
|
||||
} // namespace internal
|
||||
|
||||
// Formatting context.
|
||||
template <typename OutputIt, typename Char>
|
||||
class basic_format_context
|
||||
: public internal::context_base<
|
||||
OutputIt, basic_format_context<OutputIt, Char>, Char> {
|
||||
template <typename OutputIt, typename Char> class basic_format_context {
|
||||
public:
|
||||
/** The character type for the output. */
|
||||
typedef Char char_type;
|
||||
|
||||
private:
|
||||
OutputIt out_;
|
||||
basic_format_args<basic_format_context> args_;
|
||||
internal::arg_map<basic_format_context> map_;
|
||||
internal::locale_ref loc_;
|
||||
|
||||
basic_format_context(const basic_format_context&) = delete;
|
||||
void operator=(const basic_format_context&) = delete;
|
||||
|
||||
public:
|
||||
typedef OutputIt iterator;
|
||||
typedef basic_format_arg<basic_format_context> format_arg;
|
||||
|
||||
// using formatter_type = formatter<T, char_type>;
|
||||
template <typename T> struct formatter_type {
|
||||
typedef formatter<T, char_type> type;
|
||||
};
|
||||
|
||||
private:
|
||||
internal::arg_map<basic_format_context> map_;
|
||||
|
||||
basic_format_context(const basic_format_context&) = delete;
|
||||
void operator=(const basic_format_context&) = delete;
|
||||
|
||||
typedef internal::context_base<OutputIt, basic_format_context, Char> base;
|
||||
using base::arg;
|
||||
|
||||
public:
|
||||
using typename base::iterator;
|
||||
typedef typename base::format_arg format_arg;
|
||||
|
||||
/**
|
||||
Constructs a ``basic_format_context`` object. References to the arguments are
|
||||
stored in the object so make sure they have appropriate lifetimes.
|
||||
*/
|
||||
basic_format_context(OutputIt out, basic_string_view<char_type> format_str,
|
||||
basic_format_context(OutputIt out,
|
||||
basic_format_args<basic_format_context> ctx_args,
|
||||
internal::locale_ref loc = internal::locale_ref())
|
||||
: base(out, format_str, ctx_args, loc) {}
|
||||
: out_(out), args_(ctx_args), loc_(loc) {}
|
||||
|
||||
format_arg next_arg() {
|
||||
return this->do_get_arg(get_parse_context(*this).next_arg_id());
|
||||
}
|
||||
format_arg arg(unsigned arg_id) { return this->do_get_arg(arg_id); }
|
||||
format_arg arg(unsigned id) const { return args_.get(id); }
|
||||
|
||||
// Checks if manual indexing is used and returns the argument with the
|
||||
// specified name.
|
||||
format_arg arg(basic_string_view<char_type> name);
|
||||
|
||||
FMT_DEPRECATED format_arg get_arg(unsigned arg_id) { return arg(arg_id); }
|
||||
FMT_DEPRECATED format_arg get_arg(basic_string_view<char_type> name) {
|
||||
return arg(name);
|
||||
}
|
||||
internal::error_handler error_handler() { return {}; }
|
||||
void on_error(const char* message) { error_handler().on_error(message); }
|
||||
|
||||
// Returns an iterator to the beginning of the output range.
|
||||
iterator out() { return out_; }
|
||||
|
||||
// Advances the begin iterator to ``it``.
|
||||
void advance_to(iterator it) { out_ = it; }
|
||||
|
||||
internal::locale_ref locale() { return loc_; }
|
||||
};
|
||||
|
||||
template <typename Char> struct buffer_context {
|
||||
@ -1399,6 +1336,13 @@ struct char_t : std::enable_if<internal::is_string<S>::value,
|
||||
#endif
|
||||
|
||||
namespace internal {
|
||||
template <typename Context>
|
||||
FMT_CONSTEXPR basic_format_arg<Context> get_arg(Context& ctx, unsigned id) {
|
||||
auto arg = ctx.arg(id);
|
||||
if (!arg) ctx.on_error("argument index out of range");
|
||||
return arg;
|
||||
}
|
||||
|
||||
template <typename Char> struct named_arg_base {
|
||||
basic_string_view<Char> name;
|
||||
|
||||
|
@ -1567,16 +1567,20 @@ FMT_CONSTEXPR unsigned parse_nonnegative_int(const Char*& begin,
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename Char, typename Context>
|
||||
class custom_formatter : public function<bool> {
|
||||
template <typename Context> class custom_formatter : public function<bool> {
|
||||
private:
|
||||
typedef typename Context::char_type char_type;
|
||||
|
||||
basic_parse_context<char_type>& parse_ctx_;
|
||||
Context& ctx_;
|
||||
|
||||
public:
|
||||
explicit custom_formatter(Context& ctx) : ctx_(ctx) {}
|
||||
explicit custom_formatter(basic_parse_context<char_type>& parse_ctx,
|
||||
Context& ctx)
|
||||
: parse_ctx_(parse_ctx), ctx_(ctx) {}
|
||||
|
||||
bool operator()(typename basic_format_arg<Context>::handle h) const {
|
||||
h.format(get_parse_context(ctx_), ctx_);
|
||||
h.format(parse_ctx_, ctx_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1769,7 +1773,9 @@ class specs_handler : public specs_setter<typename Context::char_type> {
|
||||
|
||||
FMT_CONSTEXPR specs_handler(basic_format_specs<char_type>& specs,
|
||||
ParseContext& parse_ctx, Context& ctx)
|
||||
: specs_setter<char_type>(specs), parse_ctx_(parse_ctx), context_(ctx) {}
|
||||
: specs_setter<char_type>(specs),
|
||||
parse_context_(parse_ctx),
|
||||
context_(ctx) {}
|
||||
|
||||
template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
|
||||
set_dynamic_spec<width_checker>(this->specs_.width_, get_arg(arg_id),
|
||||
@ -1787,14 +1793,21 @@ class specs_handler : public specs_setter<typename Context::char_type> {
|
||||
// This is only needed for compatibility with gcc 4.4.
|
||||
typedef typename Context::format_arg format_arg;
|
||||
|
||||
FMT_CONSTEXPR format_arg get_arg(auto_id) { return context_.next_arg(); }
|
||||
FMT_CONSTEXPR format_arg get_arg(auto_id) {
|
||||
return internal::get_arg(context_, parse_context_.next_arg_id());
|
||||
}
|
||||
|
||||
template <typename Id> FMT_CONSTEXPR format_arg get_arg(Id arg_id) {
|
||||
parse_ctx_.check_arg_id(arg_id);
|
||||
FMT_CONSTEXPR format_arg get_arg(unsigned arg_id) {
|
||||
parse_context_.check_arg_id(arg_id);
|
||||
return internal::get_arg(context_, arg_id);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR format_arg get_arg(basic_string_view<char_type> arg_id) {
|
||||
parse_context_.check_arg_id(arg_id);
|
||||
return context_.arg(arg_id);
|
||||
}
|
||||
|
||||
ParseContext& parse_ctx_;
|
||||
ParseContext& parse_context_;
|
||||
Context& context_;
|
||||
};
|
||||
|
||||
@ -2264,7 +2277,8 @@ struct format_type
|
||||
|
||||
template <template <typename> class Handler, typename Spec, typename Context>
|
||||
void handle_dynamic_spec(Spec& value, arg_ref<typename Context::char_type> ref,
|
||||
Context& ctx) {
|
||||
Context& ctx,
|
||||
const typename Context::char_type* format_str) {
|
||||
typedef typename Context::char_type char_type;
|
||||
switch (ref.kind) {
|
||||
case arg_ref<char_type>::NONE:
|
||||
@ -2274,7 +2288,7 @@ void handle_dynamic_spec(Spec& value, arg_ref<typename Context::char_type> ref,
|
||||
ctx.error_handler());
|
||||
break;
|
||||
case arg_ref<char_type>::NAME: {
|
||||
const auto arg_id = ref.val.name.to_view(get_parse_context(ctx).begin());
|
||||
const auto arg_id = ref.val.name.to_view(format_str);
|
||||
internal::set_dynamic_spec<Handler>(value, ctx.arg(arg_id),
|
||||
ctx.error_handler());
|
||||
} break;
|
||||
@ -2294,6 +2308,7 @@ class arg_formatter
|
||||
typedef basic_format_context<typename base::iterator, char_type> context_type;
|
||||
|
||||
context_type& ctx_;
|
||||
basic_parse_context<char_type>* parse_ctx_;
|
||||
|
||||
public:
|
||||
typedef Range range;
|
||||
@ -2307,8 +2322,12 @@ class arg_formatter
|
||||
*spec* contains format specifier information for standard argument types.
|
||||
\endrst
|
||||
*/
|
||||
explicit arg_formatter(context_type& ctx, format_specs* spec = FMT_NULL)
|
||||
: base(Range(ctx.out()), spec, ctx.locale()), ctx_(ctx) {}
|
||||
explicit arg_formatter(context_type& ctx,
|
||||
basic_parse_context<char_type>* parse_ctx = FMT_NULL,
|
||||
format_specs* spec = FMT_NULL)
|
||||
: base(Range(ctx.out()), spec, ctx.locale()),
|
||||
ctx_(ctx),
|
||||
parse_ctx_(parse_ctx) {}
|
||||
|
||||
FMT_DEPRECATED arg_formatter(context_type& ctx, format_specs& spec)
|
||||
: base(Range(ctx.out()), &spec), ctx_(ctx) {}
|
||||
@ -2317,7 +2336,7 @@ class arg_formatter
|
||||
|
||||
/** Formats an argument of a user-defined type. */
|
||||
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||
handle.format(get_parse_context(ctx_), ctx_);
|
||||
handle.format(*parse_ctx_, ctx_);
|
||||
return this->out();
|
||||
}
|
||||
};
|
||||
@ -3023,10 +3042,13 @@ template <typename T, typename Char>
|
||||
struct formatter<T, Char,
|
||||
typename std::enable_if<internal::format_type<
|
||||
typename buffer_context<Char>::type, T>::value>::type> {
|
||||
FMT_CONSTEXPR formatter() : format_str_(FMT_NULL) {}
|
||||
|
||||
// Parses format specifiers stopping either at the end of the range or at the
|
||||
// terminating '}'.
|
||||
template <typename ParseContext>
|
||||
FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) {
|
||||
format_str_ = ctx.begin();
|
||||
typedef internal::dynamic_specs_handler<ParseContext> handler_type;
|
||||
auto type =
|
||||
internal::get_type<typename buffer_context<Char>::type, T>::value;
|
||||
@ -3078,18 +3100,19 @@ struct formatter<T, Char,
|
||||
template <typename FormatContext>
|
||||
auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||
internal::handle_dynamic_spec<internal::width_checker>(
|
||||
specs_.width_, specs_.width_ref, ctx);
|
||||
specs_.width_, specs_.width_ref, ctx, format_str_);
|
||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
||||
specs_.precision, specs_.precision_ref, ctx);
|
||||
specs_.precision, specs_.precision_ref, ctx, format_str_);
|
||||
typedef output_range<typename FormatContext::iterator,
|
||||
typename FormatContext::char_type>
|
||||
range_type;
|
||||
return visit_format_arg(arg_formatter<range_type>(ctx, &specs_),
|
||||
return visit_format_arg(arg_formatter<range_type>(ctx, FMT_NULL, &specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
}
|
||||
|
||||
private:
|
||||
internal::dynamic_format_specs<Char> specs_;
|
||||
const Char* format_str_;
|
||||
};
|
||||
|
||||
// A formatter for types known only at run time such as variant alternatives.
|
||||
@ -3115,6 +3138,7 @@ template <typename Char = char> class dynamic_formatter {
|
||||
public:
|
||||
template <typename ParseContext>
|
||||
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||
format_str_ = ctx.begin();
|
||||
// Checks are deferred to formatting time when the argument type is known.
|
||||
internal::dynamic_specs_handler<ParseContext> handler(specs_, ctx);
|
||||
return parse_format_specs(ctx.begin(), ctx.end(), handler);
|
||||
@ -3138,7 +3162,7 @@ template <typename Char = char> class dynamic_formatter {
|
||||
typedef output_range<typename FormatContext::iterator,
|
||||
typename FormatContext::char_type>
|
||||
range;
|
||||
visit_format_arg(arg_formatter<range>(ctx, &specs_),
|
||||
visit_format_arg(arg_formatter<range>(ctx, FMT_NULL, &specs_),
|
||||
internal::make_arg<FormatContext>(val));
|
||||
return ctx.out();
|
||||
}
|
||||
@ -3146,18 +3170,19 @@ template <typename Char = char> class dynamic_formatter {
|
||||
private:
|
||||
template <typename Context> void handle_specs(Context& ctx) {
|
||||
internal::handle_dynamic_spec<internal::width_checker>(
|
||||
specs_.width_, specs_.width_ref, ctx);
|
||||
specs_.width_, specs_.width_ref, ctx, format_str_);
|
||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
||||
specs_.precision, specs_.precision_ref, ctx);
|
||||
specs_.precision, specs_.precision_ref, ctx, format_str_);
|
||||
}
|
||||
|
||||
internal::dynamic_format_specs<Char> specs_;
|
||||
const Char* format_str_;
|
||||
};
|
||||
|
||||
template <typename Range, typename Char>
|
||||
typename basic_format_context<Range, Char>::format_arg
|
||||
basic_format_context<Range, Char>::arg(basic_string_view<char_type> name) {
|
||||
map_.init(this->args());
|
||||
map_.init(args_);
|
||||
format_arg arg = map_.find(name);
|
||||
if (arg.type() == internal::none_type) this->on_error("argument not found");
|
||||
return arg;
|
||||
@ -3170,7 +3195,7 @@ struct format_handler : internal::error_handler {
|
||||
format_handler(range r, basic_string_view<Char> str,
|
||||
basic_format_args<Context> format_args,
|
||||
internal::locale_ref loc)
|
||||
: context(r.begin(), str, format_args, loc) {}
|
||||
: parse_context(str), context(r.begin(), format_args, loc) {}
|
||||
|
||||
void on_text(const Char* begin, const Char* end) {
|
||||
auto size = internal::to_unsigned(end - begin);
|
||||
@ -3180,39 +3205,42 @@ struct format_handler : internal::error_handler {
|
||||
context.advance_to(out);
|
||||
}
|
||||
|
||||
void on_arg_id() { arg = context.next_arg(); }
|
||||
void get_arg(unsigned id) { arg = internal::get_arg(context, id); }
|
||||
|
||||
void on_arg_id() { get_arg(parse_context.next_arg_id()); }
|
||||
void on_arg_id(unsigned id) {
|
||||
get_parse_context(context).check_arg_id(id);
|
||||
arg = context.arg(id);
|
||||
parse_context.check_arg_id(id);
|
||||
get_arg(id);
|
||||
}
|
||||
void on_arg_id(basic_string_view<Char> id) { arg = context.arg(id); }
|
||||
|
||||
void on_replacement_field(const Char* p) {
|
||||
get_parse_context(context).advance_to(p);
|
||||
internal::custom_formatter<Char, Context> f(context);
|
||||
parse_context.advance_to(p);
|
||||
internal::custom_formatter<Context> f(parse_context, context);
|
||||
if (!visit_format_arg(f, arg))
|
||||
context.advance_to(visit_format_arg(ArgFormatter(context), arg));
|
||||
context.advance_to(
|
||||
visit_format_arg(ArgFormatter(context, &parse_context), arg));
|
||||
}
|
||||
|
||||
const Char* on_format_specs(const Char* begin, const Char* end) {
|
||||
auto& parse_ctx = get_parse_context(context);
|
||||
parse_ctx.advance_to(begin);
|
||||
internal::custom_formatter<Char, Context> f(context);
|
||||
if (visit_format_arg(f, arg)) return parse_ctx.begin();
|
||||
parse_context.advance_to(begin);
|
||||
internal::custom_formatter<Context> f(parse_context, context);
|
||||
if (visit_format_arg(f, arg)) return parse_context.begin();
|
||||
basic_format_specs<Char> specs;
|
||||
using internal::specs_handler;
|
||||
typedef basic_parse_context<Char> parse_context;
|
||||
internal::specs_checker<specs_handler<parse_context, Context>> handler(
|
||||
specs_handler<parse_context, Context>(specs, get_parse_context(context),
|
||||
context),
|
||||
typedef basic_parse_context<Char> parse_context_t;
|
||||
internal::specs_checker<specs_handler<parse_context_t, Context>> handler(
|
||||
specs_handler<parse_context_t, Context>(specs, parse_context, context),
|
||||
arg.type());
|
||||
begin = parse_format_specs(begin, end, handler);
|
||||
if (begin == end || *begin != '}') on_error("missing '}' in format string");
|
||||
parse_ctx.advance_to(begin);
|
||||
context.advance_to(visit_format_arg(ArgFormatter(context, &specs), arg));
|
||||
parse_context.advance_to(begin);
|
||||
context.advance_to(
|
||||
visit_format_arg(ArgFormatter(context, &parse_context, &specs), arg));
|
||||
return begin;
|
||||
}
|
||||
|
||||
basic_parse_context<Char> parse_context;
|
||||
Context context;
|
||||
basic_format_arg<Context> arg;
|
||||
};
|
||||
|
@ -253,7 +253,8 @@ class prepared_format {
|
||||
typename Context::iterator vformat_to(Range out,
|
||||
basic_format_args<Context> args) const {
|
||||
const auto format_view = internal::to_string_view(format_);
|
||||
Context ctx(out.begin(), format_view, args);
|
||||
basic_parse_context<char_type> parse_ctx(format_view);
|
||||
Context ctx(out.begin(), args);
|
||||
|
||||
const auto& parts = parts_provider_.parts();
|
||||
for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) {
|
||||
@ -270,14 +271,14 @@ class prepared_format {
|
||||
} break;
|
||||
|
||||
case format_part_t::which_value::argument_id: {
|
||||
advance_parse_context_to_specification(ctx, part);
|
||||
format_arg<Range>(ctx, value.arg_id);
|
||||
advance_parse_context_to_specification(parse_ctx, part);
|
||||
format_arg<Range>(parse_ctx, ctx, value.arg_id);
|
||||
} break;
|
||||
|
||||
case format_part_t::which_value::named_argument_id: {
|
||||
advance_parse_context_to_specification(ctx, part);
|
||||
advance_parse_context_to_specification(parse_ctx, part);
|
||||
const auto named_arg_id = value.named_arg_id.to_view(format_view);
|
||||
format_arg<Range>(ctx, named_arg_id);
|
||||
format_arg<Range>(parse_ctx, ctx, named_arg_id);
|
||||
} break;
|
||||
case format_part_t::which_value::specification: {
|
||||
const auto& arg_id_value = value.spec.arg_id.val;
|
||||
@ -289,15 +290,15 @@ class prepared_format {
|
||||
|
||||
auto specs = value.spec.parsed_specs;
|
||||
|
||||
handle_dynamic_spec<internal::width_checker>(specs.width_,
|
||||
specs.width_ref, ctx);
|
||||
handle_dynamic_spec<internal::width_checker>(
|
||||
specs.width_, specs.width_ref, ctx, format_view.begin());
|
||||
handle_dynamic_spec<internal::precision_checker>(
|
||||
specs.precision, specs.precision_ref, ctx);
|
||||
specs.precision, specs.precision_ref, ctx, format_view.begin());
|
||||
|
||||
check_prepared_specs(specs, arg.type());
|
||||
advance_parse_context_to_specification(ctx, part);
|
||||
advance_parse_context_to_specification(parse_ctx, part);
|
||||
ctx.advance_to(
|
||||
visit_format_arg(arg_formatter<Range>(ctx, &specs), arg));
|
||||
visit_format_arg(arg_formatter<Range>(ctx, FMT_NULL, &specs), arg));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@ -305,17 +306,18 @@ class prepared_format {
|
||||
return ctx.out();
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
void advance_parse_context_to_specification(Context& ctx,
|
||||
const format_part_t& part) const {
|
||||
void advance_parse_context_to_specification(
|
||||
basic_parse_context<char_type>& parse_ctx,
|
||||
const format_part_t& part) const {
|
||||
const auto view = to_string_view(format_);
|
||||
const auto specification_begin = view.data() + part.end_of_argument_id;
|
||||
get_parse_context(ctx).advance_to(specification_begin);
|
||||
parse_ctx.advance_to(specification_begin);
|
||||
}
|
||||
|
||||
template <typename Range, typename Context, typename Id>
|
||||
void format_arg(Context& ctx, Id arg_id) const {
|
||||
get_parse_context(ctx).check_arg_id(arg_id);
|
||||
void format_arg(basic_parse_context<char_type>& parse_ctx, Context& ctx,
|
||||
Id arg_id) const {
|
||||
parse_ctx.check_arg_id(arg_id);
|
||||
const auto stopped_at =
|
||||
visit_format_arg(arg_formatter<Range>(ctx), ctx.arg(arg_id));
|
||||
ctx.advance_to(stopped_at);
|
||||
|
@ -250,7 +250,7 @@ class printf_arg_formatter
|
||||
\endrst
|
||||
*/
|
||||
printf_arg_formatter(iterator iter, format_specs& spec, context_type& ctx)
|
||||
: base(Range(iter), &spec, ctx.locale()), context_(ctx) {}
|
||||
: base(Range(iter), &spec, internal::locale_ref()), context_(ctx) {}
|
||||
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_integral<T>::value, iterator>::type
|
||||
@ -319,7 +319,7 @@ class printf_arg_formatter
|
||||
|
||||
/** Formats an argument of a custom (user-defined) type. */
|
||||
iterator operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||
handle.format(get_parse_context(context_), context_);
|
||||
handle.format(context_.parse_context(), context_);
|
||||
return this->out();
|
||||
}
|
||||
};
|
||||
@ -339,11 +339,7 @@ template <typename T> struct printf_formatter {
|
||||
|
||||
/** This template formats data and writes the output to a writer. */
|
||||
template <typename OutputIt, typename Char, typename ArgFormatter>
|
||||
class basic_printf_context :
|
||||
// Inherit publicly as a workaround for the icc bug
|
||||
// https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476.
|
||||
public internal::context_base<
|
||||
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
|
||||
class basic_printf_context {
|
||||
public:
|
||||
/** The character type for the output. */
|
||||
typedef Char char_type;
|
||||
@ -354,9 +350,13 @@ class basic_printf_context :
|
||||
|
||||
private:
|
||||
typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
|
||||
typedef typename base::format_arg format_arg;
|
||||
typedef basic_format_arg<basic_printf_context> format_arg;
|
||||
typedef basic_format_specs<char_type> format_specs;
|
||||
|
||||
OutputIt out_;
|
||||
basic_format_args<basic_printf_context> args_;
|
||||
basic_parse_context<Char> parse_ctx_;
|
||||
|
||||
static void parse_flags(format_specs& spec, const Char*& it, const Char* end);
|
||||
|
||||
// Returns the argument with specified index or, if arg_index is equal
|
||||
@ -376,10 +376,18 @@ class basic_printf_context :
|
||||
*/
|
||||
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
|
||||
basic_format_args<basic_printf_context> args)
|
||||
: base(out, format_str, args) {}
|
||||
: out_(out), args_(args), parse_ctx_(format_str) {}
|
||||
|
||||
using base::advance_to;
|
||||
using base::out;
|
||||
OutputIt out() { return out_; }
|
||||
void advance_to(OutputIt it) { out_ = it; }
|
||||
|
||||
format_arg arg(unsigned id) const { return args_.get(id); }
|
||||
|
||||
basic_parse_context<Char>& parse_context() { return parse_ctx_; }
|
||||
|
||||
FMT_CONSTEXPR void on_error(const char* message) {
|
||||
parse_ctx_.on_error(message);
|
||||
}
|
||||
|
||||
/** Formats stored arguments and writes the output to the range. */
|
||||
OutputIt format();
|
||||
@ -416,8 +424,10 @@ template <typename OutputIt, typename Char, typename AF>
|
||||
typename basic_printf_context<OutputIt, Char, AF>::format_arg
|
||||
basic_printf_context<OutputIt, Char, AF>::get_arg(unsigned arg_index) {
|
||||
if (arg_index == std::numeric_limits<unsigned>::max())
|
||||
return this->do_get_arg(get_parse_context(*this).next_arg_id());
|
||||
return base::arg(arg_index - 1);
|
||||
arg_index = parse_ctx_.next_arg_id();
|
||||
else
|
||||
parse_ctx_.check_arg_id(--arg_index);
|
||||
return internal::get_arg(*this, arg_index);
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename Char, typename AF>
|
||||
@ -461,9 +471,8 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
||||
template <typename OutputIt, typename Char, typename AF>
|
||||
OutputIt basic_printf_context<OutputIt, Char, AF>::format() {
|
||||
auto out = this->out();
|
||||
const auto range = get_parse_context(*this);
|
||||
const Char* const end = range.end();
|
||||
const Char* start = range.begin();
|
||||
const Char* start = parse_ctx_.begin();
|
||||
const Char* end = parse_ctx_.end();
|
||||
auto it = start;
|
||||
while (it != end) {
|
||||
char_type c = *it++;
|
||||
|
@ -377,8 +377,9 @@ struct check_custom {
|
||||
void grow(std::size_t) {}
|
||||
} buffer;
|
||||
fmt::internal::basic_buffer<char>& base = buffer;
|
||||
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
|
||||
h.format(get_parse_context(ctx), ctx);
|
||||
fmt::format_parse_context parse_ctx("");
|
||||
fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
|
||||
h.format(parse_ctx, ctx);
|
||||
EXPECT_EQ("test", std::string(buffer.data, buffer.size()));
|
||||
return test_result();
|
||||
}
|
||||
|
@ -20,8 +20,9 @@ class custom_arg_formatter
|
||||
typedef fmt::arg_formatter<range> base;
|
||||
|
||||
custom_arg_formatter(fmt::format_context& ctx,
|
||||
fmt::format_parse_context* parse_ctx,
|
||||
fmt::format_specs* s = FMT_NULL)
|
||||
: base(ctx, s) {}
|
||||
: base(ctx, parse_ctx, s) {}
|
||||
|
||||
using base::operator();
|
||||
|
||||
|
@ -1927,7 +1927,8 @@ class mock_arg_formatter
|
||||
typedef fmt::internal::arg_formatter_base<buffer_range> base;
|
||||
typedef buffer_range range;
|
||||
|
||||
mock_arg_formatter(fmt::format_context& ctx, fmt::format_specs* s = FMT_NULL)
|
||||
mock_arg_formatter(fmt::format_context& ctx, fmt::format_parse_context*,
|
||||
fmt::format_specs* s = FMT_NULL)
|
||||
: base(fmt::internal::get_container(ctx.out()), s, ctx.locale()) {
|
||||
EXPECT_CALL(*this, call(42));
|
||||
}
|
||||
@ -2167,7 +2168,7 @@ TEST(FormatTest, ConstexprParseFormatSpecs) {
|
||||
struct test_parse_context {
|
||||
typedef char char_type;
|
||||
|
||||
FMT_CONSTEXPR unsigned next_arg_id() { return 33; }
|
||||
FMT_CONSTEXPR unsigned next_arg_id() { return 11; }
|
||||
template <typename Id> FMT_CONSTEXPR void check_arg_id(Id) {}
|
||||
|
||||
FMT_CONSTEXPR const char* begin() { return FMT_NULL; }
|
||||
@ -2184,13 +2185,9 @@ struct test_context {
|
||||
typedef fmt::formatter<T, char_type> type;
|
||||
};
|
||||
|
||||
FMT_CONSTEXPR fmt::basic_format_arg<test_context> next_arg() {
|
||||
return fmt::internal::make_arg<test_context>(11);
|
||||
}
|
||||
|
||||
template <typename Id>
|
||||
FMT_CONSTEXPR fmt::basic_format_arg<test_context> arg(Id) {
|
||||
return fmt::internal::make_arg<test_context>(22);
|
||||
FMT_CONSTEXPR fmt::basic_format_arg<test_context> arg(Id id) {
|
||||
return fmt::internal::make_arg<test_context>(id);
|
||||
}
|
||||
|
||||
void on_error(const char*) {}
|
||||
@ -2219,10 +2216,10 @@ TEST(FormatTest, ConstexprSpecsHandler) {
|
||||
static_assert(parse_specs("0").align() == fmt::ALIGN_NUMERIC, "");
|
||||
static_assert(parse_specs("42").width() == 42, "");
|
||||
static_assert(parse_specs("{}").width() == 11, "");
|
||||
static_assert(parse_specs("{0}").width() == 22, "");
|
||||
static_assert(parse_specs("{22}").width() == 22, "");
|
||||
static_assert(parse_specs(".42").precision == 42, "");
|
||||
static_assert(parse_specs(".{}").precision == 11, "");
|
||||
static_assert(parse_specs(".{0}").precision == 22, "");
|
||||
static_assert(parse_specs(".{22}").precision == 22, "");
|
||||
static_assert(parse_specs("d").type == 'd', "");
|
||||
}
|
||||
|
||||
@ -2245,10 +2242,10 @@ TEST(FormatTest, ConstexprDynamicSpecsHandler) {
|
||||
static_assert(parse_dynamic_specs("#").has(fmt::HASH_FLAG), "");
|
||||
static_assert(parse_dynamic_specs("0").align() == fmt::ALIGN_NUMERIC, "");
|
||||
static_assert(parse_dynamic_specs("42").width() == 42, "");
|
||||
static_assert(parse_dynamic_specs("{}").width_ref.val.index == 33, "");
|
||||
static_assert(parse_dynamic_specs("{}").width_ref.val.index == 11, "");
|
||||
static_assert(parse_dynamic_specs("{42}").width_ref.val.index == 42, "");
|
||||
static_assert(parse_dynamic_specs(".42").precision == 42, "");
|
||||
static_assert(parse_dynamic_specs(".{}").precision_ref.val.index == 33, "");
|
||||
static_assert(parse_dynamic_specs(".{}").precision_ref.val.index == 11, "");
|
||||
static_assert(parse_dynamic_specs(".{42}").precision_ref.val.index == 42, "");
|
||||
static_assert(parse_dynamic_specs("d").type == 'd', "");
|
||||
}
|
||||
|
@ -54,14 +54,15 @@ TEST(OStreamTest, Enum) {
|
||||
typedef fmt::back_insert_range<fmt::internal::buffer> range;
|
||||
|
||||
struct test_arg_formatter : fmt::arg_formatter<range> {
|
||||
fmt::format_parse_context parse_ctx;
|
||||
test_arg_formatter(fmt::format_context& ctx, fmt::format_specs& s)
|
||||
: fmt::arg_formatter<range>(ctx, &s) {}
|
||||
: fmt::arg_formatter<range>(ctx, &parse_ctx, &s), parse_ctx("") {}
|
||||
};
|
||||
|
||||
TEST(OStreamTest, CustomArg) {
|
||||
fmt::memory_buffer buffer;
|
||||
fmt::internal::buffer& base = buffer;
|
||||
fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args());
|
||||
fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
|
||||
fmt::format_specs spec;
|
||||
test_arg_formatter af(ctx, spec);
|
||||
fmt::visit_format_arg(
|
||||
|
Loading…
Reference in New Issue
Block a user