diff --git a/cppformat/format.h b/cppformat/format.h index 08bb9b5d..67f02f22 100644 --- a/cppformat/format.h +++ b/cppformat/format.h @@ -371,7 +371,13 @@ class BasicWriter; typedef BasicWriter Writer; typedef BasicWriter WWriter; +namespace internal { template +class BasicArgFormatter; +} + +template > class BasicFormatter; template @@ -1885,7 +1891,7 @@ class PrintfFormatter : private FormatterBase { } // namespace internal /** This template formats data and writes the output to a writer. */ -template +template class BasicFormatter : private internal::FormatterBase { public: /** The character type for the output. */ @@ -3475,9 +3481,9 @@ void check_sign(const Char *&s, const Arg &arg) { } } // namespace internal -template -inline internal::Arg BasicFormatter::get_arg( - BasicStringRef arg_name, const char *&error) { +template +inline internal::Arg BasicFormatter::get_arg( + BasicStringRef arg_name, const char *&error) { if (check_no_auto_index(error)) { map_.init(args()); const internal::Arg *arg = map_.find(arg_name); @@ -3488,8 +3494,8 @@ inline internal::Arg BasicFormatter::get_arg( return internal::Arg(); } -template -inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { +template +inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { const char *error = 0; internal::Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); @@ -3500,8 +3506,8 @@ inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { return arg; } -template -inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { +template +inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { assert(internal::is_name_start(*s)); const Char *start = s; Char c; @@ -3515,8 +3521,8 @@ inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { return arg; } -template -const Char *BasicFormatter::format( +template +const Char *BasicFormatter::format( const Char *&format_str, const internal::Arg &arg) { using internal::Arg; const Char *s = format_str; @@ -3681,12 +3687,12 @@ const Char *BasicFormatter::format( FMT_THROW(FormatError("missing '}' in format string")); // Format argument. - internal::BasicArgFormatter(*this, spec, s - 1).visit(arg); + ArgFormatter(*this, spec, s - 1).visit(arg); return s; } -template -void BasicFormatter::format(BasicCStringRef format_str) { +template +void BasicFormatter::format(BasicCStringRef format_str) { const Char *s = format_str.c_str(); const Char *start = s; while (*s) { diff --git a/test/format-test.cc b/test/format-test.cc index dd7a1c7c..2096110b 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1658,3 +1658,36 @@ std::ostream &operator<<(std::ostream &os, EmptyTest) { TEST(FormatTest, EmptyCustomOutput) { EXPECT_EQ("", fmt::format("{}", EmptyTest())); } + +class CustomArgFormatter : + public fmt::internal::ArgFormatterBase { + public: + typedef fmt::internal::ArgFormatterBase Base; + + CustomArgFormatter(fmt::BasicFormatter &f, + fmt::FormatSpec &s, const char *) + : fmt::internal::ArgFormatterBase(f.writer(), s) { + } + + void visit_int(int value) { + fmt::FormatSpec &spec = this->spec(); + if (spec.type() == 'x') + visit_uint(value); // convert to unsigned and format + else + Base::visit_int(value); + } +}; + +std::string custom_format(const char *format_str, fmt::ArgList args) { + fmt::MemoryWriter writer; + fmt::BasicFormatter formatter(args, writer); + formatter.format(format_str); + return writer.str(); +} +FMT_VARIADIC(std::string, custom_format, const char *) + +TEST(FormatTest, CustomArgFormatter) { + int x = -0xbeef; + EXPECT_EQ(fmt::format("{:x}", static_cast(x)), + custom_format("{:x}", x)); +}