diff --git a/format-test.cc b/format-test.cc index 523f4227..32c00351 100644 --- a/format-test.cc +++ b/format-test.cc @@ -1227,7 +1227,7 @@ TEST(FormatterTest, FormatUsingIOStreams) { class Answer {}; template -void Format(BasicWriter &f, const fmt::FormatSpec &spec, Answer) { +void Format(BasicWriter &f, const fmt::FormatSpec &spec, Answer) { f.Write("42", spec); } diff --git a/format.cc b/format.cc index 5307b6c6..e2083ecf 100644 --- a/format.cc +++ b/format.cc @@ -170,7 +170,7 @@ void fmt::BasicWriter::FormatDecimal( template typename fmt::BasicWriter::CharPtr fmt::BasicWriter::PrepareFilledBuffer( - unsigned size, const AlignSpec &spec, char sign) { + unsigned size, const AlignSpec &spec, char sign) { unsigned width = spec.width(); if (width <= size) { CharPtr p = GrowBuffer(size); @@ -208,7 +208,7 @@ typename fmt::BasicWriter::CharPtr template template void fmt::BasicWriter::FormatDouble( - T value, const FormatSpec &spec, int precision) { + T value, const FormatSpec &spec, int precision) { // Check type. char type = spec.type(); bool upper = false; @@ -438,7 +438,7 @@ void fmt::BasicFormatter::DoFormat() { const Arg &arg = ParseArgIndex(s); - FormatSpec spec; + FormatSpec spec; int precision = -1; if (*s == ':') { ++s; @@ -666,10 +666,10 @@ void fmt::BasicFormatter::DoFormat() { // Explicit instantiations for char. template void fmt::BasicWriter::FormatDouble( - double value, const FormatSpec &spec, int precision); + double value, const FormatSpec &spec, int precision); template void fmt::BasicWriter::FormatDouble( - long double value, const FormatSpec &spec, int precision); + long double value, const FormatSpec &spec, int precision); template fmt::BasicWriter::CharPtr fmt::BasicWriter::FillPadding(CharPtr buffer, @@ -680,7 +680,7 @@ template void fmt::BasicWriter::FormatDecimal( template fmt::BasicWriter::CharPtr fmt::BasicWriter::PrepareFilledBuffer( - unsigned size, const AlignSpec &spec, char sign); + unsigned size, const AlignSpec &spec, char sign); template void fmt::BasicFormatter::ReportError( const char *s, StringRef message) const; @@ -698,10 +698,10 @@ template void fmt::BasicFormatter::DoFormat(); // Explicit instantiations for wchar_t. template void fmt::BasicWriter::FormatDouble( - double value, const FormatSpec &spec, int precision); + double value, const FormatSpec &spec, int precision); template void fmt::BasicWriter::FormatDouble( - long double value, const FormatSpec &spec, int precision); + long double value, const FormatSpec &spec, int precision); template fmt::BasicWriter::CharPtr fmt::BasicWriter::FillPadding(CharPtr buffer, @@ -712,7 +712,7 @@ template void fmt::BasicWriter::FormatDecimal( template fmt::BasicWriter::CharPtr fmt::BasicWriter::PrepareFilledBuffer( - unsigned size, const AlignSpec &spec, char sign); + unsigned size, const AlignSpec &spec, char sign); template void fmt::BasicFormatter::ReportError( const wchar_t *s, StringRef message) const; diff --git a/format.h b/format.h index 15f7b9f0..4e505089 100644 --- a/format.h +++ b/format.h @@ -175,11 +175,14 @@ template <> class CharTraits { private: // Conversion from wchar_t to char is not supported. + // TODO: rename to ConvertChar static char ConvertWChar(wchar_t); public: typedef const wchar_t *UnsupportedStrType; + static char ConvertWChar(char value) { return value; } + template static int FormatFloat(char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value); @@ -190,6 +193,7 @@ class CharTraits { public: typedef const char *UnsupportedStrType; + static wchar_t ConvertWChar(char value) { return value; } static wchar_t ConvertWChar(wchar_t value) { return value; } template @@ -353,7 +357,6 @@ struct WidthSpec { }; // An alignment specifier. -template struct AlignSpec : WidthSpec { Alignment align_; @@ -364,9 +367,9 @@ struct AlignSpec : WidthSpec { }; // An alignment and type specifier. -template -struct AlignTypeSpec : AlignSpec { - AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} +template +struct AlignTypeSpec : AlignSpec { + AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} bool sign_flag() const { return false; } bool plus_flag() const { return false; } @@ -376,13 +379,12 @@ struct AlignTypeSpec : AlignSpec { }; // A full format specifier. -template -struct FormatSpec : AlignSpec { +struct FormatSpec : AlignSpec { unsigned flags_; char type_; FormatSpec(unsigned width = 0, char type = 0, wchar_t fill = ' ') - : AlignSpec(width, fill), flags_(0), type_(type) {} + : AlignSpec(width, fill), flags_(0), type_(type) {} bool sign_flag() const { return (flags_ & SIGN_FLAG) != 0; } bool plus_flag() const { return (flags_ & PLUS_FLAG) != 0; } @@ -392,8 +394,7 @@ struct FormatSpec : AlignSpec { }; // An integer format specifier. -// TODO: additional argument typename Char = char -template +template , typename Char = char> class IntFormatSpec : public SpecT { private: T value_; @@ -407,13 +408,13 @@ class IntFormatSpec : public SpecT { // A string format specifier. template -class StrFormatSpec : public AlignSpec { +class StrFormatSpec : public AlignSpec { private: const T *str_; public: StrFormatSpec(const T *str, unsigned width, wchar_t fill) - : AlignSpec(width, fill), str_(str) {} + : AlignSpec(width, fill), str_(str) {} const T *str() const { return str_; } }; @@ -453,8 +454,8 @@ IntFormatSpec > hexu(int value); \endrst */ -template -IntFormatSpec > pad( +template +IntFormatSpec, Char> pad( int value, unsigned width, Char fill = ' '); #define DEFINE_INT_FORMATTERS(TYPE) \ @@ -475,35 +476,35 @@ inline IntFormatSpec > hexu(TYPE value) { \ } \ \ template \ -inline IntFormatSpec > pad( \ +inline IntFormatSpec > pad( \ IntFormatSpec > f, unsigned width) { \ - return IntFormatSpec >( \ - f.value(), AlignTypeSpec(width, ' ')); \ + return IntFormatSpec >( \ + f.value(), AlignTypeSpec(width, ' ')); \ } \ \ /* For compatibility with older compilers we provide two overloads for pad, */ \ /* one that takes a fill character and one that doesn't. In the future this */ \ -/* can be replaced with one overload and making the template argument Char */ \ +/* can be replaced with one overload making the template argument Char */ \ /* default to char (C++11). */ \ template \ -inline IntFormatSpec > pad( \ - IntFormatSpec > f, \ +inline IntFormatSpec, Char> pad( \ + IntFormatSpec, Char> f, \ unsigned width, Char fill) { \ - return IntFormatSpec >( \ - f.value(), AlignTypeSpec(width, fill)); \ + return IntFormatSpec, Char>( \ + f.value(), AlignTypeSpec(width, fill)); \ } \ \ -inline IntFormatSpec > pad( \ +inline IntFormatSpec > pad( \ TYPE value, unsigned width) { \ - return IntFormatSpec >( \ - value, AlignTypeSpec(width, ' ')); \ + return IntFormatSpec >( \ + value, AlignTypeSpec<0>(width, ' ')); \ } \ \ template \ -inline IntFormatSpec > pad( \ +inline IntFormatSpec, Char> pad( \ TYPE value, unsigned width, Char fill) { \ - return IntFormatSpec >( \ - value, AlignTypeSpec(width, fill)); \ + return IntFormatSpec, Char>( \ + value, AlignTypeSpec<0>(width, fill)); \ } DEFINE_INT_FORMATTERS(int) @@ -608,17 +609,20 @@ class BasicWriter { return p + size - 1; } - CharPtr PrepareFilledBuffer( - unsigned size, const AlignSpec &spec, char sign); + CharPtr PrepareFilledBuffer(unsigned size, const AlignSpec &spec, char sign); + + // Formats an integer. + template + void FormatInt(T value, const Spec &spec); // Formats a floating-point number (double or long double). template - void FormatDouble(T value, const FormatSpec &spec, int precision); + void FormatDouble(T value, const FormatSpec &spec, int precision); // Formats a string. template CharPtr FormatString( - const StringChar *s, std::size_t size, const AlignSpec &spec); + const StringChar *s, std::size_t size, const AlignSpec &spec); // This method is private to disallow writing a wide string to a // char stream and vice versa. If you want to print a wide string @@ -683,33 +687,30 @@ class BasicWriter { BasicFormatter Format(StringRef format); BasicWriter &operator<<(int value) { - return *this << IntFormatSpec >(value, TypeSpec<0>()); + return *this << IntFormatSpec(value); } BasicWriter &operator<<(unsigned value) { - return *this << IntFormatSpec >(value, TypeSpec<0>()); + return *this << IntFormatSpec(value); } BasicWriter &operator<<(long value) { - return *this << IntFormatSpec >(value, TypeSpec<0>()); + return *this << IntFormatSpec(value); } BasicWriter &operator<<(unsigned long value) { - return *this - << IntFormatSpec >(value, TypeSpec<0>()); + return *this << IntFormatSpec(value); } BasicWriter &operator<<(long long value) { - return *this - << IntFormatSpec >(value, TypeSpec<0>()); + return *this << IntFormatSpec(value); } /** Formats *value* and writes it to the stream. */ BasicWriter &operator<<(unsigned long long value) { - return *this << - IntFormatSpec >(value, TypeSpec<0>()); + return *this << IntFormatSpec(value); } BasicWriter &operator<<(double value) { - FormatDouble(value, FormatSpec(), -1); + FormatDouble(value, FormatSpec(), -1); return *this; } @@ -718,7 +719,7 @@ class BasicWriter { (``'g'``) and writes it to the stream. */ BasicWriter &operator<<(long double value) { - FormatDouble(value, FormatSpec(), -1); + FormatDouble(value, FormatSpec(), -1); return *this; } @@ -745,8 +746,12 @@ class BasicWriter { return *this; } - template - BasicWriter &operator<<(const IntFormatSpec &spec); + template + BasicWriter &operator<<(const IntFormatSpec &spec) { + internal::CharTraits::ConvertWChar(FillChar()); + FormatInt(spec.value(), spec); + return *this; + } template BasicWriter &operator<<(const StrFormatSpec &spec) { @@ -755,7 +760,7 @@ class BasicWriter { return *this; } - void Write(const std::basic_string &s, const FormatSpec &spec) { + void Write(const std::basic_string &s, const FormatSpec &spec) { FormatString(s.data(), s.size(), spec); } @@ -767,7 +772,7 @@ class BasicWriter { template template typename BasicWriter::CharPtr BasicWriter::FormatString( - const StringChar *s, std::size_t size, const AlignSpec &spec) { + const StringChar *s, std::size_t size, const AlignSpec &spec) { CharPtr out = CharPtr(); if (spec.width() > size) { out = GrowBuffer(spec.width()); @@ -789,9 +794,7 @@ typename BasicWriter::CharPtr BasicWriter::FormatString( template template -BasicWriter &BasicWriter::operator<<( - const IntFormatSpec &spec) { - T value = spec.value(); +void BasicWriter::FormatInt(T value, const Spec &spec) { unsigned size = 0; char sign = 0; typedef typename internal::IntTraits::UnsignedType UnsignedType; @@ -870,7 +873,6 @@ BasicWriter &BasicWriter::operator<<( internal::ReportUnknownType(spec.type(), "integer"); break; } - return *this; } template @@ -884,7 +886,7 @@ typedef BasicWriter WWriter; // The default formatting function. template -void Format(BasicWriter &w, const FormatSpec &spec, const T &value) { +void Format(BasicWriter &w, const FormatSpec &spec, const T &value) { std::basic_ostringstream os; os << value; w.Write(os.str(), spec); @@ -894,7 +896,7 @@ namespace internal { // Formats an argument of a custom type, such as a user-defined class. template void FormatCustomArg( - BasicWriter &w, const void *arg, const FormatSpec &spec) { + BasicWriter &w, const void *arg, const FormatSpec &spec) { Format(w, spec, *static_cast(arg)); } } @@ -921,7 +923,7 @@ class BasicFormatter { }; typedef void (*FormatFunc)( - BasicWriter &w, const void *arg, const FormatSpec &spec); + BasicWriter &w, const void *arg, const FormatSpec &spec); // A format argument. class Arg { @@ -1063,9 +1065,10 @@ class BasicFormatter { void DoFormat(); // Formats an integer. + // TODO: remove template - void FormatInt(T value, const FormatSpec &spec) { - *writer_ << IntFormatSpec >(value, spec); + void FormatInt(T value, const FormatSpec &spec) { + *writer_ << IntFormatSpec(value, spec); } struct Proxy {