From 7458bb7fe0f8a6db319432aec8866e510503a4a6 Mon Sep 17 00:00:00 2001 From: effzeh Date: Sat, 6 May 2017 13:43:07 +0200 Subject: [PATCH] Consistent behavior of operator<< The (templated) operator<< defined in ostream.h currently prevents efficient handling of some basic types in BasicWriter. E.g.: MemoryWriter w; w << std::string("hello"); calls this operator (if visible). This will unneccessarily construct a std::ostream object using a FormatBuf as its streambuf and insert the string into the std::ostream object. (The same is true for float and some other built-in types.) The write_str method in BasicWriter basically does the same using a cheap memcpy. Fix this performance problem by providing additional overloads of operator<<. --- fmt/format.h | 314 ++++++++++++++++++++------------------------ test/format-test.cc | 239 ++++++++++++++++----------------- 2 files changed, 259 insertions(+), 294 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 9803a27d..b0f77db1 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1155,6 +1155,9 @@ struct NamedArgWithType; template struct Null {}; +template +struct Incomplete; // never defined. + // A helper class template to enable or disable overloads taking wide // characters and strings in MakeValue. template @@ -2590,10 +2593,6 @@ class BasicWriter : public BasicWriterBase { */ virtual ~BasicWriter() {} - void clear() FMT_NOEXCEPT { buffer_.clear(); } - - Buffer &buffer() FMT_NOEXCEPT { return buffer_; } - /** Returns the total number of characters written. */ @@ -2666,7 +2665,7 @@ class BasicWriter : public BasicWriterBase { write_int(spec.value(), spec); } - template // XXX: FloatFormatSpec? + template void append_double(Float value) { write_double(value, FormatSpec()); } @@ -2689,6 +2688,14 @@ class BasicWriter : public BasicWriterBase { buffer_.push_back(ch); } + void append_char( + typename internal::WCharHelper::Unsupported) { + // Use an incomplete type to generate a compiler error if this function is + // ever used. static_assert(false) does not work here. + internal::Incomplete + converting_wide_strings_to_narrow_strings_is_not_supported; + } + void append_str(StringRef str) { buffer_.append(str.data(), str.data() + str.size()); } @@ -2698,6 +2705,12 @@ class BasicWriter : public BasicWriterBase { buffer_.append(str.data(), str.data() + str.size()); } + void append_str( + typename internal::WCharHelper::Unsupported) { + internal::Incomplete + converting_wide_strings_to_narrow_strings_is_not_supported; + } + void append_str(const StrFormatSpec &spec) { const char *s = spec.str(); write_str(s, std::char_traits::length(s), spec); @@ -2710,110 +2723,139 @@ class BasicWriter : public BasicWriterBase { write_str(s, std::char_traits::length(s), spec); } - private: - // The following methods are private to disallow writing wide characters - // and strings to a char stream. If you want to print a wide string as a - // pointer as std::ostream does, cast it to const void*. - // Do not implement! - void append_char( - typename internal::WCharHelper::Unsupported); - void append_str( - typename internal::WCharHelper::Unsupported); void append_str( typename internal::WCharHelper< - const StrFormatSpec &, Char>::Unsupported); -}; + const StrFormatSpec &, Char>::Unsupported) { + internal::Incomplete + converting_wide_strings_to_narrow_strings_is_not_supported; + } -template -inline BasicWriter &operator<<(BasicWriter &w, bool value) { - // Note: - // Uses the same format as ArgFormatterBase. - w.append_str(value ? "true" : "false"); - return w; -} + BasicWriter &operator<<(bool value) { + append_str(value ? "true" : "false"); + return *this; + } -template -inline BasicWriter &operator<<(BasicWriter &w, signed char value) { - w.append_decimal(static_cast(value)); - return w; -} + BasicWriter &operator<<(signed char value) { + append_decimal(static_cast(value)); + return *this; + } -template -inline BasicWriter &operator<<(BasicWriter &w, short value) { - w.append_decimal(static_cast(value)); - return w; -} + BasicWriter &operator<<(short value) { + append_decimal(static_cast(value)); + return *this; + } -template -inline BasicWriter &operator<<(BasicWriter &w, int value) { - w.append_decimal(static_cast(value)); - return w; -} + BasicWriter &operator<<(int value) { + append_decimal(static_cast(value)); + return *this; + } -template -inline BasicWriter &operator<<(BasicWriter &w, long value) { - w.append_decimal(value); - return w; -} + BasicWriter &operator<<(long value) { + append_decimal(value); + return *this; + } -template -inline BasicWriter &operator<<(BasicWriter &w, LongLong value) { - w.append_decimal(value); - return w; -} + BasicWriter &operator<<(LongLong value) { + append_decimal(value); + return *this; + } #if USHRT_MAX <= INT_MAX + BasicWriter &operator<<(unsigned char value) { + append_decimal(static_cast(value)); + return *this; + } -template -inline BasicWriter &operator<<( - BasicWriter &w, unsigned char value) { - w.append_decimal(static_cast(value)); - return w; -} - -template -inline BasicWriter &operator<<( - BasicWriter &w, unsigned short value) { - w.append_decimal(static_cast(value)); - return w; -} - -#else // !( USHRT_MAX <= INT_MAX ) ----> - -template -inline BasicWriter &operator<<( - BasicWriter &w, unsigned char value) { - w.append_decimal(static_cast(value)); - return w; -} - -template -inline BasicWriter &operator<<( - BasicWriter &w, unsigned short value) { - w.append_decimal(static_cast(value)); - return w; -} + BasicWriter &operator<<(unsigned short value) { + append_decimal(static_cast(value)); + return *this; + } +#else + BasicWriter &operator<<(unsigned char value) { + append_decimal(static_cast(value)); + return *this; + } + BasicWriter &operator<<(unsigned short value) { + append_decimal(static_cast(value)); + return *this; + } #endif -template -inline BasicWriter &operator<<(BasicWriter &w, unsigned int value) { - w.append_decimal(value); - return w; -} + BasicWriter &operator<<(unsigned int value) { + append_decimal(value); + return *this; + } -template -inline BasicWriter &operator<<( - BasicWriter &w, unsigned long value) { - w.append_decimal(value); - return w; -} + BasicWriter &operator<<(unsigned long value) { + append_decimal(value); + return *this; + } -template -inline BasicWriter &operator<<(BasicWriter &w, ULongLong value) { - w.append_decimal(value); - return w; -} + BasicWriter &operator<<(ULongLong value) { + append_decimal(value); + return *this; + } + + BasicWriter &operator<<(float value) { + append_double(static_cast(value)); + return *this; + } + + BasicWriter &operator<<(double value) { + append_double(value); + return *this; + } + + BasicWriter &operator<<(long double value) { + append_double(value); + return *this; + } + + BasicWriter &operator<<(char ch) { + append_char(ch); + return *this; + } + + BasicWriter &operator<<(wchar_t ch) { + append_char(ch); + return *this; + } + + BasicWriter &operator<<(const char *value) { + append_str(fmt::StringRef(value)); + return *this; + } + + BasicWriter &operator<<(const wchar_t *value) { + append_str(fmt::WStringRef(value)); + return *this; + } + + BasicWriter &operator<<(char *value) { + append_str(fmt::StringRef(value)); + return *this; + } + + BasicWriter &operator<<(wchar_t *value) { + append_str(fmt::WStringRef(value)); + return *this; + } + + BasicWriter &operator<<(const void *pointer) { + append_pointer(pointer); + return *this; + } + + BasicWriter &operator<<(void *pointer) { + append_pointer(pointer); + return *this; + } + + void clear() FMT_NOEXCEPT { buffer_.clear(); } + + Buffer &buffer() FMT_NOEXCEPT { return buffer_; } +}; template inline BasicWriter &operator<<( @@ -2822,76 +2864,6 @@ inline BasicWriter &operator<<( return w; } -template -inline BasicWriter &operator<<(BasicWriter &w, float value) { - w.append_double(static_cast(value)); - return w; -} - -template -inline BasicWriter &operator<<(BasicWriter &w, double value) { - w.append_double(value); - return w; -} - -template -inline BasicWriter &operator<<(BasicWriter &w, long double value) { - w.append_double(value); - return w; -} - -template -inline BasicWriter &operator<<(BasicWriter &w, char ch) { - w.append_char(ch); - return w; -} - -template -inline BasicWriter &operator<<(BasicWriter &w, wchar_t ch) { - w.append_char(ch); - return w; -} - -template -inline BasicWriter &operator<<(BasicWriter &w, const char *value) { - w.append_str(fmt::StringRef(value)); - return w; -} - -template -inline BasicWriter &operator<<( - BasicWriter &w, const wchar_t *value) { - w.append_str(fmt::WStringRef(value)); - return w; -} - -template -inline BasicWriter &operator<<(BasicWriter &w, char *value) { - w.append_str(fmt::StringRef(value)); - return w; -} - -template -inline BasicWriter &operator<<(BasicWriter &w, wchar_t *value) { - w.append_str(fmt::WStringRef(value)); - return w; -} - -template -inline BasicWriter &operator<<( - BasicWriter &w, fmt::BasicStringRef s) { - w.append_str(s); - return w; -} - -template -inline BasicWriter &operator<<( - BasicWriter &w, - const std::basic_string, Alloc> &value) { - w.append_str(fmt::BasicStringRef(value)); - return w; -} - template inline BasicWriter &operator<<( BasicWriter &w, const StrFormatSpec &value) { @@ -2899,16 +2871,17 @@ inline BasicWriter &operator<<( return w; } -template +template inline BasicWriter &operator<<( - BasicWriter &w, const void *pointer) { - w.append_pointer(pointer); + BasicWriter &w, const fmt::BasicStringRef &s) { + w.append_str(s); return w; } -template -inline BasicWriter &operator<<(BasicWriter &w, void *pointer) { - w.append_pointer(pointer); +template +inline BasicWriter &operator<<( + BasicWriter &w, const std::basic_string &value) { + w.append_str(fmt::BasicStringRef(value)); return w; } @@ -2923,8 +2896,7 @@ template < typename = typename std::enable_if< !std::is_lvalue_reference::value && std::is_base_of::value - >::type, - typename = decltype(std::declval() << std::declval()) + >::type > inline WriterT &&operator<<(WriterT &&w, const T &value) { w << value; diff --git a/test/format-test.cc b/test/format-test.cc index 1c672c28..e1b22f92 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -119,13 +119,8 @@ void std_format(long double value, std::wstring &result) { // as writing it to std::basic_ostringstream. template ::testing::AssertionResult check_write(const T &value, const char *type) { -#if FMT_USE_OSTREAM_RVALUE std::basic_string actual = (fmt::BasicMemoryWriter() << value).str(); -#else - fmt::BasicMemoryWriter w; - std::basic_string actual = (w << value).str(); -#endif std::basic_string expected; std_format(value, expected); if (expected == actual) @@ -369,28 +364,25 @@ TEST(WriterTest, WriteWideString) { TEST(WriterTest, bin) { using fmt::bin; - MemoryWriter w; - w.clear(); EXPECT_EQ("1100101011111110", (w << bin(0xcafe)).str()); - w.clear(); EXPECT_EQ("1011101010111110", (w << bin(0xbabeu)).str()); - w.clear(); EXPECT_EQ("1101111010101101", (w << bin(0xdeadl)).str()); - w.clear(); EXPECT_EQ("1011111011101111", (w << bin(0xbeeful)).str()); - w.clear(); - EXPECT_EQ("11001010111111101011101010111110", (w << bin(0xcafebabell)).str()); - w.clear(); + EXPECT_EQ("1100101011111110", (MemoryWriter() << bin(0xcafe)).str()); + EXPECT_EQ("1011101010111110", (MemoryWriter() << bin(0xbabeu)).str()); + EXPECT_EQ("1101111010101101", (MemoryWriter() << bin(0xdeadl)).str()); + EXPECT_EQ("1011111011101111", (MemoryWriter() << bin(0xbeeful)).str()); + EXPECT_EQ("11001010111111101011101010111110", + (MemoryWriter() << bin(0xcafebabell)).str()); EXPECT_EQ("11011110101011011011111011101111", - (w << bin(0xdeadbeefull)).str()); + (MemoryWriter() << bin(0xdeadbeefull)).str()); } TEST(WriterTest, oct) { using fmt::oct; - MemoryWriter w; - w.clear(); EXPECT_EQ("12", (w << oct(static_cast(012))).str()); - w.clear(); EXPECT_EQ("12", (w << oct(012)).str()); - w.clear(); EXPECT_EQ("34", (w << oct(034u)).str()); - w.clear(); EXPECT_EQ("56", (w << oct(056l)).str()); - w.clear(); EXPECT_EQ("70", (w << oct(070ul)).str()); - w.clear(); EXPECT_EQ("1234", (w << oct(01234ll)).str()); - w.clear(); EXPECT_EQ("5670", (w << oct(05670ull)).str()); + EXPECT_EQ("12", (MemoryWriter() << oct(static_cast(012))).str()); + EXPECT_EQ("12", (MemoryWriter() << oct(012)).str()); + EXPECT_EQ("34", (MemoryWriter() << oct(034u)).str()); + EXPECT_EQ("56", (MemoryWriter() << oct(056l)).str()); + EXPECT_EQ("70", (MemoryWriter() << oct(070ul)).str()); + EXPECT_EQ("1234", (MemoryWriter() << oct(01234ll)).str()); + EXPECT_EQ("5670", (MemoryWriter() << oct(05670ull)).str()); } TEST(WriterTest, hex) { @@ -400,24 +392,22 @@ TEST(WriterTest, hex) { // This shouldn't compile: //fmt::IntFormatSpec > (*phex2)(short value) = hex; - MemoryWriter w; - w.clear(); EXPECT_EQ("cafe", (w << hex(0xcafe)).str()); - w.clear(); EXPECT_EQ("babe", (w << hex(0xbabeu)).str()); - w.clear(); EXPECT_EQ("dead", (w << hex(0xdeadl)).str()); - w.clear(); EXPECT_EQ("beef", (w << hex(0xbeeful)).str()); - w.clear(); EXPECT_EQ("cafebabe", (w << hex(0xcafebabell)).str()); - w.clear(); EXPECT_EQ("deadbeef", (w << hex(0xdeadbeefull)).str()); + EXPECT_EQ("cafe", (MemoryWriter() << hex(0xcafe)).str()); + EXPECT_EQ("babe", (MemoryWriter() << hex(0xbabeu)).str()); + EXPECT_EQ("dead", (MemoryWriter() << hex(0xdeadl)).str()); + EXPECT_EQ("beef", (MemoryWriter() << hex(0xbeeful)).str()); + EXPECT_EQ("cafebabe", (MemoryWriter() << hex(0xcafebabell)).str()); + EXPECT_EQ("deadbeef", (MemoryWriter() << hex(0xdeadbeefull)).str()); } TEST(WriterTest, hexu) { using fmt::hexu; - MemoryWriter w; - w.clear(); EXPECT_EQ("CAFE", (w << hexu(0xcafe)).str()); - w.clear(); EXPECT_EQ("BABE", (w << hexu(0xbabeu)).str()); - w.clear(); EXPECT_EQ("DEAD", (w << hexu(0xdeadl)).str()); - w.clear(); EXPECT_EQ("BEEF", (w << hexu(0xbeeful)).str()); - w.clear(); EXPECT_EQ("CAFEBABE", (w << hexu(0xcafebabell)).str()); - w.clear(); EXPECT_EQ("DEADBEEF", (w << hexu(0xdeadbeefull)).str()); + EXPECT_EQ("CAFE", (MemoryWriter() << hexu(0xcafe)).str()); + EXPECT_EQ("BABE", (MemoryWriter() << hexu(0xbabeu)).str()); + EXPECT_EQ("DEAD", (MemoryWriter() << hexu(0xdeadl)).str()); + EXPECT_EQ("BEEF", (MemoryWriter() << hexu(0xbeeful)).str()); + EXPECT_EQ("CAFEBABE", (MemoryWriter() << hexu(0xcafebabell)).str()); + EXPECT_EQ("DEADBEEF", (MemoryWriter() << hexu(0xdeadbeefull)).str()); } template @@ -442,22 +432,22 @@ public: ISO8601DateFormatter iso8601(const Date &d) { return ISO8601DateFormatter(d); } TEST(WriterTest, pad) { - MemoryWriter w; using fmt::hex; - w.clear(); EXPECT_EQ(" cafe", (w << pad(hex(0xcafe), 8)).str()); - w.clear(); EXPECT_EQ(" babe", (w << pad(hex(0xbabeu), 8)).str()); - w.clear(); EXPECT_EQ(" dead", (w << pad(hex(0xdeadl), 8)).str()); - w.clear(); EXPECT_EQ(" beef", (w << pad(hex(0xbeeful), 8)).str()); - w.clear(); EXPECT_EQ(" dead", (w << pad(hex(0xdeadll), 8)).str()); - w.clear(); EXPECT_EQ(" beef", (w << pad(hex(0xbeefull), 8)).str()); + EXPECT_EQ(" cafe", (MemoryWriter() << pad(hex(0xcafe), 8)).str()); + EXPECT_EQ(" babe", (MemoryWriter() << pad(hex(0xbabeu), 8)).str()); + EXPECT_EQ(" dead", (MemoryWriter() << pad(hex(0xdeadl), 8)).str()); + EXPECT_EQ(" beef", (MemoryWriter() << pad(hex(0xbeeful), 8)).str()); + EXPECT_EQ(" dead", (MemoryWriter() << pad(hex(0xdeadll), 8)).str()); + EXPECT_EQ(" beef", (MemoryWriter() << pad(hex(0xbeefull), 8)).str()); - w.clear(); EXPECT_EQ(" 11", (w << pad(11, 7)).str()); - w.clear(); EXPECT_EQ(" 22", (w << pad(22u, 7)).str()); - w.clear(); EXPECT_EQ(" 33", (w << pad(33l, 7)).str()); - w.clear(); EXPECT_EQ(" 44", (w << pad(44ul, 7)).str()); - w.clear(); EXPECT_EQ(" 33", (w << pad(33ll, 7)).str()); - w.clear(); EXPECT_EQ(" 44", (w << pad(44ull, 7)).str()); + EXPECT_EQ(" 11", (MemoryWriter() << pad(11, 7)).str()); + EXPECT_EQ(" 22", (MemoryWriter() << pad(22u, 7)).str()); + EXPECT_EQ(" 33", (MemoryWriter() << pad(33l, 7)).str()); + EXPECT_EQ(" 44", (MemoryWriter() << pad(44ul, 7)).str()); + EXPECT_EQ(" 33", (MemoryWriter() << pad(33ll, 7)).str()); + EXPECT_EQ(" 44", (MemoryWriter() << pad(44ull, 7)).str()); + MemoryWriter w; w.clear(); w << pad(42, 5, '0'); EXPECT_EQ("00042", w.str()); @@ -470,24 +460,21 @@ TEST(WriterTest, pad) { } TEST(WriterTest, PadString) { - MemoryWriter w; - w.clear(); EXPECT_EQ("test ", (w << pad("test", 8)).str()); - w.clear(); EXPECT_EQ("test******", (w << pad("test", 10, '*')).str()); + EXPECT_EQ("test ", (MemoryWriter() << pad("test", 8)).str()); + EXPECT_EQ("test******", (MemoryWriter() << pad("test", 10, '*')).str()); } TEST(WriterTest, PadWString) { - WMemoryWriter w; - w.clear(); EXPECT_EQ(L"test ", (w << pad(L"test", 8)).str()); - w.clear(); EXPECT_EQ(L"test******", (w << pad(L"test", 10, '*')).str()); - w.clear(); EXPECT_EQ(L"test******", (w << pad(L"test", 10, L'*')).str()); + EXPECT_EQ(L"test ", (WMemoryWriter() << pad(L"test", 8)).str()); + EXPECT_EQ(L"test******", (WMemoryWriter() << pad(L"test", 10, '*')).str()); + EXPECT_EQ(L"test******", (WMemoryWriter() << pad(L"test", 10, L'*')).str()); } TEST(WriterTest, NoConflictWithIOManip) { using namespace std; using namespace fmt; - MemoryWriter w; - w.clear(); EXPECT_EQ("cafe", (w << hex(0xcafe)).str()); - w.clear(); EXPECT_EQ("12", (w << oct(012)).str()); + EXPECT_EQ("cafe", (MemoryWriter() << hex(0xcafe)).str()); + EXPECT_EQ("12", (MemoryWriter() << oct(012)).str()); } TEST(WriterTest, Format) { @@ -505,85 +492,94 @@ TEST(WriterTest, Format) { } TEST(WriterTest, WWriter) { - WMemoryWriter w; - EXPECT_EQ(L"cafe", (w << fmt::hex(0xcafe)).str()); + EXPECT_EQ(L"cafe", (fmt::WMemoryWriter() << fmt::hex(0xcafe)).str()); } TEST(WriterTest, Stream) { - MemoryWriter w; - const char *ncs = "ncs"; - w.clear(); EXPECT_EQ("true", (w << true).str()); - w.clear(); EXPECT_EQ("false", (w << false).str()); - w.clear(); EXPECT_EQ("0", (w << (signed char)0).str()); - w.clear(); EXPECT_EQ("0", (w << (signed short)0).str()); - w.clear(); EXPECT_EQ("0", (w << (signed int)0).str()); - w.clear(); EXPECT_EQ("0", (w << (signed long)0).str()); - w.clear(); EXPECT_EQ("0", (w << (fmt::LongLong)0).str()); - w.clear(); EXPECT_EQ("0", (w << (unsigned char)0).str()); - w.clear(); EXPECT_EQ("0", (w << (unsigned short)0).str()); - w.clear(); EXPECT_EQ("0", (w << (unsigned int)0).str()); - w.clear(); EXPECT_EQ("0", (w << (unsigned long)0).str()); - w.clear(); EXPECT_EQ("0", (w << (fmt::ULongLong)0).str()); - w.clear(); EXPECT_EQ("0", (w << (float)0).str()); - w.clear(); EXPECT_EQ("0", (w << (double)0).str()); - w.clear(); EXPECT_EQ("0", (w << (long double)0).str()); - w.clear(); EXPECT_EQ("0x1234", (w << (const void *)0x1234).str()); - w.clear(); EXPECT_EQ("0x1234", (w << (void *)0x1234).str()); - w.clear(); EXPECT_EQ("x", (w << (char)'x').str()); - w.clear(); EXPECT_EQ("ncs", (w << (const char *)ncs).str()); - w.clear(); EXPECT_EQ("ncs", (w << (char *)ncs).str()); - w.clear(); EXPECT_EQ("ncs", (w << fmt::StringRef(ncs)).str()); - w.clear(); EXPECT_EQ("ncs", (w << std::string(ncs)).str()); + EXPECT_EQ("true", (MemoryWriter() << true).str()); + EXPECT_EQ("false", (MemoryWriter() << false).str()); + EXPECT_EQ("0", (MemoryWriter() << (signed char)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (signed short)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (signed int)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (signed long)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (fmt::LongLong)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (unsigned char)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (unsigned short)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (unsigned int)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (unsigned long)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (fmt::ULongLong)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (float)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (double)0).str()); + EXPECT_EQ("0", (MemoryWriter() << (long double)0).str()); + EXPECT_EQ("0x1234", (MemoryWriter() << (const void *)0x1234).str()); + EXPECT_EQ("0x1234", (MemoryWriter() << (void *)0x1234).str()); + EXPECT_EQ("x", (MemoryWriter() << (char)'x').str()); + EXPECT_EQ("ncs", (MemoryWriter() << (const char *)ncs).str()); + EXPECT_EQ("ncs", (MemoryWriter() << (char *)ncs).str()); + EXPECT_EQ("ncs", (MemoryWriter() << fmt::StringRef(ncs)).str()); + EXPECT_EQ("ncs", (MemoryWriter() << std::string(ncs)).str()); + EXPECT_EQ("0", (MemoryWriter() << fmt::IntFormatSpec(0)).str()); + EXPECT_EQ("ncs", (MemoryWriter() << fmt::StrFormatSpec(ncs, 3, ' ')).str()); // This should not compile: #if 0 const wchar_t *wcs = L"wcs"; + MemoryWriter w; + //w << (wchar_t)'x'; + //w << (const wchar_t *)wcs; + //w << (wchar_t *)wcs; + //w << fmt::WStringRef(wcs); + //w << std::wstring(wcs); + w << fmt::StrFormatSpec(wcs, 3, ' '); +#endif - // w << (wchar_t)'x'; - // w << (const wchar_t *)wcs; - // w << (wchar_t *)wcs; - // w << fmt::WStringRef(wcs); - // w << std::wstring(wcs); +#if FMT_USE_OSTREAM_RVALUE + EXPECT_EQ("i = 123", (MemoryWriter() << "i = " << 123).str()); #endif } TEST(WWriterTest, Stream) { - WMemoryWriter w; - const wchar_t *wcs = L"wcs"; - w.clear(); EXPECT_EQ(L"true", (w << true).str()); - w.clear(); EXPECT_EQ(L"false", (w << false).str()); - w.clear(); EXPECT_EQ(L"0", (w << (signed char)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (signed short)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (signed int)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (signed long)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (fmt::LongLong)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (unsigned char)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (unsigned short)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (unsigned int)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (unsigned long)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (fmt::ULongLong)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (float)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (double)0).str()); - w.clear(); EXPECT_EQ(L"0", (w << (long double)0).str()); - w.clear(); EXPECT_EQ(L"0x1234", (w << (const void*)0x1234).str()); - w.clear(); EXPECT_EQ(L"0x1234", (w << (void *)0x1234).str()); - w.clear(); EXPECT_EQ(L"x", (w << (wchar_t)'x').str()); - w.clear(); EXPECT_EQ(L"wcs", (w << (const wchar_t *)wcs).str()); - w.clear(); EXPECT_EQ(L"wcs", (w << (wchar_t *)wcs).str()); - w.clear(); EXPECT_EQ(L"wcs", (w << fmt::WStringRef(wcs)).str()); - w.clear(); EXPECT_EQ(L"wcs", (w << std::wstring(wcs)).str()); + EXPECT_EQ(L"true", (WMemoryWriter() << true).str()); + EXPECT_EQ(L"false", (WMemoryWriter() << false).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (signed char)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (signed short)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (signed int)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (signed long)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (fmt::LongLong)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (unsigned char)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (unsigned short)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (unsigned int)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (unsigned long)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (fmt::ULongLong)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (float)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (double)0).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << (long double)0).str()); + EXPECT_EQ(L"0x1234", (WMemoryWriter() << (const void*)0x1234).str()); + EXPECT_EQ(L"0x1234", (WMemoryWriter() << (void *)0x1234).str()); + EXPECT_EQ(L"x", (WMemoryWriter() << (wchar_t)'x').str()); + EXPECT_EQ(L"wcs", (WMemoryWriter() << (const wchar_t *)wcs).str()); + EXPECT_EQ(L"wcs", (WMemoryWriter() << (wchar_t *)wcs).str()); + EXPECT_EQ(L"wcs", (WMemoryWriter() << fmt::WStringRef(wcs)).str()); + EXPECT_EQ(L"wcs", (WMemoryWriter() << std::wstring(wcs)).str()); + EXPECT_EQ(L"0", (WMemoryWriter() << fmt::IntFormatSpec(0)).str()); + EXPECT_EQ(L"wcs", (WMemoryWriter() << fmt::StrFormatSpec(wcs, 3, ' ')).str()); const char *ncs = "ncs"; - w.clear(); EXPECT_EQ(L"x", (w << (char)'x').str()); - w.clear(); EXPECT_EQ(L"ncs", (w << (const char *)ncs).str()); - w.clear(); EXPECT_EQ(L"ncs", (w << (char *)ncs).str()); - w.clear(); EXPECT_EQ(L"ncs", (w << fmt::StringRef(ncs)).str()); - w.clear(); EXPECT_EQ(L"ncs", (w << std::string(ncs)).str()); + EXPECT_EQ(L"x", (WMemoryWriter() << (char)'x').str()); + EXPECT_EQ(L"ncs", (WMemoryWriter() << (const char *)ncs).str()); + EXPECT_EQ(L"ncs", (WMemoryWriter() << (char *)ncs).str()); + EXPECT_EQ(L"ncs", (WMemoryWriter() << fmt::StringRef(ncs)).str()); + EXPECT_EQ(L"ncs", (WMemoryWriter() << std::string(ncs)).str()); + EXPECT_EQ(L"ncs", (WMemoryWriter() << fmt::StrFormatSpec(ncs, 3, ' ')).str()); + +#if FMT_USE_OSTREAM_RVALUE + EXPECT_EQ(L"i = 123", (WMemoryWriter() << L"i = " << 123).str()); +#endif } TEST(ArrayWriterTest, Ctor) { @@ -1507,10 +1503,7 @@ TEST(FormatterTest, FormatStringFromSpeedTest) { TEST(FormatterTest, FormatExamples) { using fmt::hex; - { - MemoryWriter w; - EXPECT_EQ("0000cafe", (w << pad(hex(0xcafe), 8, '0')).str()); - } + EXPECT_EQ("0000cafe", (MemoryWriter() << pad(hex(0xcafe), 8, '0')).str()); std::string message = format("The answer is {}", 42); EXPECT_EQ("The answer is 42", message);