Consistent behavior of operator<< for known types

This commit is contained in:
effzeh 2017-04-11 20:25:02 +02:00
parent 73ca9948fe
commit 01c51ffb47
5 changed files with 461 additions and 164 deletions

View File

@ -368,7 +368,7 @@ FMT_FUNC void internal::format_windows_error(
if (result != 0) {
UTF16ToUTF8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
out << message << ": " << utf8_message;
out << message << ": " << StringRef(utf8_message);
return;
}
break;

View File

@ -155,6 +155,24 @@ typedef __int64 intmax_t;
# endif
#endif
#ifndef FMT_USE_OSTREAM_RVALUE
// If non-zero, enables operator<< for BasicWriter&&, such that things like
// std::string s = (MemoryWriter() << "i = " << i).str();
// are possible.
//
// (See: http://cplusplus.github.io/LWG/lwg-active.html#1203)
//
// XXX:
// I don't know if FMT_USE_RVALUE_REFERENCES is the correct way to enable
// this... It works for g++ 6.3 and VC15, though.
//
# if FMT_USE_RVALUE_REFERENCES
# define FMT_USE_OSTREAM_RVALUE 1
# else
# define FMT_USE_OSTREAM_RVALUE 0
# endif
#endif
// Check if exceptions are disabled.
#if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0
@ -2442,6 +2460,8 @@ class SystemError : public internal::RuntimeError {
FMT_API void format_system_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT;
class BasicWriterBase {};
/**
\rst
This template provides operations for formatting and writing data into
@ -2461,7 +2481,7 @@ FMT_API void format_system_error(fmt::Writer &out, int error_code,
\endrst
*/
template <typename Char>
class BasicWriter {
class BasicWriter : public BasicWriterBase {
private:
// Output buffer.
Buffer<Char> &buffer_;
@ -2541,14 +2561,6 @@ class BasicWriter {
void write_str(const internal::Arg::StringValue<StrChar> &str,
const Spec &spec);
// This 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 operator<<(typename internal::WCharHelper<wchar_t, Char>::Unsupported);
void operator<<(
typename internal::WCharHelper<const wchar_t *, Char>::Unsupported);
// Appends floating-point length specifier to the format string.
// The second argument is only used for overload resolution.
void append_float_length(Char *&format_ptr, long double) {
@ -2578,6 +2590,10 @@ class BasicWriter {
*/
virtual ~BasicWriter() {}
void clear() FMT_NOEXCEPT { buffer_.clear(); }
Buffer<Char> &buffer() FMT_NOEXCEPT { return buffer_; }
/**
Returns the total number of characters written.
*/
@ -2639,101 +2655,283 @@ class BasicWriter {
}
FMT_VARIADIC_VOID(write, BasicCStringRef<Char>)
BasicWriter &operator<<(int value) {
template <typename Int>
void append_decimal(Int value) {
write_decimal(value);
return *this;
}
BasicWriter &operator<<(unsigned value) {
return *this << IntFormatSpec<unsigned>(value);
}
BasicWriter &operator<<(long value) {
write_decimal(value);
return *this;
}
BasicWriter &operator<<(unsigned long value) {
return *this << IntFormatSpec<unsigned long>(value);
}
BasicWriter &operator<<(LongLong value) {
write_decimal(value);
return *this;
}
/**
\rst
Formats *value* and writes it to the stream.
\endrst
*/
BasicWriter &operator<<(ULongLong value) {
return *this << IntFormatSpec<ULongLong>(value);
}
BasicWriter &operator<<(double value) {
write_double(value, FormatSpec());
return *this;
}
/**
\rst
Formats *value* using the general format for floating-point numbers
(``'g'``) and writes it to the stream.
\endrst
*/
BasicWriter &operator<<(long double value) {
write_double(value, FormatSpec());
return *this;
}
/**
Writes a character to the stream.
*/
BasicWriter &operator<<(char value) {
buffer_.push_back(value);
return *this;
}
BasicWriter &operator<<(
typename internal::WCharHelper<wchar_t, Char>::Supported value) {
buffer_.push_back(value);
return *this;
}
/**
\rst
Writes *value* to the stream.
\endrst
*/
BasicWriter &operator<<(fmt::BasicStringRef<Char> value) {
const Char *str = value.data();
buffer_.append(str, str + value.size());
return *this;
}
BasicWriter &operator<<(
typename internal::WCharHelper<StringRef, Char>::Supported value) {
const char *str = value.data();
buffer_.append(str, str + value.size());
return *this;
}
template <typename T, typename Spec, typename FillChar>
BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec) {
template <typename Int, typename Spec, typename FillChar>
void append_int(const IntFormatSpec<Int, Spec, FillChar> &spec) {
internal::CharTraits<Char>::convert(FillChar());
write_int(spec.value(), spec);
return *this;
}
template <typename StrChar>
BasicWriter &operator<<(const StrFormatSpec<StrChar> &spec) {
const StrChar *s = spec.str();
write_str(s, std::char_traits<Char>::length(s), spec);
return *this;
template <typename Float> // XXX: FloatFormatSpec?
void append_double(Float value) {
write_double(value, FormatSpec());
}
void clear() FMT_NOEXCEPT { buffer_.clear(); }
void append_pointer(const void *p) {
// Note:
// Uses the same format as ArgFormatterBase.
FormatSpec spec;
spec.flags_ = HASH_FLAG;
spec.type_ = 'x';
write_int(reinterpret_cast<uintptr_t>(p), spec);
}
Buffer<Char> &buffer() FMT_NOEXCEPT { return buffer_; }
void append_char(char ch) {
buffer_.push_back(ch);
}
void append_char(
typename internal::WCharHelper<wchar_t, Char>::Supported ch) {
buffer_.push_back(ch);
}
void append_str(StringRef str) {
buffer_.append(str.data(), str.data() + str.size());
}
void append_str(
typename internal::WCharHelper<WStringRef, Char>::Supported str) {
buffer_.append(str.data(), str.data() + str.size());
}
void append_str(const StrFormatSpec<char> &spec) {
const char *s = spec.str();
write_str(s, std::char_traits<char>::length(s), spec);
}
void append_str(
typename internal::WCharHelper<
const StrFormatSpec<wchar_t> &, Char>::Supported spec) {
const wchar_t *s = spec.str();
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);
};
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;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, signed char value) {
w.append_decimal(static_cast<int>(value));
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, short value) {
w.append_decimal(static_cast<int>(value));
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, int value) {
w.append_decimal(static_cast<int>(value));
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, long value) {
w.append_decimal(value);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, LongLong value) {
w.append_decimal(value);
return w;
}
#if USHRT_MAX <= INT_MAX
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;
}
#endif
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, unsigned int value) {
w.append_decimal(value);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, unsigned long value) {
w.append_decimal(value);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, ULongLong value) {
w.append_decimal(value);
return w;
}
template <typename Char, typename Int, typename Spec, typename FillChar>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, const IntFormatSpec<Int, Spec, FillChar> &value) {
w.append_int(value);
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) {
w.append_str(value);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(
BasicWriter<Char> &w, const void *pointer) {
w.append_pointer(pointer);
return w;
}
template <typename Char>
inline BasicWriter<Char> &operator<<(BasicWriter<Char> &w, void *pointer) {
w.append_pointer(pointer);
return w;
}
#if FMT_USE_OSTREAM_RVALUE
// http://cplusplus.github.io/LWG/lwg-active.html#1203
//
// For:
// std::string s = (MemoryWriter() << "i = " << i).str();
template <
typename WriterT,
typename T,
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&>())
>
inline WriterT &&operator<<(WriterT &&w, const T &value) {
w << value;
return std::move(w);
}
#endif
template <typename Char>
template <typename StrChar>
typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(

View File

@ -111,17 +111,11 @@ void format_arg(BasicFormatter<Char, ArgFormatter_> &f,
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
#if __cplusplus >= 201103L
template<typename T, typename Char>
typename std::enable_if<
!std::is_same<
typename std::remove_cv<typename std::decay<T>::type>::type,
char *
>::value,
BasicWriter<Char>&
>::type
operator<<(BasicWriter<Char> &writer, const T &value) {
template <typename Char, typename T>
BasicWriter<Char> &operator<<(BasicWriter<Char> &writer, const T &value) {
#if FMT_HAS_DECLTYPE_INCOMPLETE_RETURN_TYPES
FMT_STATIC_ASSERT(internal::is_streamable<T>::value, "T must be Streamable");
#endif
internal::FormatBuf<Char> format_buf(writer.buffer());
std::basic_ostream<Char> output(&format_buf);
@ -129,7 +123,7 @@ operator<<(BasicWriter<Char> &writer, const T &value) {
return writer;
}
#endif
} // namespace fmt
#ifdef FMT_HEADER_ONLY

View File

@ -79,6 +79,18 @@ using fmt::MemoryWriter;
using fmt::WMemoryWriter;
using fmt::pad;
namespace fmt {
// Mimic operator<< defined in ostream.h.
// If this gets called in any of the tests below, this is an error. All of the
// types used here should be handled by operator<< defined in format.h or a
// specific overload defined in this file.
template <typename Char, typename T>
BasicWriter<Char> &operator<<(BasicWriter<Char> &w, const T &) {
typename T::this_is_an_error t;
return w;
}
}
namespace {
// Format value using the standard library.
@ -107,8 +119,13 @@ 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)
@ -352,25 +369,28 @@ TEST(WriterTest, WriteWideString) {
TEST(WriterTest, bin) {
using fmt::bin;
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());
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("11011110101011011011111011101111",
(MemoryWriter() << bin(0xdeadbeefull)).str());
(w << bin(0xdeadbeefull)).str());
}
TEST(WriterTest, oct) {
using fmt::oct;
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());
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());
}
TEST(WriterTest, hex) {
@ -380,22 +400,24 @@ TEST(WriterTest, hex) {
// This shouldn't compile:
//fmt::IntFormatSpec<short, fmt::TypeSpec<'x'> > (*phex2)(short value) = hex;
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());
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());
}
TEST(WriterTest, hexu) {
using fmt::hexu;
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());
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());
}
template <typename Char>
@ -420,22 +442,22 @@ public:
ISO8601DateFormatter iso8601(const Date &d) { return ISO8601DateFormatter(d); }
TEST(WriterTest, pad) {
using fmt::hex;
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());
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;
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());
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());
w.clear();
w << pad(42, 5, '0');
EXPECT_EQ("00042", w.str());
@ -448,21 +470,24 @@ TEST(WriterTest, pad) {
}
TEST(WriterTest, PadString) {
EXPECT_EQ("test ", (MemoryWriter() << pad("test", 8)).str());
EXPECT_EQ("test******", (MemoryWriter() << pad("test", 10, '*')).str());
MemoryWriter w;
w.clear(); EXPECT_EQ("test ", (w << pad("test", 8)).str());
w.clear(); EXPECT_EQ("test******", (w << pad("test", 10, '*')).str());
}
TEST(WriterTest, PadWString) {
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());
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());
}
TEST(WriterTest, NoConflictWithIOManip) {
using namespace std;
using namespace fmt;
EXPECT_EQ("cafe", (MemoryWriter() << hex(0xcafe)).str());
EXPECT_EQ("12", (MemoryWriter() << oct(012)).str());
MemoryWriter w;
w.clear(); EXPECT_EQ("cafe", (w << hex(0xcafe)).str());
w.clear(); EXPECT_EQ("12", (w << oct(012)).str());
}
TEST(WriterTest, Format) {
@ -480,7 +505,85 @@ TEST(WriterTest, Format) {
}
TEST(WriterTest, WWriter) {
EXPECT_EQ(L"cafe", (fmt::WMemoryWriter() << fmt::hex(0xcafe)).str());
WMemoryWriter w;
EXPECT_EQ(L"cafe", (w << 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());
// This should not compile:
#if 0
const wchar_t *wcs = L"wcs";
// w << (wchar_t)'x';
// w << (const wchar_t *)wcs;
// w << (wchar_t *)wcs;
// w << fmt::WStringRef(wcs);
// w << std::wstring(wcs);
#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());
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());
}
TEST(ArrayWriterTest, Ctor) {
@ -1404,7 +1507,10 @@ TEST(FormatterTest, FormatStringFromSpeedTest) {
TEST(FormatterTest, FormatExamples) {
using fmt::hex;
EXPECT_EQ("0000cafe", (MemoryWriter() << pad(hex(0xcafe), 8, '0')).str());
{
MemoryWriter w;
EXPECT_EQ("0000cafe", (w << pad(hex(0xcafe), 8, '0')).str());
}
std::string message = format("The answer is {}", 42);
EXPECT_EQ("The answer is 42", message);

View File

@ -111,13 +111,11 @@ std::ostream &operator<<(std::ostream &os, EmptyTest) {
return os << "";
}
#if __cplusplus >= 201103L
struct UserDefinedTest { int i = 42; };
std::ostream &operator<<(std::ostream &os, const UserDefinedTest &u) {
return os << u.i;
}
#endif
TEST(OStreamTest, EmptyCustomOutput) {
EXPECT_EQ("", fmt::format("{}", EmptyTest()));
@ -137,7 +135,6 @@ TEST(OStreamTest, WriteToOStream) {
EXPECT_EQ("foo", os.str());
}
#if __cplusplus >= 201103L
TEST(OStreamTest, WriteUserDefinedTypeToOStream) {
std::ostringstream os;
fmt::MemoryWriter w;
@ -145,8 +142,12 @@ TEST(OStreamTest, WriteUserDefinedTypeToOStream) {
w << "The answer is " << u;
fmt::internal::write(os, w);
EXPECT_EQ("The answer is 42", os.str());
}
#if FMT_USE_OSTREAM_RVALUE
EXPECT_EQ("The answer is 42",
(fmt::MemoryWriter() << "The answer is " << UserDefinedTest()).str());
#endif
}
TEST(OStreamTest, WriteToOStreamMaxSize) {
std::size_t max_size = std::numeric_limits<std::size_t>::max();
@ -192,11 +193,10 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
fmt::internal::write(os, w);
}
#if __cplusplus >= 201103L
struct Xs {
const size_t size;
const int size;
const std::string s;
Xs() : size(200), s(size, 'x') {}
Xs() : size(200), s(static_cast<std::size_t>(size), 'x') {}
};
inline std::ostream& operator<<(std::ostream& os, Xs const& xs) {
@ -209,8 +209,7 @@ TEST(OStreamTest, FormatBuf1) {
int n = fmt::internal::INLINE_BUFFER_SIZE / xs.size + 1;
for (int i = 0; i < n; ++i)
w << xs;
EXPECT_EQ(w.size(), size_t(n * xs.size));
EXPECT_EQ(w.size(), static_cast<std::size_t>(n * xs.size));
w << xs;
EXPECT_EQ(w.size(), size_t((n + 1) * xs.size));
EXPECT_EQ(w.size(), static_cast<std::size_t>((n + 1) * xs.size));
}
#endif