diff --git a/include/fmt/core.h b/include/fmt/core.h index 8959dac9..686494e6 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -624,7 +624,7 @@ class value { typename Context::template formatter_type f; auto &&parse_ctx = ctx.parse_context(); parse_ctx.advance_to(f.parse(parse_ctx)); - f.format(*static_cast(arg), ctx); + ctx.advance_to(f.format(*static_cast(arg), ctx)); } }; @@ -788,23 +788,23 @@ class arg_map { } }; -template +template class context_base { public: - using iterator = decltype(std::declval().begin()); + using iterator = OutputIt; private: - basic_parse_context parse_context_; + basic_parse_context parse_context_; iterator out_; basic_format_args args_; protected: - using char_type = typename Range::value_type; + using char_type = Char; using format_arg = basic_arg; - context_base(Range r, basic_string_view format_str, + context_base(OutputIt out, basic_string_view format_str, basic_format_args args) - : parse_context_(format_str), out_(r.begin()), args_(args) {} + : parse_context_(format_str), out_(out), args_(args) {} basic_format_args args() const { return args_; } @@ -824,7 +824,7 @@ class context_base { } public: - constexpr basic_parse_context &parse_context() { + basic_parse_context &parse_context() { return parse_context_; } @@ -882,24 +882,22 @@ class back_insert_range: }; // Formatting context. -template +template class basic_context : - public internal::context_base> { + public internal::context_base, Char> { public: /** The character type for the output. */ - using char_type = typename Range::value_type; + using char_type = Char; template using formatter_type = formatter; - using range_type = Range; - private: internal::arg_map map_; FMT_DISALLOW_COPY_AND_ASSIGN(basic_context); - using base = internal::context_base; + using base = internal::context_base; using format_arg = typename base::format_arg; using base::get_arg; @@ -912,9 +910,9 @@ class basic_context : stored in the object so make sure they have appropriate lifetimes. \endrst */ - basic_context(Range range, basic_string_view format_str, + basic_context(OutputIt out, basic_string_view format_str, basic_format_args args) - : base(range, format_str, args) {} + : base(out, format_str, args) {} format_arg next_arg() { return this->do_get_arg(this->parse_context().next_arg_id()); @@ -926,8 +924,10 @@ class basic_context : format_arg get_arg(basic_string_view name); }; -using context = basic_context>; -using wcontext = basic_context>; +using context = basic_context< + std::back_insert_iterator, char>; +using wcontext = basic_context< + std::back_insert_iterator, wchar_t>; template class arg_store { @@ -1087,12 +1087,10 @@ inline internal::named_arg arg(wstring_view name, const T &arg) { return internal::named_arg(name, arg); } -// The following two functions are deleted intentionally to disable -// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. -template -void arg(string_view, internal::named_arg) FMT_DELETED; -template -void arg(wstring_view, internal::named_arg) FMT_DELETED; +// This function template is deleted intentionally to disable nested named +// arguments as in ``format("{}", arg("a", arg("b", 42)))``. +template +void arg(S, internal::named_arg) FMT_DELETED; enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; diff --git a/include/fmt/format.h b/include/fmt/format.h index 40e3c7bf..6ffae2d9 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2058,10 +2058,12 @@ void handle_dynamic_spec( template class arg_formatter: public internal::arg_formatter_base { private: - basic_context &ctx_; - using char_type = typename Range::value_type; + using iterator = decltype(std::declval().begin()); using base = internal::arg_formatter_base; + using context_type = basic_context; + + context_type &ctx_; public: using range = Range; @@ -2074,13 +2076,13 @@ class arg_formatter: public internal::arg_formatter_base { *spec* contains format specifier information for standard argument types. \endrst */ - arg_formatter(basic_context &ctx, format_specs &spec) + arg_formatter(context_type &ctx, format_specs &spec) : base(Range(ctx.begin()), spec), ctx_(ctx) {} using base::operator(); /** Formats an argument of a custom (user-defined) type. */ - void operator()(typename basic_arg>::handle handle) { + void operator()(typename basic_arg::handle handle) { handle.format(ctx_); } }; @@ -2851,7 +2853,8 @@ struct formatter< specs_.width_, specs_.width_ref, ctx); internal::handle_dynamic_spec( specs_.precision_, specs_.precision_ref, ctx); - using range = typename FormatContext::range_type; + using range = output_range< + typename FormatContext::iterator, typename FormatContext::char_type>; visit(arg_formatter(ctx, specs_), internal::make_arg(val)); return ctx.begin(); @@ -2919,7 +2922,9 @@ struct dynamic_formatter { } if (specs_.precision_ != -1) checker.end_precision(); - visit(arg_formatter(ctx, specs_), + using range = output_range< + typename FormatContext::iterator, typename FormatContext::char_type>; + visit(arg_formatter(ctx, specs_), internal::make_arg(val)); return ctx.begin(); } @@ -2936,9 +2941,9 @@ struct dynamic_formatter { internal::dynamic_format_specs specs_; }; -template -typename basic_context::format_arg - basic_context::get_arg(basic_string_view name) { +template +typename basic_context::format_arg + basic_context::get_arg(basic_string_view name) { map_.init(this->args()); format_arg arg = map_.find(name); if (arg.type() == internal::NONE) @@ -2957,7 +2962,7 @@ void do_vformat_to(typename ArgFormatter::range out, struct handler : internal::error_handler { handler(range r, basic_string_view str, basic_format_args format_args) - : context(r, str, format_args) {} + : context(r.begin(), str, format_args) {} void on_text(iterator begin, iterator end) { size_t size = end - begin; @@ -3089,10 +3094,10 @@ inline void format_to(wmemory_buffer &buf, wstring_view format_str, } template -using context_t = basic_context>; +using context_t = basic_context; -template -using format_args_t = basic_format_args>; +template +using format_args_t = basic_format_args>; template inline void vformat_to(OutputIt out, string_view format_str, diff --git a/include/fmt/printf.h b/include/fmt/printf.h index 11d3aeea..28630a03 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -201,7 +201,10 @@ class PrintfWidthHandler { template class printf_arg_formatter; -template > +template < + typename OutputIt, typename Char, + typename ArgFormatter = + printf_arg_formatter>>> class basic_printf_context; /** @@ -212,16 +215,18 @@ class basic_printf_context; template class printf_arg_formatter : public internal::arg_formatter_base { private: - basic_printf_context &context_; + using char_type = typename Range::value_type; + using iterator = decltype(std::declval().begin()); + using base = internal::arg_formatter_base; + using context_type = basic_printf_context; + + context_type &context_; void write_null_pointer() { this->spec().type_ = 0; this->write("(nil)"); } - using char_type = typename Range::value_type; - using base = internal::arg_formatter_base; - public: using format_specs = typename base::format_specs; @@ -233,8 +238,9 @@ class printf_arg_formatter : public internal::arg_formatter_base { \endrst */ printf_arg_formatter(internal::basic_buffer &buffer, - format_specs &spec, basic_printf_context &ctx) - : base(buffer, spec), context_(ctx) {} + format_specs &spec, context_type &ctx) + : base(back_insert_range>(buffer), spec), + context_(ctx) {} using base::operator(); @@ -276,8 +282,7 @@ class printf_arg_formatter : public internal::arg_formatter_base { } /** Formats an argument of a custom (user-defined) type. */ - void operator()( - typename basic_arg>::handle handle) { + void operator()(typename basic_arg::handle handle) { handle.format(context_); } }; @@ -295,19 +300,19 @@ struct printf_formatter { }; /** This template formats data and writes the output to a writer. */ -template +template class basic_printf_context : private internal::context_base< - Range, basic_printf_context> { + OutputIt, basic_printf_context, Char> { public: /** The character type for the output. */ - using char_type = typename Range::value_type; + using char_type = Char; template using formatter_type = printf_formatter; private: - using base = internal::context_base; + using base = internal::context_base; using format_arg = typename base::format_arg; using format_specs = basic_format_specs; using iterator = internal::null_terminating_iterator; @@ -331,9 +336,9 @@ class basic_printf_context : appropriate lifetimes. \endrst */ - basic_printf_context(Range range, basic_string_view format_str, + basic_printf_context(OutputIt out, basic_string_view format_str, basic_format_args args) - : base(range, format_str, args) {} + : base(out, format_str, args) {} using base::parse_context; using base::begin; @@ -343,8 +348,8 @@ class basic_printf_context : FMT_API void format(); }; -template -void basic_printf_context::parse_flags( +template +void basic_printf_context::parse_flags( format_specs &spec, iterator &it) { for (;;) { switch (*it++) { @@ -370,17 +375,18 @@ void basic_printf_context::parse_flags( } } -template -typename basic_printf_context::format_arg - basic_printf_context::get_arg(iterator it, unsigned arg_index) { +template +typename basic_printf_context::format_arg + basic_printf_context::get_arg( + iterator it, unsigned arg_index) { (void)it; if (arg_index == std::numeric_limits::max()) return this->do_get_arg(this->parse_context().next_arg_id()); return base::get_arg(arg_index - 1); } -template -unsigned basic_printf_context::parse_header( +template +unsigned basic_printf_context::parse_header( iterator &it, format_specs &spec) { unsigned arg_index = std::numeric_limits::max(); char_type c = *it; @@ -416,8 +422,8 @@ unsigned basic_printf_context::parse_header( return arg_index; } -template -void basic_printf_context::format() { +template +void basic_printf_context::format() { auto &buffer = internal::get_container(this->begin()); auto start = iterator(this->parse_context()); auto it = start; @@ -506,8 +512,7 @@ void basic_printf_context::format() { break; case 'c': // TODO: handle wchar_t - visit(internal::CharConverter>(arg), - arg); + visit(internal::CharConverter(arg), arg); break; } } @@ -523,11 +528,12 @@ void basic_printf_context::format() { template void printf(internal::basic_buffer &buf, basic_string_view format, basic_format_args args) { - Context(buf, format, args).format(); + Context(std::back_inserter(buf), format, args).format(); } template -using printf_context = basic_printf_context>; +using printf_context = basic_printf_context< + std::back_insert_iterator, typename Buffer::value_type>; using printf_args = basic_format_args>; diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 45408dcd..d44f7002 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -18,9 +18,11 @@ class CustomArgFormatter : public fmt::arg_formatter> { public: using range = fmt::back_insert_range; + using iterator = decltype(std::declval().begin()); using base = fmt::arg_formatter; - CustomArgFormatter(fmt::basic_context &ctx, fmt::format_specs &s) + CustomArgFormatter(fmt::basic_context &ctx, + fmt::format_specs &s) : base(ctx, s) {} using base::operator(); diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 41323330..1a0656f5 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -58,14 +58,17 @@ TEST(OStreamTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); } -struct test_arg_formatter : fmt::arg_formatter { +using range = fmt::back_insert_range; + +struct test_arg_formatter: fmt::arg_formatter { test_arg_formatter(fmt::context &ctx, fmt::format_specs &s) - : fmt::arg_formatter(ctx, s) {} + : fmt::arg_formatter(ctx, s) {} }; TEST(OStreamTest, CustomArg) { fmt::memory_buffer buffer; - fmt::context ctx(buffer, "", fmt::format_args()); + fmt::internal::buffer &base = buffer; + fmt::context ctx(std::back_inserter(base), "", fmt::format_args()); fmt::format_specs spec; test_arg_formatter af(ctx, spec); visit(af, fmt::internal::make_arg(TestEnum())); diff --git a/test/util-test.cc b/test/util-test.cc index d3127199..65d8e5f8 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -81,9 +81,10 @@ struct formatter { return ctx.begin(); } - using range = fmt::back_insert_range>; + using iterator = std::back_insert_iterator>; - auto format(Test, basic_context &ctx) -> decltype(ctx.begin()) { + auto format(Test, basic_context &ctx) + -> decltype(ctx.begin()) { const Char *test = "test"; return std::copy_n(test, std::strlen(test), ctx.begin()); } @@ -521,8 +522,8 @@ VISIT_TYPE(float, double); #define CHECK_ARG_(Char, expected, value) { \ testing::StrictMock> visitor; \ EXPECT_CALL(visitor, visit(expected)); \ - using range = fmt::back_insert_range>; \ - fmt::visit(visitor, make_arg>(value)); \ + using iterator = std::back_insert_iterator>; \ + fmt::visit(visitor, make_arg>(value)); \ } #define CHECK_ARG(value) { \ @@ -600,7 +601,8 @@ TEST(UtilTest, CustomArg) { testing::StrictMock v; EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke([&](handle h) { fmt::memory_buffer buffer; - fmt::context ctx(buffer, "", fmt::format_args()); + fmt::internal::basic_buffer &base = buffer; + fmt::context ctx(std::back_inserter(base), "", fmt::format_args()); h.format(ctx); EXPECT_EQ("test", std::string(buffer.data(), buffer.size())); return visitor::Result();