diff --git a/format-test.cc b/format-test.cc index 32c00351..523f4227 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 25bb1925..5307b6c6 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); @@ -180,6 +180,7 @@ typename fmt::BasicWriter::CharPtr CharPtr p = GrowBuffer(width); CharPtr end = p + width; Alignment align = spec.align(); + // TODO: error if fill is not convertible to Char Char fill = static_cast(spec.fill()); if (align == ALIGN_LEFT) { *p = sign; @@ -207,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; @@ -437,7 +438,7 @@ void fmt::BasicFormatter::DoFormat() { const Arg &arg = ParseArgIndex(s); - FormatSpec spec; + FormatSpec spec; int precision = -1; if (*s == ':') { ++s; @@ -665,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, @@ -679,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; @@ -697,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, @@ -711,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 935434b3..15f7b9f0 100644 --- a/format.h +++ b/format.h @@ -353,6 +353,7 @@ struct WidthSpec { }; // An alignment specifier. +template struct AlignSpec : WidthSpec { Alignment align_; @@ -363,9 +364,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; } @@ -375,12 +376,13 @@ struct AlignTypeSpec : AlignSpec { }; // A full format specifier. -struct FormatSpec : AlignSpec { +template +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; } @@ -390,6 +392,7 @@ struct FormatSpec : AlignSpec { }; // An integer format specifier. +// TODO: additional argument typename Char = char template class IntFormatSpec : public SpecT { private: @@ -404,13 +407,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_; } }; @@ -450,9 +453,9 @@ IntFormatSpec > hexu(int value); \endrst */ -template -IntFormatSpec > pad( - int value, unsigned width, wchar_t fill = ' '); +template +IntFormatSpec > pad( + int value, unsigned width, Char fill = ' '); #define DEFINE_INT_FORMATTERS(TYPE) \ inline IntFormatSpec > bin(TYPE value) { \ @@ -472,17 +475,35 @@ inline IntFormatSpec > hexu(TYPE value) { \ } \ \ template \ -inline IntFormatSpec > pad( \ - IntFormatSpec > f, \ - unsigned width, wchar_t fill = ' ') { \ - return IntFormatSpec >( \ - f.value(), AlignTypeSpec(width, fill)); \ +inline IntFormatSpec > pad( \ + IntFormatSpec > f, unsigned width) { \ + return IntFormatSpec >( \ + f.value(), AlignTypeSpec(width, ' ')); \ } \ \ -inline IntFormatSpec > pad( \ - TYPE value, unsigned width, wchar_t fill = ' ') { \ - return IntFormatSpec >( \ - value, AlignTypeSpec<0>(width, fill)); \ +/* 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 */ \ +/* default to char (C++11). */ \ +template \ +inline IntFormatSpec > pad( \ + IntFormatSpec > f, \ + unsigned width, Char fill) { \ + return IntFormatSpec >( \ + f.value(), AlignTypeSpec(width, fill)); \ +} \ + \ +inline IntFormatSpec > pad( \ + TYPE value, unsigned width) { \ + return IntFormatSpec >( \ + value, AlignTypeSpec(width, ' ')); \ +} \ + \ +template \ +inline IntFormatSpec > pad( \ + TYPE value, unsigned width, Char fill) { \ + return IntFormatSpec >( \ + value, AlignTypeSpec(width, fill)); \ } DEFINE_INT_FORMATTERS(int) @@ -587,16 +608,17 @@ 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 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 @@ -687,7 +709,7 @@ class BasicWriter { } BasicWriter &operator<<(double value) { - FormatDouble(value, FormatSpec(), -1); + FormatDouble(value, FormatSpec(), -1); return *this; } @@ -696,7 +718,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; } @@ -733,7 +755,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); } @@ -745,7 +767,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()); @@ -862,7 +884,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); @@ -872,7 +894,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)); } } @@ -899,7 +921,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 { @@ -1042,8 +1064,8 @@ class BasicFormatter { // Formats an integer. 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 {