Consistent behavior of operator<< for known types
This commit is contained in:
parent
73ca9948fe
commit
01c51ffb47
@ -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;
|
||||
|
||||
382
fmt/format.h
382
fmt/format.h
@ -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(
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user