diff --git a/format.h b/format.h index 31c52bde..b5af5135 100644 --- a/format.h +++ b/format.h @@ -130,6 +130,9 @@ typedef BasicWriter WWriter; struct FormatSpec; +template +void format(BasicWriter &w, const FormatSpec &spec, const T &value); + /** \rst A string reference. It can be constructed from a C string or @@ -359,7 +362,7 @@ template <> class CharTraits : public BasicCharTraits { private: // Conversion from wchar_t to char is not allowed. - static char ConvertChar(wchar_t); + static char convert(wchar_t); // Conversion from const wchar_t * to const char * is not allowed. static const wchar_t *check(const wchar_t *s); @@ -367,7 +370,7 @@ class CharTraits : public BasicCharTraits { public: typedef const wchar_t *UnsupportedStrType; - static char ConvertChar(char value) { return value; } + static char convert(char value) { return value; } static StringValue convert(StringValue) { StringValue s = {"", 0}; @@ -384,8 +387,8 @@ class CharTraits : public BasicCharTraits { public: typedef const char *UnsupportedStrType; - static wchar_t ConvertChar(char value) { return value; } - static wchar_t ConvertChar(wchar_t value) { return value; } + static wchar_t convert(char value) { return value; } + static wchar_t convert(wchar_t value) { return value; } static StringValue convert(StringValue s) { return s; } @@ -503,9 +506,6 @@ void FormatDecimal(Char *buffer, UInt value, unsigned num_digits) { buffer[0] = DIGITS[index]; } -template -void FormatCustomArg(void *writer, const void *arg, const FormatSpec &spec); - #ifdef _WIN32 // A converter from UTF-8 to UTF-16. // It is only provided for Windows since other systems use UTF-8. @@ -633,18 +633,26 @@ class MakeArg : public Arg { template MakeArg(T *value); - void SetString(StringRef str) { + void set_string(StringRef str) { type = STRING; string.value = str.c_str(); string.size = str.size(); } - void SetString(WStringRef str) { + void set_string(WStringRef str) { type = WSTRING; wstring.value = CharTraits::check(str.c_str()); wstring.size = str.size(); } + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg( + void *writer, const void *arg, const FormatSpec &spec) { + format(*static_cast*>(writer), + spec, *static_cast(arg)); + } + public: MakeArg() {} MakeArg(bool value) { type = INT; int_value = value; } @@ -682,18 +690,18 @@ public: MakeArg(char value) { type = CHAR; int_value = value; } MakeArg(wchar_t value) { type = CHAR; - int_value = internal::CharTraits::ConvertChar(value); + int_value = internal::CharTraits::convert(value); } - MakeArg(char *value) { SetString(value); } - MakeArg(const char *value) { SetString(value); } - MakeArg(const std::string &value) { SetString(value); } - MakeArg(StringRef value) { SetString(value); } + MakeArg(char *value) { set_string(value); } + MakeArg(const char *value) { set_string(value); } + MakeArg(const std::string &value) { set_string(value); } + MakeArg(StringRef value) { set_string(value); } - MakeArg(wchar_t *value) { SetString(value); } - MakeArg(const wchar_t *value) { SetString(value); } - MakeArg(const std::wstring &value) { SetString(value); } - MakeArg(WStringRef value) { SetString(value); } + MakeArg(wchar_t *value) { set_string(value); } + MakeArg(const wchar_t *value) { set_string(value); } + MakeArg(const std::wstring &value) { set_string(value); } + MakeArg(WStringRef value) { set_string(value); } MakeArg(void *value) { type = POINTER; pointer_value = value; } MakeArg(const void *value) { type = POINTER; pointer_value = value; } @@ -702,7 +710,7 @@ public: MakeArg(const T &value) { type = CUSTOM; custom.value = &value; - custom.format = &internal::FormatCustomArg; + custom.format = &format_custom_arg; } }; @@ -1364,7 +1372,7 @@ class BasicWriter { } BasicWriter &operator<<(wchar_t value) { - *GrowBuffer(1) = internal::CharTraits::ConvertChar(value); + *GrowBuffer(1) = internal::CharTraits::convert(value); return *this; } @@ -1380,7 +1388,7 @@ class BasicWriter { template BasicWriter &operator<<(const IntFormatSpec &spec) { - internal::CharTraits::ConvertChar(FillChar()); + internal::CharTraits::convert(FillChar()); FormatInt(spec.value(), spec); return *this; } @@ -1575,15 +1583,6 @@ void format(BasicWriter &w, const FormatSpec &spec, const T &value) { w.write_str(os.str(), spec); } -namespace internal { -// Formats an argument of a custom type, such as a user-defined class. -template -void FormatCustomArg(void *writer, const void *arg, const FormatSpec &spec) { - format(*static_cast*>(writer), - spec, *static_cast(arg)); -} -} - // Reports a system error without throwing an exception. // Can be used to report errors from destructors. void ReportSystemError(int error_code, StringRef message) FMT_NOEXCEPT(true); diff --git a/test/util-test.cc b/test/util-test.cc index 5168d7fe..39fac2a9 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -56,6 +56,9 @@ std::string GetSystemErrorMessage(int error_code) { return buffer; #endif } + +struct Test {}; +std::ostream &operator<<(std::ostream &os, Test) { return os << "test"; } } TEST(UtilTest, Increment) { @@ -173,7 +176,17 @@ TEST(UtilTest, MakeArg) { EXPECT_ARGW(WSTRING, std::wstring, wstring.value, WSTR); EXPECT_ARGW(WSTRING, fmt::WStringRef, wstring.value, WSTR); - // TODO: test that wide string is rejected by MakeArg + int n = 42; + EXPECT_ARG(POINTER, void*, pointer_value, &n); + EXPECT_ARG(POINTER, const void*, pointer_value, &n); + + ::Test t; + fmt::internal::Arg arg = fmt::internal::MakeArg(t); + EXPECT_EQ(fmt::internal::Arg::CUSTOM, arg.type); + arg.custom.value = &t; + fmt::Writer w; + arg.custom.format(&w, &t, fmt::FormatSpec()); + EXPECT_EQ("test", w.str()); } // Tests fmt::internal::CountDigits for integer type Int.