From e787f6b74b2ff1e55b98b7ac4d850f13386b174e Mon Sep 17 00:00:00 2001 From: Arthur Danskin Date: Thu, 30 Mar 2017 00:32:07 -0400 Subject: [PATCH 1/5] %.f should have zero precision, not default precision --- fmt/printf.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fmt/printf.h b/fmt/printf.h index 038b9f26..06c999a7 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -439,6 +439,8 @@ void PrintfFormatter::format(BasicCStringRef format_str) { } else if (*s == '*') { ++s; spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); + } else { + spec.precision_ = 0; } } From 7c62a60fc7b6c84c69041ac5ccf7c6b236117e17 Mon Sep 17 00:00:00 2001 From: Arthur Danskin Date: Mon, 3 Apr 2017 18:43:14 -0400 Subject: [PATCH 2/5] add tests for printf %f precision, fix spacing on %.f precision fix --- fmt/printf.h | 2 +- test/printf-test.cc | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/fmt/printf.h b/fmt/printf.h index 06c999a7..6ce752e7 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -440,7 +440,7 @@ void PrintfFormatter::format(BasicCStringRef format_str) { ++s; spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); } else { - spec.precision_ = 0; + spec.precision_ = 0; } } diff --git a/test/printf-test.cc b/test/printf-test.cc index 7d9e21dd..0d8b268a 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -401,6 +401,9 @@ TEST(PrintfTest, LongLong) { TEST(PrintfTest, Float) { EXPECT_PRINTF("392.650000", "%f", 392.65); + EXPECT_PRINTF("392.65", "%.2f", 392.65); + EXPECT_PRINTF("392.6", "%.1f", 392.65); + EXPECT_PRINTF("392", "%.f", 392.65); EXPECT_PRINTF("392.650000", "%F", 392.65); EXPECT_PRINTF("392.65", "%s", 392.65); char buffer[BUFFER_SIZE]; From 1aa09d6da2c4489db2756e65a4c42412716d78af Mon Sep 17 00:00:00 2001 From: Arthur Danskin Date: Wed, 5 Apr 2017 02:13:44 -0400 Subject: [PATCH 3/5] fix printf float test (forgot about rounding) --- test/printf-test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/printf-test.cc b/test/printf-test.cc index 0d8b268a..81a041d7 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -403,7 +403,7 @@ TEST(PrintfTest, Float) { EXPECT_PRINTF("392.650000", "%f", 392.65); EXPECT_PRINTF("392.65", "%.2f", 392.65); EXPECT_PRINTF("392.6", "%.1f", 392.65); - EXPECT_PRINTF("392", "%.f", 392.65); + EXPECT_PRINTF("393", "%.f", 392.65); EXPECT_PRINTF("392.650000", "%F", 392.65); EXPECT_PRINTF("392.65", "%s", 392.65); char buffer[BUFFER_SIZE]; From dacb973dac3a74d2d52e13661728b86f662b4004 Mon Sep 17 00:00:00 2001 From: Arthur Danskin Date: Thu, 6 Apr 2017 01:25:32 -0400 Subject: [PATCH 4/5] modify extension format to allow accessing precision/etc. within user formatter. fix compilation when custom formatting a type with alignment restrictions (e.g. an sse2 vector type) --- fmt/format.h | 72 ++++++++++++++++++++++++++++++++++++++++++++------- fmt/ostream.h | 4 +-- fmt/printf.h | 5 ++-- fmt/time.h | 2 +- 4 files changed, 69 insertions(+), 14 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 07d02098..514c7dba 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1179,10 +1179,31 @@ struct ConvertToIntImpl2 { }; }; +template +struct ConvertToIntImpl3 { + enum { + value = false + }; +}; + +template +struct ConvertToIntImpl3 { + enum { + // This results in error C2718 in Visual Studio if T has alignment restrictions. + value = sizeof(fmt::internal::convert(get())) == sizeof(Yes) + }; +}; + +#if FMT_MSC_VER >= 1700 +#define FMT_INT_ALIGNABLE(T) (alignof(T) <= alignof(fmt::ULongLong)) +#else +#define FMT_INT_ALIGNABLE(T) (true) +#endif + template struct ConvertToInt { enum { - enable_conversion = sizeof(fmt::internal::convert(get())) == sizeof(Yes) + enable_conversion = ConvertToIntImpl3::value }; enum { value = ConvertToIntImpl2::value }; }; @@ -1262,6 +1283,7 @@ void format_arg(Formatter &, const Char *, const T &) { "an overload of format_arg."); } + // Makes an Arg object from any type. template class MakeValue : public Arg { @@ -1305,7 +1327,7 @@ class MakeValue : public Arg { template static void format_custom_arg( void *formatter, const void *arg, void *format_str_ptr) { - format_arg(*static_cast(formatter), + format_arg(*static_cast*>(formatter), *static_cast(format_str_ptr), *static_cast(arg)); } @@ -1463,6 +1485,29 @@ class RuntimeError : public std::runtime_error { template class ArgMap; + + +// first argument to format_arg for custom formatters +template +class UserFormatter { + AF &af_; +public: + typedef AF ArgFormatter; + typedef typename AF::Char Char; + typedef MakeArg< UserFormatter > MakeArg; + + UserFormatter(AF &af) : af_(af) {} + + BasicWriter &writer() { return af_.writer(); } + + void visit(const Arg &arg) { af_.visit(arg); } + + const Char *format(const Char *&format_str, const internal::Arg &arg) + { + af_.visit(format_str, arg); + } +}; + } // namespace internal /** An argument list. */ @@ -1945,10 +1990,10 @@ class ArgMap { } }; -template +template class ArgFormatterBase : public ArgVisitor { private: - BasicWriter &writer_; + BasicWriter &writer_; Spec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); @@ -1960,7 +2005,7 @@ class ArgFormatterBase : public ArgVisitor { } protected: - BasicWriter &writer() { return writer_; } + BasicWriter &writer() { return writer_; } Spec &spec() { return spec_; } void write(bool value) { @@ -1976,6 +2021,10 @@ class ArgFormatterBase : public ArgVisitor { public: typedef Spec SpecType; + typedef CharType Char; + + template + friend class UserFormatter; ArgFormatterBase(BasicWriter &w, Spec &s) : writer_(w), spec_(s) {} @@ -2134,7 +2183,8 @@ class BasicArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - c.format(&formatter_, c.value, &format_); + UserFormatter uf(*this); + c.format(&uf, c.value, &format_); } }; @@ -2151,11 +2201,12 @@ class ArgFormatter : }; /** 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. */ typedef CharType Char; + typedef AF ArgFormatter; private: BasicWriter &writer_; @@ -3693,7 +3744,8 @@ const Char *BasicFormatter::format( typename ArgFormatter::SpecType spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { - arg.custom.format(this, arg.custom.value, &s); + UserFormatter > uf(*this); + arg.custom.format(&uf, arg.custom.value, &s); return s; } ++s; @@ -3913,8 +3965,10 @@ auto join(const Range& range, const BasicCStringRef& sep) } #endif +using internal::UserFormatter; + template -void format_arg(fmt::BasicFormatter &f, +void format_arg(fmt::UserFormatter &f, const Char *&format_str, const ArgJoin& e) { const Char* end = format_str; if (*end == ':') diff --git a/fmt/ostream.h b/fmt/ostream.h index 7e13a5a7..f1805d22 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -90,8 +90,8 @@ public: } // namespace internal // Formats a value. -template -void format_arg(BasicFormatter &f, +template +void format_arg(UserFormatter &f, const Char *&format_str, const T &value) { internal::MemoryBuffer buffer; diff --git a/fmt/printf.h b/fmt/printf.h index 6ce752e7..15186078 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -290,7 +290,7 @@ class BasicPrintfArgFormatter : /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - BasicFormatter formatter(ArgList(), this->writer()); + UserFormatter formatter(*this); const Char format_str[] = {'}', 0}; const Char *format = format_str; c.format(&formatter, c.value, &format); @@ -308,7 +308,7 @@ class PrintfArgFormatter : }; /** This template formats data and writes the output to a writer. */ -template > +template > class PrintfFormatter : private internal::FormatterBase { private: BasicWriter &writer_; @@ -325,6 +325,7 @@ class PrintfFormatter : private internal::FormatterBase { unsigned parse_header(const Char *&s, FormatSpec &spec); public: + typedef AF ArgFormatter; /** \rst Constructs a ``PrintfFormatter`` object. References to the arguments and diff --git a/fmt/time.h b/fmt/time.h index c98b0e01..bf35ec5a 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -21,7 +21,7 @@ namespace fmt { template -void format_arg(BasicFormatter &f, +void format_arg(UserFormatter &f, const char *&format_str, const std::tm &tm) { if (*format_str == ':') ++format_str; From 74fc821cd6d6c76d0c0dde76ec1ab6873654b7c5 Mon Sep 17 00:00:00 2001 From: Arthur Danskin Date: Thu, 6 Apr 2017 16:31:33 -0400 Subject: [PATCH 5/5] fix for xcode build --- fmt/format.h | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 514c7dba..82912ead 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1283,6 +1283,30 @@ void format_arg(Formatter &, const Char *, const T &) { "an overload of format_arg."); } +template +class MakeArg; + +// first argument to format_arg for custom formatters +template +class UserFormatter { + AF &af_; +public: + typedef AF ArgFormatter; + typedef typename AF::Char Char; + typedef MakeArg< UserFormatter > MakeArg; + + UserFormatter(AF &af) : af_(af) {} + + BasicWriter &writer() { return af_.writer(); } + + void visit(const Arg &arg) { af_.visit(arg); } + + const Char *format(const Char *&format_str, const internal::Arg &arg) + { + af_.visit(format_str, arg); + } +}; + // Makes an Arg object from any type. template @@ -1485,28 +1509,6 @@ class RuntimeError : public std::runtime_error { template class ArgMap; - - -// first argument to format_arg for custom formatters -template -class UserFormatter { - AF &af_; -public: - typedef AF ArgFormatter; - typedef typename AF::Char Char; - typedef MakeArg< UserFormatter > MakeArg; - - UserFormatter(AF &af) : af_(af) {} - - BasicWriter &writer() { return af_.writer(); } - - void visit(const Arg &arg) { af_.visit(arg); } - - const Char *format(const Char *&format_str, const internal::Arg &arg) - { - af_.visit(format_str, arg); - } -}; } // namespace internal @@ -2183,7 +2185,7 @@ class BasicArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - UserFormatter uf(*this); + internal::UserFormatter uf(*this); c.format(&uf, c.value, &format_); } }; @@ -3744,7 +3746,7 @@ const Char *BasicFormatter::format( typename ArgFormatter::SpecType spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { - UserFormatter > uf(*this); + internal::UserFormatter > uf(*this); arg.custom.format(&uf, arg.custom.value, &s); return s; }