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<<.
This commit is contained in:
effzeh 2017-05-06 13:43:07 +02:00
parent 5d9a88f83a
commit 7458bb7fe0
2 changed files with 259 additions and 294 deletions

View File

@ -1155,6 +1155,9 @@ struct NamedArgWithType;
template <typename T = void>
struct Null {};
template <typename T = void>
struct Incomplete; // never defined.
// A helper class template to enable or disable overloads taking wide
// characters and strings in MakeValue.
template <typename T, typename Char>
@ -2590,10 +2593,6 @@ class BasicWriter : public BasicWriterBase {
*/
virtual ~BasicWriter() {}
void clear() FMT_NOEXCEPT { buffer_.clear(); }
Buffer<Char> &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 <typename Float> // XXX: FloatFormatSpec?
template <typename Float>
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<wchar_t, Char>::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<Char>
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<WStringRef, Char>::Unsupported) {
internal::Incomplete<Char>
converting_wide_strings_to_narrow_strings_is_not_supported;
}
void append_str(const StrFormatSpec<char> &spec) {
const char *s = spec.str();
write_str(s, std::char_traits<char>::length(s), spec);
@ -2710,110 +2723,139 @@ class BasicWriter : public BasicWriterBase {
write_str(s, std::char_traits<wchar_t>::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<wchar_t, Char>::Unsupported);
void append_str(
typename internal::WCharHelper<WStringRef, Char>::Unsupported);
void append_str(
typename internal::WCharHelper<
const StrFormatSpec<wchar_t> &, Char>::Unsupported);
};
const StrFormatSpec<wchar_t> &, Char>::Unsupported) {
internal::Incomplete<Char>
converting_wide_strings_to_narrow_strings_is_not_supported;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &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 <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, signed char value) {
w.append_decimal(static_cast<int>(value));
return w;
}
BasicWriter &operator<<(signed char value) {
append_decimal(static_cast<int>(value));
return *this;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, short value) {
w.append_decimal(static_cast<int>(value));
return w;
}
BasicWriter &operator<<(short value) {
append_decimal(static_cast<int>(value));
return *this;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, int value) {
w.append_decimal(static_cast<int>(value));
return w;
}
BasicWriter &operator<<(int value) {
append_decimal(static_cast<int>(value));
return *this;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, long value) {
w.append_decimal(value);
return w;
}
BasicWriter &operator<<(long value) {
append_decimal(value);
return *this;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &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<int>(value));
return *this;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, unsigned char value) {
w.append_decimal(static_cast<int>(value));
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, unsigned short value) {
w.append_decimal(static_cast<int>(value));
return w;
}
#else // !( USHRT_MAX <= INT_MAX ) ---->
template <typename Char>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, unsigned char value) {
w.append_decimal(static_cast<unsigned int>(value));
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, unsigned short value) {
w.append_decimal(static_cast<unsigned int>(value));
return w;
}
BasicWriter &operator<<(unsigned short value) {
append_decimal(static_cast<int>(value));
return *this;
}
#else
BasicWriter &operator<<(unsigned char value) {
append_decimal(static_cast<unsigned int>(value));
return *this;
}
BasicWriter &operator<<(unsigned short value) {
append_decimal(static_cast<unsigned int>(value));
return *this;
}
#endif
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, unsigned int value) {
w.append_decimal(value);
return w;
}
BasicWriter &operator<<(unsigned int value) {
append_decimal(value);
return *this;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, unsigned long value) {
w.append_decimal(value);
return w;
}
BasicWriter &operator<<(unsigned long value) {
append_decimal(value);
return *this;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &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<double>(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<Char> &buffer() FMT_NOEXCEPT { return buffer_; }
};
template <typename Char, typename Int, typename Spec, typename FillChar>
inline BasicWriter<Char> &operator<<(
@ -2822,76 +2864,6 @@ inline BasicWriter<Char> &operator<<(
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, float value) {
w.append_double(static_cast<double>(value));
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, double value) {
w.append_double(value);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, long double value) {
w.append_double(value);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, char ch) {
w.append_char(ch);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, wchar_t ch) {
w.append_char(ch);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, const char *value) {
w.append_str(fmt::StringRef(value));
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, const wchar_t *value) {
w.append_str(fmt::WStringRef(value));
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, char *value) {
w.append_str(fmt::StringRef(value));
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, wchar_t *value) {
w.append_str(fmt::WStringRef(value));
return w;
}
template <typename Char, typename Elem>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, fmt::BasicStringRef<Elem> s) {
w.append_str(s);
return w;
}
template <typename Char, typename Elem, typename Alloc>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w,
const std::basic_string<Elem, std::char_traits<Elem>, Alloc> &value) {
w.append_str(fmt::BasicStringRef<Elem>(value));
return w;
}
template <typename Char, typename Elem>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, const StrFormatSpec<Elem> &value) {
@ -2899,16 +2871,17 @@ inline BasicWriter<Char> &operator<<(
return w;
}
template <typename Char>
template <typename Char, typename Elem>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, const void *pointer) {
w.append_pointer(pointer);
BasicWriter<Char> &w, const fmt::BasicStringRef<Elem> &s) {
w.append_str(s);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, void *pointer) {
w.append_pointer(pointer);
template <typename Char, typename Elem, typename Traits, typename Alloc>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, const std::basic_string<Elem, Traits, Alloc> &value) {
w.append_str(fmt::BasicStringRef<Elem>(value));
return w;
}
@ -2923,8 +2896,7 @@ template <
typename = typename std::enable_if<
!std::is_lvalue_reference<WriterT>::value
&& std::is_base_of<BasicWriterBase, WriterT>::value
>::type,
typename = decltype(std::declval<WriterT &>() << std::declval<const T&>())
>::type
>
inline WriterT &&operator<<(WriterT &&w, const T &value) {
w << value;

View File

@ -119,13 +119,8 @@ void std_format(long double value, std::wstring &result) {
// as writing it to std::basic_ostringstream<Char>.
template <typename Char, typename T>
::testing::AssertionResult check_write(const T &value, const char *type) {
#if FMT_USE_OSTREAM_RVALUE
std::basic_string<Char> actual =
(fmt::BasicMemoryWriter<Char>() << value).str();
#else
fmt::BasicMemoryWriter<Char> w;
std::basic_string<Char> actual = (w << value).str();
#endif
std::basic_string<Char> 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<short>(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<short>(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<short, fmt::TypeSpec<'x'> > (*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 <typename Char>
@ -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<int>(0)).str());
EXPECT_EQ("ncs", (MemoryWriter() << fmt::StrFormatSpec<char>(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<wchar_t>(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<int>(0)).str());
EXPECT_EQ(L"wcs", (WMemoryWriter() << fmt::StrFormatSpec<wchar_t>(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<char>(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);