diff --git a/format.cc b/format.cc index 2971be5d..8466358c 100644 --- a/format.cc +++ b/format.cc @@ -396,13 +396,14 @@ inline const typename fmt::BasicFormatter::Arg template void fmt::BasicFormatter::CheckSign(const Char *&s, const Arg &arg) { + char sign = static_cast(*s); if (arg.type > LAST_NUMERIC_TYPE) { ReportError(s, - Format("format specifier '{0}' requires numeric argument") << *s); + Format("format specifier '{}' requires numeric argument") << sign); } if (arg.type == UINT || arg.type == ULONG || arg.type == ULONG_LONG) { ReportError(s, - Format("format specifier '{0}' requires signed argument") << *s); + Format("format specifier '{}' requires signed argument") << sign); } ++s; } @@ -521,7 +522,7 @@ void fmt::BasicFormatter::DoFormat() { ++s; ++num_open_braces_; const Arg &precision_arg = ParseArgIndex(s); - unsigned long long value = 0; + ULongLong value = 0; switch (precision_arg.type) { case INT: if (precision_arg.int_value < 0) diff --git a/format.h b/format.h index 4fec8eb4..786049f4 100644 --- a/format.h +++ b/format.h @@ -42,21 +42,34 @@ #include #include +#ifdef __GNUC__ +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#endif + // Compatibility with compilers other than clang. #ifndef __has_feature # define __has_feature(x) 0 #endif +#ifndef FMT_USE_INITIALIZER_LIST +# define FMT_USE_INITIALIZER_LIST \ + (__has_feature(cxx_generalized_initializers) || \ + (FMT_GCC_VERSION >= 404 && __cplusplus >= 201103) || _MSC_VER >= 1700) +#endif + +#if FMT_USE_INITIALIZER_LIST +# include +#endif + // Define FMT_USE_NOEXCEPT to make format use noexcept (C++11 feature). -#if FMT_USE_NOEXCEPT || \ - (defined(__has_feature) && __has_feature(cxx_noexcept)) || \ - (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) +#if FMT_USE_NOEXCEPT || __has_feature(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && __cplusplus >= 201103) # define FMT_NOEXCEPT(expr) noexcept(expr) #else # define FMT_NOEXCEPT(expr) #endif -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) +#if FMT_GCC_VERSION >= 406 # define FMT_GCC_DIAGNOSTIC # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wlong-long" @@ -156,11 +169,16 @@ void Array::append(const T *begin, const T *end) { } template -struct CharTraits; +class CharTraits; template <> -struct CharTraits { - typedef wchar_t UnsupportedType; +class CharTraits { + private: + // Conversion from wchar_t to char is not supported. + static char ConvertWChar(wchar_t); + + public: + typedef const wchar_t *UnsupportedStrType; template static int FormatFloat(char *buffer, std::size_t size, @@ -168,8 +186,11 @@ struct CharTraits { }; template <> -struct CharTraits { - typedef char UnsupportedType; +class CharTraits { + public: + typedef const char *UnsupportedStrType; + + static wchar_t ConvertWChar(wchar_t value) { return value; } template static int FormatFloat(wchar_t *buffer, std::size_t size, @@ -565,7 +586,7 @@ class BasicWriter { // char stream and vice versa. If you want to print a wide string // as a pointer as std::ostream does, cast it to const void*. // Do not implement! - void operator<<(const typename internal::CharTraits::UnsupportedType *); + void operator<<(typename internal::CharTraits::UnsupportedStrType); public: /** @@ -861,12 +882,6 @@ class BasicFormatter { template Arg(T *value); - // This method is private to disallow formatting of wide characters. - // If you want to output a wide character cast it to integer type. - // Do not implement! - // TODO - //Arg(wchar_t value); - public: Type type; union { @@ -904,7 +919,10 @@ class BasicFormatter { Arg(double value) : type(DOUBLE), double_value(value), formatter(0) {} Arg(long double value) : type(LONG_DOUBLE), long_double_value(value), formatter(0) {} - Arg(Char value) : type(CHAR), int_value(value), formatter(0) {} + Arg(char value) : type(CHAR), int_value(value), formatter(0) {} + Arg(wchar_t value) + : type(CHAR), int_value(internal::CharTraits::ConvertWChar(value)), + formatter(0) {} Arg(const Char *value) : type(STRING), formatter(0) { string.value = value; @@ -973,10 +991,6 @@ class BasicFormatter { BasicFormatter(const BasicFormatter &); BasicFormatter& operator=(const BasicFormatter &); - void Add(const Arg &arg) { - args_.push_back(&arg); - } - void ReportError(const Char *s, StringRef message) const; unsigned ParseUInt(const Char *&s) const; @@ -1015,6 +1029,17 @@ class BasicFormatter { BasicFormatter(BasicWriter &w, const Char *format = 0) : writer_(&w), format_(format) {} +#if FMT_USE_INITIALIZER_LIST + // Constructs a formatter with formatting arguments. + BasicFormatter(BasicWriter &w, + const Char *format, std::initializer_list args) + : writer_(&w), format_(format) { + args_.reserve(args.size()); + for (const Arg &arg: args) + args_.push_back(&arg); + } +#endif + // Performs formatting if the format string is non-null. The format string // can be null if its ownership has been transferred to another formatter. ~BasicFormatter() { @@ -1028,7 +1053,7 @@ class BasicFormatter { // Feeds an argument to a formatter. BasicFormatter &operator<<(const Arg &arg) { arg.formatter = this; - Add(arg); + args_.push_back(&arg); return *this; } @@ -1117,7 +1142,8 @@ class NoAction { // Formats an error message and prints it to stdout. fmt::Formatter ReportError(const char *format) { - return Move(fmt::Formatter(format)); + fmt::Formatter f(format); + return f; } ReportError("File not found: {}") << path; @@ -1165,12 +1191,6 @@ class Formatter : private Action, public BasicFormatter { } }; -// Removes a const qualifier from a formatter object making it moveable. -template -Formatter &Move(const Formatter &f) { - return const_cast &>(f); -} - /** Fast integer formatter. */ @@ -1244,11 +1264,13 @@ class FormatInt { \endrst */ inline Formatter<> Format(StringRef format) { - return Move(Formatter<>(format)); + Formatter<> f(format); + return f; } inline Formatter Format(WStringRef format) { - return Move(Formatter(format)); + Formatter f(format); + return f; } /** A formatting action that writes formatted output to stdout. */ @@ -1264,7 +1286,8 @@ class Write { // Example: // Print("Elapsed time: {0:.2f} seconds") << 1.23; inline Formatter Print(StringRef format) { - return Move(Formatter(format)); + Formatter f(format); + return f; } }