Update std implementation

This commit is contained in:
Victor Zverovich 2019-02-10 06:34:47 -08:00
parent 442fa1bd46
commit e4572e5def
3 changed files with 50 additions and 46 deletions

View File

@ -1337,7 +1337,7 @@ struct char_t : std::enable_if<internal::is_string<S>::value,
namespace internal { namespace internal {
template <typename Context> template <typename Context>
FMT_CONSTEXPR basic_format_arg<Context> get_arg(Context& ctx, unsigned id) { FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, unsigned id) {
auto arg = ctx.arg(id); auto arg = ctx.arg(id);
if (!arg) ctx.on_error("argument index out of range"); if (!arg) ctx.on_error("argument index out of range");
return arg; return arg;

View File

@ -343,6 +343,7 @@ class basic_printf_context {
public: public:
/** The character type for the output. */ /** The character type for the output. */
typedef Char char_type; typedef Char char_type;
typedef basic_format_arg<basic_printf_context> format_arg;
template <typename T> struct formatter_type { template <typename T> struct formatter_type {
typedef printf_formatter<T> type; typedef printf_formatter<T> type;
@ -350,7 +351,6 @@ 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 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_; OutputIt out_;

View File

@ -191,9 +191,8 @@ constexpr void basic_format_parse_context<charT>::check_arg_id(size_t) {
namespace std { namespace std {
template<class O, class charT> FMT_REQUIRES(OutputIterator<O, const charT&>) template<class O, class charT> FMT_REQUIRES(OutputIterator<O, const charT&>)
class basic_format_context { class basic_format_context {
basic_format_parse_context<charT> parse_context_; // exposition only basic_format_args<basic_format_context> args_; // exposition only
basic_format_args<basic_format_context> args_; // exposition only O out_; // exposition only
O out_; // exposition only
public: public:
using iterator = O; using iterator = O;
@ -202,7 +201,6 @@ namespace std {
template<class T> template<class T>
using formatter_type = formatter<T>; using formatter_type = formatter<T>;
basic_format_parse_context<charT>& parse_context() noexcept;
basic_format_arg<basic_format_context> arg(size_t id) const; basic_format_arg<basic_format_context> arg(size_t id) const;
iterator out(); iterator out();
@ -210,11 +208,8 @@ namespace std {
// Implementation details: // Implementation details:
using format_arg = basic_format_arg<basic_format_context>; using format_arg = basic_format_arg<basic_format_context>;
basic_format_context(O out, fmt::string_view fmt, basic_format_args<basic_format_context> args, fmt::internal::locale_ref) basic_format_context(O out, basic_format_args<basic_format_context> args, fmt::internal::locale_ref)
: out_(out), parse_context_({fmt.data(), fmt.size()}), args_(args) {} : out_(out), args_(args) {}
basic_format_arg<basic_format_context> next_arg() {
return arg(parse_context_.next_arg_id());
}
fmt::internal::error_handler error_handler() const { return {}; } fmt::internal::error_handler error_handler() const { return {}; }
basic_format_arg<basic_format_context> arg(fmt::basic_string_view<charT>) const { basic_format_arg<basic_format_context> arg(fmt::basic_string_view<charT>) const {
return {}; // unused: named arguments are not supported yet return {}; // unused: named arguments are not supported yet
@ -224,9 +219,6 @@ namespace std {
} }
namespace std { namespace std {
template<class O, class charT>
basic_format_parse_context<charT>& basic_format_context<O, charT>::parse_context() noexcept { return parse_context_; }
template<class O, class charT> template<class O, class charT>
basic_format_arg<basic_format_context<O, charT>> basic_format_context<O, charT>::arg(size_t id) const { return args_.get(id); } basic_format_arg<basic_format_context<O, charT>> basic_format_context<O, charT>::arg(size_t id) const { return args_.get(id); }
@ -360,33 +352,39 @@ template<class Context>
template<class T, typename> template<class T, typename>
/* explicit */ basic_format_arg<Context>::basic_format_arg(const T& v) noexcept /* explicit */ basic_format_arg<Context>::basic_format_arg(const T& v) noexcept
: value(handle(v)) {} : value(handle(v)) {}
template<class Context>
/* explicit */ basic_format_arg<Context>::operator bool() const noexcept {
return !holds_alternative<monostate>(value);
}
} }
namespace std { namespace std {
template<class Context> template<class Context>
class basic_format_arg<Context>::handle { class basic_format_arg<Context>::handle {
const void* ptr_; // exposition only const void* ptr_; // exposition only
void (*format_)(Context&, const void*); // exposition only void (*format_)(basic_format_parse_context<char_type>&,
Context&, const void*); // exposition only
public: public:
template<class T> explicit handle(const T& val) noexcept; // exposition only template<class T> explicit handle(const T& val) noexcept; // exposition only
void format(Context& ctx) const; void format(basic_format_parse_context<char_type>&, Context& ctx) const;
}; };
} }
namespace std { namespace std {
template<class Context> template<class Context>
template<class T> /* explicit */ basic_format_arg<Context>::handle::handle(const T& val) noexcept template<class T> /* explicit */ basic_format_arg<Context>::handle::handle(const T& val) noexcept
: ptr_(&val), format_([](Context& ctx, const void* ptr) { : ptr_(&val), format_([](basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx, const void* ptr) {
typename Context::template formatter_type<T> f; typename Context::template formatter_type<T> f;
ctx.parse_context().advance_to(f.parse(ctx.parse_context())); parse_ctx.advance_to(f.parse(parse_ctx));
ctx.advance_to(f.format(*static_cast<const T*>(ptr), ctx)); format_ctx.advance_to(f.format(*static_cast<const T*>(ptr), format_ctx));
}) {} }) {}
template<class Context> template<class Context>
void basic_format_arg<Context>::handle::format(Context& ctx) const { void basic_format_arg<Context>::handle::format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx) const {
format_(ctx, ptr_); format_(parse_ctx, format_ctx, ptr_);
} }
// http://fmtlib.net/Text%20Formatting.html#format.visit // http://fmtlib.net/Text%20Formatting.html#format.visit
@ -460,11 +458,13 @@ class arg_formatter
typename fmt::internal::arg_formatter_base<Range>::iterator>, typename fmt::internal::arg_formatter_base<Range>::iterator>,
public fmt::internal::arg_formatter_base<Range> { public fmt::internal::arg_formatter_base<Range> {
private: private:
typedef typename Range::value_type char_type; using char_type = typename Range::value_type;
typedef fmt::internal::arg_formatter_base<Range> base; using base = fmt::internal::arg_formatter_base<Range>;
typedef std::basic_format_context<typename base::iterator, char_type> context_type; using format_context = std::basic_format_context<typename base::iterator, char_type>;
using parse_context = basic_format_parse_context<char_type>;
context_type& ctx_; parse_context& parse_ctx_;
format_context& ctx_;
public: public:
typedef Range range; typedef Range range;
@ -478,14 +478,14 @@ 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, fmt::format_specs* spec = FMT_NULL) arg_formatter(parse_context& parse_ctx, format_context& ctx, fmt::format_specs* spec = FMT_NULL)
: base(Range(ctx.out()), spec, {}), ctx_(ctx) {} : base(Range(ctx.out()), spec, {}), parse_ctx_(parse_ctx), ctx_(ctx) {}
using base::operator(); using base::operator();
/** Formats an argument of a user-defined type. */ /** Formats an argument of a user-defined type. */
iterator operator()(typename std::basic_format_arg<context_type>::handle handle) { iterator operator()(typename std::basic_format_arg<format_context>::handle handle) {
handle.format(ctx_); handle.format(parse_ctx_, ctx_);
return this->out(); return this->out();
} }
@ -528,16 +528,18 @@ inline fmt::internal::type get_type(basic_format_arg<Context> arg) {
}, arg); }, arg);
} }
template <typename Char, typename Context> template <typename Context>
class custom_formatter { class custom_formatter {
private: private:
Context& ctx_; using parse_context = basic_format_parse_context<typename Context::char_type>;
parse_context& parse_ctx_;
Context& format_ctx_;
public: public:
explicit custom_formatter(Context& ctx) : ctx_(ctx) {} custom_formatter(parse_context& parse_ctx, Context& ctx) : parse_ctx_(parse_ctx), format_ctx_(ctx) {}
bool operator()(typename basic_format_arg<Context>::handle h) const { bool operator()(typename basic_format_arg<Context>::handle h) const {
h.format(ctx_); h.format(parse_ctx_, format_ctx_);
return true; return true;
} }
@ -551,7 +553,7 @@ struct format_handler : fmt::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,
fmt::internal::locale_ref loc) fmt::internal::locale_ref loc)
: context(r.begin(), str, format_args, loc) {} : parse_ctx(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 = fmt::internal::to_unsigned(end - begin); auto size = fmt::internal::to_unsigned(end - begin);
@ -561,24 +563,25 @@ struct format_handler : fmt::internal::error_handler {
context.advance_to(out); context.advance_to(out);
} }
void on_arg_id() { arg = context.next_arg(); } void on_arg_id() {
arg = context.arg(parse_ctx.next_arg_id());
}
void on_arg_id(unsigned id) { void on_arg_id(unsigned id) {
context.parse_context().check_arg_id(id); parse_ctx.check_arg_id(id);
arg = context.arg(id); arg = context.arg(id);
} }
void on_arg_id(fmt::basic_string_view<Char> id) {} void on_arg_id(fmt::basic_string_view<Char> id) {}
void on_replacement_field(const Char* p) { void on_replacement_field(const Char* p) {
context.parse_context().advance_to(p); parse_ctx.advance_to(p);
custom_formatter<Char, Context> f(context); custom_formatter<Context> f(parse_ctx, 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(parse_ctx, 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 = context.parse_context();
parse_ctx.advance_to(begin); parse_ctx.advance_to(begin);
custom_formatter<Char, Context> f(context); custom_formatter<Context> f(parse_ctx, context);
if (visit_format_arg(f, arg)) return parse_ctx.begin(); if (visit_format_arg(f, arg)) return parse_ctx.begin();
fmt::basic_format_specs<Char> specs; fmt::basic_format_specs<Char> specs;
using fmt::internal::specs_handler; using fmt::internal::specs_handler;
@ -588,10 +591,11 @@ struct format_handler : fmt::internal::error_handler {
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_ctx.advance_to(begin);
context.advance_to(visit_format_arg(ArgFormatter(context, &specs), arg)); context.advance_to(visit_format_arg(ArgFormatter(parse_ctx, context, &specs), arg));
return begin; return begin;
} }
basic_format_parse_context<Char> parse_ctx;
Context context; Context context;
basic_format_arg<Context> arg; basic_format_arg<Context> arg;
}; };
@ -705,7 +709,7 @@ template<FMT_CONCEPT(OutputIterator<const wchar_t&>) O, class... Args>
template<FMT_CONCEPT(OutputIterator<const char&>) O> template<FMT_CONCEPT(OutputIterator<const char&>) O>
O vformat_to(O out, string_view fmt, format_args_t<O, char> args) { O vformat_to(O out, string_view fmt, format_args_t<O, char> args) {
typedef fmt::output_range<O, char> range; typedef fmt::output_range<O, char> range;
detail::format_handler<detail::arg_formatter<range>, char, format_context> detail::format_handler<detail::arg_formatter<range>, char, basic_format_context<O, char>>
h(range(out), fmt, args, {}); h(range(out), fmt, args, {});
fmt::internal::parse_format_string<false>(fmt::to_string_view(fmt), h); fmt::internal::parse_format_string<false>(fmt::to_string_view(fmt), h);
return h.context.out(); return h.context.out();