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