This commit is contained in:
Arthur Danskin 2017-05-29 23:32:31 +00:00 committed by GitHub
commit e908e56640
4 changed files with 71 additions and 14 deletions

View File

@ -1172,10 +1172,31 @@ struct ConvertToIntImpl2<T, true> {
}; };
}; };
template <typename T, bool ENABLE_CONVERSION>
struct ConvertToIntImpl3 {
enum {
value = false
};
};
template <typename T>
struct ConvertToIntImpl3<T, true> {
enum {
// This results in error C2718 in Visual Studio if T has alignment restrictions.
value = sizeof(fmt::internal::convert(get<T>())) == 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<typename T> template<typename T>
struct ConvertToInt { struct ConvertToInt {
enum { enum {
enable_conversion = sizeof(fmt::internal::convert(get<T>())) == sizeof(Yes) enable_conversion = ConvertToIntImpl3<T, FMT_INT_ALIGNABLE(T)>::value
}; };
enum { value = ConvertToIntImpl2<T, enable_conversion>::value }; enum { value = ConvertToIntImpl2<T, enable_conversion>::value };
}; };
@ -1255,6 +1276,31 @@ void format_arg(Formatter &, const Char *, const T &) {
"an overload of format_arg."); "an overload of format_arg.");
} }
template <typename Formatter>
class MakeArg;
// first argument to format_arg for custom formatters
template <typename AF>
class UserFormatter {
AF &af_;
public:
typedef AF ArgFormatter;
typedef typename AF::Char Char;
typedef MakeArg< UserFormatter > MakeArg;
UserFormatter(AF &af) : af_(af) {}
BasicWriter<typename AF::Char> &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. // Makes an Arg object from any type.
template <typename Formatter> template <typename Formatter>
class MakeValue : public Arg { class MakeValue : public Arg {
@ -1298,7 +1344,7 @@ class MakeValue : public Arg {
template <typename T> template <typename T>
static void format_custom_arg( static void format_custom_arg(
void *formatter, const void *arg, void *format_str_ptr) { void *formatter, const void *arg, void *format_str_ptr) {
format_arg(*static_cast<Formatter*>(formatter), format_arg(*static_cast<UserFormatter<typename Formatter::ArgFormatter>*>(formatter),
*static_cast<const Char**>(format_str_ptr), *static_cast<const Char**>(format_str_ptr),
*static_cast<const T*>(arg)); *static_cast<const T*>(arg));
} }
@ -1451,6 +1497,7 @@ class RuntimeError : public std::runtime_error {
template <typename Char> template <typename Char>
class ArgMap; class ArgMap;
} // namespace internal } // namespace internal
/** An argument list. */ /** An argument list. */
@ -1933,10 +1980,10 @@ class ArgMap {
} }
}; };
template <typename Impl, typename Char, typename Spec = fmt::FormatSpec> template <typename Impl, typename CharType, typename Spec = fmt::FormatSpec>
class ArgFormatterBase : public ArgVisitor<Impl, void> { class ArgFormatterBase : public ArgVisitor<Impl, void> {
private: private:
BasicWriter<Char> &writer_; BasicWriter<CharType> &writer_;
Spec &spec_; Spec &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase);
@ -1951,7 +1998,7 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
typedef internal::Arg Arg; typedef internal::Arg Arg;
protected: protected:
BasicWriter<Char> &writer() { return writer_; } BasicWriter<CharType> &writer() { return writer_; }
Spec &spec() { return spec_; } Spec &spec() { return spec_; }
void write(bool value) { void write(bool value) {
@ -1967,6 +2014,10 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
public: public:
typedef Spec SpecType; typedef Spec SpecType;
typedef CharType Char;
template <typename ArgFormatter>
friend class UserFormatter;
ArgFormatterBase(BasicWriter<Char> &w, Spec &s) ArgFormatterBase(BasicWriter<Char> &w, Spec &s)
: writer_(w), spec_(s) {} : writer_(w), spec_(s) {}
@ -2125,7 +2176,8 @@ class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char, Spec> {
/** Formats an argument of a custom (user-defined) type. */ /** Formats an argument of a custom (user-defined) type. */
void visit_custom(internal::Arg::CustomValue c) { void visit_custom(internal::Arg::CustomValue c) {
c.format(&formatter_, c.value, &format_); internal::UserFormatter<BasicArgFormatter> 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. */ /** This template formats data and writes the output to a writer. */
template <typename CharType, typename ArgFormatter> template <typename CharType, typename AF>
class BasicFormatter : private internal::FormatterBase { class BasicFormatter : private internal::FormatterBase {
public: public:
/** The character type for the output. */ /** The character type for the output. */
typedef CharType Char; typedef CharType Char;
typedef AF ArgFormatter;
private: private:
BasicWriter<Char> &writer_; BasicWriter<Char> &writer_;
@ -3684,7 +3737,8 @@ const Char *BasicFormatter<Char, ArgFormatter>::format(
typename ArgFormatter::SpecType spec; typename ArgFormatter::SpecType spec;
if (*s == ':') { if (*s == ':') {
if (arg.type == Arg::CUSTOM) { if (arg.type == Arg::CUSTOM) {
arg.custom.format(this, arg.custom.value, &s); internal::UserFormatter<BasicFormatter<Char, ArgFormatter> > uf(*this);
arg.custom.format(&uf, arg.custom.value, &s);
return s; return s;
} }
++s; ++s;
@ -3904,8 +3958,10 @@ auto join(const Range& range, const BasicCStringRef<wchar_t>& sep)
} }
#endif #endif
using internal::UserFormatter;
template <typename ArgFormatter, typename Char, typename It> template <typename ArgFormatter, typename Char, typename It>
void format_arg(fmt::BasicFormatter<Char, ArgFormatter> &f, void format_arg(fmt::UserFormatter<ArgFormatter> &f,
const Char *&format_str, const ArgJoin<Char, It>& e) { const Char *&format_str, const ArgJoin<Char, It>& e) {
const Char* end = format_str; const Char* end = format_str;
if (*end == ':') if (*end == ':')

View File

@ -71,8 +71,8 @@ FMT_API void write(std::ostream &os, Writer &w);
} // namespace internal } // namespace internal
// Formats a value. // Formats a value.
template <typename Char, typename ArgFormatter_, typename T> template <typename ArgFormatter_, typename T, typename Char=typename ArgFormatter_::Char>
void format_arg(BasicFormatter<Char, ArgFormatter_> &f, void format_arg(UserFormatter<ArgFormatter_> &f,
const Char *&format_str, const T &value) { const Char *&format_str, const T &value) {
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer; internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;

View File

@ -290,7 +290,7 @@ class BasicPrintfArgFormatter :
/** Formats an argument of a custom (user-defined) type. */ /** Formats an argument of a custom (user-defined) type. */
void visit_custom(internal::Arg::CustomValue c) { void visit_custom(internal::Arg::CustomValue c) {
BasicFormatter<Char> formatter(ArgList(), this->writer()); UserFormatter<BasicPrintfArgFormatter> formatter(*this);
const Char format_str[] = {'}', 0}; const Char format_str[] = {'}', 0};
const Char *format = format_str; const Char *format = format_str;
c.format(&formatter, c.value, &format); c.format(&formatter, c.value, &format);
@ -308,7 +308,7 @@ class PrintfArgFormatter :
}; };
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> > template <typename Char, typename AF = PrintfArgFormatter<Char> >
class PrintfFormatter : private internal::FormatterBase { class PrintfFormatter : private internal::FormatterBase {
private: private:
BasicWriter<Char> &writer_; BasicWriter<Char> &writer_;
@ -325,6 +325,7 @@ class PrintfFormatter : private internal::FormatterBase {
unsigned parse_header(const Char *&s, FormatSpec &spec); unsigned parse_header(const Char *&s, FormatSpec &spec);
public: public:
typedef AF ArgFormatter;
/** /**
\rst \rst
Constructs a ``PrintfFormatter`` object. References to the arguments and Constructs a ``PrintfFormatter`` object. References to the arguments and

View File

@ -21,7 +21,7 @@
namespace fmt { namespace fmt {
template <typename ArgFormatter> template <typename ArgFormatter>
void format_arg(BasicFormatter<char, ArgFormatter> &f, void format_arg(UserFormatter<ArgFormatter> &f,
const char *&format_str, const std::tm &tm) { const char *&format_str, const std::tm &tm) {
if (*format_str == ':') if (*format_str == ':')
++format_str; ++format_str;