This commit is contained in:
wind85 2017-07-03 10:57:25 +00:00 committed by GitHub
commit 5a6b1a430a

View File

@ -12,6 +12,7 @@
#include <algorithm> // std::fill_n #include <algorithm> // std::fill_n
#include <limits> // std::numeric_limits #include <limits> // std::numeric_limits
#include <mutex>
#include "ostream.h" #include "ostream.h"
@ -58,7 +59,9 @@ class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
class IsZeroInt : public ArgVisitor<IsZeroInt, bool> { class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
public: public:
template <typename T> template <typename T>
bool visit_any_int(T value) { return value == 0; } bool visit_any_int(T value) {
return value == 0;
}
}; };
// returns the default type for format specific "%s" // returns the default type for format specific "%s"
@ -71,10 +74,14 @@ class DefaultType : public ArgVisitor<DefaultType, char> {
char visit_pointer(const void *) { return 'p'; } char visit_pointer(const void *) { return 'p'; }
template <typename T> template <typename T>
char visit_any_int(T) { return 'd'; } char visit_any_int(T) {
return 'd';
}
template <typename T> template <typename T>
char visit_any_double(T) { return 'g'; } char visit_any_double(T) {
return 'g';
}
char visit_unhandled_arg() { return 's'; } char visit_unhandled_arg() { return 's'; }
}; };
@ -102,17 +109,14 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
public: public:
ArgConverter(internal::Arg &arg, wchar_t type) ArgConverter(internal::Arg &arg, wchar_t type) : arg_(arg), type_(type) {}
: arg_(arg), type_(type) {}
void visit_bool(bool value) { void visit_bool(bool value) {
if (type_ != 's') if (type_ != 's') visit_any_int(value);
visit_any_int(value);
} }
void visit_char(char value) { void visit_char(char value) {
if (type_ != 's') if (type_ != 's') visit_any_int(value);
visit_any_int(value);
} }
template <typename U> template <typename U>
@ -123,8 +127,8 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
} }
using internal::Arg; using internal::Arg;
typedef typename internal::Conditional< typedef typename internal::Conditional<is_same<T, void>::value, U, T>::type
is_same<T, void>::value, U, T>::type TargetType; TargetType;
if (sizeof(TargetType) <= sizeof(int)) { if (sizeof(TargetType) <= sizeof(int)) {
// Extra casts are used to silence warnings. // Extra casts are used to silence warnings.
if (is_signed) { if (is_signed) {
@ -138,9 +142,12 @@ class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
} else { } else {
if (is_signed) { if (is_signed) {
arg_.type = Arg::LONG_LONG; arg_.type = Arg::LONG_LONG;
// glibc's printf doesn't sign extend arguments of smaller types: // glibc's printf doesn't sign extend arguments
// std::printf("%lld", -42); // prints "4294967254" // of smaller types:
// but we don't have to do the same because it's a UB. // std::printf("%lld", -42); // prints
// "4294967254"
// but we don't have to do the same because it's
// a UB.
arg_.long_long_value = static_cast<LongLong>(value); arg_.long_long_value = static_cast<LongLong>(value);
} else { } else {
arg_.type = Arg::ULONG_LONG; arg_.type = Arg::ULONG_LONG;
@ -192,8 +199,7 @@ class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
width = 0 - width; width = 0 - width;
} }
unsigned int_max = std::numeric_limits<int>::max(); unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max) if (width > int_max) FMT_THROW(FormatError("number is too big"));
FMT_THROW(FormatError("number is too big"));
return static_cast<unsigned>(width); return static_cast<unsigned>(width);
} }
}; };
@ -217,8 +223,8 @@ class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
\endrst \endrst
*/ */
template <typename Impl, typename Char, typename Spec> template <typename Impl, typename Char, typename Spec>
class BasicPrintfArgFormatter : class BasicPrintfArgFormatter
public internal::ArgFormatterBase<Impl, Char, Spec> { : public internal::ArgFormatterBase<Impl, Char, Spec> {
private: private:
void write_null_pointer() { void write_null_pointer() {
this->spec().type_ = 0; this->spec().type_ = 0;
@ -231,18 +237,18 @@ class BasicPrintfArgFormatter :
/** /**
\rst \rst
Constructs an argument formatter object. Constructs an argument formatter object.
*writer* is a reference to the output writer and *spec* contains format *writer* is a reference to the output writer and *spec* contains
format
specifier information for standard argument types. specifier information for standard argument types.
\endrst \endrst
*/ */
BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s) BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s)
: internal::ArgFormatterBase<Impl, Char, Spec>(w, s) {} : internal::ArgFormatterBase<Impl, Char, Spec>(w, s) {}
/** Formats an argument of type ``bool``. */ /** Formats an argument of type ``bool``. */
void visit_bool(bool value) { void visit_bool(bool value) {
Spec &fmt_spec = this->spec(); Spec &fmt_spec = this->spec();
if (fmt_spec.type_ != 's') if (fmt_spec.type_ != 's') return this->visit_any_int(value);
return this->visit_any_int(value);
fmt_spec.type_ = 0; fmt_spec.type_ = 0;
this->write(value); this->write(value);
} }
@ -251,8 +257,7 @@ class BasicPrintfArgFormatter :
void visit_char(int value) { void visit_char(int value) {
const Spec &fmt_spec = this->spec(); const Spec &fmt_spec = this->spec();
BasicWriter<Char> &w = this->writer(); BasicWriter<Char> &w = this->writer();
if (fmt_spec.type_ && fmt_spec.type_ != 'c') if (fmt_spec.type_ && fmt_spec.type_ != 'c') w.write_int(value, fmt_spec);
w.write_int(value, fmt_spec);
typedef typename BasicWriter<Char>::CharPtr CharPtr; typedef typename BasicWriter<Char>::CharPtr CharPtr;
CharPtr out = CharPtr(); CharPtr out = CharPtr();
if (fmt_spec.width_ > 1) { if (fmt_spec.width_ > 1) {
@ -282,8 +287,7 @@ class BasicPrintfArgFormatter :
/** Formats a pointer. */ /** Formats a pointer. */
void visit_pointer(const void *value) { void visit_pointer(const void *value) {
if (value) if (value) return Base::visit_pointer(value);
return Base::visit_pointer(value);
this->spec().type_ = 0; this->spec().type_ = 0;
write_null_pointer(); write_null_pointer();
} }
@ -299,12 +303,14 @@ class BasicPrintfArgFormatter :
/** The default printf argument formatter. */ /** The default printf argument formatter. */
template <typename Char> template <typename Char>
class PrintfArgFormatter : class PrintfArgFormatter
public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec> { : public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char,
FormatSpec> {
public: public:
/** Constructs an argument formatter object. */ /** Constructs an argument formatter object. */
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(w, s) {} : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(
w, s) {}
}; };
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
@ -321,19 +327,21 @@ class PrintfFormatter : private internal::FormatterBase {
const Char *s, const Char *s,
unsigned arg_index = (std::numeric_limits<unsigned>::max)()); unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index. // Parses argument index, flags and width and returns the argument
// index.
unsigned parse_header(const Char *&s, FormatSpec &spec); unsigned parse_header(const Char *&s, FormatSpec &spec);
public: public:
/** /**
\rst \rst
Constructs a ``PrintfFormatter`` object. References to the arguments and Constructs a ``PrintfFormatter`` object. References to the arguments
and
the writer are stored in the formatter object so make sure they have the writer are stored in the formatter object so make sure they have
appropriate lifetimes. appropriate lifetimes.
\endrst \endrst
*/ */
explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w) explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)
: FormatterBase(al), writer_(w) {} : FormatterBase(al), writer_(w) {}
/** Formats stored arguments and writes the output to the writer. */ /** Formats stored arguments and writes the output to the writer. */
void format(BasicCStringRef<Char> format_str); void format(BasicCStringRef<Char> format_str);
@ -370,30 +378,31 @@ internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
unsigned arg_index) { unsigned arg_index) {
(void)s; (void)s;
const char *error = FMT_NULL; const char *error = FMT_NULL;
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max()
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); ? next_arg(error)
if (error) : FormatterBase::get_arg(arg_index - 1, error);
FMT_THROW(FormatError(!*s ? "invalid format string" : error)); if (error) FMT_THROW(FormatError(!*s ? "invalid format string" : error));
return arg; return arg;
} }
template <typename Char, typename AF> template <typename Char, typename AF>
unsigned PrintfFormatter<Char, AF>::parse_header( unsigned PrintfFormatter<Char, AF>::parse_header(const Char *&s,
const Char *&s, FormatSpec &spec) { FormatSpec &spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max(); unsigned arg_index = std::numeric_limits<unsigned>::max();
Char c = *s; Char c = *s;
if (c >= '0' && c <= '9') { if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly // Parse an argument index (if followed by '$') or a width
// possibly
// preceded with '0' flag(s). // preceded with '0' flag(s).
unsigned value = internal::parse_nonnegative_int(s); unsigned value = internal::parse_nonnegative_int(s);
if (*s == '$') { // value is an argument index if (*s == '$') { // value is an argument index
++s; ++s;
arg_index = value; arg_index = value;
} else { } else {
if (c == '0') if (c == '0') spec.fill_ = '0';
spec.fill_ = '0';
if (value != 0) { if (value != 0) {
// Nonzero value means that we parsed width and don't need to // Nonzero value means that we parsed width and
// don't need to
// parse it or flags again, so return now. // parse it or flags again, so return now.
spec.width_ = value; spec.width_ = value;
return arg_index; return arg_index;
@ -452,62 +461,65 @@ void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
if (arg.type <= Arg::LAST_NUMERIC_TYPE) if (arg.type <= Arg::LAST_NUMERIC_TYPE)
spec.align_ = ALIGN_NUMERIC; spec.align_ = ALIGN_NUMERIC;
else else
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. spec.fill_ = ' '; // Ignore '0' flag for
// non-numeric types.
} }
// Parse length and convert the argument to the required type. // Parse length and convert the argument to the required type.
using internal::ArgConverter; using internal::ArgConverter;
switch (*s++) { switch (*s++) {
case 'h': case 'h':
if (*s == 'h') if (*s == 'h')
ArgConverter<signed char>(arg, *++s).visit(arg); ArgConverter<signed char>(arg, *++s).visit(arg);
else else
ArgConverter<short>(arg, *s).visit(arg); ArgConverter<short>(arg, *s).visit(arg);
break; break;
case 'l': case 'l':
if (*s == 'l') if (*s == 'l')
ArgConverter<fmt::LongLong>(arg, *++s).visit(arg); ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
else else
ArgConverter<long>(arg, *s).visit(arg); ArgConverter<long>(arg, *s).visit(arg);
break; break;
case 'j': case 'j':
ArgConverter<intmax_t>(arg, *s).visit(arg); ArgConverter<intmax_t>(arg, *s).visit(arg);
break; break;
case 'z': case 'z':
ArgConverter<std::size_t>(arg, *s).visit(arg); ArgConverter<std::size_t>(arg, *s).visit(arg);
break; break;
case 't': case 't':
ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg); ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
break; break;
case 'L': case 'L':
// printf produces garbage when 'L' is omitted for long double, no // printf produces garbage when 'L' is omitted
// need to do the same. // for long double, no
break; // need to do the same.
default: break;
--s; default:
ArgConverter<void>(arg, *s).visit(arg); --s;
ArgConverter<void>(arg, *s).visit(arg);
} }
// Parse type. // Parse type.
if (!*s) if (!*s) FMT_THROW(FormatError("invalid format string"));
FMT_THROW(FormatError("invalid format string"));
spec.type_ = static_cast<char>(*s++); spec.type_ = static_cast<char>(*s++);
if (spec.type_ == 's') { if (spec.type_ == 's') {
// set the format type to the default if 's' is specified // set the format type to the default if 's' is
// specified
spec.type_ = internal::DefaultType().visit(arg); spec.type_ = internal::DefaultType().visit(arg);
} }
if (arg.type <= Arg::LAST_INTEGER_TYPE) { if (arg.type <= Arg::LAST_INTEGER_TYPE) {
// Normalize type. // Normalize type.
switch (spec.type_) { switch (spec.type_) {
case 'i': case 'u': case 'i':
spec.type_ = 'd'; case 'u':
break; spec.type_ = 'd';
case 'c': break;
// TODO: handle wchar_t case 'c':
internal::CharConverter(arg).visit(arg); // TODO: handle wchar_t
break; internal::CharConverter(arg).visit(arg);
break;
} }
} }
@ -588,6 +600,8 @@ FMT_VARIADIC(int, printf, CStringRef)
\endrst \endrst
*/ */
inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) { inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) {
std::mutex mtx;
std::unique_lock<std::mutex> lck(mtx);
MemoryWriter w; MemoryWriter w;
printf(w, format_str, args); printf(w, format_str, args);
internal::write(os, w); internal::write(os, w);
@ -597,7 +611,7 @@ FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt } // namespace fmt
#ifdef FMT_HEADER_ONLY #ifdef FMT_HEADER_ONLY
# include "printf.cc" #include "printf.cc"
#endif #endif
#endif // FMT_PRINTF_H_ #endif // FMT_PRINTF_H_