diff --git a/fmt/printf.h b/fmt/printf.h index 30cbc49b..b22f6016 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -12,6 +12,7 @@ #include // std::fill_n #include // std::numeric_limits +#include #include "ostream.h" @@ -22,71 +23,78 @@ namespace internal { // signed and unsigned integers. template struct IntChecker { - template - static bool fits_in_int(T value) { - unsigned max = std::numeric_limits::max(); - return value <= max; - } - static bool fits_in_int(bool) { return true; } + template + static bool fits_in_int(T value) { + unsigned max = std::numeric_limits::max(); + return value <= max; + } + static bool fits_in_int(bool) { return true; } }; template <> struct IntChecker { - template - static bool fits_in_int(T value) { - return value >= std::numeric_limits::min() && - value <= std::numeric_limits::max(); - } - static bool fits_in_int(int) { return true; } + template + static bool fits_in_int(T value) { + return value >= std::numeric_limits::min() && + value <= std::numeric_limits::max(); + } + static bool fits_in_int(int) { return true; } }; class PrecisionHandler : public ArgVisitor { - public: - void report_unhandled_arg() { - FMT_THROW(FormatError("precision is not integer")); - } + public: + void report_unhandled_arg() { + FMT_THROW(FormatError("precision is not integer")); + } - template - int visit_any_int(T value) { - if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(FormatError("number is too big")); - return static_cast(value); - } + template + int visit_any_int(T value) { + if (!IntChecker::is_signed>::fits_in_int( + value)) + FMT_THROW(FormatError("number is too big")); + return static_cast(value); + } }; // IsZeroInt::visit(arg) returns true iff arg is a zero integer. class IsZeroInt : public ArgVisitor { - public: - template - bool visit_any_int(T value) { return value == 0; } + public: + template + bool visit_any_int(T value) { + return value == 0; + } }; // returns the default type for format specific "%s" class DefaultType : public ArgVisitor { - public: - char visit_char(int) { return 'c'; } + public: + char visit_char(int) { return 'c'; } - char visit_bool(bool) { return 's'; } + char visit_bool(bool) { return 's'; } - char visit_pointer(const void *) { return 'p'; } + char visit_pointer(const void *) { return 'p'; } - template - char visit_any_int(T) { return 'd'; } + template + char visit_any_int(T) { + return 'd'; + } - template - char visit_any_double(T) { return 'g'; } + template + char visit_any_double(T) { + return 'g'; + } - char visit_unhandled_arg() { return 's'; } + char visit_unhandled_arg() { return 's'; } }; template struct is_same { - enum { value = 0 }; + enum { value = 0 }; }; template struct is_same { - enum { value = 1 }; + enum { value = 1 }; }; // An argument visitor that converts an integer argument to T for printf, @@ -95,107 +103,113 @@ struct is_same { // 'd' and 'i' - signed, other - unsigned) template class ArgConverter : public ArgVisitor, void> { - private: - internal::Arg &arg_; - wchar_t type_; + private: + internal::Arg &arg_; + wchar_t type_; - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); + FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - public: - ArgConverter(internal::Arg &arg, wchar_t type) - : arg_(arg), type_(type) {} + public: + ArgConverter(internal::Arg &arg, wchar_t type) + : arg_(arg), type_(type) {} - void visit_bool(bool value) { - if (type_ != 's') - visit_any_int(value); - } + void visit_bool(bool value) { + if (type_ != 's') visit_any_int(value); + } - void visit_char(char value) { - if (type_ != 's') - visit_any_int(value); - } + void visit_char(char value) { + if (type_ != 's') visit_any_int(value); + } - template - void visit_any_int(U value) { - bool is_signed = type_ == 'd' || type_ == 'i'; - if (type_ == 's') { - is_signed = std::numeric_limits::is_signed; - } + template + void visit_any_int(U value) { + bool is_signed = type_ == 'd' || type_ == 'i'; + if (type_ == 's') { + is_signed = std::numeric_limits::is_signed; + } - using internal::Arg; - typedef typename internal::Conditional< - is_same::value, U, T>::type TargetType; - if (sizeof(TargetType) <= sizeof(int)) { - // Extra casts are used to silence warnings. - if (is_signed) { - arg_.type = Arg::INT; - arg_.int_value = static_cast(static_cast(value)); - } else { - arg_.type = Arg::UINT; - typedef typename internal::MakeUnsigned::Type Unsigned; - arg_.uint_value = static_cast(static_cast(value)); - } - } else { - if (is_signed) { - arg_.type = Arg::LONG_LONG; - // glibc's printf doesn't sign extend arguments of smaller types: - // 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(value); - } else { - arg_.type = Arg::ULONG_LONG; - arg_.ulong_long_value = - static_cast::Type>(value); - } - } - } + using internal::Arg; + typedef typename internal::Conditional::value, + U, T>::type TargetType; + if (sizeof(TargetType) <= sizeof(int)) { + // Extra casts are used to silence warnings. + if (is_signed) { + arg_.type = Arg::INT; + arg_.int_value = static_cast( + static_cast(value)); + } else { + arg_.type = Arg::UINT; + typedef typename internal::MakeUnsigned< + TargetType>::Type Unsigned; + arg_.uint_value = static_cast( + static_cast(value)); + } + } else { + if (is_signed) { + arg_.type = Arg::LONG_LONG; + // glibc's printf doesn't sign extend arguments + // of smaller types: + // 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(value); + } else { + arg_.type = Arg::ULONG_LONG; + arg_.ulong_long_value = static_cast< + typename internal::MakeUnsigned::Type>( + value); + } + } + } }; // Converts an integer argument to char for printf. class CharConverter : public ArgVisitor { - private: - internal::Arg &arg_; + private: + internal::Arg &arg_; - FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); + FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); - public: - explicit CharConverter(internal::Arg &arg) : arg_(arg) {} + public: + explicit CharConverter(internal::Arg &arg) : arg_(arg) {} - template - void visit_any_int(T value) { - arg_.type = internal::Arg::CHAR; - arg_.int_value = static_cast(value); - } + template + void visit_any_int(T value) { + arg_.type = internal::Arg::CHAR; + arg_.int_value = static_cast(value); + } }; // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. class WidthHandler : public ArgVisitor { - private: - FormatSpec &spec_; + private: + FormatSpec &spec_; - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); + FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); - public: - explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} + public: + explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} - void report_unhandled_arg() { - FMT_THROW(FormatError("width is not integer")); - } + void report_unhandled_arg() { + FMT_THROW(FormatError("width is not integer")); + } - template - unsigned visit_any_int(T value) { - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType width = static_cast(value); - if (internal::is_negative(value)) { - spec_.align_ = ALIGN_LEFT; - width = 0 - width; - } - unsigned int_max = std::numeric_limits::max(); - if (width > int_max) - FMT_THROW(FormatError("number is too big")); - return static_cast(width); - } + template + unsigned visit_any_int(T value) { + typedef typename internal::IntTraits::MainType UnsignedType; + UnsignedType width = static_cast(value); + if (internal::is_negative(value)) { + spec_.align_ = ALIGN_LEFT; + width = 0 - width; + } + unsigned int_max = std::numeric_limits::max(); + if (width > int_max) + FMT_THROW(FormatError("number is too big")); + return static_cast(width); + } }; } // namespace internal @@ -217,315 +231,329 @@ class WidthHandler : public ArgVisitor { \endrst */ template -class BasicPrintfArgFormatter : - public internal::ArgFormatterBase { - private: - void write_null_pointer() { - this->spec().type_ = 0; - this->write("(nil)"); - } +class BasicPrintfArgFormatter + : public internal::ArgFormatterBase { + private: + void write_null_pointer() { + this->spec().type_ = 0; + this->write("(nil)"); + } - typedef internal::ArgFormatterBase Base; + typedef internal::ArgFormatterBase Base; - public: - /** - \rst - Constructs an argument formatter object. - *writer* is a reference to the output writer and *spec* contains format - specifier information for standard argument types. - \endrst - */ - BasicPrintfArgFormatter(BasicWriter &w, Spec &s) - : internal::ArgFormatterBase(w, s) {} + public: + /** + \rst + Constructs an argument formatter object. + *writer* is a reference to the output writer and *spec* contains + format + specifier information for standard argument types. + \endrst + */ + BasicPrintfArgFormatter(BasicWriter &w, Spec &s) + : internal::ArgFormatterBase(w, s) {} - /** Formats an argument of type ``bool``. */ - void visit_bool(bool value) { - Spec &fmt_spec = this->spec(); - if (fmt_spec.type_ != 's') - return this->visit_any_int(value); - fmt_spec.type_ = 0; - this->write(value); - } + /** Formats an argument of type ``bool``. */ + void visit_bool(bool value) { + Spec &fmt_spec = this->spec(); + if (fmt_spec.type_ != 's') return this->visit_any_int(value); + fmt_spec.type_ = 0; + this->write(value); + } - /** Formats a character. */ - void visit_char(int value) { - const Spec &fmt_spec = this->spec(); - BasicWriter &w = this->writer(); - if (fmt_spec.type_ && fmt_spec.type_ != 'c') - w.write_int(value, fmt_spec); - typedef typename BasicWriter::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (fmt_spec.width_ > 1) { - Char fill = ' '; - out = w.grow_buffer(fmt_spec.width_); - if (fmt_spec.align_ != ALIGN_LEFT) { - std::fill_n(out, fmt_spec.width_ - 1, fill); - out += fmt_spec.width_ - 1; - } else { - std::fill_n(out + 1, fmt_spec.width_ - 1, fill); - } - } else { - out = w.grow_buffer(1); - } - *out = static_cast(value); - } + /** Formats a character. */ + void visit_char(int value) { + const Spec &fmt_spec = this->spec(); + BasicWriter &w = this->writer(); + if (fmt_spec.type_ && fmt_spec.type_ != 'c') + w.write_int(value, fmt_spec); + typedef typename BasicWriter::CharPtr CharPtr; + CharPtr out = CharPtr(); + if (fmt_spec.width_ > 1) { + Char fill = ' '; + out = w.grow_buffer(fmt_spec.width_); + if (fmt_spec.align_ != ALIGN_LEFT) { + std::fill_n(out, fmt_spec.width_ - 1, fill); + out += fmt_spec.width_ - 1; + } else { + std::fill_n(out + 1, fmt_spec.width_ - 1, fill); + } + } else { + out = w.grow_buffer(1); + } + *out = static_cast(value); + } - /** Formats a null-terminated C string. */ - void visit_cstring(const char *value) { - if (value) - Base::visit_cstring(value); - else if (this->spec().type_ == 'p') - write_null_pointer(); - else - this->write("(null)"); - } + /** Formats a null-terminated C string. */ + void visit_cstring(const char *value) { + if (value) + Base::visit_cstring(value); + else if (this->spec().type_ == 'p') + write_null_pointer(); + else + this->write("(null)"); + } - /** Formats a pointer. */ - void visit_pointer(const void *value) { - if (value) - return Base::visit_pointer(value); - this->spec().type_ = 0; - write_null_pointer(); - } + /** Formats a pointer. */ + void visit_pointer(const void *value) { + if (value) return Base::visit_pointer(value); + this->spec().type_ = 0; + write_null_pointer(); + } - /** Formats an argument of a custom (user-defined) type. */ - void visit_custom(internal::Arg::CustomValue c) { - BasicFormatter formatter(ArgList(), this->writer()); - const Char format_str[] = {'}', 0}; - const Char *format = format_str; - c.format(&formatter, c.value, &format); - } + /** Formats an argument of a custom (user-defined) type. */ + void visit_custom(internal::Arg::CustomValue c) { + BasicFormatter formatter(ArgList(), this->writer()); + const Char format_str[] = {'}', 0}; + const Char *format = format_str; + c.format(&formatter, c.value, &format); + } }; /** The default printf argument formatter. */ template -class PrintfArgFormatter : - public BasicPrintfArgFormatter, Char, FormatSpec> { - public: - /** Constructs an argument formatter object. */ - PrintfArgFormatter(BasicWriter &w, FormatSpec &s) - : BasicPrintfArgFormatter, Char, FormatSpec>(w, s) {} +class PrintfArgFormatter + : public BasicPrintfArgFormatter, Char, + FormatSpec> { + public: + /** Constructs an argument formatter object. */ + PrintfArgFormatter(BasicWriter &w, FormatSpec &s) + : BasicPrintfArgFormatter, Char, + FormatSpec>(w, s) {} }; /** This template formats data and writes the output to a writer. */ template > class PrintfFormatter : private internal::FormatterBase { - private: - BasicWriter &writer_; + private: + BasicWriter &writer_; - void parse_flags(FormatSpec &spec, const Char *&s); + void parse_flags(FormatSpec &spec, const Char *&s); - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - internal::Arg get_arg( - const Char *s, - unsigned arg_index = (std::numeric_limits::max)()); + // Returns the argument with specified index or, if arg_index is equal + // to the maximum unsigned value, the next argument. + internal::Arg get_arg( + const Char *s, + unsigned arg_index = (std::numeric_limits::max)()); - // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, FormatSpec &spec); + // Parses argument index, flags and width and returns the argument + // index. + unsigned parse_header(const Char *&s, FormatSpec &spec); - public: - /** - \rst - Constructs a ``PrintfFormatter`` object. References to the arguments and - the writer are stored in the formatter object so make sure they have - appropriate lifetimes. - \endrst - */ - explicit PrintfFormatter(const ArgList &al, BasicWriter &w) - : FormatterBase(al), writer_(w) {} + public: + /** + \rst + Constructs a ``PrintfFormatter`` object. References to the arguments + and + the writer are stored in the formatter object so make sure they have + appropriate lifetimes. + \endrst + */ + explicit PrintfFormatter(const ArgList &al, BasicWriter &w) + : FormatterBase(al), writer_(w) {} - /** Formats stored arguments and writes the output to the writer. */ - void format(BasicCStringRef format_str); + /** Formats stored arguments and writes the output to the writer. */ + void format(BasicCStringRef format_str); }; template void PrintfFormatter::parse_flags(FormatSpec &spec, const Char *&s) { - for (;;) { - switch (*s++) { - case '-': - spec.align_ = ALIGN_LEFT; - break; - case '+': - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '0': - spec.fill_ = '0'; - break; - case ' ': - spec.flags_ |= SIGN_FLAG; - break; - case '#': - spec.flags_ |= HASH_FLAG; - break; - default: - --s; - return; - } - } + for (;;) { + switch (*s++) { + case '-': + spec.align_ = ALIGN_LEFT; + break; + case '+': + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '0': + spec.fill_ = '0'; + break; + case ' ': + spec.flags_ |= SIGN_FLAG; + break; + case '#': + spec.flags_ |= HASH_FLAG; + break; + default: + --s; + return; + } + } } template internal::Arg PrintfFormatter::get_arg(const Char *s, - unsigned arg_index) { - (void)s; - const char *error = FMT_NULL; - internal::Arg arg = arg_index == std::numeric_limits::max() ? - next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); - if (error) - FMT_THROW(FormatError(!*s ? "invalid format string" : error)); - return arg; + unsigned arg_index) { + (void)s; + const char *error = FMT_NULL; + internal::Arg arg = arg_index == std::numeric_limits::max() + ? next_arg(error) + : FormatterBase::get_arg(arg_index - 1, error); + if (error) + FMT_THROW(FormatError(!*s ? "invalid format string" : error)); + return arg; } template -unsigned PrintfFormatter::parse_header( - const Char *&s, FormatSpec &spec) { - unsigned arg_index = std::numeric_limits::max(); - Char c = *s; - if (c >= '0' && c <= '9') { - // Parse an argument index (if followed by '$') or a width possibly - // preceded with '0' flag(s). - unsigned value = internal::parse_nonnegative_int(s); - if (*s == '$') { // value is an argument index - ++s; - arg_index = value; - } else { - if (c == '0') - spec.fill_ = '0'; - if (value != 0) { - // Nonzero value means that we parsed width and don't need to - // parse it or flags again, so return now. - spec.width_ = value; - return arg_index; - } - } - } - parse_flags(spec, s); - // Parse width. - if (*s >= '0' && *s <= '9') { - spec.width_ = internal::parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); - } - return arg_index; +unsigned PrintfFormatter::parse_header(const Char *&s, + FormatSpec &spec) { + unsigned arg_index = std::numeric_limits::max(); + Char c = *s; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width + // possibly + // preceded with '0' flag(s). + unsigned value = internal::parse_nonnegative_int(s); + if (*s == '$') { // value is an argument index + ++s; + arg_index = value; + } else { + if (c == '0') spec.fill_ = '0'; + if (value != 0) { + // Nonzero value means that we parsed width and + // don't need to + // parse it or flags again, so return now. + spec.width_ = value; + return arg_index; + } + } + } + parse_flags(spec, s); + // Parse width. + if (*s >= '0' && *s <= '9') { + spec.width_ = internal::parse_nonnegative_int(s); + } else if (*s == '*') { + ++s; + spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); + } + return arg_index; } template void PrintfFormatter::format(BasicCStringRef format_str) { - const Char *start = format_str.c_str(); - const Char *s = start; - while (*s) { - Char c = *s++; - if (c != '%') continue; - if (*s == c) { - write(writer_, start, s); - start = ++s; - continue; - } - write(writer_, start, s - 1); + const Char *start = format_str.c_str(); + const Char *s = start; + while (*s) { + Char c = *s++; + if (c != '%') continue; + if (*s == c) { + write(writer_, start, s); + start = ++s; + continue; + } + write(writer_, start, s - 1); - FormatSpec spec; - spec.align_ = ALIGN_RIGHT; + FormatSpec spec; + spec.align_ = ALIGN_RIGHT; - // Parse argument index, flags and width. - unsigned arg_index = parse_header(s, spec); + // Parse argument index, flags and width. + unsigned arg_index = parse_header(s, spec); - // Parse precision. - if (*s == '.') { - ++s; - if ('0' <= *s && *s <= '9') { - spec.precision_ = static_cast(internal::parse_nonnegative_int(s)); - } else if (*s == '*') { - ++s; - spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); - } else { - spec.precision_ = 0; - } - } + // Parse precision. + if (*s == '.') { + ++s; + if ('0' <= *s && *s <= '9') { + spec.precision_ = static_cast( + internal::parse_nonnegative_int(s)); + } else if (*s == '*') { + ++s; + spec.precision_ = + internal::PrecisionHandler().visit( + get_arg(s)); + } else { + spec.precision_ = 0; + } + } - using internal::Arg; - Arg arg = get_arg(s, arg_index); - if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) - spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); - if (spec.fill_ == '0') { - if (arg.type <= Arg::LAST_NUMERIC_TYPE) - spec.align_ = ALIGN_NUMERIC; - else - spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. - } + using internal::Arg; + Arg arg = get_arg(s, arg_index); + if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) + spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); + if (spec.fill_ == '0') { + if (arg.type <= Arg::LAST_NUMERIC_TYPE) + spec.align_ = ALIGN_NUMERIC; + else + spec.fill_ = ' '; // Ignore '0' flag for + // non-numeric types. + } - // Parse length and convert the argument to the required type. - using internal::ArgConverter; - switch (*s++) { - case 'h': - if (*s == 'h') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'l': - if (*s == 'l') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'j': - ArgConverter(arg, *s).visit(arg); - break; - case 'z': - ArgConverter(arg, *s).visit(arg); - break; - case 't': - ArgConverter(arg, *s).visit(arg); - break; - case 'L': - // printf produces garbage when 'L' is omitted for long double, no - // need to do the same. - break; - default: - --s; - ArgConverter(arg, *s).visit(arg); - } + // Parse length and convert the argument to the required type. + using internal::ArgConverter; + switch (*s++) { + case 'h': + if (*s == 'h') + ArgConverter(arg, *++s) + .visit(arg); + else + ArgConverter(arg, *s).visit(arg); + break; + case 'l': + if (*s == 'l') + ArgConverter(arg, *++s) + .visit(arg); + else + ArgConverter(arg, *s).visit(arg); + break; + case 'j': + ArgConverter(arg, *s).visit(arg); + break; + case 'z': + ArgConverter(arg, *s).visit(arg); + break; + case 't': + ArgConverter(arg, *s).visit( + arg); + break; + case 'L': + // printf produces garbage when 'L' is omitted + // for long double, no + // need to do the same. + break; + default: + --s; + ArgConverter(arg, *s).visit(arg); + } - // Parse type. - if (!*s) - FMT_THROW(FormatError("invalid format string")); - spec.type_ = static_cast(*s++); + // Parse type. + if (!*s) FMT_THROW(FormatError("invalid format string")); + spec.type_ = static_cast(*s++); - if (spec.type_ == 's') { - // set the format type to the default if 's' is specified - spec.type_ = internal::DefaultType().visit(arg); - } + if (spec.type_ == 's') { + // set the format type to the default if 's' is + // specified + spec.type_ = internal::DefaultType().visit(arg); + } - if (arg.type <= Arg::LAST_INTEGER_TYPE) { - // Normalize type. - switch (spec.type_) { - case 'i': case 'u': - spec.type_ = 'd'; - break; - case 'c': - // TODO: handle wchar_t - internal::CharConverter(arg).visit(arg); - break; - } - } + if (arg.type <= Arg::LAST_INTEGER_TYPE) { + // Normalize type. + switch (spec.type_) { + case 'i': + case 'u': + spec.type_ = 'd'; + break; + case 'c': + // TODO: handle wchar_t + internal::CharConverter(arg).visit(arg); + break; + } + } - start = s; + start = s; - // Format argument. - AF(writer_, spec).visit(arg); - } - write(writer_, start, s); + // Format argument. + AF(writer_, spec).visit(arg); + } + write(writer_, start, s); } inline void printf(Writer &w, CStringRef format, ArgList args) { - PrintfFormatter(args, w).format(format); + PrintfFormatter(args, w).format(format); } FMT_VARIADIC(void, printf, Writer &, CStringRef) inline void printf(WWriter &w, WCStringRef format, ArgList args) { - PrintfFormatter(args, w).format(format); + PrintfFormatter(args, w).format(format); } FMT_VARIADIC(void, printf, WWriter &, WCStringRef) @@ -539,16 +567,16 @@ FMT_VARIADIC(void, printf, WWriter &, WCStringRef) \endrst */ inline std::string sprintf(CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); + MemoryWriter w; + printf(w, format, args); + return w.str(); } FMT_VARIADIC(std::string, sprintf, CStringRef) inline std::wstring sprintf(WCStringRef format, ArgList args) { - WMemoryWriter w; - printf(w, format, args); - return w.str(); + WMemoryWriter w; + printf(w, format, args); + return w.str(); } FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) @@ -574,7 +602,7 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) \endrst */ inline int printf(CStringRef format, ArgList args) { - return fprintf(stdout, format, args); + return fprintf(stdout, format, args); } FMT_VARIADIC(int, printf, CStringRef) @@ -588,16 +616,18 @@ FMT_VARIADIC(int, printf, CStringRef) \endrst */ inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) { - MemoryWriter w; - printf(w, format_str, args); - internal::write(os, w); - return static_cast(w.size()); + std::mutex mtx; + std::unique_lock lck(mtx); + MemoryWriter w; + printf(w, format_str, args); + internal::write(os, w); + return static_cast(w.size()); } FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) } // namespace fmt #ifdef FMT_HEADER_ONLY -# include "printf.cc" +#include "printf.cc" #endif #endif // FMT_PRINTF_H_