diff --git a/fmt/format.h b/fmt/format.h index b56b8589..94c9e3a3 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1172,10 +1172,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 }; }; @@ -1255,6 +1276,31 @@ 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 class MakeValue : public Arg { @@ -1298,7 +1344,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)); } @@ -1451,6 +1497,7 @@ class RuntimeError : public std::runtime_error { template class ArgMap; + } // namespace internal /** An argument list. */ @@ -1933,10 +1980,10 @@ class ArgMap { } }; -template +template class ArgFormatterBase : public ArgVisitor { private: - BasicWriter &writer_; + BasicWriter &writer_; Spec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); @@ -1951,7 +1998,7 @@ class ArgFormatterBase : public ArgVisitor { typedef internal::Arg Arg; protected: - BasicWriter &writer() { return writer_; } + BasicWriter &writer() { return writer_; } Spec &spec() { return spec_; } void write(bool value) { @@ -1967,6 +2014,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) {} @@ -2125,7 +2176,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_); + internal::UserFormatter uf(*this); + c.format(&uf, c.value, &format_); } }; @@ -2142,11 +2194,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_; @@ -3684,7 +3737,8 @@ const Char *BasicFormatter::format( typename ArgFormatter::SpecType spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { - arg.custom.format(this, arg.custom.value, &s); + internal::UserFormatter > uf(*this); + arg.custom.format(&uf, arg.custom.value, &s); return s; } ++s; @@ -3904,8 +3958,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 84a02d17..c39e1336 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -71,8 +71,8 @@ FMT_API void write(std::ostream &os, Writer &w); } // 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 30cbc49b..a9b49724 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;