From dacb973dac3a74d2d52e13661728b86f662b4004 Mon Sep 17 00:00:00 2001 From: Arthur Danskin Date: Thu, 6 Apr 2017 01:25:32 -0400 Subject: [PATCH] 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;