mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Move ostream support to ostream.{h,cc}
This commit is contained in:
@ -1,12 +1,12 @@
|
|||||||
# Define the fmt library, its includes and the needed defines.
|
# Define the fmt library, its includes and the needed defines.
|
||||||
# format.cc is added to FMT_HEADERS for the header-only configuration.
|
# format.cc is added to FMT_HEADERS for the header-only configuration.
|
||||||
set(FMT_HEADERS format.h format.cc time.h)
|
set(FMT_HEADERS format.h format.cc ostream.h ostream.cc time.h)
|
||||||
if (HAVE_OPEN)
|
if (HAVE_OPEN)
|
||||||
set(FMT_HEADERS ${FMT_HEADERS} posix.h)
|
set(FMT_HEADERS ${FMT_HEADERS} posix.h)
|
||||||
set(FMT_SOURCES ${FMT_SOURCES} posix.cc)
|
set(FMT_SOURCES ${FMT_SOURCES} posix.cc)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS})
|
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../ChangeLog.rst)
|
||||||
|
|
||||||
option(FMT_CPPFORMAT "Build cppformat library for backward compatibility." OFF)
|
option(FMT_CPPFORMAT "Build cppformat library for backward compatibility." OFF)
|
||||||
if (FMT_CPPFORMAT)
|
if (FMT_CPPFORMAT)
|
||||||
|
@ -60,12 +60,6 @@ using fmt::internal::Arg;
|
|||||||
# define FMT_CATCH(x) if (false)
|
# define FMT_CATCH(x) if (false)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef FMT_HEADER_ONLY
|
|
||||||
# define FMT_FUNC inline
|
|
||||||
#else
|
|
||||||
# define FMT_FUNC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# pragma warning(push)
|
# pragma warning(push)
|
||||||
# pragma warning(disable: 4127) // conditional expression is constant
|
# pragma warning(disable: 4127) // conditional expression is constant
|
||||||
@ -361,21 +355,6 @@ class CharConverter : public ArgVisitor<CharConverter, void> {
|
|||||||
arg_.int_value = static_cast<char>(value);
|
arg_.int_value = static_cast<char>(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write the content of w to os.
|
|
||||||
void write(std::ostream &os, Writer &w) {
|
|
||||||
const char *data = w.data();
|
|
||||||
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
|
|
||||||
UnsignedStreamSize size = w.size();
|
|
||||||
UnsignedStreamSize max_size =
|
|
||||||
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
|
|
||||||
do {
|
|
||||||
UnsignedStreamSize n = size <= max_size ? size : max_size;
|
|
||||||
os.write(data, static_cast<std::streamsize>(n));
|
|
||||||
data += n;
|
|
||||||
size -= n;
|
|
||||||
} while (size != 0);
|
|
||||||
}
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
@ -896,13 +875,6 @@ FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) {
|
|||||||
print(stdout, format_str, args);
|
print(stdout, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str,
|
|
||||||
ArgList args) {
|
|
||||||
MemoryWriter w;
|
|
||||||
w.write(format_str, args);
|
|
||||||
write(os, w);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
|
FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
|
||||||
char escape[] = "\x1b[30m";
|
char escape[] = "\x1b[30m";
|
||||||
escape[3] = static_cast<char>('0' + c);
|
escape[3] = static_cast<char>('0' + c);
|
||||||
@ -918,13 +890,6 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) {
|
|||||||
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
|
return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args) {
|
|
||||||
MemoryWriter w;
|
|
||||||
printf(w, format, args);
|
|
||||||
write(os, w);
|
|
||||||
return static_cast<int>(w.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
|
|
||||||
template struct fmt::internal::BasicData<void>;
|
template struct fmt::internal::BasicData<void>;
|
||||||
|
113
fmt/format.h
113
fmt/format.h
@ -40,14 +40,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#ifndef FMT_USE_IOSTREAMS
|
|
||||||
# define FMT_USE_IOSTREAMS 1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FMT_USE_IOSTREAMS
|
|
||||||
# include <ostream>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _SECURE_SCL
|
#ifdef _SECURE_SCL
|
||||||
# define FMT_SECURE_SCL _SECURE_SCL
|
# define FMT_SECURE_SCL _SECURE_SCL
|
||||||
#else
|
#else
|
||||||
@ -387,10 +379,6 @@ template <typename CharType,
|
|||||||
typename ArgFormatter = fmt::ArgFormatter<CharType> >
|
typename ArgFormatter = fmt::ArgFormatter<CharType> >
|
||||||
class BasicFormatter;
|
class BasicFormatter;
|
||||||
|
|
||||||
template <typename Char, typename ArgFormatter, typename T>
|
|
||||||
void format(BasicFormatter<Char, ArgFormatter> &f,
|
|
||||||
const Char *&format_str, const T &value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
A string reference. It can be constructed from a C string or ``std::string``.
|
A string reference. It can be constructed from a C string or ``std::string``.
|
||||||
@ -1057,33 +1045,16 @@ struct WCharHelper<T, wchar_t> {
|
|||||||
typedef char Yes[1];
|
typedef char Yes[1];
|
||||||
typedef char No[2];
|
typedef char No[2];
|
||||||
|
|
||||||
// These are non-members to workaround an overload resolution bug in bcc32.
|
|
||||||
Yes &convert(fmt::ULongLong);
|
|
||||||
Yes &convert(std::ostream &);
|
|
||||||
No &convert(...);
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T &get();
|
T &get();
|
||||||
|
|
||||||
struct DummyStream : std::ostream {
|
// These are non-members to workaround an overload resolution bug in bcc32.
|
||||||
DummyStream(); // Suppress a bogus warning in MSVC.
|
Yes &convert(fmt::ULongLong);
|
||||||
// Hide all operator<< overloads from std::ostream.
|
No &convert(...);
|
||||||
void operator<<(Null<>);
|
|
||||||
};
|
|
||||||
|
|
||||||
No &operator<<(std::ostream &, int);
|
|
||||||
|
|
||||||
template<typename T, bool ENABLE_CONVERSION>
|
template<typename T, bool ENABLE_CONVERSION>
|
||||||
struct ConvertToIntImpl {
|
struct ConvertToIntImpl {
|
||||||
enum { value = false };
|
enum { value = ENABLE_CONVERSION };
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct ConvertToIntImpl<T, true> {
|
|
||||||
// Convert to int only if T doesn't have an overloaded operator<<.
|
|
||||||
enum {
|
|
||||||
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, bool ENABLE_CONVERSION>
|
template<typename T, bool ENABLE_CONVERSION>
|
||||||
@ -2140,38 +2111,6 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
|
|||||||
(t12.type << 48) | (t13.type << 52) | (t14.type << 56);
|
(t12.type << 48) | (t13.type << 52) | (t14.type << 56);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class Char>
|
|
||||||
class FormatBuf : public std::basic_streambuf<Char> {
|
|
||||||
private:
|
|
||||||
typedef typename std::basic_streambuf<Char>::int_type int_type;
|
|
||||||
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
|
|
||||||
|
|
||||||
Buffer<Char> &buffer_;
|
|
||||||
Char *start_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) {
|
|
||||||
this->setp(start_, start_ + buffer_.capacity());
|
|
||||||
}
|
|
||||||
|
|
||||||
int_type overflow(int_type ch = traits_type::eof()) {
|
|
||||||
if (!traits_type::eq_int_type(ch, traits_type::eof())) {
|
|
||||||
size_t size = this->size();
|
|
||||||
buffer_.resize(size);
|
|
||||||
buffer_.reserve(size * 2);
|
|
||||||
|
|
||||||
start_ = &buffer_[0];
|
|
||||||
start_[size] = traits_type::to_char_type(ch);
|
|
||||||
this->setp(start_+ size + 1, start_ + size * 2);
|
|
||||||
}
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t size() const {
|
|
||||||
return to_unsigned(this->pptr() - start_);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n
|
# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n
|
||||||
@ -3100,21 +3039,6 @@ class BasicArrayWriter : public BasicWriter<Char> {
|
|||||||
typedef BasicArrayWriter<char> ArrayWriter;
|
typedef BasicArrayWriter<char> ArrayWriter;
|
||||||
typedef BasicArrayWriter<wchar_t> WArrayWriter;
|
typedef BasicArrayWriter<wchar_t> WArrayWriter;
|
||||||
|
|
||||||
// Formats a value.
|
|
||||||
template <typename Char, typename ArgFormatter, typename T>
|
|
||||||
void format(BasicFormatter<Char, ArgFormatter> &f,
|
|
||||||
const Char *&format_str, const T &value) {
|
|
||||||
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
|
|
||||||
|
|
||||||
internal::FormatBuf<Char> format_buf(buffer);
|
|
||||||
std::basic_ostream<Char> output(&format_buf);
|
|
||||||
output << value;
|
|
||||||
|
|
||||||
BasicStringRef<Char> str(&buffer[0], format_buf.size());
|
|
||||||
typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
|
|
||||||
format_str = f.format(format_str, MakeArg(str));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reports a system error without throwing an exception.
|
// Reports a system error without throwing an exception.
|
||||||
// Can be used to report errors from destructors.
|
// Can be used to report errors from destructors.
|
||||||
FMT_API void report_system_error(int error_code,
|
FMT_API void report_system_error(int error_code,
|
||||||
@ -3544,32 +3468,6 @@ FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
|
|||||||
FMT_VARIADIC(int, printf, CStringRef)
|
FMT_VARIADIC(int, printf, CStringRef)
|
||||||
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
|
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
|
||||||
|
|
||||||
#if FMT_USE_IOSTREAMS
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
Prints formatted data to the stream *os*.
|
|
||||||
|
|
||||||
**Example**::
|
|
||||||
|
|
||||||
print(cerr, "Don't {}!", "panic");
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
|
|
||||||
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
|
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
Prints formatted data to the stream *os*.
|
|
||||||
|
|
||||||
**Example**::
|
|
||||||
|
|
||||||
fprintf(cerr, "Don't %s!", "panic");
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args);
|
|
||||||
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
inline bool is_name_start(Char c) {
|
inline bool is_name_start(Char c) {
|
||||||
@ -3924,7 +3822,10 @@ operator"" _a(const wchar_t *s, std::size_t) { return {s}; }
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef FMT_HEADER_ONLY
|
#ifdef FMT_HEADER_ONLY
|
||||||
|
# define FMT_FUNC inline
|
||||||
# include "format.cc"
|
# include "format.cc"
|
||||||
|
#else
|
||||||
|
# define FMT_FUNC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // FMT_FORMAT_H_
|
#endif // FMT_FORMAT_H_
|
||||||
|
61
fmt/ostream.cc
Normal file
61
fmt/ostream.cc
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
Formatting library for C++ - std::ostream support
|
||||||
|
|
||||||
|
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ostream.h"
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Write the content of w to os.
|
||||||
|
void write(std::ostream &os, Writer &w) {
|
||||||
|
const char *data = w.data();
|
||||||
|
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
|
||||||
|
UnsignedStreamSize size = w.size();
|
||||||
|
UnsignedStreamSize max_size =
|
||||||
|
internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
|
||||||
|
do {
|
||||||
|
UnsignedStreamSize n = size <= max_size ? size : max_size;
|
||||||
|
os.write(data, static_cast<std::streamsize>(n));
|
||||||
|
data += n;
|
||||||
|
size -= n;
|
||||||
|
} while (size != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {
|
||||||
|
MemoryWriter w;
|
||||||
|
w.write(format_str, args);
|
||||||
|
write(os, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args) {
|
||||||
|
MemoryWriter w;
|
||||||
|
printf(w, format, args);
|
||||||
|
write(os, w);
|
||||||
|
return static_cast<int>(w.size());
|
||||||
|
}
|
||||||
|
} // namespace fmt
|
133
fmt/ostream.h
Normal file
133
fmt/ostream.h
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
Formatting library for C++ - std::ostream support
|
||||||
|
|
||||||
|
Copyright (c) 2012 - 2016, Victor Zverovich
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FMT_OSTREAM_H_
|
||||||
|
#define FMT_OSTREAM_H_
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <class Char>
|
||||||
|
class FormatBuf : public std::basic_streambuf<Char> {
|
||||||
|
private:
|
||||||
|
typedef typename std::basic_streambuf<Char>::int_type int_type;
|
||||||
|
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
|
||||||
|
|
||||||
|
Buffer<Char> &buffer_;
|
||||||
|
Char *start_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) {
|
||||||
|
this->setp(start_, start_ + buffer_.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
int_type overflow(int_type ch = traits_type::eof()) {
|
||||||
|
if (!traits_type::eq_int_type(ch, traits_type::eof())) {
|
||||||
|
size_t size = this->size();
|
||||||
|
buffer_.resize(size);
|
||||||
|
buffer_.reserve(size * 2);
|
||||||
|
|
||||||
|
start_ = &buffer_[0];
|
||||||
|
start_[size] = traits_type::to_char_type(ch);
|
||||||
|
this->setp(start_+ size + 1, start_ + size * 2);
|
||||||
|
}
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return to_unsigned(this->pptr() - start_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Yes &convert(std::ostream &);
|
||||||
|
|
||||||
|
struct DummyStream : std::ostream {
|
||||||
|
DummyStream(); // Suppress a bogus warning in MSVC.
|
||||||
|
// Hide all operator<< overloads from std::ostream.
|
||||||
|
void operator<<(Null<>);
|
||||||
|
};
|
||||||
|
|
||||||
|
No &operator<<(std::ostream &, int);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ConvertToIntImpl<T, true> {
|
||||||
|
// Convert to int only if T doesn't have an overloaded operator<<.
|
||||||
|
enum {
|
||||||
|
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// Formats a value.
|
||||||
|
template <typename Char, typename ArgFormatter, typename T>
|
||||||
|
void format(BasicFormatter<Char, ArgFormatter> &f,
|
||||||
|
const Char *&format_str, const T &value) {
|
||||||
|
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
|
||||||
|
|
||||||
|
internal::FormatBuf<Char> format_buf(buffer);
|
||||||
|
std::basic_ostream<Char> output(&format_buf);
|
||||||
|
output << value;
|
||||||
|
|
||||||
|
BasicStringRef<Char> str(&buffer[0], format_buf.size());
|
||||||
|
typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
|
||||||
|
format_str = f.format(format_str, MakeArg(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Prints formatted data to the stream *os*.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
print(cerr, "Don't {}!", "panic");
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
|
||||||
|
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Prints formatted data to the stream *os*.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fprintf(cerr, "Don't %s!", "panic");
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args);
|
||||||
|
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
|
#ifdef FMT_HEADER_ONLY
|
||||||
|
# include "ostream.cc"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // FMT_OSTREAM_H_
|
@ -75,6 +75,7 @@ add_fmt_test(assert-test)
|
|||||||
add_fmt_test(gtest-extra-test)
|
add_fmt_test(gtest-extra-test)
|
||||||
add_fmt_test(format-test)
|
add_fmt_test(format-test)
|
||||||
add_fmt_test(format-impl-test)
|
add_fmt_test(format-impl-test)
|
||||||
|
add_fmt_test(ostream-test)
|
||||||
add_fmt_test(printf-test)
|
add_fmt_test(printf-test)
|
||||||
add_fmt_test(util-test mock-allocator.h)
|
add_fmt_test(util-test mock-allocator.h)
|
||||||
add_fmt_test(macro-test)
|
add_fmt_test(macro-test)
|
||||||
|
@ -123,55 +123,3 @@ TEST(FormatTest, FormatErrorCode) {
|
|||||||
EXPECT_EQ(msg, w.str());
|
EXPECT_EQ(msg, w.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, WriteToOStream) {
|
|
||||||
std::ostringstream os;
|
|
||||||
fmt::MemoryWriter w;
|
|
||||||
w << "foo";
|
|
||||||
fmt::write(os, w);
|
|
||||||
EXPECT_EQ("foo", os.str());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FormatTest, WriteToOStreamMaxSize) {
|
|
||||||
std::size_t max_size = std::numeric_limits<std::size_t>::max();
|
|
||||||
std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max();
|
|
||||||
if (max_size <= fmt::internal::to_unsigned(max_streamsize))
|
|
||||||
return;
|
|
||||||
|
|
||||||
class TestWriter : public fmt::BasicWriter<char> {
|
|
||||||
private:
|
|
||||||
struct TestBuffer : fmt::Buffer<char> {
|
|
||||||
explicit TestBuffer(std::size_t size) { size_ = size; }
|
|
||||||
void grow(std::size_t) {}
|
|
||||||
} buffer_;
|
|
||||||
public:
|
|
||||||
explicit TestWriter(std::size_t size)
|
|
||||||
: fmt::BasicWriter<char>(buffer_), buffer_(size) {}
|
|
||||||
} w(max_size);
|
|
||||||
|
|
||||||
struct MockStreamBuf : std::streambuf {
|
|
||||||
MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n));
|
|
||||||
std::streamsize xsputn(const char *s, std::streamsize n) {
|
|
||||||
const void *v = s;
|
|
||||||
return xsputn(v, n);
|
|
||||||
}
|
|
||||||
} buffer;
|
|
||||||
|
|
||||||
struct TestOStream : std::ostream {
|
|
||||||
explicit TestOStream(MockStreamBuf &buffer) : std::ostream(&buffer) {}
|
|
||||||
} os(buffer);
|
|
||||||
|
|
||||||
testing::InSequence sequence;
|
|
||||||
const char *data = 0;
|
|
||||||
std::size_t size = max_size;
|
|
||||||
do {
|
|
||||||
typedef fmt::internal::MakeUnsigned<std::streamsize>::Type UStreamSize;
|
|
||||||
UStreamSize n = std::min<UStreamSize>(
|
|
||||||
size, fmt::internal::to_unsigned(max_streamsize));
|
|
||||||
EXPECT_CALL(buffer, xsputn(data, static_cast<std::streamsize>(n)))
|
|
||||||
.WillOnce(testing::Return(max_streamsize));
|
|
||||||
data += n;
|
|
||||||
size -= static_cast<std::size_t>(n);
|
|
||||||
} while (size != 0);
|
|
||||||
fmt::write(os, w);
|
|
||||||
}
|
|
||||||
|
@ -31,10 +31,7 @@
|
|||||||
#include <clocale>
|
#include <clocale>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#if FMT_USE_TYPE_TRAITS
|
#if FMT_USE_TYPE_TRAITS
|
||||||
@ -386,30 +383,10 @@ TEST(WriterTest, hexu) {
|
|||||||
EXPECT_EQ("DEADBEEF", (MemoryWriter() << hexu(0xdeadbeefull)).str());
|
EXPECT_EQ("DEADBEEF", (MemoryWriter() << hexu(0xdeadbeefull)).str());
|
||||||
}
|
}
|
||||||
|
|
||||||
class Date {
|
template <typename Char>
|
||||||
int year_, month_, day_;
|
BasicWriter<Char> &operator<<(BasicWriter<Char> &f, const Date &d) {
|
||||||
public:
|
return f << d.year() << '-' << d.month() << '-' << d.day();
|
||||||
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
|
}
|
||||||
|
|
||||||
int year() const { return year_; }
|
|
||||||
int month() const { return month_; }
|
|
||||||
int day() const { return day_; }
|
|
||||||
|
|
||||||
friend std::ostream &operator<<(std::ostream &os, const Date &d) {
|
|
||||||
os << d.year_ << '-' << d.month_ << '-' << d.day_;
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend std::wostream &operator<<(std::wostream &os, const Date &d) {
|
|
||||||
os << d.year_ << L'-' << d.month_ << L'-' << d.day_;
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
friend BasicWriter<Char> &operator<<(BasicWriter<Char> &f, const Date &d) {
|
|
||||||
return f << d.year_ << '-' << d.month_ << '-' << d.day_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ISO8601DateFormatter {
|
class ISO8601DateFormatter {
|
||||||
const Date *date_;
|
const Date *date_;
|
||||||
@ -665,7 +642,6 @@ TEST(FormatterTest, LeftAlign) {
|
|||||||
EXPECT_EQ("c ", format("{0:<5}", 'c'));
|
EXPECT_EQ("c ", format("{0:<5}", 'c'));
|
||||||
EXPECT_EQ("abc ", format("{0:<5}", "abc"));
|
EXPECT_EQ("abc ", format("{0:<5}", "abc"));
|
||||||
EXPECT_EQ("0xface ", format("{0:<8}", reinterpret_cast<void*>(0xface)));
|
EXPECT_EQ("0xface ", format("{0:<8}", reinterpret_cast<void*>(0xface)));
|
||||||
EXPECT_EQ("def ", format("{0:<5}", TestString("def")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, RightAlign) {
|
TEST(FormatterTest, RightAlign) {
|
||||||
@ -683,7 +659,6 @@ TEST(FormatterTest, RightAlign) {
|
|||||||
EXPECT_EQ(" c", format("{0:>5}", 'c'));
|
EXPECT_EQ(" c", format("{0:>5}", 'c'));
|
||||||
EXPECT_EQ(" abc", format("{0:>5}", "abc"));
|
EXPECT_EQ(" abc", format("{0:>5}", "abc"));
|
||||||
EXPECT_EQ(" 0xface", format("{0:>8}", reinterpret_cast<void*>(0xface)));
|
EXPECT_EQ(" 0xface", format("{0:>8}", reinterpret_cast<void*>(0xface)));
|
||||||
EXPECT_EQ(" def", format("{0:>5}", TestString("def")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, NumericAlign) {
|
TEST(FormatterTest, NumericAlign) {
|
||||||
@ -709,8 +684,6 @@ TEST(FormatterTest, NumericAlign) {
|
|||||||
FormatError, "format specifier '=' requires numeric argument");
|
FormatError, "format specifier '=' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:=8}", reinterpret_cast<void*>(0xface)),
|
EXPECT_THROW_MSG(format("{0:=8}", reinterpret_cast<void*>(0xface)),
|
||||||
FormatError, "format specifier '=' requires numeric argument");
|
FormatError, "format specifier '=' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")),
|
|
||||||
FormatError, "format specifier '=' requires numeric argument");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, CenterAlign) {
|
TEST(FormatterTest, CenterAlign) {
|
||||||
@ -728,7 +701,6 @@ TEST(FormatterTest, CenterAlign) {
|
|||||||
EXPECT_EQ(" c ", format("{0:^5}", 'c'));
|
EXPECT_EQ(" c ", format("{0:^5}", 'c'));
|
||||||
EXPECT_EQ(" abc ", format("{0:^6}", "abc"));
|
EXPECT_EQ(" abc ", format("{0:^6}", "abc"));
|
||||||
EXPECT_EQ(" 0xface ", format("{0:^8}", reinterpret_cast<void*>(0xface)));
|
EXPECT_EQ(" 0xface ", format("{0:^8}", reinterpret_cast<void*>(0xface)));
|
||||||
EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, Fill) {
|
TEST(FormatterTest, Fill) {
|
||||||
@ -748,7 +720,6 @@ TEST(FormatterTest, Fill) {
|
|||||||
EXPECT_EQ("c****", format("{0:*<5}", 'c'));
|
EXPECT_EQ("c****", format("{0:*<5}", 'c'));
|
||||||
EXPECT_EQ("abc**", format("{0:*<5}", "abc"));
|
EXPECT_EQ("abc**", format("{0:*<5}", "abc"));
|
||||||
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
|
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
|
||||||
EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, PlusSign) {
|
TEST(FormatterTest, PlusSign) {
|
||||||
@ -773,8 +744,6 @@ TEST(FormatterTest, PlusSign) {
|
|||||||
FormatError, "format specifier '+' requires numeric argument");
|
FormatError, "format specifier '+' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:+}", reinterpret_cast<void*>(0x42)),
|
EXPECT_THROW_MSG(format("{0:+}", reinterpret_cast<void*>(0x42)),
|
||||||
FormatError, "format specifier '+' requires numeric argument");
|
FormatError, "format specifier '+' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:+}", TestString()),
|
|
||||||
FormatError, "format specifier '+' requires numeric argument");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, MinusSign) {
|
TEST(FormatterTest, MinusSign) {
|
||||||
@ -799,8 +768,6 @@ TEST(FormatterTest, MinusSign) {
|
|||||||
FormatError, "format specifier '-' requires numeric argument");
|
FormatError, "format specifier '-' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:-}", reinterpret_cast<void*>(0x42)),
|
EXPECT_THROW_MSG(format("{0:-}", reinterpret_cast<void*>(0x42)),
|
||||||
FormatError, "format specifier '-' requires numeric argument");
|
FormatError, "format specifier '-' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:-}", TestString()),
|
|
||||||
FormatError, "format specifier '-' requires numeric argument");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, SpaceSign) {
|
TEST(FormatterTest, SpaceSign) {
|
||||||
@ -825,8 +792,6 @@ TEST(FormatterTest, SpaceSign) {
|
|||||||
FormatError, "format specifier ' ' requires numeric argument");
|
FormatError, "format specifier ' ' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0: }", reinterpret_cast<void*>(0x42)),
|
EXPECT_THROW_MSG(format("{0: }", reinterpret_cast<void*>(0x42)),
|
||||||
FormatError, "format specifier ' ' requires numeric argument");
|
FormatError, "format specifier ' ' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0: }", TestString()),
|
|
||||||
FormatError, "format specifier ' ' requires numeric argument");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, HashFlag) {
|
TEST(FormatterTest, HashFlag) {
|
||||||
@ -872,8 +837,6 @@ TEST(FormatterTest, HashFlag) {
|
|||||||
FormatError, "format specifier '#' requires numeric argument");
|
FormatError, "format specifier '#' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:#}", reinterpret_cast<void*>(0x42)),
|
EXPECT_THROW_MSG(format("{0:#}", reinterpret_cast<void*>(0x42)),
|
||||||
FormatError, "format specifier '#' requires numeric argument");
|
FormatError, "format specifier '#' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:#}", TestString()),
|
|
||||||
FormatError, "format specifier '#' requires numeric argument");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, ZeroFlag) {
|
TEST(FormatterTest, ZeroFlag) {
|
||||||
@ -894,8 +857,6 @@ TEST(FormatterTest, ZeroFlag) {
|
|||||||
FormatError, "format specifier '0' requires numeric argument");
|
FormatError, "format specifier '0' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:05}", reinterpret_cast<void*>(0x42)),
|
EXPECT_THROW_MSG(format("{0:05}", reinterpret_cast<void*>(0x42)),
|
||||||
FormatError, "format specifier '0' requires numeric argument");
|
FormatError, "format specifier '0' requires numeric argument");
|
||||||
EXPECT_THROW_MSG(format("{0:05}", TestString()),
|
|
||||||
FormatError, "format specifier '0' requires numeric argument");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, Width) {
|
TEST(FormatterTest, Width) {
|
||||||
@ -923,7 +884,6 @@ TEST(FormatterTest, Width) {
|
|||||||
EXPECT_EQ(" 0xcafe", format("{0:10}", reinterpret_cast<void*>(0xcafe)));
|
EXPECT_EQ(" 0xcafe", format("{0:10}", reinterpret_cast<void*>(0xcafe)));
|
||||||
EXPECT_EQ("x ", format("{0:11}", 'x'));
|
EXPECT_EQ("x ", format("{0:11}", 'x'));
|
||||||
EXPECT_EQ("str ", format("{0:12}", "str"));
|
EXPECT_EQ("str ", format("{0:12}", "str"));
|
||||||
EXPECT_EQ("test ", format("{0:13}", TestString("test")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, RuntimeWidth) {
|
TEST(FormatterTest, RuntimeWidth) {
|
||||||
@ -982,7 +942,6 @@ TEST(FormatterTest, RuntimeWidth) {
|
|||||||
format("{0:{1}}", reinterpret_cast<void*>(0xcafe), 10));
|
format("{0:{1}}", reinterpret_cast<void*>(0xcafe), 10));
|
||||||
EXPECT_EQ("x ", format("{0:{1}}", 'x', 11));
|
EXPECT_EQ("x ", format("{0:{1}}", 'x', 11));
|
||||||
EXPECT_EQ("str ", format("{0:{1}}", "str", 12));
|
EXPECT_EQ("str ", format("{0:{1}}", "str", 12));
|
||||||
EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, Precision) {
|
TEST(FormatterTest, Precision) {
|
||||||
@ -1042,7 +1001,6 @@ TEST(FormatterTest, Precision) {
|
|||||||
FormatError, "precision not allowed in pointer format specifier");
|
FormatError, "precision not allowed in pointer format specifier");
|
||||||
|
|
||||||
EXPECT_EQ("st", format("{0:.2}", "str"));
|
EXPECT_EQ("st", format("{0:.2}", "str"));
|
||||||
EXPECT_EQ("te", format("{0:.2}", TestString("test")));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, RuntimePrecision) {
|
TEST(FormatterTest, RuntimePrecision) {
|
||||||
@ -1126,7 +1084,6 @@ TEST(FormatterTest, RuntimePrecision) {
|
|||||||
FormatError, "precision not allowed in pointer format specifier");
|
FormatError, "precision not allowed in pointer format specifier");
|
||||||
|
|
||||||
EXPECT_EQ("st", format("{0:.{1}}", "str", 2));
|
EXPECT_EQ("st", format("{0:.{1}}", "str", 2));
|
||||||
EXPECT_EQ("te", format("{0:.{1}}", TestString("test"), 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -1393,14 +1350,14 @@ TEST(FormatterTest, FormatCStringRef) {
|
|||||||
EXPECT_EQ("test", format("{0}", CStringRef("test")));
|
EXPECT_EQ("test", format("{0}", CStringRef("test")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatUsingIOStreams) {
|
void format(fmt::BasicFormatter<char> &f, const char *, const Date &d) {
|
||||||
EXPECT_EQ("a string", format("{0}", TestString("a string")));
|
f.writer() << d.year() << '-' << d.month() << '-' << d.day();
|
||||||
std::string s = format("The date is {0}", Date(2012, 12, 9));
|
}
|
||||||
EXPECT_EQ("The date is 2012-12-9", s);
|
|
||||||
|
TEST(FormatterTest, FormatCustom) {
|
||||||
Date date(2012, 12, 9);
|
Date date(2012, 12, 9);
|
||||||
check_unknown_types(date, "s", "string");
|
EXPECT_THROW_MSG(fmt::format("{:s}", date), FormatError,
|
||||||
EXPECT_EQ(L"The date is 2012-12-9",
|
"unmatched '}' in format string");
|
||||||
format(L"The date is {0}", Date(2012, 12, 9)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Answer {};
|
class Answer {};
|
||||||
@ -1563,9 +1520,6 @@ TEST(FormatTest, Print) {
|
|||||||
EXPECT_WRITE(stderr,
|
EXPECT_WRITE(stderr,
|
||||||
fmt::print(stderr, "Don't {}!", "panic"), "Don't panic!");
|
fmt::print(stderr, "Don't {}!", "panic"), "Don't panic!");
|
||||||
#endif
|
#endif
|
||||||
std::ostringstream os;
|
|
||||||
fmt::print(os, "Don't {}!", "panic");
|
|
||||||
EXPECT_EQ("Don't panic!", os.str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FILE_DESCRIPTORS
|
||||||
@ -1660,27 +1614,12 @@ TEST(LiteralsTest, NamedArg) {
|
|||||||
}
|
}
|
||||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||||
|
|
||||||
enum TestEnum {};
|
enum TestEnum { A };
|
||||||
std::ostream &operator<<(std::ostream &os, TestEnum) {
|
|
||||||
return os << "TestEnum";
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TestEnum2 { A };
|
|
||||||
|
|
||||||
TEST(FormatTest, Enum) {
|
TEST(FormatTest, Enum) {
|
||||||
EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
|
|
||||||
EXPECT_EQ("0", fmt::format("{}", A));
|
EXPECT_EQ("0", fmt::format("{}", A));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EmptyTest {};
|
|
||||||
std::ostream &operator<<(std::ostream &os, EmptyTest) {
|
|
||||||
return os << "";
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FormatTest, EmptyCustomOutput) {
|
|
||||||
EXPECT_EQ("", fmt::format("{}", EmptyTest()));
|
|
||||||
}
|
|
||||||
|
|
||||||
class MockArgFormatter :
|
class MockArgFormatter :
|
||||||
public fmt::internal::ArgFormatterBase<MockArgFormatter, char> {
|
public fmt::internal::ArgFormatterBase<MockArgFormatter, char> {
|
||||||
public:
|
public:
|
||||||
@ -1705,19 +1644,3 @@ FMT_VARIADIC(void, custom_format, const char *)
|
|||||||
TEST(FormatTest, CustomArgFormatter) {
|
TEST(FormatTest, CustomArgFormatter) {
|
||||||
custom_format("{}", 42);
|
custom_format("{}", 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestArgFormatter : fmt::BasicArgFormatter<TestArgFormatter, char> {
|
|
||||||
TestArgFormatter(fmt::BasicFormatter<char, TestArgFormatter> &f,
|
|
||||||
fmt::FormatSpec &s, const char *fmt)
|
|
||||||
: fmt::BasicArgFormatter<TestArgFormatter, char>(f, s, fmt) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(ArgFormatterTest, CustomArg) {
|
|
||||||
fmt::MemoryWriter writer;
|
|
||||||
typedef fmt::BasicFormatter<char, TestArgFormatter> Formatter;
|
|
||||||
Formatter formatter(fmt::ArgList(), writer);
|
|
||||||
fmt::FormatSpec spec;
|
|
||||||
TestArgFormatter af(formatter, spec, "}");
|
|
||||||
af.visit(fmt::internal::MakeArg<Formatter>(TestEnum()));
|
|
||||||
EXPECT_EQ("TestEnum", writer.str());
|
|
||||||
}
|
|
||||||
|
192
test/ostream-test.cc
Normal file
192
test/ostream-test.cc
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
std::ostream support tests
|
||||||
|
|
||||||
|
Copyright (c) 2012-2016, Victor Zverovich
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "fmt/ostream.cc"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
#include "gtest-extra.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
using fmt::format;
|
||||||
|
using fmt::FormatError;
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
std::basic_ostream<Char> &operator<<(
|
||||||
|
std::basic_ostream<Char> &os, const BasicTestString<Char> &s) {
|
||||||
|
os << s.value();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream &operator<<(std::ostream &os, const Date &d) {
|
||||||
|
os << d.year() << '-' << d.month() << '-' << d.day();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wostream &operator<<(std::wostream &os, const Date &d) {
|
||||||
|
os << d.year() << L'-' << d.month() << L'-' << d.day();
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TestEnum {};
|
||||||
|
std::ostream &operator<<(std::ostream &os, TestEnum) {
|
||||||
|
return os << "TestEnum";
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TestEnum2 {A};
|
||||||
|
|
||||||
|
TEST(OStreamTest, Enum) {
|
||||||
|
EXPECT_FALSE(fmt::internal::ConvertToInt<TestEnum>::value);
|
||||||
|
EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum()));
|
||||||
|
EXPECT_EQ("0", fmt::format("{}", A));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TestArgFormatter : fmt::BasicArgFormatter<TestArgFormatter, char> {
|
||||||
|
TestArgFormatter(fmt::BasicFormatter<char, TestArgFormatter> &f,
|
||||||
|
fmt::FormatSpec &s, const char *fmt)
|
||||||
|
: fmt::BasicArgFormatter<TestArgFormatter, char>(f, s, fmt) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(OStreamTest, CustomArg) {
|
||||||
|
fmt::MemoryWriter writer;
|
||||||
|
typedef fmt::BasicFormatter<char, TestArgFormatter> Formatter;
|
||||||
|
Formatter formatter(fmt::ArgList(), writer);
|
||||||
|
fmt::FormatSpec spec;
|
||||||
|
TestArgFormatter af(formatter, spec, "}");
|
||||||
|
af.visit(fmt::internal::MakeArg<Formatter>(TestEnum()));
|
||||||
|
EXPECT_EQ("TestEnum", writer.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OStreamTest, Format) {
|
||||||
|
EXPECT_EQ("a string", format("{0}", TestString("a string")));
|
||||||
|
std::string s = format("The date is {0}", Date(2012, 12, 9));
|
||||||
|
EXPECT_EQ("The date is 2012-12-9", s);
|
||||||
|
Date date(2012, 12, 9);
|
||||||
|
EXPECT_EQ(L"The date is 2012-12-9",
|
||||||
|
format(L"The date is {0}", Date(2012, 12, 9)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OStreamTest, FormatSpecs) {
|
||||||
|
EXPECT_EQ("def ", format("{0:<5}", TestString("def")));
|
||||||
|
EXPECT_EQ(" def", format("{0:>5}", TestString("def")));
|
||||||
|
EXPECT_THROW_MSG(format("{0:=5}", TestString("def")),
|
||||||
|
FormatError, "format specifier '=' requires numeric argument");
|
||||||
|
EXPECT_EQ(" def ", format("{0:^5}", TestString("def")));
|
||||||
|
EXPECT_EQ("def**", format("{0:*<5}", TestString("def")));
|
||||||
|
EXPECT_THROW_MSG(format("{0:+}", TestString()),
|
||||||
|
FormatError, "format specifier '+' requires numeric argument");
|
||||||
|
EXPECT_THROW_MSG(format("{0:-}", TestString()),
|
||||||
|
FormatError, "format specifier '-' requires numeric argument");
|
||||||
|
EXPECT_THROW_MSG(format("{0: }", TestString()),
|
||||||
|
FormatError, "format specifier ' ' requires numeric argument");
|
||||||
|
EXPECT_THROW_MSG(format("{0:#}", TestString()),
|
||||||
|
FormatError, "format specifier '#' requires numeric argument");
|
||||||
|
EXPECT_THROW_MSG(format("{0:05}", TestString()),
|
||||||
|
FormatError, "format specifier '0' requires numeric argument");
|
||||||
|
EXPECT_EQ("test ", format("{0:13}", TestString("test")));
|
||||||
|
EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13));
|
||||||
|
EXPECT_EQ("te", format("{0:.2}", TestString("test")));
|
||||||
|
EXPECT_EQ("te", format("{0:.{1}}", TestString("test"), 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EmptyTest {};
|
||||||
|
std::ostream &operator<<(std::ostream &os, EmptyTest) {
|
||||||
|
return os << "";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OStreamTest, EmptyCustomOutput) {
|
||||||
|
EXPECT_EQ("", fmt::format("{}", EmptyTest()));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OStreamTest, Print) {
|
||||||
|
std::ostringstream os;
|
||||||
|
fmt::print(os, "Don't {}!", "panic");
|
||||||
|
EXPECT_EQ("Don't panic!", os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OStreamTest, PrintfCustom) {
|
||||||
|
EXPECT_EQ("abc", fmt::sprintf("%s", TestString("abc")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OStreamTest, FPrintf) {
|
||||||
|
std::ostringstream os;
|
||||||
|
int ret = fmt::fprintf(os, "Don't %s!", "panic");
|
||||||
|
EXPECT_EQ("Don't panic!", os.str());
|
||||||
|
EXPECT_EQ(12, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OStreamTest, WriteToOStream) {
|
||||||
|
std::ostringstream os;
|
||||||
|
fmt::MemoryWriter w;
|
||||||
|
w << "foo";
|
||||||
|
fmt::write(os, w);
|
||||||
|
EXPECT_EQ("foo", os.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(OStreamTest, WriteToOStreamMaxSize) {
|
||||||
|
std::size_t max_size = std::numeric_limits<std::size_t>::max();
|
||||||
|
std::streamsize max_streamsize = std::numeric_limits<std::streamsize>::max();
|
||||||
|
if (max_size <= fmt::internal::to_unsigned(max_streamsize))
|
||||||
|
return;
|
||||||
|
|
||||||
|
class TestWriter : public fmt::BasicWriter<char> {
|
||||||
|
private:
|
||||||
|
struct TestBuffer : fmt::Buffer<char> {
|
||||||
|
explicit TestBuffer(std::size_t size) { size_ = size; }
|
||||||
|
void grow(std::size_t) {}
|
||||||
|
} buffer_;
|
||||||
|
public:
|
||||||
|
explicit TestWriter(std::size_t size)
|
||||||
|
: fmt::BasicWriter<char>(buffer_), buffer_(size) {}
|
||||||
|
} w(max_size);
|
||||||
|
|
||||||
|
struct MockStreamBuf : std::streambuf {
|
||||||
|
MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n));
|
||||||
|
std::streamsize xsputn(const char *s, std::streamsize n) {
|
||||||
|
const void *v = s;
|
||||||
|
return xsputn(v, n);
|
||||||
|
}
|
||||||
|
} buffer;
|
||||||
|
|
||||||
|
struct TestOStream : std::ostream {
|
||||||
|
explicit TestOStream(MockStreamBuf &buffer) : std::ostream(&buffer) {}
|
||||||
|
} os(buffer);
|
||||||
|
|
||||||
|
testing::InSequence sequence;
|
||||||
|
const char *data = 0;
|
||||||
|
std::size_t size = max_size;
|
||||||
|
do {
|
||||||
|
typedef fmt::internal::MakeUnsigned<std::streamsize>::Type UStreamSize;
|
||||||
|
UStreamSize n = std::min<UStreamSize>(
|
||||||
|
size, fmt::internal::to_unsigned(max_streamsize));
|
||||||
|
EXPECT_CALL(buffer, xsputn(data, static_cast<std::streamsize>(n)))
|
||||||
|
.WillOnce(testing::Return(max_streamsize));
|
||||||
|
data += n;
|
||||||
|
size -= static_cast<std::size_t>(n);
|
||||||
|
} while (size != 0);
|
||||||
|
fmt::write(os, w);
|
||||||
|
}
|
@ -447,10 +447,6 @@ TEST(PrintfTest, Pointer) {
|
|||||||
EXPECT_PRINTF("(nil)", "%p", null_str);
|
EXPECT_PRINTF("(nil)", "%p", null_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, Custom) {
|
|
||||||
EXPECT_PRINTF("abc", "%s", TestString("abc"));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(PrintfTest, Location) {
|
TEST(PrintfTest, Location) {
|
||||||
// TODO: test %n
|
// TODO: test %n
|
||||||
}
|
}
|
||||||
@ -479,12 +475,5 @@ TEST(PrintfTest, PrintfError) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST(PrintfTest, WideString) {
|
TEST(PrintfTest, WideString) {
|
||||||
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", TestWString(L"abc")));
|
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
|
||||||
}
|
|
||||||
|
|
||||||
TEST(PrintfTest, Iostream) {
|
|
||||||
std::ostringstream os;
|
|
||||||
int ret = fmt::fprintf(os, "Don't %s!", "panic");
|
|
||||||
EXPECT_EQ("Don't panic!", os.str());
|
|
||||||
EXPECT_EQ(12, ret);
|
|
||||||
}
|
}
|
||||||
|
@ -62,9 +62,10 @@ using testing::StrictMock;
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct Test {};
|
struct Test {};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
std::basic_ostream<Char> &operator<<(std::basic_ostream<Char> &os, Test) {
|
void format(fmt::BasicFormatter<Char> &f, const Char *, Test) {
|
||||||
return os << "test";
|
f.writer() << "test";
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
@ -914,14 +915,11 @@ TEST(UtilTest, ReportWindowsError) {
|
|||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
enum TestEnum2 {};
|
enum TestEnum2 {};
|
||||||
enum TestEnum3 {};
|
|
||||||
std::ostream &operator<<(std::ostream &, TestEnum3);
|
|
||||||
|
|
||||||
TEST(UtilTest, ConvertToInt) {
|
TEST(UtilTest, ConvertToInt) {
|
||||||
EXPECT_TRUE(fmt::internal::ConvertToInt<char>::enable_conversion);
|
EXPECT_TRUE(fmt::internal::ConvertToInt<char>::enable_conversion);
|
||||||
EXPECT_FALSE(fmt::internal::ConvertToInt<const char *>::enable_conversion);
|
EXPECT_FALSE(fmt::internal::ConvertToInt<const char *>::enable_conversion);
|
||||||
EXPECT_TRUE(fmt::internal::ConvertToInt<TestEnum2>::value);
|
EXPECT_TRUE(fmt::internal::ConvertToInt<TestEnum2>::value);
|
||||||
EXPECT_FALSE(fmt::internal::ConvertToInt<TestEnum3>::value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_ENUM_BASE
|
#if FMT_USE_ENUM_BASE
|
||||||
|
16
test/util.h
16
test/util.h
@ -78,11 +78,7 @@ class BasicTestString {
|
|||||||
public:
|
public:
|
||||||
explicit BasicTestString(const Char *value = EMPTY) : value_(value) {}
|
explicit BasicTestString(const Char *value = EMPTY) : value_(value) {}
|
||||||
|
|
||||||
friend std::basic_ostream<Char> &operator<<(
|
const std::basic_string<Char> &value() const { return value_; }
|
||||||
std::basic_ostream<Char> &os, const BasicTestString &s) {
|
|
||||||
os << s.value_;
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -90,3 +86,13 @@ const Char BasicTestString<Char>::EMPTY[] = {0};
|
|||||||
|
|
||||||
typedef BasicTestString<char> TestString;
|
typedef BasicTestString<char> TestString;
|
||||||
typedef BasicTestString<wchar_t> TestWString;
|
typedef BasicTestString<wchar_t> TestWString;
|
||||||
|
|
||||||
|
class Date {
|
||||||
|
int year_, month_, day_;
|
||||||
|
public:
|
||||||
|
Date(int year, int month, int day) : year_(year), month_(month), day_(day) {}
|
||||||
|
|
||||||
|
int year() const { return year_; }
|
||||||
|
int month() const { return month_; }
|
||||||
|
int day() const { return day_; }
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user